From 0ced98e71d2e0be1996a88631a5e6470c16ffae6 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 2 Feb 2004 07:29:28 +0000 Subject: [PATCH 1/1] Bring GNU binutils-2.14. This commit is an exact copy of the contents of binutils-2.14.tar.gz. No files have been modified. Files that we do not currently used have been deleted and two files, README.DRAGONFLY and README.DELETED have been added. --- contrib/binutils-2.14/COPYING | 340 + contrib/binutils-2.14/COPYING.LIB | 482 + contrib/binutils-2.14/README | 47 + contrib/binutils-2.14/README.DELETED | 5093 ++++++++ contrib/binutils-2.14/README.DRAGONFLY | 60 + contrib/binutils-2.14/bfd/COPYING | 340 + contrib/binutils-2.14/bfd/MAINTAINERS | 1 + contrib/binutils-2.14/bfd/PORTING | 83 + contrib/binutils-2.14/bfd/README | 49 + contrib/binutils-2.14/bfd/TODO | 25 + contrib/binutils-2.14/bfd/archive.c | 2237 ++++ contrib/binutils-2.14/bfd/archive64.c | 245 + contrib/binutils-2.14/bfd/archures.c | 1148 ++ contrib/binutils-2.14/bfd/bfd-in2.h | 4442 +++++++ contrib/binutils-2.14/bfd/bfd.c | 1441 +++ contrib/binutils-2.14/bfd/bfdio.c | 436 + contrib/binutils-2.14/bfd/binary.c | 400 + contrib/binutils-2.14/bfd/cache.c | 374 + contrib/binutils-2.14/bfd/coffgen.c | 2498 ++++ contrib/binutils-2.14/bfd/config.bfd | 1275 ++ contrib/binutils-2.14/bfd/corefile.c | 105 + contrib/binutils-2.14/bfd/cpu-i386.c | 101 + contrib/binutils-2.14/bfd/doc/bfdsumm.texi | 148 + contrib/binutils-2.14/bfd/dwarf1.c | 586 + contrib/binutils-2.14/bfd/dwarf2.c | 2005 +++ contrib/binutils-2.14/bfd/elf-bfd.h | 1664 +++ contrib/binutils-2.14/bfd/elf-eh-frame.c | 1189 ++ contrib/binutils-2.14/bfd/elf-strtab.c | 450 + contrib/binutils-2.14/bfd/elf.c | 7537 +++++++++++ contrib/binutils-2.14/bfd/elf32-i386.c | 3435 +++++ contrib/binutils-2.14/bfd/elf32.c | 22 + contrib/binutils-2.14/bfd/elf64-gen.c | 105 + contrib/binutils-2.14/bfd/elf64-x86-64.c | 2947 +++++ contrib/binutils-2.14/bfd/elf64.c | 22 + contrib/binutils-2.14/bfd/elfcode.h | 1605 +++ contrib/binutils-2.14/bfd/elfcore.h | 259 + contrib/binutils-2.14/bfd/elflink.c | 652 + contrib/binutils-2.14/bfd/elflink.h | 8745 +++++++++++++ contrib/binutils-2.14/bfd/elfxx-target.h | 714 ++ contrib/binutils-2.14/bfd/format.c | 444 + contrib/binutils-2.14/bfd/genlink.h | 111 + contrib/binutils-2.14/bfd/hash.c | 735 ++ contrib/binutils-2.14/bfd/ihex.c | 1052 ++ contrib/binutils-2.14/bfd/init.c | 51 + contrib/binutils-2.14/bfd/libaout.h | 694 + contrib/binutils-2.14/bfd/libbfd.c | 924 ++ contrib/binutils-2.14/bfd/libbfd.h | 1532 +++ contrib/binutils-2.14/bfd/libcoff.h | 933 ++ contrib/binutils-2.14/bfd/libecoff.h | 362 + contrib/binutils-2.14/bfd/linker.c | 2910 +++++ contrib/binutils-2.14/bfd/merge.c | 954 ++ contrib/binutils-2.14/bfd/opncls.c | 1039 ++ contrib/binutils-2.14/bfd/reloc.c | 4188 ++++++ contrib/binutils-2.14/bfd/section.c | 1391 ++ contrib/binutils-2.14/bfd/simple.c | 292 + contrib/binutils-2.14/bfd/srec.c | 1403 ++ contrib/binutils-2.14/bfd/stab-syms.c | 58 + contrib/binutils-2.14/bfd/stabs.c | 836 ++ contrib/binutils-2.14/bfd/syms.c | 1385 ++ contrib/binutils-2.14/bfd/sysdep.h | 164 + contrib/binutils-2.14/bfd/targets.c | 1350 ++ contrib/binutils-2.14/bfd/targmatch.sed | 33 + contrib/binutils-2.14/bfd/tekhex.c | 1068 ++ contrib/binutils-2.14/bfd/version.h | 3 + contrib/binutils-2.14/binutils/MAINTAINERS | 163 + contrib/binutils-2.14/binutils/NEWS | 249 + contrib/binutils-2.14/binutils/README | 216 + contrib/binutils-2.14/binutils/addr2line.c | 355 + contrib/binutils-2.14/binutils/ar.c | 1438 +++ contrib/binutils-2.14/binutils/arlex.l | 91 + contrib/binutils-2.14/binutils/arparse.h | 35 + contrib/binutils-2.14/binutils/arparse.y | 203 + contrib/binutils-2.14/binutils/arsup.c | 496 + contrib/binutils-2.14/binutils/arsup.h | 61 + contrib/binutils-2.14/binutils/binemul.c | 165 + contrib/binutils-2.14/binutils/binemul.h | 74 + contrib/binutils-2.14/binutils/bucomm.c | 470 + contrib/binutils-2.14/binutils/bucomm.h | 214 + contrib/binutils-2.14/binutils/budbg.h | 65 + contrib/binutils-2.14/binutils/budemang.c | 77 + contrib/binutils-2.14/binutils/budemang.h | 25 + contrib/binutils-2.14/binutils/debug.c | 3555 +++++ contrib/binutils-2.14/binutils/debug.h | 801 ++ .../binutils-2.14/binutils/doc/addr2line.1 | 230 + contrib/binutils-2.14/binutils/doc/ar.1 | 377 + .../binutils-2.14/binutils/doc/binutils.texi | 3482 +++++ contrib/binutils-2.14/binutils/doc/nm.1 | 426 + contrib/binutils-2.14/binutils/doc/objcopy.1 | 638 + contrib/binutils-2.14/binutils/doc/objdump.1 | 580 + contrib/binutils-2.14/binutils/doc/ranlib.1 | 175 + contrib/binutils-2.14/binutils/doc/readelf.1 | 348 + contrib/binutils-2.14/binutils/doc/size.1 | 250 + contrib/binutils-2.14/binutils/doc/strings.1 | 236 + contrib/binutils-2.14/binutils/doc/strip.1 | 289 + contrib/binutils-2.14/binutils/emul_vanilla.c | 30 + contrib/binutils-2.14/binutils/filemode.c | 267 + contrib/binutils-2.14/binutils/ieee.c | 7675 +++++++++++ contrib/binutils-2.14/binutils/is-ranlib.c | 3 + contrib/binutils-2.14/binutils/is-strip.c | 4 + contrib/binutils-2.14/binutils/nm.c | 1708 +++ contrib/binutils-2.14/binutils/not-ranlib.c | 3 + contrib/binutils-2.14/binutils/not-strip.c | 4 + contrib/binutils-2.14/binutils/objcopy.c | 2850 ++++ contrib/binutils-2.14/binutils/objdump.c | 2809 ++++ contrib/binutils-2.14/binutils/prdbg.c | 1896 +++ contrib/binutils-2.14/binutils/rdcoff.c | 908 ++ contrib/binutils-2.14/binutils/rddbg.c | 463 + contrib/binutils-2.14/binutils/readelf.c | 10694 ++++++++++++++++ contrib/binutils-2.14/binutils/rename.c | 221 + contrib/binutils-2.14/binutils/size.c | 592 + contrib/binutils-2.14/binutils/stabs.c | 5204 ++++++++ contrib/binutils-2.14/binutils/strings.c | 675 + contrib/binutils-2.14/binutils/unwind-ia64.c | 1129 ++ contrib/binutils-2.14/binutils/unwind-ia64.h | 31 + contrib/binutils-2.14/binutils/version.c | 41 + contrib/binutils-2.14/binutils/wrstabs.c | 2442 ++++ contrib/binutils-2.14/gas/CONTRIBUTORS | 110 + contrib/binutils-2.14/gas/COPYING | 340 + contrib/binutils-2.14/gas/MAINTAINERS | 1 + contrib/binutils-2.14/gas/NEWS | 386 + contrib/binutils-2.14/gas/README | 278 + contrib/binutils-2.14/gas/app.c | 1348 ++ contrib/binutils-2.14/gas/as.c | 1123 ++ contrib/binutils-2.14/gas/as.h | 691 + contrib/binutils-2.14/gas/asintl.h | 43 + contrib/binutils-2.14/gas/atof-generic.c | 634 + contrib/binutils-2.14/gas/bignum-copy.c | 81 + contrib/binutils-2.14/gas/bignum.h | 52 + contrib/binutils-2.14/gas/bit_fix.h | 48 + contrib/binutils-2.14/gas/cond.c | 554 + contrib/binutils-2.14/gas/config/atof-ieee.c | 734 ++ contrib/binutils-2.14/gas/config/obj-elf.c | 2366 ++++ contrib/binutils-2.14/gas/config/obj-elf.h | 243 + contrib/binutils-2.14/gas/config/tc-i386.c | 6301 +++++++++ contrib/binutils-2.14/gas/config/tc-i386.h | 548 + contrib/binutils-2.14/gas/depend.c | 213 + contrib/binutils-2.14/gas/doc/as.info | 480 + contrib/binutils-2.14/gas/doc/as.texinfo | 6412 +++++++++ contrib/binutils-2.14/gas/doc/c-i386.texi | 750 ++ contrib/binutils-2.14/gas/doc/fdl.texi | 367 + contrib/binutils-2.14/gas/dwarf2dbg.c | 1539 +++ contrib/binutils-2.14/gas/dwarf2dbg.h | 85 + contrib/binutils-2.14/gas/ecoff.c | 5292 ++++++++ contrib/binutils-2.14/gas/ecoff.h | 111 + contrib/binutils-2.14/gas/ehopt.c | 546 + contrib/binutils-2.14/gas/expr.c | 1926 +++ contrib/binutils-2.14/gas/expr.h | 172 + contrib/binutils-2.14/gas/flonum-copy.c | 73 + contrib/binutils-2.14/gas/flonum-konst.c | 228 + contrib/binutils-2.14/gas/flonum-mult.c | 190 + contrib/binutils-2.14/gas/flonum.h | 102 + contrib/binutils-2.14/gas/frags.c | 385 + contrib/binutils-2.14/gas/frags.h | 163 + contrib/binutils-2.14/gas/hash.c | 598 + contrib/binutils-2.14/gas/hash.h | 78 + contrib/binutils-2.14/gas/input-file.c | 253 + contrib/binutils-2.14/gas/input-file.h | 66 + contrib/binutils-2.14/gas/input-scrub.c | 529 + contrib/binutils-2.14/gas/listing.c | 1404 ++ contrib/binutils-2.14/gas/listing.h | 67 + contrib/binutils-2.14/gas/literal.c | 95 + contrib/binutils-2.14/gas/macro.c | 1230 ++ contrib/binutils-2.14/gas/macro.h | 88 + contrib/binutils-2.14/gas/messages.c | 519 + contrib/binutils-2.14/gas/obj.h | 94 + contrib/binutils-2.14/gas/output-file.c | 154 + contrib/binutils-2.14/gas/output-file.h | 26 + contrib/binutils-2.14/gas/read.c | 5346 ++++++++ contrib/binutils-2.14/gas/read.h | 187 + contrib/binutils-2.14/gas/sb.c | 291 + contrib/binutils-2.14/gas/sb.h | 99 + contrib/binutils-2.14/gas/stabs.c | 713 ++ contrib/binutils-2.14/gas/struc-symbol.h | 159 + contrib/binutils-2.14/gas/subsegs.c | 658 + contrib/binutils-2.14/gas/subsegs.h | 155 + contrib/binutils-2.14/gas/symbols.c | 2664 ++++ contrib/binutils-2.14/gas/symbols.h | 207 + contrib/binutils-2.14/gas/tc.h | 110 + contrib/binutils-2.14/gas/write.c | 2897 +++++ contrib/binutils-2.14/gas/write.h | 216 + contrib/binutils-2.14/gprof/MAINTAINERS | 1 + contrib/binutils-2.14/gprof/README | 442 + contrib/binutils-2.14/gprof/TEST | 7 + contrib/binutils-2.14/gprof/TODO | 69 + contrib/binutils-2.14/include/COPYING | 340 + contrib/binutils-2.14/include/MAINTAINERS | 1 + contrib/binutils-2.14/include/ansidecl.h | 326 + contrib/binutils-2.14/include/aout/aout64.h | 519 + contrib/binutils-2.14/include/aout/ar.h | 52 + contrib/binutils-2.14/include/aout/ranlib.h | 62 + contrib/binutils-2.14/include/aout/stab.def | 268 + contrib/binutils-2.14/include/aout/stab_gnu.h | 54 + contrib/binutils-2.14/include/bfdlink.h | 646 + contrib/binutils-2.14/include/bin-bugs.h | 3 + contrib/binutils-2.14/include/coff/ecoff.h | 437 + contrib/binutils-2.14/include/coff/internal.h | 741 ++ contrib/binutils-2.14/include/coff/sym.h | 484 + contrib/binutils-2.14/include/demangle.h | 163 + contrib/binutils-2.14/include/dis-asm.h | 328 + contrib/binutils-2.14/include/dyn-string.h | 92 + contrib/binutils-2.14/include/elf/alpha.h | 126 + contrib/binutils-2.14/include/elf/arc.h | 56 + contrib/binutils-2.14/include/elf/arm.h | 146 + contrib/binutils-2.14/include/elf/avr.h | 58 + contrib/binutils-2.14/include/elf/common.h | 690 + contrib/binutils-2.14/include/elf/cris.h | 101 + contrib/binutils-2.14/include/elf/d10v.h | 38 + contrib/binutils-2.14/include/elf/d30v.h | 42 + contrib/binutils-2.14/include/elf/dlx.h | 53 + contrib/binutils-2.14/include/elf/dwarf.h | 320 + contrib/binutils-2.14/include/elf/dwarf2.h | 728 ++ contrib/binutils-2.14/include/elf/external.h | 261 + contrib/binutils-2.14/include/elf/fr30.h | 42 + contrib/binutils-2.14/include/elf/frv.h | 95 + contrib/binutils-2.14/include/elf/h8.h | 98 + contrib/binutils-2.14/include/elf/hppa.h | 552 + contrib/binutils-2.14/include/elf/i370.h | 68 + contrib/binutils-2.14/include/elf/i386.h | 70 + contrib/binutils-2.14/include/elf/i860.h | 66 + contrib/binutils-2.14/include/elf/i960.h | 37 + contrib/binutils-2.14/include/elf/ia64.h | 216 + contrib/binutils-2.14/include/elf/internal.h | 247 + contrib/binutils-2.14/include/elf/ip2k.h | 62 + contrib/binutils-2.14/include/elf/iq2000.h | 58 + contrib/binutils-2.14/include/elf/m32r.h | 67 + contrib/binutils-2.14/include/elf/m68hc11.h | 95 + contrib/binutils-2.14/include/elf/m68k.h | 58 + contrib/binutils-2.14/include/elf/mcore.h | 46 + contrib/binutils-2.14/include/elf/mips.h | 972 ++ contrib/binutils-2.14/include/elf/mmix.h | 168 + contrib/binutils-2.14/include/elf/mn10200.h | 39 + contrib/binutils-2.14/include/elf/mn10300.h | 53 + contrib/binutils-2.14/include/elf/msp430.h | 55 + contrib/binutils-2.14/include/elf/or32.h | 62 + contrib/binutils-2.14/include/elf/pj.h | 44 + contrib/binutils-2.14/include/elf/ppc.h | 159 + contrib/binutils-2.14/include/elf/ppc64.h | 156 + .../binutils-2.14/include/elf/reloc-macros.h | 106 + contrib/binutils-2.14/include/elf/s390.h | 120 + contrib/binutils-2.14/include/elf/sh.h | 190 + contrib/binutils-2.14/include/elf/sparc.h | 175 + contrib/binutils-2.14/include/elf/v850.h | 107 + contrib/binutils-2.14/include/elf/vax.h | 51 + contrib/binutils-2.14/include/elf/x86-64.h | 56 + contrib/binutils-2.14/include/elf/xstormy16.h | 57 + contrib/binutils-2.14/include/elf/xtensa.h | 87 + contrib/binutils-2.14/include/filenames.h | 51 + contrib/binutils-2.14/include/floatformat.h | 121 + contrib/binutils-2.14/include/fnmatch.h | 70 + contrib/binutils-2.14/include/fopen-same.h | 27 + contrib/binutils-2.14/include/getopt.h | 144 + contrib/binutils-2.14/include/hashtab.h | 190 + contrib/binutils-2.14/include/ieee.h | 165 + contrib/binutils-2.14/include/libiberty.h | 335 + contrib/binutils-2.14/include/mpw/README | 1 + contrib/binutils-2.14/include/objalloc.h | 115 + contrib/binutils-2.14/include/obstack.h | 599 + contrib/binutils-2.14/include/opcode/i386.h | 1565 +++ contrib/binutils-2.14/include/progress.h | 37 + contrib/binutils-2.14/include/safe-ctype.h | 103 + contrib/binutils-2.14/include/symcat.h | 49 + contrib/binutils-2.14/ld/MAINTAINERS | 1 + contrib/binutils-2.14/ld/NEWS | 281 + contrib/binutils-2.14/ld/README | 67 + contrib/binutils-2.14/ld/TODO | 9 + .../binutils-2.14/ld/emulparams/elf_i386.sh | 12 + .../binutils-2.14/ld/emulparams/elf_x86_64.sh | 30 + .../binutils-2.14/ld/emultempl/astring.sed | 13 + contrib/binutils-2.14/ld/emultempl/elf32.em | 1779 +++ contrib/binutils-2.14/ld/gen-doc.texi | 20 + contrib/binutils-2.14/ld/genscripts.sh | 237 + contrib/binutils-2.14/ld/ld.1 | 1816 +++ contrib/binutils-2.14/ld/ld.h | 252 + contrib/binutils-2.14/ld/ld.texinfo | 5599 ++++++++ contrib/binutils-2.14/ld/ldcref.c | 570 + contrib/binutils-2.14/ld/ldctor.c | 383 + contrib/binutils-2.14/ld/ldctor.h | 60 + contrib/binutils-2.14/ld/ldemul.c | 341 + contrib/binutils-2.14/ld/ldemul.h | 197 + contrib/binutils-2.14/ld/ldexp.c | 1185 ++ contrib/binutils-2.14/ld/ldexp.h | 144 + contrib/binutils-2.14/ld/ldfile.c | 625 + contrib/binutils-2.14/ld/ldfile.h | 64 + contrib/binutils-2.14/ld/ldgram.y | 1184 ++ contrib/binutils-2.14/ld/ldlang.c | 5419 ++++++++ contrib/binutils-2.14/ld/ldlang.h | 527 + contrib/binutils-2.14/ld/ldlex.h | 63 + contrib/binutils-2.14/ld/ldlex.l | 688 + contrib/binutils-2.14/ld/ldmain.c | 1451 +++ contrib/binutils-2.14/ld/ldmain.h | 44 + contrib/binutils-2.14/ld/ldmisc.c | 519 + contrib/binutils-2.14/ld/ldmisc.h | 46 + contrib/binutils-2.14/ld/ldver.c | 60 + contrib/binutils-2.14/ld/ldver.h | 20 + contrib/binutils-2.14/ld/ldwrite.c | 551 + contrib/binutils-2.14/ld/ldwrite.h | 20 + contrib/binutils-2.14/ld/lexsup.c | 1348 ++ contrib/binutils-2.14/ld/mri.c | 366 + contrib/binutils-2.14/ld/mri.h | 39 + contrib/binutils-2.14/ld/scripttempl/elf.sc | 399 + contrib/binutils-2.14/ld/sysdep.h | 97 + contrib/binutils-2.14/libiberty/COPYING.LIB | 504 + contrib/binutils-2.14/libiberty/README | 66 + contrib/binutils-2.14/libiberty/argv.c | 355 + contrib/binutils-2.14/libiberty/basename.c | 60 + contrib/binutils-2.14/libiberty/choose-temp.c | 72 + contrib/binutils-2.14/libiberty/concat.c | 236 + contrib/binutils-2.14/libiberty/cp-demangle.c | 4199 ++++++ contrib/binutils-2.14/libiberty/cplus-dem.c | 4891 +++++++ contrib/binutils-2.14/libiberty/dyn-string.c | 442 + contrib/binutils-2.14/libiberty/floatformat.c | 452 + contrib/binutils-2.14/libiberty/getopt.c | 1056 ++ contrib/binutils-2.14/libiberty/getopt1.c | 190 + contrib/binutils-2.14/libiberty/getpwd.c | 127 + contrib/binutils-2.14/libiberty/getruntime.c | 116 + contrib/binutils-2.14/libiberty/hashtab.c | 711 + contrib/binutils-2.14/libiberty/hex.c | 180 + contrib/binutils-2.14/libiberty/lbasename.c | 80 + contrib/binutils-2.14/libiberty/lrealpath.c | 128 + .../libiberty/make-relative-prefix.c | 396 + .../binutils-2.14/libiberty/make-temp-file.c | 179 + contrib/binutils-2.14/libiberty/objalloc.c | 298 + contrib/binutils-2.14/libiberty/obstack.c | 593 + contrib/binutils-2.14/libiberty/safe-ctype.c | 163 + contrib/binutils-2.14/libiberty/xatexit.c | 101 + contrib/binutils-2.14/libiberty/xexit.c | 53 + contrib/binutils-2.14/libiberty/xmalloc.c | 183 + contrib/binutils-2.14/libiberty/xstrdup.c | 34 + contrib/binutils-2.14/libiberty/xstrerror.c | 67 + contrib/binutils-2.14/opcodes/MAINTAINERS | 1 + contrib/binutils-2.14/opcodes/dis-buf.c | 118 + contrib/binutils-2.14/opcodes/disassemble.c | 396 + contrib/binutils-2.14/opcodes/i386-dis.c | 4146 ++++++ contrib/binutils-2.14/opcodes/opintl.h | 42 + contrib/binutils-2.14/opcodes/sysdep.h | 42 + 335 files changed, 249433 insertions(+) create mode 100644 contrib/binutils-2.14/COPYING create mode 100644 contrib/binutils-2.14/COPYING.LIB create mode 100644 contrib/binutils-2.14/README create mode 100644 contrib/binutils-2.14/README.DELETED create mode 100644 contrib/binutils-2.14/README.DRAGONFLY create mode 100644 contrib/binutils-2.14/bfd/COPYING create mode 100644 contrib/binutils-2.14/bfd/MAINTAINERS create mode 100644 contrib/binutils-2.14/bfd/PORTING create mode 100644 contrib/binutils-2.14/bfd/README create mode 100644 contrib/binutils-2.14/bfd/TODO create mode 100644 contrib/binutils-2.14/bfd/archive.c create mode 100644 contrib/binutils-2.14/bfd/archive64.c create mode 100644 contrib/binutils-2.14/bfd/archures.c create mode 100644 contrib/binutils-2.14/bfd/bfd-in2.h create mode 100644 contrib/binutils-2.14/bfd/bfd.c create mode 100644 contrib/binutils-2.14/bfd/bfdio.c create mode 100644 contrib/binutils-2.14/bfd/binary.c create mode 100644 contrib/binutils-2.14/bfd/cache.c create mode 100644 contrib/binutils-2.14/bfd/coffgen.c create mode 100644 contrib/binutils-2.14/bfd/config.bfd create mode 100644 contrib/binutils-2.14/bfd/corefile.c create mode 100644 contrib/binutils-2.14/bfd/cpu-i386.c create mode 100644 contrib/binutils-2.14/bfd/doc/bfdsumm.texi create mode 100644 contrib/binutils-2.14/bfd/dwarf1.c create mode 100644 contrib/binutils-2.14/bfd/dwarf2.c create mode 100644 contrib/binutils-2.14/bfd/elf-bfd.h create mode 100644 contrib/binutils-2.14/bfd/elf-eh-frame.c create mode 100644 contrib/binutils-2.14/bfd/elf-strtab.c create mode 100644 contrib/binutils-2.14/bfd/elf.c create mode 100644 contrib/binutils-2.14/bfd/elf32-i386.c create mode 100644 contrib/binutils-2.14/bfd/elf32.c create mode 100644 contrib/binutils-2.14/bfd/elf64-gen.c create mode 100644 contrib/binutils-2.14/bfd/elf64-x86-64.c create mode 100644 contrib/binutils-2.14/bfd/elf64.c create mode 100644 contrib/binutils-2.14/bfd/elfcode.h create mode 100644 contrib/binutils-2.14/bfd/elfcore.h create mode 100644 contrib/binutils-2.14/bfd/elflink.c create mode 100644 contrib/binutils-2.14/bfd/elflink.h create mode 100644 contrib/binutils-2.14/bfd/elfxx-target.h create mode 100644 contrib/binutils-2.14/bfd/format.c create mode 100644 contrib/binutils-2.14/bfd/genlink.h create mode 100644 contrib/binutils-2.14/bfd/hash.c create mode 100644 contrib/binutils-2.14/bfd/ihex.c create mode 100644 contrib/binutils-2.14/bfd/init.c create mode 100644 contrib/binutils-2.14/bfd/libaout.h create mode 100644 contrib/binutils-2.14/bfd/libbfd.c create mode 100644 contrib/binutils-2.14/bfd/libbfd.h create mode 100644 contrib/binutils-2.14/bfd/libcoff.h create mode 100644 contrib/binutils-2.14/bfd/libecoff.h create mode 100644 contrib/binutils-2.14/bfd/linker.c create mode 100644 contrib/binutils-2.14/bfd/merge.c create mode 100644 contrib/binutils-2.14/bfd/opncls.c create mode 100644 contrib/binutils-2.14/bfd/reloc.c create mode 100644 contrib/binutils-2.14/bfd/section.c create mode 100644 contrib/binutils-2.14/bfd/simple.c create mode 100644 contrib/binutils-2.14/bfd/srec.c create mode 100644 contrib/binutils-2.14/bfd/stab-syms.c create mode 100644 contrib/binutils-2.14/bfd/stabs.c create mode 100644 contrib/binutils-2.14/bfd/syms.c create mode 100644 contrib/binutils-2.14/bfd/sysdep.h create mode 100644 contrib/binutils-2.14/bfd/targets.c create mode 100644 contrib/binutils-2.14/bfd/targmatch.sed create mode 100644 contrib/binutils-2.14/bfd/tekhex.c create mode 100644 contrib/binutils-2.14/bfd/version.h create mode 100644 contrib/binutils-2.14/binutils/MAINTAINERS create mode 100644 contrib/binutils-2.14/binutils/NEWS create mode 100644 contrib/binutils-2.14/binutils/README create mode 100644 contrib/binutils-2.14/binutils/addr2line.c create mode 100644 contrib/binutils-2.14/binutils/ar.c create mode 100644 contrib/binutils-2.14/binutils/arlex.l create mode 100644 contrib/binutils-2.14/binutils/arparse.h create mode 100644 contrib/binutils-2.14/binutils/arparse.y create mode 100644 contrib/binutils-2.14/binutils/arsup.c create mode 100644 contrib/binutils-2.14/binutils/arsup.h create mode 100644 contrib/binutils-2.14/binutils/binemul.c create mode 100644 contrib/binutils-2.14/binutils/binemul.h create mode 100644 contrib/binutils-2.14/binutils/bucomm.c create mode 100644 contrib/binutils-2.14/binutils/bucomm.h create mode 100644 contrib/binutils-2.14/binutils/budbg.h create mode 100644 contrib/binutils-2.14/binutils/budemang.c create mode 100644 contrib/binutils-2.14/binutils/budemang.h create mode 100644 contrib/binutils-2.14/binutils/debug.c create mode 100644 contrib/binutils-2.14/binutils/debug.h create mode 100644 contrib/binutils-2.14/binutils/doc/addr2line.1 create mode 100644 contrib/binutils-2.14/binutils/doc/ar.1 create mode 100644 contrib/binutils-2.14/binutils/doc/binutils.texi create mode 100644 contrib/binutils-2.14/binutils/doc/nm.1 create mode 100644 contrib/binutils-2.14/binutils/doc/objcopy.1 create mode 100644 contrib/binutils-2.14/binutils/doc/objdump.1 create mode 100644 contrib/binutils-2.14/binutils/doc/ranlib.1 create mode 100644 contrib/binutils-2.14/binutils/doc/readelf.1 create mode 100644 contrib/binutils-2.14/binutils/doc/size.1 create mode 100644 contrib/binutils-2.14/binutils/doc/strings.1 create mode 100644 contrib/binutils-2.14/binutils/doc/strip.1 create mode 100644 contrib/binutils-2.14/binutils/emul_vanilla.c create mode 100644 contrib/binutils-2.14/binutils/filemode.c create mode 100644 contrib/binutils-2.14/binutils/ieee.c create mode 100644 contrib/binutils-2.14/binutils/is-ranlib.c create mode 100644 contrib/binutils-2.14/binutils/is-strip.c create mode 100644 contrib/binutils-2.14/binutils/nm.c create mode 100644 contrib/binutils-2.14/binutils/not-ranlib.c create mode 100644 contrib/binutils-2.14/binutils/not-strip.c create mode 100644 contrib/binutils-2.14/binutils/objcopy.c create mode 100644 contrib/binutils-2.14/binutils/objdump.c create mode 100644 contrib/binutils-2.14/binutils/prdbg.c create mode 100644 contrib/binutils-2.14/binutils/rdcoff.c create mode 100644 contrib/binutils-2.14/binutils/rddbg.c create mode 100644 contrib/binutils-2.14/binutils/readelf.c create mode 100644 contrib/binutils-2.14/binutils/rename.c create mode 100644 contrib/binutils-2.14/binutils/size.c create mode 100644 contrib/binutils-2.14/binutils/stabs.c create mode 100644 contrib/binutils-2.14/binutils/strings.c create mode 100644 contrib/binutils-2.14/binutils/unwind-ia64.c create mode 100644 contrib/binutils-2.14/binutils/unwind-ia64.h create mode 100644 contrib/binutils-2.14/binutils/version.c create mode 100644 contrib/binutils-2.14/binutils/wrstabs.c create mode 100644 contrib/binutils-2.14/gas/CONTRIBUTORS create mode 100644 contrib/binutils-2.14/gas/COPYING create mode 100644 contrib/binutils-2.14/gas/MAINTAINERS create mode 100644 contrib/binutils-2.14/gas/NEWS create mode 100644 contrib/binutils-2.14/gas/README create mode 100644 contrib/binutils-2.14/gas/app.c create mode 100644 contrib/binutils-2.14/gas/as.c create mode 100644 contrib/binutils-2.14/gas/as.h create mode 100644 contrib/binutils-2.14/gas/asintl.h create mode 100644 contrib/binutils-2.14/gas/atof-generic.c create mode 100644 contrib/binutils-2.14/gas/bignum-copy.c create mode 100644 contrib/binutils-2.14/gas/bignum.h create mode 100644 contrib/binutils-2.14/gas/bit_fix.h create mode 100644 contrib/binutils-2.14/gas/cond.c create mode 100644 contrib/binutils-2.14/gas/config/atof-ieee.c create mode 100644 contrib/binutils-2.14/gas/config/obj-elf.c create mode 100644 contrib/binutils-2.14/gas/config/obj-elf.h create mode 100644 contrib/binutils-2.14/gas/config/tc-i386.c create mode 100644 contrib/binutils-2.14/gas/config/tc-i386.h create mode 100644 contrib/binutils-2.14/gas/depend.c create mode 100644 contrib/binutils-2.14/gas/doc/as.info create mode 100644 contrib/binutils-2.14/gas/doc/as.texinfo create mode 100644 contrib/binutils-2.14/gas/doc/c-i386.texi create mode 100644 contrib/binutils-2.14/gas/doc/fdl.texi create mode 100644 contrib/binutils-2.14/gas/dwarf2dbg.c create mode 100644 contrib/binutils-2.14/gas/dwarf2dbg.h create mode 100644 contrib/binutils-2.14/gas/ecoff.c create mode 100644 contrib/binutils-2.14/gas/ecoff.h create mode 100644 contrib/binutils-2.14/gas/ehopt.c create mode 100644 contrib/binutils-2.14/gas/expr.c create mode 100644 contrib/binutils-2.14/gas/expr.h create mode 100644 contrib/binutils-2.14/gas/flonum-copy.c create mode 100644 contrib/binutils-2.14/gas/flonum-konst.c create mode 100644 contrib/binutils-2.14/gas/flonum-mult.c create mode 100644 contrib/binutils-2.14/gas/flonum.h create mode 100644 contrib/binutils-2.14/gas/frags.c create mode 100644 contrib/binutils-2.14/gas/frags.h create mode 100644 contrib/binutils-2.14/gas/hash.c create mode 100644 contrib/binutils-2.14/gas/hash.h create mode 100644 contrib/binutils-2.14/gas/input-file.c create mode 100644 contrib/binutils-2.14/gas/input-file.h create mode 100644 contrib/binutils-2.14/gas/input-scrub.c create mode 100644 contrib/binutils-2.14/gas/listing.c create mode 100644 contrib/binutils-2.14/gas/listing.h create mode 100644 contrib/binutils-2.14/gas/literal.c create mode 100644 contrib/binutils-2.14/gas/macro.c create mode 100644 contrib/binutils-2.14/gas/macro.h create mode 100644 contrib/binutils-2.14/gas/messages.c create mode 100644 contrib/binutils-2.14/gas/obj.h create mode 100644 contrib/binutils-2.14/gas/output-file.c create mode 100644 contrib/binutils-2.14/gas/output-file.h create mode 100644 contrib/binutils-2.14/gas/read.c create mode 100644 contrib/binutils-2.14/gas/read.h create mode 100644 contrib/binutils-2.14/gas/sb.c create mode 100644 contrib/binutils-2.14/gas/sb.h create mode 100644 contrib/binutils-2.14/gas/stabs.c create mode 100644 contrib/binutils-2.14/gas/struc-symbol.h create mode 100644 contrib/binutils-2.14/gas/subsegs.c create mode 100644 contrib/binutils-2.14/gas/subsegs.h create mode 100644 contrib/binutils-2.14/gas/symbols.c create mode 100644 contrib/binutils-2.14/gas/symbols.h create mode 100644 contrib/binutils-2.14/gas/tc.h create mode 100644 contrib/binutils-2.14/gas/write.c create mode 100644 contrib/binutils-2.14/gas/write.h create mode 100644 contrib/binutils-2.14/gprof/MAINTAINERS create mode 100644 contrib/binutils-2.14/gprof/README create mode 100644 contrib/binutils-2.14/gprof/TEST create mode 100644 contrib/binutils-2.14/gprof/TODO create mode 100644 contrib/binutils-2.14/include/COPYING create mode 100644 contrib/binutils-2.14/include/MAINTAINERS create mode 100644 contrib/binutils-2.14/include/ansidecl.h create mode 100644 contrib/binutils-2.14/include/aout/aout64.h create mode 100644 contrib/binutils-2.14/include/aout/ar.h create mode 100644 contrib/binutils-2.14/include/aout/ranlib.h create mode 100644 contrib/binutils-2.14/include/aout/stab.def create mode 100644 contrib/binutils-2.14/include/aout/stab_gnu.h create mode 100644 contrib/binutils-2.14/include/bfdlink.h create mode 100644 contrib/binutils-2.14/include/bin-bugs.h create mode 100644 contrib/binutils-2.14/include/coff/ecoff.h create mode 100644 contrib/binutils-2.14/include/coff/internal.h create mode 100644 contrib/binutils-2.14/include/coff/sym.h create mode 100644 contrib/binutils-2.14/include/demangle.h create mode 100644 contrib/binutils-2.14/include/dis-asm.h create mode 100644 contrib/binutils-2.14/include/dyn-string.h create mode 100644 contrib/binutils-2.14/include/elf/alpha.h create mode 100644 contrib/binutils-2.14/include/elf/arc.h create mode 100644 contrib/binutils-2.14/include/elf/arm.h create mode 100644 contrib/binutils-2.14/include/elf/avr.h create mode 100644 contrib/binutils-2.14/include/elf/common.h create mode 100644 contrib/binutils-2.14/include/elf/cris.h create mode 100644 contrib/binutils-2.14/include/elf/d10v.h create mode 100644 contrib/binutils-2.14/include/elf/d30v.h create mode 100644 contrib/binutils-2.14/include/elf/dlx.h create mode 100644 contrib/binutils-2.14/include/elf/dwarf.h create mode 100644 contrib/binutils-2.14/include/elf/dwarf2.h create mode 100644 contrib/binutils-2.14/include/elf/external.h create mode 100644 contrib/binutils-2.14/include/elf/fr30.h create mode 100644 contrib/binutils-2.14/include/elf/frv.h create mode 100644 contrib/binutils-2.14/include/elf/h8.h create mode 100644 contrib/binutils-2.14/include/elf/hppa.h create mode 100644 contrib/binutils-2.14/include/elf/i370.h create mode 100644 contrib/binutils-2.14/include/elf/i386.h create mode 100644 contrib/binutils-2.14/include/elf/i860.h create mode 100644 contrib/binutils-2.14/include/elf/i960.h create mode 100644 contrib/binutils-2.14/include/elf/ia64.h create mode 100644 contrib/binutils-2.14/include/elf/internal.h create mode 100644 contrib/binutils-2.14/include/elf/ip2k.h create mode 100644 contrib/binutils-2.14/include/elf/iq2000.h create mode 100644 contrib/binutils-2.14/include/elf/m32r.h create mode 100644 contrib/binutils-2.14/include/elf/m68hc11.h create mode 100644 contrib/binutils-2.14/include/elf/m68k.h create mode 100644 contrib/binutils-2.14/include/elf/mcore.h create mode 100644 contrib/binutils-2.14/include/elf/mips.h create mode 100644 contrib/binutils-2.14/include/elf/mmix.h create mode 100644 contrib/binutils-2.14/include/elf/mn10200.h create mode 100644 contrib/binutils-2.14/include/elf/mn10300.h create mode 100644 contrib/binutils-2.14/include/elf/msp430.h create mode 100644 contrib/binutils-2.14/include/elf/or32.h create mode 100644 contrib/binutils-2.14/include/elf/pj.h create mode 100644 contrib/binutils-2.14/include/elf/ppc.h create mode 100644 contrib/binutils-2.14/include/elf/ppc64.h create mode 100644 contrib/binutils-2.14/include/elf/reloc-macros.h create mode 100644 contrib/binutils-2.14/include/elf/s390.h create mode 100644 contrib/binutils-2.14/include/elf/sh.h create mode 100644 contrib/binutils-2.14/include/elf/sparc.h create mode 100644 contrib/binutils-2.14/include/elf/v850.h create mode 100644 contrib/binutils-2.14/include/elf/vax.h create mode 100644 contrib/binutils-2.14/include/elf/x86-64.h create mode 100644 contrib/binutils-2.14/include/elf/xstormy16.h create mode 100644 contrib/binutils-2.14/include/elf/xtensa.h create mode 100644 contrib/binutils-2.14/include/filenames.h create mode 100644 contrib/binutils-2.14/include/floatformat.h create mode 100644 contrib/binutils-2.14/include/fnmatch.h create mode 100644 contrib/binutils-2.14/include/fopen-same.h create mode 100644 contrib/binutils-2.14/include/getopt.h create mode 100644 contrib/binutils-2.14/include/hashtab.h create mode 100644 contrib/binutils-2.14/include/ieee.h create mode 100644 contrib/binutils-2.14/include/libiberty.h create mode 100644 contrib/binutils-2.14/include/mpw/README create mode 100644 contrib/binutils-2.14/include/objalloc.h create mode 100644 contrib/binutils-2.14/include/obstack.h create mode 100644 contrib/binutils-2.14/include/opcode/i386.h create mode 100644 contrib/binutils-2.14/include/progress.h create mode 100644 contrib/binutils-2.14/include/safe-ctype.h create mode 100644 contrib/binutils-2.14/include/symcat.h create mode 100644 contrib/binutils-2.14/ld/MAINTAINERS create mode 100644 contrib/binutils-2.14/ld/NEWS create mode 100644 contrib/binutils-2.14/ld/README create mode 100644 contrib/binutils-2.14/ld/TODO create mode 100644 contrib/binutils-2.14/ld/emulparams/elf_i386.sh create mode 100644 contrib/binutils-2.14/ld/emulparams/elf_x86_64.sh create mode 100644 contrib/binutils-2.14/ld/emultempl/astring.sed create mode 100644 contrib/binutils-2.14/ld/emultempl/elf32.em create mode 100644 contrib/binutils-2.14/ld/gen-doc.texi create mode 100644 contrib/binutils-2.14/ld/genscripts.sh create mode 100644 contrib/binutils-2.14/ld/ld.1 create mode 100644 contrib/binutils-2.14/ld/ld.h create mode 100644 contrib/binutils-2.14/ld/ld.texinfo create mode 100644 contrib/binutils-2.14/ld/ldcref.c create mode 100644 contrib/binutils-2.14/ld/ldctor.c create mode 100644 contrib/binutils-2.14/ld/ldctor.h create mode 100644 contrib/binutils-2.14/ld/ldemul.c create mode 100644 contrib/binutils-2.14/ld/ldemul.h create mode 100644 contrib/binutils-2.14/ld/ldexp.c create mode 100644 contrib/binutils-2.14/ld/ldexp.h create mode 100644 contrib/binutils-2.14/ld/ldfile.c create mode 100644 contrib/binutils-2.14/ld/ldfile.h create mode 100644 contrib/binutils-2.14/ld/ldgram.y create mode 100644 contrib/binutils-2.14/ld/ldlang.c create mode 100644 contrib/binutils-2.14/ld/ldlang.h create mode 100644 contrib/binutils-2.14/ld/ldlex.h create mode 100644 contrib/binutils-2.14/ld/ldlex.l create mode 100644 contrib/binutils-2.14/ld/ldmain.c create mode 100644 contrib/binutils-2.14/ld/ldmain.h create mode 100644 contrib/binutils-2.14/ld/ldmisc.c create mode 100644 contrib/binutils-2.14/ld/ldmisc.h create mode 100644 contrib/binutils-2.14/ld/ldver.c create mode 100644 contrib/binutils-2.14/ld/ldver.h create mode 100644 contrib/binutils-2.14/ld/ldwrite.c create mode 100644 contrib/binutils-2.14/ld/ldwrite.h create mode 100644 contrib/binutils-2.14/ld/lexsup.c create mode 100644 contrib/binutils-2.14/ld/mri.c create mode 100644 contrib/binutils-2.14/ld/mri.h create mode 100644 contrib/binutils-2.14/ld/scripttempl/elf.sc create mode 100644 contrib/binutils-2.14/ld/sysdep.h create mode 100644 contrib/binutils-2.14/libiberty/COPYING.LIB create mode 100644 contrib/binutils-2.14/libiberty/README create mode 100644 contrib/binutils-2.14/libiberty/argv.c create mode 100644 contrib/binutils-2.14/libiberty/basename.c create mode 100644 contrib/binutils-2.14/libiberty/choose-temp.c create mode 100644 contrib/binutils-2.14/libiberty/concat.c create mode 100644 contrib/binutils-2.14/libiberty/cp-demangle.c create mode 100644 contrib/binutils-2.14/libiberty/cplus-dem.c create mode 100644 contrib/binutils-2.14/libiberty/dyn-string.c create mode 100644 contrib/binutils-2.14/libiberty/floatformat.c create mode 100644 contrib/binutils-2.14/libiberty/getopt.c create mode 100644 contrib/binutils-2.14/libiberty/getopt1.c create mode 100644 contrib/binutils-2.14/libiberty/getpwd.c create mode 100644 contrib/binutils-2.14/libiberty/getruntime.c create mode 100644 contrib/binutils-2.14/libiberty/hashtab.c create mode 100644 contrib/binutils-2.14/libiberty/hex.c create mode 100644 contrib/binutils-2.14/libiberty/lbasename.c create mode 100644 contrib/binutils-2.14/libiberty/lrealpath.c create mode 100644 contrib/binutils-2.14/libiberty/make-relative-prefix.c create mode 100644 contrib/binutils-2.14/libiberty/make-temp-file.c create mode 100644 contrib/binutils-2.14/libiberty/objalloc.c create mode 100644 contrib/binutils-2.14/libiberty/obstack.c create mode 100644 contrib/binutils-2.14/libiberty/safe-ctype.c create mode 100644 contrib/binutils-2.14/libiberty/xatexit.c create mode 100644 contrib/binutils-2.14/libiberty/xexit.c create mode 100644 contrib/binutils-2.14/libiberty/xmalloc.c create mode 100644 contrib/binutils-2.14/libiberty/xstrdup.c create mode 100644 contrib/binutils-2.14/libiberty/xstrerror.c create mode 100644 contrib/binutils-2.14/opcodes/MAINTAINERS create mode 100644 contrib/binutils-2.14/opcodes/dis-buf.c create mode 100644 contrib/binutils-2.14/opcodes/disassemble.c create mode 100644 contrib/binutils-2.14/opcodes/i386-dis.c create mode 100644 contrib/binutils-2.14/opcodes/opintl.h create mode 100644 contrib/binutils-2.14/opcodes/sysdep.h diff --git a/contrib/binutils-2.14/COPYING b/contrib/binutils-2.14/COPYING new file mode 100644 index 0000000000..60549be514 --- /dev/null +++ b/contrib/binutils-2.14/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/binutils-2.14/COPYING.LIB b/contrib/binutils-2.14/COPYING.LIB new file mode 100644 index 0000000000..161a3d1d47 --- /dev/null +++ b/contrib/binutils-2.14/COPYING.LIB @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if +you distribute copies of the library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, so that any problems introduced by others will not reflect on +the original authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the source code distributed need not include anything that is normally +distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/contrib/binutils-2.14/README b/contrib/binutils-2.14/README new file mode 100644 index 0000000000..eb0e436d86 --- /dev/null +++ b/contrib/binutils-2.14/README @@ -0,0 +1,47 @@ + 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/binutils-2.14/README.DELETED b/contrib/binutils-2.14/README.DELETED new file mode 100644 index 0000000000..d33bf0387b --- /dev/null +++ b/contrib/binutils-2.14/README.DELETED @@ -0,0 +1,5093 @@ +./binutils/doc/Makefile.am +./binutils/doc/Makefile.in +./binutils/doc/fdl.texi +./binutils/doc/binutils.info +./binutils/doc/binutils.info-1 +./binutils/doc/binutils.info-2 +./binutils/doc/binutils.info-3 +./binutils/doc/dlltool.1 +./binutils/doc/nlmconv.1 +./binutils/doc/windres.1 +./binutils/doc/cxxfilt.man +./binutils/po/.cvsignore +./binutils/po/Make-in +./binutils/po/POTFILES.in +./binutils/po/binutils.pot +./binutils/po/da.po +./binutils/po/es.po +./binutils/po/fr.po +./binutils/po/ja.po +./binutils/po/sv.po +./binutils/po/tr.po +./binutils/po/da.gmo +./binutils/po/es.gmo +./binutils/po/fr.gmo +./binutils/po/ja.gmo +./binutils/po/sv.gmo +./binutils/po/tr.gmo +./binutils/po/zh_CN.gmo +./binutils/po/zh_CN.po +./binutils/ChangeLog +./binutils/ChangeLog-9197 +./binutils/ChangeLog-9899 +./binutils/Makefile.am +./binutils/Makefile.in +./binutils/acinclude.m4 +./binutils/aclocal.m4 +./binutils/coffdump.c +./binutils/coffgrok.c +./binutils/coffgrok.h +./binutils/config.in +./binutils/configure +./binutils/configure.com +./binutils/configure.in +./binutils/configure.tgt +./binutils/cxxfilt.c +./binutils/deflex.l +./binutils/defparse.y +./binutils/dep-in.sed +./binutils/dlltool.c +./binutils/dlltool.h +./binutils/dllwrap.c +./binutils/emul_aix.c +./binutils/mac-binutils.r +./binutils/makefile.vms-in +./binutils/nlmconv.c +./binutils/maybe-ranlib.c +./binutils/maybe-strip.c +./binutils/mpw-config.in +./binutils/mpw-make.sed +./binutils/nlmconv.h +./binutils/nlmheader.y +./binutils/ranlib.sh +./binutils/rclex.l +./binutils/rcparse.y +./binutils/resbin.c +./binutils/rescoff.c +./binutils/resrc.c +./binutils/resres.c +./binutils/sanity.sh +./binutils/srconv.c +./binutils/stamp-h.in +./binutils/sysdump.c +./binutils/sysinfo.y +./binutils/syslex.l +./binutils/sysroff.info +./binutils/windres.c +./binutils/windres.h +./binutils/winduni.c +./binutils/winduni.h +./binutils/testsuite/binutils-all/bintest.s +./binutils/testsuite/binutils-all/ar.exp +./binutils/testsuite/binutils-all/hppa/addendbug.s +./binutils/testsuite/binutils-all/hppa/freg.s +./binutils/testsuite/binutils-all/hppa/objdump.exp +./binutils/testsuite/binutils-all/dlltool.exp +./binutils/testsuite/binutils-all/fastcall.def +./binutils/testsuite/binutils-all/nm.exp +./binutils/testsuite/binutils-all/objcopy.exp +./binutils/testsuite/binutils-all/objdump.exp +./binutils/testsuite/binutils-all/readelf.exp +./binutils/testsuite/binutils-all/readelf.h +./binutils/testsuite/binutils-all/readelf.r +./binutils/testsuite/binutils-all/readelf.r-64 +./binutils/testsuite/binutils-all/readelf.s +./binutils/testsuite/binutils-all/readelf.s-64 +./binutils/testsuite/binutils-all/readelf.ss +./binutils/testsuite/binutils-all/readelf.ss-64 +./binutils/testsuite/binutils-all/readelf.ss-mips +./binutils/testsuite/binutils-all/readelf.ss-tmips +./binutils/testsuite/binutils-all/size.exp +./binutils/testsuite/binutils-all/testprog.c +./binutils/testsuite/binutils-all/windres/bmp1.bmp +./binutils/testsuite/binutils-all/windres/README +./binutils/testsuite/binutils-all/windres/bmpalign.rc +./binutils/testsuite/binutils-all/windres/bmpalign.rsd +./binutils/testsuite/binutils-all/windres/capstyle.rc +./binutils/testsuite/binutils-all/windres/capstyle.rsd +./binutils/testsuite/binutils-all/windres/deflang.rc +./binutils/testsuite/binutils-all/windres/deflang.rsd +./binutils/testsuite/binutils-all/windres/dialog0.rc +./binutils/testsuite/binutils-all/windres/dialog0.rsd +./binutils/testsuite/binutils-all/windres/dialog1.rc +./binutils/testsuite/binutils-all/windres/dialog1.rsd +./binutils/testsuite/binutils-all/windres/dialogid.rc +./binutils/testsuite/binutils-all/windres/dialogid.rsd +./binutils/testsuite/binutils-all/windres/dialogsignature.rc +./binutils/testsuite/binutils-all/windres/dialogsignature.rsd +./binutils/testsuite/binutils-all/windres/dlgfont.rc +./binutils/testsuite/binutils-all/windres/dlgfont.rsd +./binutils/testsuite/binutils-all/windres/escapea.rc +./binutils/testsuite/binutils-all/windres/escapea.rsd +./binutils/testsuite/binutils-all/windres/escapex.rc +./binutils/testsuite/binutils-all/windres/escapex.rsd +./binutils/testsuite/binutils-all/windres/lang.rc +./binutils/testsuite/binutils-all/windres/lang.rsd +./binutils/testsuite/binutils-all/windres/msupdate +./binutils/testsuite/binutils-all/windres/nocaption.rc +./binutils/testsuite/binutils-all/windres/nocaption.rsd +./binutils/testsuite/binutils-all/windres/printstyle.rc +./binutils/testsuite/binutils-all/windres/printstyle.rsd +./binutils/testsuite/binutils-all/windres/quoteclass.rc +./binutils/testsuite/binutils-all/windres/strtab1.rc +./binutils/testsuite/binutils-all/windres/strtab1.rsd +./binutils/testsuite/binutils-all/windres/sublang.rc +./binutils/testsuite/binutils-all/windres/sublang.rsd +./binutils/testsuite/binutils-all/windres/windres.exp +./binutils/testsuite/ChangeLog +./binutils/testsuite/config/default.exp +./binutils/testsuite/config/hppa.sed +./binutils/testsuite/lib/utils-lib.exp +./binutils/arparse.c +./binutils/arlex.c +./binutils/nlmheader.c +./binutils/nlmheader.h +./binutils/sysinfo.c +./binutils/sysinfo.h +./binutils/syslex.c +./binutils/deflex.c +./binutils/defparse.c +./binutils/defparse.h +./binutils/rclex.c +./binutils/rcparse.c +./binutils/rcparse.h +./Makefile.in +./configure +./configure.in +./config.guess +./config.if +./config.sub +./config/ChangeLog +./config/accross.m4 +./config/acinclude.m4 +./config/acx.m4 +./config/mh-armpic +./config/mh-cxux +./config/mh-cygwin +./config/mh-decstation +./config/mh-dgux386 +./config/mh-djgpp +./config/mh-elfalphapic +./config/mh-i370pic +./config/mh-ia64pic +./config/mh-interix +./config/mh-lynxrs6k +./config/mh-m68kpic +./config/mh-mingw32 +./config/mh-ncr3000 +./config/mh-necv4 +./config/mh-papic +./config/mh-ppcpic +./config/mh-s390pic +./config/mh-sco +./config/mh-solaris +./config/mh-sparcpic +./config/mh-sysv4 +./config/mh-sysv5 +./config/mh-x86pic +./config/mt-alphaieee +./config/mt-d30v +./config/mt-linux +./config/mt-netware +./config/mt-ospace +./config/mt-v810 +./config/mt-wince +./move-if-change +./mpw-README +./mpw-build.in +./mpw-config.in +./mpw-configure +./mpw-install +./install-sh +./config-ml.in +./symlink-tree +./mkinstalldirs +./ltconfig +./ltmain.sh +./missing +./ylwrap +./libtool.m4 +./gettext.m4 +./ltcf-c.sh +./ltcf-cxx.sh +./ltcf-gcj.sh +./Makefile.def +./Makefile.tpl +./src-release +./bfd/ChangeLog +./bfd/doc/ChangeLog +./bfd/doc/Makefile.am +./bfd/doc/Makefile.in +./bfd/doc/bfd.texinfo +./bfd/doc/bfdint.texi +./bfd/doc/chew.c +./bfd/doc/doc.str +./bfd/doc/fdl.texi +./bfd/doc/header.sed +./bfd/doc/makefile.vms +./bfd/doc/proto.str +./bfd/doc/aoutx.texi +./bfd/doc/archive.texi +./bfd/doc/archures.texi +./bfd/doc/bfdt.texi +./bfd/doc/cache.texi +./bfd/doc/coffcode.texi +./bfd/doc/core.texi +./bfd/doc/elf.texi +./bfd/doc/elfcode.texi +./bfd/doc/format.texi +./bfd/doc/libbfd.texi +./bfd/doc/bfdwin.texi +./bfd/doc/bfdio.texi +./bfd/doc/opncls.texi +./bfd/doc/reloc.texi +./bfd/doc/section.texi +./bfd/doc/syms.texi +./bfd/doc/targets.texi +./bfd/doc/init.texi +./bfd/doc/hash.texi +./bfd/doc/linker.texi +./bfd/doc/mmo.texi +./bfd/doc/bfd.info +./bfd/doc/bfd.info-1 +./bfd/doc/bfd.info-2 +./bfd/doc/bfd.info-3 +./bfd/doc/bfd.info-4 +./bfd/doc/bfd.info-5 +./bfd/doc/bfd.info-6 +./bfd/doc/bfd.info-7 +./bfd/doc/bfd.info-8 +./bfd/doc/bfd.info-9 +./bfd/po/.cvsignore +./bfd/po/BLD-POTFILES.in +./bfd/po/Make-in +./bfd/po/SRC-POTFILES.in +./bfd/po/bfd.pot +./bfd/po/da.po +./bfd/po/es.po +./bfd/po/fr.po +./bfd/po/ja.po +./bfd/po/sv.po +./bfd/po/tr.po +./bfd/po/zh_CN.po +./bfd/po/da.gmo +./bfd/po/es.gmo +./bfd/po/fr.gmo +./bfd/po/ja.gmo +./bfd/po/sv.gmo +./bfd/po/tr.gmo +./bfd/po/zh_CN.gmo +./bfd/ChangeLog-0001 +./bfd/ChangeLog-9193 +./bfd/ChangeLog-9495 +./bfd/ChangeLog-9697 +./bfd/ChangeLog-9899 +./bfd/Makefile.am +./bfd/Makefile.in +./bfd/acinclude.m4 +./bfd/aclocal.m4 +./bfd/aix386-core.c +./bfd/aix5ppc-core.c +./bfd/aout-adobe.c +./bfd/aout-arm.c +./bfd/aout-cris.c +./bfd/aout-encap.c +./bfd/aout0.c +./bfd/aout-ns32k.c +./bfd/aout-sparcle.c +./bfd/aout-target.h +./bfd/aout-tic30.c +./bfd/aout32.c +./bfd/aout64.c +./bfd/aoutf1.h +./bfd/aoutx.h +./bfd/armnetbsd.c +./bfd/bfd-in.h +./bfd/bfdwin.c +./bfd/bout.c +./bfd/cf-i386lynx.c +./bfd/cf-m68klynx.c +./bfd/cf-sparclynx.c +./bfd/cisco-core.c +./bfd/coff-a29k.c +./bfd/coff-alpha.c +./bfd/coff-apollo.c +./bfd/coff-arm.c +./bfd/coff-aux.c +./bfd/coff-go32.c +./bfd/coff-h8300.c +./bfd/coff-h8500.c +./bfd/coff-i386.c +./bfd/coff-i860.c +./bfd/coff-i960.c +./bfd/coff-ia64.c +./bfd/coff-m68k.c +./bfd/coff-m88k.c +./bfd/coff-mcore.c +./bfd/coff-mips.c +./bfd/coff-or32.c +./bfd/coff-pmac.c +./bfd/coff-ppc.c +./bfd/coff-rs6000.c +./bfd/coff-sh.c +./bfd/coff-sparc.c +./bfd/coff-stgo32.c +./bfd/coff-svm68k.c +./bfd/ecoff.c +./bfd/coff-tic30.c +./bfd/coff-tic4x.c +./bfd/coff-tic54x.c +./bfd/coff-tic80.c +./bfd/coff-u68k.c +./bfd/coff-w65.c +./bfd/coff-we32k.c +./bfd/coff-z8k.c +./bfd/coff64-rs6000.c +./bfd/coffcode.h +./bfd/cofflink.c +./bfd/coffswap.h +./bfd/config.in +./bfd/configure +./bfd/configure.com +./bfd/configure.host +./bfd/configure.in +./bfd/cpu-a29k.c +./bfd/cpu-alpha.c +./bfd/cpu-arc.c +./bfd/cpu-arm.c +./bfd/cpu-avr.c +./bfd/cpu-cris.c +./bfd/cpu-d10v.c +./bfd/cpu-d30v.c +./bfd/cpu-dlx.c +./bfd/cpu-fr30.c +./bfd/cpu-frv.c +./bfd/cpu-h8300.c +./bfd/cpu-h8500.c +./bfd/cpu-hppa.c +./bfd/cpu-i370.c +./bfd/cpu-i860.c +./bfd/cpu-i960.c +./bfd/cpu-ia64-opc.c +./bfd/cpu-ia64.c +./bfd/cpu-ip2k.c +./bfd/cpu-iq2000.c +./bfd/cpu-m10200.c +./bfd/cpu-m10300.c +./bfd/cpu-m32r.c +./bfd/cpu-m68hc11.c +./bfd/cpu-m68hc12.c +./bfd/cpu-m68k.c +./bfd/cpu-m88k.c +./bfd/cpu-mcore.c +./bfd/cpu-mips.c +./bfd/cpu-mmix.c +./bfd/cpu-msp430.c +./bfd/cpu-ns32k.c +./bfd/cpu-openrisc.c +./bfd/cpu-or32.c +./bfd/cpu-pdp11.c +./bfd/cpu-pj.c +./bfd/cpu-powerpc.c +./bfd/cpu-rs6000.c +./bfd/cpu-s390.c +./bfd/cpu-sh.c +./bfd/cpu-sparc.c +./bfd/cpu-tic30.c +./bfd/cpu-tic4x.c +./bfd/cpu-tic54x.c +./bfd/cpu-tic80.c +./bfd/cpu-v850.c +./bfd/cpu-vax.c +./bfd/cpu-w65.c +./bfd/cpu-we32k.c +./bfd/cpu-xstormy16.c +./bfd/cpu-xtensa.c +./bfd/cpu-z8k.c +./bfd/demo64.c +./bfd/dep-in.sed +./bfd/ecofflink.c +./bfd/ecoffswap.h +./bfd/efi-app-ia32.c +./bfd/efi-app-ia64.c +./bfd/elf-hppa.h +./bfd/elf-m10200.c +./bfd/elf-m10300.c +./bfd/elf32-arc.c +./bfd/elf32-arm.h +./bfd/elf32-avr.c +./bfd/elf32-cris.c +./bfd/elf32-d10v.c +./bfd/elf32-d30v.c +./bfd/elf32-dlx.c +./bfd/elf32-fr30.c +./bfd/elf32-frv.c +./bfd/elf32-gen.c +./bfd/elf32-h8300.c +./bfd/elf32-hppa.c +./bfd/elf32-hppa.h +./bfd/elf32-i370.c +./bfd/elf32-i860.c +./bfd/elf32-i960.c +./bfd/elf32-ip2k.c +./bfd/elf32-iq2000.c +./bfd/elf32-m32r.c +./bfd/elf32-m68hc11.c +./bfd/elf32-m68hc12.c +./bfd/elf32-m68hc1x.c +./bfd/elf32-m68hc1x.h +./bfd/elf32-m68k.c +./bfd/elf32-m88k.c +./bfd/elf32-mcore.c +./bfd/elf32-pj.c +./bfd/elf32-mips.c +./bfd/elf32-msp430.c +./bfd/elf32-openrisc.c +./bfd/elf32-or32.c +./bfd/elf32-ppc.c +./bfd/elf32-ppc.h +./bfd/elf32-s390.c +./bfd/elf32-sh.c +./bfd/elf32-sh64-com.c +./bfd/elf32-sh64.c +./bfd/elf32-sh64.h +./bfd/elf32-sparc.c +./bfd/elf32-v850.c +./bfd/elf32-vax.c +./bfd/elf32-xstormy16.c +./bfd/elf32-xtensa.c +./bfd/elf64-alpha.c +./bfd/elf64-hppa.c +./bfd/elf64-hppa.h +./bfd/elf64-mips.c +./bfd/elf64-mmix.c +./bfd/elf64-ppc.c +./bfd/elf64-ppc.h +./bfd/elf64-s390.c +./bfd/elf64-sh64.c +./bfd/elf64-sparc.c +./bfd/elfarm-nabi.c +./bfd/elfarm-oabi.c +./bfd/elfn32-mips.c +./bfd/elfxx-ia64.c +./bfd/elfxx-mips.c +./bfd/elfxx-mips.h +./bfd/epoc-pe-arm.c +./bfd/epoc-pei-arm.c +./bfd/freebsd.h +./bfd/gen-aout.c +./bfd/go32stub.h +./bfd/host-aout.c +./bfd/hp300bsd.c +./bfd/hp300hpux.c +./bfd/hppabsd-core.c +./bfd/hpux-core.c +./bfd/i386aout.c +./bfd/i386bsd.c +./bfd/i386dynix.c +./bfd/i386freebsd.c +./bfd/i386linux.c +./bfd/i386lynx.c +./bfd/i386mach3.c +./bfd/i386msdos.c +./bfd/i386netbsd.c +./bfd/i386os9k.c +./bfd/ieee.c +./bfd/irix-core.c +./bfd/libbfd-in.h +./bfd/libcoff-in.h +./bfd/libhppa.h +./bfd/libieee.h +./bfd/libnlm.h +./bfd/liboasys.h +./bfd/libpei.h +./bfd/libxcoff.h +./bfd/lynx-core.c +./bfd/m68k4knetbsd.c +./bfd/m68klinux.c +./bfd/m68klynx.c +./bfd/m68knetbsd.c +./bfd/m88kmach3.c +./bfd/mach-o-target.c +./bfd/mach-o.c +./bfd/mach-o.h +./bfd/makefile.vms +./bfd/mipsbsd.c +./bfd/mmo.c +./bfd/nlm.c +./bfd/mpw-config.in +./bfd/mpw-make.sed +./bfd/netbsd-core.c +./bfd/netbsd.h +./bfd/newsos3.c +./bfd/nlm-target.h +./bfd/nlm32-alpha.c +./bfd/nlm32-i386.c +./bfd/nlm32-ppc.c +./bfd/nlm32-sparc.c +./bfd/nlm32.c +./bfd/nlm64.c +./bfd/nlmcode.h +./bfd/nlmswap.h +./bfd/ns32k.h +./bfd/ns32knetbsd.c +./bfd/oasys.c +./bfd/osf-core.c +./bfd/pc532-mach.c +./bfd/pdp11.c +./bfd/pe-arm.c +./bfd/pe-i386.c +./bfd/pe-mcore.c +./bfd/pe-sh.c +./bfd/pe-mips.c +./bfd/pe-ppc.c +./bfd/peXXigen.c +./bfd/pef-traceback.h +./bfd/pef.c +./bfd/pef.h +./bfd/pei-arm.c +./bfd/pei-i386.c +./bfd/pei-mcore.c +./bfd/pei-mips.c +./bfd/pei-ppc.c +./bfd/pei-sh.c +./bfd/peicode.h +./bfd/ppcboot.c +./bfd/ptrace-core.c +./bfd/reloc16.c +./bfd/riscix.c +./bfd/rs6000-core.c +./bfd/sco5-core.c +./bfd/som.c +./bfd/som.h +./bfd/sparclinux.c +./bfd/sparclynx.c +./bfd/sparcnetbsd.c +./bfd/stamp-h.in +./bfd/sunos.c +./bfd/ticoff.h +./bfd/trad-core.c +./bfd/vax1knetbsd.c +./bfd/vaxbsd.c +./bfd/vaxnetbsd.c +./bfd/versados.c +./bfd/vms-gsd.c +./bfd/vms-hdr.c +./bfd/vms-misc.c +./bfd/vms-tir.c +./bfd/vms.c +./bfd/vms.h +./bfd/xcoff-target.h +./bfd/xsym.c +./bfd/xcofflink.c +./bfd/xsym.h +./bfd/xtensa-isa.c +./bfd/xtensa-modules.c +./bfd/hosts/alphalinux.h +./bfd/hosts/alphavms.h +./bfd/hosts/decstation.h +./bfd/hosts/delta68.h +./bfd/hosts/dpx2.h +./bfd/hosts/hp300bsd.h +./bfd/hosts/i386bsd.h +./bfd/hosts/i386linux.h +./bfd/hosts/i386mach3.h +./bfd/hosts/i386sco.h +./bfd/hosts/i860mach3.h +./bfd/hosts/m68kaux.h +./bfd/hosts/m68klinux.h +./bfd/hosts/m88kmach3.h +./bfd/hosts/mipsbsd.h +./bfd/hosts/mipsmach3.h +./bfd/hosts/news-mips.h +./bfd/hosts/news.h +./bfd/hosts/pc532mach.h +./bfd/hosts/riscos.h +./bfd/hosts/symmetry.h +./bfd/hosts/tahoe.h +./bfd/hosts/vaxbsd.h +./bfd/hosts/vaxult.h +./bfd/hosts/vaxult2.h +./gas/config/aout_gnu.h +./gas/config/atof-tahoe.c +./gas/config/atof-vax.c +./gas/config/e-crisaout.c +./gas/config/e-criself.c +./gas/config/e-i386aout.c +./gas/config/e-i386coff.c +./gas/config/e-i386elf.c +./gas/config/e-mipsecoff.c +./gas/config/e-mipself.c +./gas/config/itbl-mips.h +./gas/config/m68k-parse.h +./gas/config/m68k-parse.y +./gas/config/m88k-opcode.h +./gas/config/obj-aout.c +./gas/config/obj-aout.h +./gas/config/obj-bout.c +./gas/config/obj-bout.h +./gas/config/obj-coff.c +./gas/config/obj-coff.h +./gas/config/obj-ecoff.c +./gas/config/tc-pj.c +./gas/config/obj-ecoff.h +./gas/config/obj-evax.c +./gas/config/obj-evax.h +./gas/config/obj-hp300.c +./gas/config/obj-hp300.h +./gas/config/obj-ieee.c +./gas/config/obj-ieee.h +./gas/config/obj-multi.c +./gas/config/obj-multi.h +./gas/config/obj-som.c +./gas/config/obj-som.h +./gas/config/obj-vms.c +./gas/config/obj-vms.h +./gas/config/tc-a29k.c +./gas/config/tc-a29k.h +./gas/config/tc-alpha.c +./gas/config/tc-alpha.h +./gas/config/tc-arc.c +./gas/config/tc-arc.h +./gas/config/tc-arm.c +./gas/config/tc-arm.h +./gas/config/tc-avr.c +./gas/config/tc-avr.h +./gas/config/tc-cris.c +./gas/config/tc-cris.h +./gas/config/tc-d10v.c +./gas/config/tc-d10v.h +./gas/config/tc-d30v.c +./gas/config/tc-d30v.h +./gas/config/tc-dlx.c +./gas/config/tc-dlx.h +./gas/config/tc-fr30.c +./gas/config/tc-fr30.h +./gas/config/tc-frv.c +./gas/config/tc-frv.h +./gas/config/tc-generic.c +./gas/config/tc-generic.h +./gas/config/tc-h8300.c +./gas/config/tc-h8300.h +./gas/config/tc-h8500.c +./gas/config/tc-h8500.h +./gas/config/tc-hppa.c +./gas/config/tc-hppa.h +./gas/config/tc-i370.c +./gas/config/tc-i370.h +./gas/config/tc-i860.c +./gas/config/tc-i860.h +./gas/config/tc-i960.c +./gas/config/tc-i960.h +./gas/config/tc-ia64.c +./gas/config/tc-ia64.h +./gas/config/tc-ip2k.c +./gas/config/tc-ip2k.h +./gas/config/tc-iq2000.c +./gas/config/tc-iq2000.h +./gas/config/tc-m32r.c +./gas/config/tc-m32r.h +./gas/config/tc-m68851.h +./gas/config/tc-m68hc11.c +./gas/config/tc-m68hc11.h +./gas/config/tc-m68k.c +./gas/config/tc-m68k.h +./gas/config/tc-m88k.c +./gas/config/tc-m88k.h +./gas/config/tc-mcore.c +./gas/config/tc-mcore.h +./gas/config/tc-mips.c +./gas/config/tc-mips.h +./gas/config/tc-mmix.c +./gas/config/tc-mmix.h +./gas/config/tc-mn10200.c +./gas/config/tc-mn10200.h +./gas/config/tc-mn10300.c +./gas/config/tc-mn10300.h +./gas/config/tc-msp430.c +./gas/config/tc-msp430.h +./gas/config/tc-ns32k.c +./gas/config/tc-ns32k.h +./gas/config/tc-openrisc.c +./gas/config/tc-openrisc.h +./gas/config/tc-or32.c +./gas/config/tc-or32.h +./gas/config/tc-pdp11.c +./gas/config/tc-pdp11.h +./gas/config/tc-pj.h +./gas/config/tc-ppc.c +./gas/config/tc-ppc.h +./gas/config/tc-s390.c +./gas/config/tc-s390.h +./gas/config/tc-sh.c +./gas/config/tc-sh.h +./gas/config/tc-sh64.c +./gas/config/tc-sh64.h +./gas/config/tc-sparc.c +./gas/config/tc-sparc.h +./gas/config/tc-tahoe.c +./gas/config/tc-tahoe.h +./gas/config/tc-tic30.c +./gas/config/tc-tic30.h +./gas/config/tc-tic4x.c +./gas/config/tc-tic4x.h +./gas/config/tc-tic54x.c +./gas/config/tc-tic54x.h +./gas/config/tc-tic80.c +./gas/config/tc-tic80.h +./gas/config/tc-v850.c +./gas/config/tc-v850.h +./gas/config/tc-vax.c +./gas/config/tc-vax.h +./gas/config/tc-w65.c +./gas/config/tc-w65.h +./gas/config/tc-xstormy16.c +./gas/config/tc-xstormy16.h +./gas/config/tc-xtensa.c +./gas/config/tc-xtensa.h +./gas/config/tc-z8k.c +./gas/config/tc-z8k.h +./gas/config/te-386bsd.h +./gas/config/te-aix5.h +./gas/config/te-aux.h +./gas/config/te-delt88.h +./gas/config/te-delta.h +./gas/config/te-dpx2.h +./gas/config/te-dynix.h +./gas/config/te-epoc-pe.h +./gas/config/te-freebsd.h +./gas/config/te-generic.h +./gas/config/te-go32.h +./gas/config/te-hp300.h +./gas/config/te-hppa.h +./gas/config/te-hppa64.h +./gas/config/te-hppalinux64.h +./gas/config/te-hpux.h +./gas/config/te-i386aix.h +./gas/config/te-ia64aix.h +./gas/config/te-ic960.h +./gas/config/te-interix.h +./gas/config/te-irix.h +./gas/config/te-linux.h +./gas/config/te-lnews.h +./gas/config/te-lynx.h +./gas/config/te-mach.h +./gas/config/te-macos.h +./gas/config/te-nbsd.h +./gas/config/te-pe.h +./gas/config/te-nbsd532.h +./gas/config/te-pc532mach.h +./gas/config/te-ppcnw.h +./gas/config/te-psos.h +./gas/config/te-riscix.h +./gas/config/te-sparcaout.h +./gas/config/te-sun3.h +./gas/config/te-svr4.h +./gas/config/te-sysv32.h +./gas/config/te-tmips.h +./gas/config/te-wince-pe.h +./gas/config/vax-inst.h +./gas/config/vms-a-conf.h +./gas/config/vms-conf.h +./gas/config/xtensa-istack.h +./gas/config/xtensa-relax.c +./gas/config/xtensa-relax.h +./gas/ChangeLog +./gas/ChangeLog-0001 +./gas/ChangeLog-9295 +./gas/ChangeLog-9697 +./gas/ChangeLog-9899 +./gas/Makefile.am +./gas/Makefile.in +./gas/README-vms +./gas/acinclude.m4 +./gas/aclocal.m4 +./gas/cgen.c +./gas/cgen.h +./gas/config-gas.com +./gas/config.in +./gas/configure +./gas/configure.in +./gas/debug.c +./gas/dep-in.sed +./gas/emul-target.h +./gas/emul.h +./gas/gdbinit.in +./gas/itbl-lex.l +./gas/itbl-ops.c +./gas/itbl-ops.h +./gas/itbl-parse.y +./gas/link.cmd +./gas/mac-as.r +./gas/makefile.vms +./gas/mpw-config.in +./gas/mpw-make.sed +./gas/stamp-h.in +./gas/vmsconf.sh +./gas/doc/Makefile.am +./gas/doc/Makefile.in +./gas/doc/all.texi +./gas/doc/c-a29k.texi +./gas/doc/c-alpha.texi +./gas/doc/c-arc.texi +./gas/doc/c-arm.texi +./gas/doc/c-cris.texi +./gas/doc/c-d10v.texi +./gas/doc/c-d30v.texi +./gas/doc/c-h8300.texi +./gas/doc/c-h8500.texi +./gas/doc/c-hppa.texi +./gas/doc/c-i370.texi +./gas/doc/c-i860.texi +./gas/doc/c-i960.texi +./gas/doc/c-ia64.texi +./gas/doc/c-ip2k.texi +./gas/doc/c-m32r.texi +./gas/doc/c-m68hc11.texi +./gas/doc/c-m68k.texi +./gas/doc/c-m88k.texi +./gas/doc/c-mips.texi +./gas/doc/c-mmix.texi +./gas/doc/c-msp430.texi +./gas/doc/c-ns32k.texi +./gas/doc/c-pdp11.texi +./gas/doc/c-pj.texi +./gas/doc/c-ppc.texi +./gas/doc/c-sh.texi +./gas/doc/c-sh64.texi +./gas/doc/c-sparc.texi +./gas/doc/c-tic54x.texi +./gas/doc/c-v850.texi +./gas/doc/c-vax.texi +./gas/doc/c-xtensa.texi +./gas/doc/c-z8k.texi +./gas/doc/h8.texi +./gas/doc/internals.texi +./gas/doc/gasver.texi +./gas/doc/as.info-1 +./gas/doc/as.info-2 +./gas/doc/as.info-3 +./gas/doc/as.info-4 +./gas/doc/as.info-5 +./gas/doc/as.info-6 +./gas/doc/as.info-7 +./gas/doc/as.info-8 +./gas/doc/as.info-9 +./gas/doc/as.info-10 +./gas/doc/as.info-11 +./gas/doc/as.info-12 +./gas/doc/as.1 +./gas/po/.cvsignore +./gas/po/Make-in +./gas/po/POTFILES.in +./gas/po/es.po +./gas/po/fr.po +./gas/po/gas.pot +./gas/po/tr.po +./gas/po/es.gmo +./gas/po/fr.gmo +./gas/po/tr.gmo +./gas/testsuite/config/default.exp +./gas/testsuite/ChangeLog +./gas/testsuite/gas/all/align2.d +./gas/testsuite/gas/all/align.d +./gas/testsuite/gas/all/align.s +./gas/testsuite/gas/all/align2.s +./gas/testsuite/gas/all/cofftag.d +./gas/testsuite/gas/all/cofftag.s +./gas/testsuite/gas/all/comment.s +./gas/testsuite/gas/all/cond.d +./gas/testsuite/gas/all/cond.s +./gas/testsuite/gas/all/diff1.s +./gas/testsuite/gas/all/fastcall.s +./gas/testsuite/gas/all/float.s +./gas/testsuite/gas/all/gas.exp +./gas/testsuite/gas/all/incbin.d +./gas/testsuite/gas/all/incbin.dat +./gas/testsuite/gas/all/incbin.s +./gas/testsuite/gas/all/itbl +./gas/testsuite/gas/all/itbl-test.c +./gas/testsuite/gas/all/itbl.s +./gas/testsuite/gas/all/p1480.s +./gas/testsuite/gas/all/p2425.s +./gas/testsuite/gas/all/struct.d +./gas/testsuite/gas/all/struct.s +./gas/testsuite/gas/all/test-example.c +./gas/testsuite/gas/all/test-gen.c +./gas/testsuite/gas/all/x930509.s +./gas/testsuite/gas/arc/branch.d +./gas/testsuite/gas/arc/adc.d +./gas/testsuite/gas/arc/adc.s +./gas/testsuite/gas/arc/add.d +./gas/testsuite/gas/arc/add.s +./gas/testsuite/gas/arc/alias.d +./gas/testsuite/gas/arc/alias.s +./gas/testsuite/gas/arc/and.d +./gas/testsuite/gas/arc/and.s +./gas/testsuite/gas/arc/arc.exp +./gas/testsuite/gas/arc/asl.d +./gas/testsuite/gas/arc/asl.s +./gas/testsuite/gas/arc/asr.d +./gas/testsuite/gas/arc/asr.s +./gas/testsuite/gas/arc/b.d +./gas/testsuite/gas/arc/b.s +./gas/testsuite/gas/arc/bic.d +./gas/testsuite/gas/arc/bic.s +./gas/testsuite/gas/arc/bl.d +./gas/testsuite/gas/arc/bl.s +./gas/testsuite/gas/arc/branch.s +./gas/testsuite/gas/arc/brk.d +./gas/testsuite/gas/arc/brk.s +./gas/testsuite/gas/arc/extb.d +./gas/testsuite/gas/arc/extb.s +./gas/testsuite/gas/arc/extw.d +./gas/testsuite/gas/arc/extw.s +./gas/testsuite/gas/arc/flag.d +./gas/testsuite/gas/arc/flag.s +./gas/testsuite/gas/arc/insn3.d +./gas/testsuite/gas/arc/insn3.s +./gas/testsuite/gas/arc/j.d +./gas/testsuite/gas/arc/j.s +./gas/testsuite/gas/arc/jl.d +./gas/testsuite/gas/arc/jl.s +./gas/testsuite/gas/arc/ld.d +./gas/testsuite/gas/arc/ld.s +./gas/testsuite/gas/arc/ld2.d +./gas/testsuite/gas/arc/ld2.s +./gas/testsuite/gas/arc/lp.d +./gas/testsuite/gas/arc/lp.s +./gas/testsuite/gas/arc/lsr.d +./gas/testsuite/gas/arc/lsr.s +./gas/testsuite/gas/arc/math.d +./gas/testsuite/gas/arc/math.s +./gas/testsuite/gas/arc/mov.d +./gas/testsuite/gas/arc/mov.s +./gas/testsuite/gas/arc/nop.d +./gas/testsuite/gas/arc/nop.s +./gas/testsuite/gas/arc/or.d +./gas/testsuite/gas/arc/or.s +./gas/testsuite/gas/arc/rlc.d +./gas/testsuite/gas/arc/rlc.s +./gas/testsuite/gas/arc/ror.d +./gas/testsuite/gas/arc/ror.s +./gas/testsuite/gas/arc/rrc.d +./gas/testsuite/gas/arc/rrc.s +./gas/testsuite/gas/arc/sbc.d +./gas/testsuite/gas/arc/sbc.s +./gas/testsuite/gas/arc/sexb.d +./gas/testsuite/gas/arc/sexb.s +./gas/testsuite/gas/arc/sexw.d +./gas/testsuite/gas/arc/sexw.s +./gas/testsuite/gas/arc/sleep.d +./gas/testsuite/gas/arc/sleep.s +./gas/testsuite/gas/arc/sshift.d +./gas/testsuite/gas/arc/sshift.s +./gas/testsuite/gas/arc/st.d +./gas/testsuite/gas/arc/st.s +./gas/testsuite/gas/arc/sub.d +./gas/testsuite/gas/arc/sub.s +./gas/testsuite/gas/arc/swi.d +./gas/testsuite/gas/arc/swi.s +./gas/testsuite/gas/arc/warn.exp +./gas/testsuite/gas/arc/warn.s +./gas/testsuite/gas/arc/xor.d +./gas/testsuite/gas/arc/xor.s +./gas/testsuite/gas/template +./gas/testsuite/gas/alpha/alpha.exp +./gas/testsuite/gas/alpha/elf-reloc-1.d +./gas/testsuite/gas/alpha/elf-reloc-1.s +./gas/testsuite/gas/alpha/elf-reloc-2.l +./gas/testsuite/gas/alpha/elf-reloc-2.s +./gas/testsuite/gas/alpha/elf-reloc-3.l +./gas/testsuite/gas/alpha/elf-reloc-3.s +./gas/testsuite/gas/alpha/elf-reloc-4.d +./gas/testsuite/gas/alpha/elf-reloc-4.s +./gas/testsuite/gas/alpha/elf-reloc-5.d +./gas/testsuite/gas/alpha/elf-reloc-5.s +./gas/testsuite/gas/alpha/elf-reloc-6.l +./gas/testsuite/gas/alpha/elf-reloc-6.s +./gas/testsuite/gas/alpha/elf-reloc-7.d +./gas/testsuite/gas/alpha/elf-reloc-7.s +./gas/testsuite/gas/alpha/elf-reloc-8.d +./gas/testsuite/gas/alpha/elf-reloc-8.s +./gas/testsuite/gas/alpha/elf-tls-1.d +./gas/testsuite/gas/alpha/elf-tls-1.s +./gas/testsuite/gas/alpha/elf-tls-2.l +./gas/testsuite/gas/alpha/elf-tls-2.s +./gas/testsuite/gas/alpha/elf-tls-3.l +./gas/testsuite/gas/alpha/elf-tls-3.s +./gas/testsuite/gas/alpha/fp.d +./gas/testsuite/gas/alpha/fp.s +./gas/testsuite/gas/alpha/unop.d +./gas/testsuite/gas/alpha/unop.s +./gas/testsuite/gas/arm/arch4t.s +./gas/testsuite/gas/arm/adrl.d +./gas/testsuite/gas/arm/adrl.s +./gas/testsuite/gas/arm/arch5tej.d +./gas/testsuite/gas/arm/arch5tej.s +./gas/testsuite/gas/arm/arm.exp +./gas/testsuite/gas/arm/arm3.s +./gas/testsuite/gas/arm/arm6.s +./gas/testsuite/gas/arm/arm7dm.s +./gas/testsuite/gas/arm/arm7t.d +./gas/testsuite/gas/arm/arm7t.s +./gas/testsuite/gas/arm/armv1-bad.l +./gas/testsuite/gas/arm/armv1-bad.s +./gas/testsuite/gas/arm/armv1.d +./gas/testsuite/gas/arm/armv1.s +./gas/testsuite/gas/arm/copro.s +./gas/testsuite/gas/arm/el_segundo.d +./gas/testsuite/gas/arm/el_segundo.s +./gas/testsuite/gas/arm/float.s +./gas/testsuite/gas/arm/fpa-dyadic.d +./gas/testsuite/gas/arm/fpa-dyadic.s +./gas/testsuite/gas/arm/fpa-mem.d +./gas/testsuite/gas/arm/fpa-mem.s +./gas/testsuite/gas/arm/fpa-monadic.d +./gas/testsuite/gas/arm/fpa-monadic.s +./gas/testsuite/gas/arm/immed.s +./gas/testsuite/gas/arm/inst.d +./gas/testsuite/gas/arm/inst.s +./gas/testsuite/gas/arm/iwmmxt.d +./gas/testsuite/gas/arm/iwmmxt.s +./gas/testsuite/gas/arm/ldconst.d +./gas/testsuite/gas/arm/ldconst.s +./gas/testsuite/gas/arm/le-fpconst.d +./gas/testsuite/gas/arm/le-fpconst.s +./gas/testsuite/gas/arm/maverick.c +./gas/testsuite/gas/arm/maverick.d +./gas/testsuite/gas/arm/maverick.s +./gas/testsuite/gas/arm/offset.s +./gas/testsuite/gas/arm/pic.d +./gas/testsuite/gas/arm/pic.s +./gas/testsuite/gas/arm/thumb.s +./gas/testsuite/gas/arm/vfp-bad.l +./gas/testsuite/gas/arm/vfp-bad.s +./gas/testsuite/gas/arm/vfp1.d +./gas/testsuite/gas/arm/vfp1.s +./gas/testsuite/gas/arm/vfp1xD.d +./gas/testsuite/gas/arm/vfp1xD.s +./gas/testsuite/gas/arm/xscale.d +./gas/testsuite/gas/arm/xscale.s +./gas/testsuite/gas/cris/binop-extx.d +./gas/testsuite/gas/cris/addi.d +./gas/testsuite/gas/cris/addi.s +./gas/testsuite/gas/cris/binop-cmpmove.d +./gas/testsuite/gas/cris/binop-cmpmovx.d +./gas/testsuite/gas/cris/binop-segref.s +./gas/testsuite/gas/cris/binop.d +./gas/testsuite/gas/cris/binop.s +./gas/testsuite/gas/cris/bork.d +./gas/testsuite/gas/cris/bork.s +./gas/testsuite/gas/cris/branch-warn-1.s +./gas/testsuite/gas/cris/branch-warn-2.s +./gas/testsuite/gas/cris/branch-warn-3.s +./gas/testsuite/gas/cris/branch.d +./gas/testsuite/gas/cris/branch.s +./gas/testsuite/gas/cris/break.d +./gas/testsuite/gas/cris/break.s +./gas/testsuite/gas/cris/brokw-1.d +./gas/testsuite/gas/cris/brokw-1.s +./gas/testsuite/gas/cris/brokw-2.d +./gas/testsuite/gas/cris/brokw-2.s +./gas/testsuite/gas/cris/brokw-3.d +./gas/testsuite/gas/cris/brokw-3.s +./gas/testsuite/gas/cris/bwtest-err-1.s +./gas/testsuite/gas/cris/ccr.d +./gas/testsuite/gas/cris/ccr.s +./gas/testsuite/gas/cris/clear.d +./gas/testsuite/gas/cris/continue.d +./gas/testsuite/gas/cris/continue.s +./gas/testsuite/gas/cris/cris.exp +./gas/testsuite/gas/cris/diffexp-ovwr.d +./gas/testsuite/gas/cris/diffexp-ovwr.s +./gas/testsuite/gas/cris/fragtest.d +./gas/testsuite/gas/cris/fragtest.s +./gas/testsuite/gas/cris/jump-type.d +./gas/testsuite/gas/cris/labfloat.d +./gas/testsuite/gas/cris/labfloat.s +./gas/testsuite/gas/cris/macroat.d +./gas/testsuite/gas/cris/macroat.s +./gas/testsuite/gas/cris/movem-to-reg.d +./gas/testsuite/gas/cris/nosep.d +./gas/testsuite/gas/cris/nosep.s +./gas/testsuite/gas/cris/oneop-type.d +./gas/testsuite/gas/cris/operand-err-1.s +./gas/testsuite/gas/cris/pic-err-1.s +./gas/testsuite/gas/cris/prefix.d +./gas/testsuite/gas/cris/prefix.s +./gas/testsuite/gas/cris/pushpop-byte-sreg.d +./gas/testsuite/gas/cris/pushpop.d +./gas/testsuite/gas/cris/pushpop-dcr1-sreg.d +./gas/testsuite/gas/cris/pushpop-dword-sreg.d +./gas/testsuite/gas/cris/pushpop-word-sreg.d +./gas/testsuite/gas/cris/pushpop.s +./gas/testsuite/gas/cris/quick-s6.d +./gas/testsuite/gas/cris/quick-u5.d +./gas/testsuite/gas/cris/quick-u6.d +./gas/testsuite/gas/cris/quick.s +./gas/testsuite/gas/cris/range-err-1.s +./gas/testsuite/gas/cris/range-err-2.s +./gas/testsuite/gas/cris/rd-bcnst.d +./gas/testsuite/gas/cris/rd-bcnst.s +./gas/testsuite/gas/cris/rd-dw2-1.d +./gas/testsuite/gas/cris/rd-dw2-10.d +./gas/testsuite/gas/cris/rd-dw2-11.d +./gas/testsuite/gas/cris/rd-dw2-12.d +./gas/testsuite/gas/cris/rd-dw2-13.d +./gas/testsuite/gas/cris/rd-dw2-14.d +./gas/testsuite/gas/cris/rd-dw2-15.d +./gas/testsuite/gas/cris/rd-dw2-2.d +./gas/testsuite/gas/cris/rd-dw2-3.d +./gas/testsuite/gas/cris/rd-dw2-4.d +./gas/testsuite/gas/cris/rd-dw2-5.d +./gas/testsuite/gas/cris/rd-dw2-6.d +./gas/testsuite/gas/cris/rd-dw2-7.d +./gas/testsuite/gas/cris/rd-dw2-8.d +./gas/testsuite/gas/cris/rd-dw2-9.d +./gas/testsuite/gas/cris/rd-pcrel1.d +./gas/testsuite/gas/cris/rd-pcrel1.s +./gas/testsuite/gas/cris/rd-pcrel2.d +./gas/testsuite/gas/cris/rd-pcrel2.s +./gas/testsuite/gas/cris/rd-pic-1.d +./gas/testsuite/gas/cris/rd-pic-1.s +./gas/testsuite/gas/cris/rd-regprefix-1.d +./gas/testsuite/gas/cris/rd-regprefix-1.s +./gas/testsuite/gas/cris/rd-regprefix-1b.d +./gas/testsuite/gas/cris/reg-to-mem.d +./gas/testsuite/gas/cris/regprefix-err-1.s +./gas/testsuite/gas/cris/regreg.d +./gas/testsuite/gas/cris/regreg.s +./gas/testsuite/gas/cris/return.d +./gas/testsuite/gas/cris/return.s +./gas/testsuite/gas/cris/scc.d +./gas/testsuite/gas/cris/scc.s +./gas/testsuite/gas/cris/sep-err-1.s +./gas/testsuite/gas/cris/sep-err-2.s +./gas/testsuite/gas/cris/sep-err-3.s +./gas/testsuite/gas/cris/separator.d +./gas/testsuite/gas/cris/separator.s +./gas/testsuite/gas/cris/shexpr-1.d +./gas/testsuite/gas/cris/shexpr-1.s +./gas/testsuite/gas/cris/sreg-to-x.d +./gas/testsuite/gas/cris/string-1.d +./gas/testsuite/gas/cris/string-1.s +./gas/testsuite/gas/cris/string-2.d +./gas/testsuite/gas/cris/string-2.s +./gas/testsuite/gas/cris/test.d +./gas/testsuite/gas/cris/unimplemented.d +./gas/testsuite/gas/cris/unimplemented.s +./gas/testsuite/gas/cris/unop-mem.d +./gas/testsuite/gas/cris/unop.s +./gas/testsuite/gas/cris/us-err-1.s +./gas/testsuite/gas/cris/us-err-2.s +./gas/testsuite/gas/cris/us-err-3.s +./gas/testsuite/gas/cris/x-to-byte-sreg.d +./gas/testsuite/gas/cris/x-to-dcr1-sreg.d +./gas/testsuite/gas/cris/x-to-dword-sreg.d +./gas/testsuite/gas/cris/x-to-word-sreg.d +./gas/testsuite/gas/d10v/address-001.d +./gas/testsuite/gas/d10v/address-001.s +./gas/testsuite/gas/d10v/address-002.l +./gas/testsuite/gas/d10v/address-002.s +./gas/testsuite/gas/d10v/address-003.l +./gas/testsuite/gas/d10v/address-003.s +./gas/testsuite/gas/d10v/address-004.l +./gas/testsuite/gas/d10v/address-004.s +./gas/testsuite/gas/d10v/address-005.l +./gas/testsuite/gas/d10v/address-005.s +./gas/testsuite/gas/d10v/address-006.l +./gas/testsuite/gas/d10v/address-006.s +./gas/testsuite/gas/d10v/address-007.l +./gas/testsuite/gas/d10v/address-007.s +./gas/testsuite/gas/d10v/address-008.l +./gas/testsuite/gas/d10v/address-008.s +./gas/testsuite/gas/d10v/address-009.l +./gas/testsuite/gas/d10v/address-009.s +./gas/testsuite/gas/d10v/address-010.l +./gas/testsuite/gas/d10v/address-010.s +./gas/testsuite/gas/d10v/address-011.l +./gas/testsuite/gas/d10v/address-011.s +./gas/testsuite/gas/d10v/address-012.l +./gas/testsuite/gas/d10v/address-012.s +./gas/testsuite/gas/d10v/address-013.l +./gas/testsuite/gas/d10v/address-013.s +./gas/testsuite/gas/d10v/address-014.l +./gas/testsuite/gas/d10v/address-014.s +./gas/testsuite/gas/d10v/address-015.l +./gas/testsuite/gas/d10v/address-015.s +./gas/testsuite/gas/d10v/address-016.l +./gas/testsuite/gas/d10v/address-016.s +./gas/testsuite/gas/d10v/address-017.l +./gas/testsuite/gas/d10v/address-017.s +./gas/testsuite/gas/d10v/address-018.l +./gas/testsuite/gas/d10v/address-018.s +./gas/testsuite/gas/d10v/address-019.l +./gas/testsuite/gas/d10v/address-019.s +./gas/testsuite/gas/d10v/address-020.l +./gas/testsuite/gas/d10v/address-020.s +./gas/testsuite/gas/d10v/address-021.l +./gas/testsuite/gas/d10v/address-021.s +./gas/testsuite/gas/d10v/address-022.l +./gas/testsuite/gas/d10v/address-022.s +./gas/testsuite/gas/d10v/address-023.l +./gas/testsuite/gas/d10v/address-023.s +./gas/testsuite/gas/d10v/address-024.l +./gas/testsuite/gas/d10v/address-024.s +./gas/testsuite/gas/d10v/address-025.l +./gas/testsuite/gas/d10v/address-025.s +./gas/testsuite/gas/d10v/address-026.l +./gas/testsuite/gas/d10v/address-026.s +./gas/testsuite/gas/d10v/address-027.l +./gas/testsuite/gas/d10v/address-027.s +./gas/testsuite/gas/d10v/address-028.l +./gas/testsuite/gas/d10v/address-028.s +./gas/testsuite/gas/d10v/address-029.l +./gas/testsuite/gas/d10v/address-029.s +./gas/testsuite/gas/d10v/address-030.l +./gas/testsuite/gas/d10v/address-030.s +./gas/testsuite/gas/d10v/address-031.l +./gas/testsuite/gas/d10v/address-031.s +./gas/testsuite/gas/d10v/address-032.l +./gas/testsuite/gas/d10v/address-032.s +./gas/testsuite/gas/d10v/address-033.l +./gas/testsuite/gas/d10v/address-033.s +./gas/testsuite/gas/d10v/address-034.l +./gas/testsuite/gas/d10v/address-034.s +./gas/testsuite/gas/d10v/address-035.l +./gas/testsuite/gas/d10v/address-035.s +./gas/testsuite/gas/d10v/address-036.l +./gas/testsuite/gas/d10v/address-036.s +./gas/testsuite/gas/d10v/address-037.l +./gas/testsuite/gas/d10v/address-037.s +./gas/testsuite/gas/d10v/address-038.l +./gas/testsuite/gas/d10v/address-038.s +./gas/testsuite/gas/d10v/address-039.l +./gas/testsuite/gas/d10v/address-039.s +./gas/testsuite/gas/d10v/address-040.l +./gas/testsuite/gas/d10v/address-040.s +./gas/testsuite/gas/d10v/address-041.l +./gas/testsuite/gas/d10v/address-041.s +./gas/testsuite/gas/d10v/control-001.d +./gas/testsuite/gas/d10v/control-001.s +./gas/testsuite/gas/d10v/d10v.exp +./gas/testsuite/gas/d10v/error-001.d +./gas/testsuite/gas/d10v/error-001.s +./gas/testsuite/gas/d10v/error-002.d +./gas/testsuite/gas/d10v/error-002.s +./gas/testsuite/gas/d10v/immediate-001.d +./gas/testsuite/gas/d10v/immediate-001.s +./gas/testsuite/gas/d10v/immediate-002.d +./gas/testsuite/gas/d10v/immediate-002.s +./gas/testsuite/gas/d10v/immediate-003.d +./gas/testsuite/gas/d10v/immediate-003.s +./gas/testsuite/gas/d10v/immediate-004.d +./gas/testsuite/gas/d10v/immediate-004.s +./gas/testsuite/gas/d10v/immediate-005.d +./gas/testsuite/gas/d10v/immediate-005.s +./gas/testsuite/gas/d10v/immediate-006.d +./gas/testsuite/gas/d10v/immediate-006.s +./gas/testsuite/gas/d10v/immediate-007.d +./gas/testsuite/gas/d10v/immediate-007.s +./gas/testsuite/gas/d10v/inst.d +./gas/testsuite/gas/d10v/inst.s +./gas/testsuite/gas/d10v/label-001.d +./gas/testsuite/gas/d10v/instruction_packing-001.d +./gas/testsuite/gas/d10v/instruction_packing-001.s +./gas/testsuite/gas/d10v/instruction_packing-002.d +./gas/testsuite/gas/d10v/instruction_packing-002.s +./gas/testsuite/gas/d10v/instruction_packing-003.d +./gas/testsuite/gas/d10v/instruction_packing-003.s +./gas/testsuite/gas/d10v/instruction_packing-004.d +./gas/testsuite/gas/d10v/instruction_packing-004.s +./gas/testsuite/gas/d10v/instruction_packing-005.d +./gas/testsuite/gas/d10v/instruction_packing-005.s +./gas/testsuite/gas/d10v/instruction_packing-006.d +./gas/testsuite/gas/d10v/instruction_packing-006.s +./gas/testsuite/gas/d10v/instruction_packing-007.d +./gas/testsuite/gas/d10v/instruction_packing-007.s +./gas/testsuite/gas/d10v/instruction_packing-008.d +./gas/testsuite/gas/d10v/instruction_packing-009.d +./gas/testsuite/gas/d10v/instruction_packing-010.d +./gas/testsuite/gas/d10v/instruction_packing.d +./gas/testsuite/gas/d10v/instruction_packing.s +./gas/testsuite/gas/d10v/label-001.s +./gas/testsuite/gas/d10v/warning-001.d +./gas/testsuite/gas/d10v/warning-001.s +./gas/testsuite/gas/d10v/warning-002.d +./gas/testsuite/gas/d10v/warning-002.s +./gas/testsuite/gas/d10v/warning-003.d +./gas/testsuite/gas/d10v/warning-003.s +./gas/testsuite/gas/d10v/warning-004.d +./gas/testsuite/gas/d10v/warning-004.s +./gas/testsuite/gas/d10v/warning-005.d +./gas/testsuite/gas/d10v/warning-005.s +./gas/testsuite/gas/d10v/warning-006.d +./gas/testsuite/gas/d10v/warning-006.s +./gas/testsuite/gas/d10v/warning-007.d +./gas/testsuite/gas/d10v/warning-007.s +./gas/testsuite/gas/d10v/warning-008.d +./gas/testsuite/gas/d10v/warning-008.s +./gas/testsuite/gas/d10v/warning-009.d +./gas/testsuite/gas/d10v/warning-009.s +./gas/testsuite/gas/d10v/warning-010.d +./gas/testsuite/gas/d10v/warning-010.s +./gas/testsuite/gas/d10v/warning-011.d +./gas/testsuite/gas/d10v/warning-011.s +./gas/testsuite/gas/d10v/warning-012.d +./gas/testsuite/gas/d10v/warning-012.s +./gas/testsuite/gas/d10v/warning-013.d +./gas/testsuite/gas/d10v/warning-013.s +./gas/testsuite/gas/d10v/warning-014.d +./gas/testsuite/gas/d10v/warning-014.s +./gas/testsuite/gas/d10v/warning-015.d +./gas/testsuite/gas/d10v/warning-016.d +./gas/testsuite/gas/d10v/warning-016.s +./gas/testsuite/gas/d10v/warning-017.d +./gas/testsuite/gas/d10v/warning-017.s +./gas/testsuite/gas/d10v/warning-018.d +./gas/testsuite/gas/d10v/warning-018.s +./gas/testsuite/gas/d10v/warning-019.d +./gas/testsuite/gas/d10v/warning-019.s +./gas/testsuite/gas/d30v/bittest.d +./gas/testsuite/gas/d30v/align.d +./gas/testsuite/gas/d30v/align.s +./gas/testsuite/gas/d30v/array.d +./gas/testsuite/gas/d30v/array.s +./gas/testsuite/gas/d30v/bittest.l +./gas/testsuite/gas/d30v/bittest.s +./gas/testsuite/gas/d30v/d30.exp +./gas/testsuite/gas/d30v/guard-debug.d +./gas/testsuite/gas/d30v/guard-debug.s +./gas/testsuite/gas/d30v/guard.d +./gas/testsuite/gas/d30v/guard.s +./gas/testsuite/gas/d30v/inst.d +./gas/testsuite/gas/d30v/inst.s +./gas/testsuite/gas/d30v/label-debug.d +./gas/testsuite/gas/d30v/label-debug.s +./gas/testsuite/gas/d30v/label.d +./gas/testsuite/gas/d30v/label.s +./gas/testsuite/gas/d30v/mul.d +./gas/testsuite/gas/d30v/mul.s +./gas/testsuite/gas/d30v/opt.d +./gas/testsuite/gas/d30v/opt.s +./gas/testsuite/gas/d30v/reloc.d +./gas/testsuite/gas/d30v/reloc.s +./gas/testsuite/gas/d30v/serial.l +./gas/testsuite/gas/d30v/serial.s +./gas/testsuite/gas/d30v/serial2.l +./gas/testsuite/gas/d30v/serial2.s +./gas/testsuite/gas/d30v/serial2O.l +./gas/testsuite/gas/d30v/serial2O.s +./gas/testsuite/gas/d30v/warn_oddreg.l +./gas/testsuite/gas/d30v/warn_oddreg.s +./gas/testsuite/gas/dlx/alltests.exp +./gas/testsuite/gas/dlx/branch.d +./gas/testsuite/gas/dlx/branch.s +./gas/testsuite/gas/dlx/itype.d +./gas/testsuite/gas/dlx/itype.s +./gas/testsuite/gas/dlx/lhi.d +./gas/testsuite/gas/dlx/lhi.s +./gas/testsuite/gas/dlx/load.d +./gas/testsuite/gas/dlx/load.s +./gas/testsuite/gas/dlx/rtype.d +./gas/testsuite/gas/dlx/rtype.s +./gas/testsuite/gas/dlx/store.d +./gas/testsuite/gas/dlx/store.s +./gas/testsuite/gas/elf/ehopt0.d +./gas/testsuite/gas/elf/ehopt0.s +./gas/testsuite/gas/elf/elf.exp +./gas/testsuite/gas/elf/section0.d +./gas/testsuite/gas/elf/section0.s +./gas/testsuite/gas/elf/section1.d +./gas/testsuite/gas/elf/section1.s +./gas/testsuite/gas/elf/section2.e +./gas/testsuite/gas/elf/section2.e-m32r +./gas/testsuite/gas/elf/section2.e-mips +./gas/testsuite/gas/elf/section2.e-miwmmxt +./gas/testsuite/gas/elf/section2.l +./gas/testsuite/gas/elf/section2.s +./gas/testsuite/gas/elf/symver.d +./gas/testsuite/gas/elf/symver.s +./gas/testsuite/gas/fr30/allinsn.d +./gas/testsuite/gas/fr30/allinsn.exp +./gas/testsuite/gas/fr30/allinsn.s +./gas/testsuite/gas/fr30/fr30.exp +./gas/testsuite/gas/frv/allinsn.d +./gas/testsuite/gas/frv/allinsn.exp +./gas/testsuite/gas/frv/allinsn.s +./gas/testsuite/gas/h8300/addsub.s +./gas/testsuite/gas/h8300/addsubh.s +./gas/testsuite/gas/h8300/addsubs.s +./gas/testsuite/gas/h8300/bitops1.s +./gas/testsuite/gas/h8300/bitops1h.s +./gas/testsuite/gas/h8300/bitops1s.s +./gas/testsuite/gas/h8300/bitops2.s +./gas/testsuite/gas/h8300/bitops2h.s +./gas/testsuite/gas/h8300/bitops2s.s +./gas/testsuite/gas/h8300/bitops3.s +./gas/testsuite/gas/h8300/bitops3h.s +./gas/testsuite/gas/h8300/bitops3s.s +./gas/testsuite/gas/h8300/bitops4.s +./gas/testsuite/gas/h8300/bitops4h.s +./gas/testsuite/gas/h8300/bitops4s.s +./gas/testsuite/gas/h8300/branch-coff.s +./gas/testsuite/gas/h8300/branch-elf.s +./gas/testsuite/gas/h8300/branchh-coff.s +./gas/testsuite/gas/h8300/branchh-elf.s +./gas/testsuite/gas/h8300/branchs-coff.s +./gas/testsuite/gas/h8300/branchs-elf.s +./gas/testsuite/gas/h8300/cbranch.s +./gas/testsuite/gas/h8300/cbranchh.s +./gas/testsuite/gas/h8300/cbranchs.s +./gas/testsuite/gas/h8300/cmpsi2.s +./gas/testsuite/gas/h8300/compare.s +./gas/testsuite/gas/h8300/compareh.s +./gas/testsuite/gas/h8300/compares.s +./gas/testsuite/gas/h8300/decimal.s +./gas/testsuite/gas/h8300/decimalh.s +./gas/testsuite/gas/h8300/decimals.s +./gas/testsuite/gas/h8300/divmul.s +./gas/testsuite/gas/h8300/divmulh.s +./gas/testsuite/gas/h8300/divmuls.s +./gas/testsuite/gas/h8300/extendh.s +./gas/testsuite/gas/h8300/extends.s +./gas/testsuite/gas/h8300/ffxx1-coff.d +./gas/testsuite/gas/h8300/ffxx1-coff.s +./gas/testsuite/gas/h8300/ffxx1-elf.d +./gas/testsuite/gas/h8300/ffxx1-elf.s +./gas/testsuite/gas/h8300/h8300-coff.exp +./gas/testsuite/gas/h8300/h8300-elf.exp +./gas/testsuite/gas/h8300/h8300.exp +./gas/testsuite/gas/h8300/incdec.s +./gas/testsuite/gas/h8300/incdech.s +./gas/testsuite/gas/h8300/incdecs.s +./gas/testsuite/gas/h8300/logical.s +./gas/testsuite/gas/h8300/macs.s +./gas/testsuite/gas/h8300/logicalh.s +./gas/testsuite/gas/h8300/logicals.s +./gas/testsuite/gas/h8300/misc.s +./gas/testsuite/gas/h8300/misch.s +./gas/testsuite/gas/h8300/miscs.s +./gas/testsuite/gas/h8300/mov32bug.s +./gas/testsuite/gas/h8300/movb.s +./gas/testsuite/gas/h8300/movbh.s +./gas/testsuite/gas/h8300/movbs.s +./gas/testsuite/gas/h8300/movlh.s +./gas/testsuite/gas/h8300/movls.s +./gas/testsuite/gas/h8300/movw.s +./gas/testsuite/gas/h8300/movwh.s +./gas/testsuite/gas/h8300/movws.s +./gas/testsuite/gas/h8300/multiples.s +./gas/testsuite/gas/h8300/pushpop.s +./gas/testsuite/gas/h8300/pushpoph.s +./gas/testsuite/gas/h8300/pushpops.s +./gas/testsuite/gas/h8300/rotsh.s +./gas/testsuite/gas/h8300/rotshh.s +./gas/testsuite/gas/h8300/rotshs.s +./gas/testsuite/gas/hppa/basic/basic.exp +./gas/testsuite/gas/hppa/basic/add.s +./gas/testsuite/gas/hppa/basic/add2.s +./gas/testsuite/gas/hppa/basic/addi.s +./gas/testsuite/gas/hppa/basic/branch.s +./gas/testsuite/gas/hppa/basic/branch2.s +./gas/testsuite/gas/hppa/basic/comclr.s +./gas/testsuite/gas/hppa/basic/copr.s +./gas/testsuite/gas/hppa/basic/coprmem.s +./gas/testsuite/gas/hppa/basic/dcor.s +./gas/testsuite/gas/hppa/basic/dcor2.s +./gas/testsuite/gas/hppa/basic/deposit.s +./gas/testsuite/gas/hppa/basic/deposit2.s +./gas/testsuite/gas/hppa/basic/deposit3.s +./gas/testsuite/gas/hppa/basic/ds.s +./gas/testsuite/gas/hppa/basic/extract.s +./gas/testsuite/gas/hppa/basic/extract2.s +./gas/testsuite/gas/hppa/basic/extract3.s +./gas/testsuite/gas/hppa/basic/fmem.s +./gas/testsuite/gas/hppa/basic/fmemLRbug.s +./gas/testsuite/gas/hppa/basic/fp_comp.s +./gas/testsuite/gas/hppa/basic/fp_comp2.s +./gas/testsuite/gas/hppa/basic/fp_conv.s +./gas/testsuite/gas/hppa/basic/fp_fcmp.s +./gas/testsuite/gas/hppa/basic/fp_misc.s +./gas/testsuite/gas/hppa/basic/imem.s +./gas/testsuite/gas/hppa/basic/immed.s +./gas/testsuite/gas/hppa/basic/logical.s +./gas/testsuite/gas/hppa/basic/media.s +./gas/testsuite/gas/hppa/basic/perf.s +./gas/testsuite/gas/hppa/basic/purge.s +./gas/testsuite/gas/hppa/basic/purge2.s +./gas/testsuite/gas/hppa/basic/sh1add.s +./gas/testsuite/gas/hppa/basic/sh2add.s +./gas/testsuite/gas/hppa/basic/sh3add.s +./gas/testsuite/gas/hppa/basic/shift.s +./gas/testsuite/gas/hppa/basic/shift2.s +./gas/testsuite/gas/hppa/basic/shift3.s +./gas/testsuite/gas/hppa/basic/shladd.s +./gas/testsuite/gas/hppa/basic/shladd2.s +./gas/testsuite/gas/hppa/basic/special.s +./gas/testsuite/gas/hppa/basic/spop.s +./gas/testsuite/gas/hppa/basic/sub.s +./gas/testsuite/gas/hppa/basic/sub2.s +./gas/testsuite/gas/hppa/basic/subi.s +./gas/testsuite/gas/hppa/basic/system.s +./gas/testsuite/gas/hppa/basic/system2.s +./gas/testsuite/gas/hppa/basic/unit.s +./gas/testsuite/gas/hppa/basic/unit2.s +./gas/testsuite/gas/hppa/basic/weird.s +./gas/testsuite/gas/hppa/README +./gas/testsuite/gas/hppa/parse/align1.s +./gas/testsuite/gas/hppa/parse/align2.s +./gas/testsuite/gas/hppa/parse/appbug.s +./gas/testsuite/gas/hppa/parse/badfmpyadd.s +./gas/testsuite/gas/hppa/parse/block1.s +./gas/testsuite/gas/hppa/parse/block2.s +./gas/testsuite/gas/hppa/parse/calldatabug.s +./gas/testsuite/gas/hppa/parse/callinfobug.s +./gas/testsuite/gas/hppa/parse/defbug.s +./gas/testsuite/gas/hppa/parse/entrybug.s +./gas/testsuite/gas/hppa/parse/exportbug.s +./gas/testsuite/gas/hppa/parse/exprbug.s +./gas/testsuite/gas/hppa/parse/fixup7bug.s +./gas/testsuite/gas/hppa/parse/global.s +./gas/testsuite/gas/hppa/parse/labelbug.s +./gas/testsuite/gas/hppa/parse/linesepbug.s +./gas/testsuite/gas/hppa/parse/lselbug.s +./gas/testsuite/gas/hppa/parse/nosubspace.s +./gas/testsuite/gas/hppa/parse/parse.exp +./gas/testsuite/gas/hppa/parse/procbug.s +./gas/testsuite/gas/hppa/parse/regpopbug.s +./gas/testsuite/gas/hppa/parse/spacebug.s +./gas/testsuite/gas/hppa/parse/ssbug.s +./gas/testsuite/gas/hppa/parse/stdreg.s +./gas/testsuite/gas/hppa/parse/stringer.s +./gas/testsuite/gas/hppa/parse/undefbug.s +./gas/testsuite/gas/hppa/parse/versionbug.s +./gas/testsuite/gas/hppa/parse/xmpyubug.s +./gas/testsuite/gas/hppa/reloc/applybug.s +./gas/testsuite/gas/hppa/reloc/blebug.s +./gas/testsuite/gas/hppa/reloc/blebug2.s +./gas/testsuite/gas/hppa/reloc/blebug3.s +./gas/testsuite/gas/hppa/reloc/exitbug.s +./gas/testsuite/gas/hppa/reloc/fixupbug.s +./gas/testsuite/gas/hppa/reloc/funcrelocbug.s +./gas/testsuite/gas/hppa/reloc/labelopbug.s +./gas/testsuite/gas/hppa/reloc/longcall.s +./gas/testsuite/gas/hppa/reloc/picreloc.s +./gas/testsuite/gas/hppa/reloc/plabelbug.s +./gas/testsuite/gas/hppa/reloc/r_no_reloc.s +./gas/testsuite/gas/hppa/reloc/reduce.s +./gas/testsuite/gas/hppa/reloc/reduce2.s +./gas/testsuite/gas/hppa/reloc/reduce3.s +./gas/testsuite/gas/hppa/reloc/reloc.exp +./gas/testsuite/gas/hppa/reloc/roundmode.s +./gas/testsuite/gas/hppa/reloc/selectorbug.s +./gas/testsuite/gas/hppa/unsorted/align3.s +./gas/testsuite/gas/hppa/unsorted/align4.s +./gas/testsuite/gas/hppa/unsorted/brlenbug.s +./gas/testsuite/gas/hppa/unsorted/common.s +./gas/testsuite/gas/hppa/unsorted/fragbug.s +./gas/testsuite/gas/hppa/unsorted/globalbug.s +./gas/testsuite/gas/hppa/unsorted/importbug.s +./gas/testsuite/gas/hppa/unsorted/labeldiffs.s +./gas/testsuite/gas/hppa/unsorted/locallabel.s +./gas/testsuite/gas/hppa/unsorted/ss_align.s +./gas/testsuite/gas/hppa/unsorted/unsorted.exp +./gas/testsuite/gas/i386/absrel.d +./gas/testsuite/gas/i386/absrel.s +./gas/testsuite/gas/i386/amd.d +./gas/testsuite/gas/i386/amd.s +./gas/testsuite/gas/i386/float.l +./gas/testsuite/gas/i386/float.s +./gas/testsuite/gas/i386/general.l +./gas/testsuite/gas/i386/general.s +./gas/testsuite/gas/i386/gotpc.d +./gas/testsuite/gas/i386/gotpc.s +./gas/testsuite/gas/i386/i386.exp +./gas/testsuite/gas/i386/intel.d +./gas/testsuite/gas/i386/intel.s +./gas/testsuite/gas/i386/intel16.d +./gas/testsuite/gas/i386/intel16.s +./gas/testsuite/gas/i386/intelpic.d +./gas/testsuite/gas/i386/intelpic.s +./gas/testsuite/gas/i386/inval.l +./gas/testsuite/gas/i386/inval.s +./gas/testsuite/gas/i386/jump.d +./gas/testsuite/gas/i386/jump.s +./gas/testsuite/gas/i386/jump16.d +./gas/testsuite/gas/i386/jump16.s +./gas/testsuite/gas/i386/katmai.d +./gas/testsuite/gas/i386/katmai.s +./gas/testsuite/gas/i386/modrm.l +./gas/testsuite/gas/i386/modrm.s +./gas/testsuite/gas/i386/naked.d +./gas/testsuite/gas/i386/naked.s +./gas/testsuite/gas/i386/opcode.d +./gas/testsuite/gas/i386/opcode.s +./gas/testsuite/gas/i386/pcrel.d +./gas/testsuite/gas/i386/pcrel.s +./gas/testsuite/gas/i386/prefix.d +./gas/testsuite/gas/i386/prefix.s +./gas/testsuite/gas/i386/relax.d +./gas/testsuite/gas/i386/relax.s +./gas/testsuite/gas/i386/reloc.d +./gas/testsuite/gas/i386/reloc.s +./gas/testsuite/gas/i386/sse2.d +./gas/testsuite/gas/i386/sse2.s +./gas/testsuite/gas/i386/ssemmx2.d +./gas/testsuite/gas/i386/ssemmx2.s +./gas/testsuite/gas/i386/sub.d +./gas/testsuite/gas/i386/sub.s +./gas/testsuite/gas/i386/tlsd.d +./gas/testsuite/gas/i386/tlsd.s +./gas/testsuite/gas/i386/tlsnopic.d +./gas/testsuite/gas/i386/tlsnopic.s +./gas/testsuite/gas/i386/tlspic.d +./gas/testsuite/gas/i386/tlspic.s +./gas/testsuite/gas/i386/white.l +./gas/testsuite/gas/i386/white.s +./gas/testsuite/gas/i386/x86-64-inval.l +./gas/testsuite/gas/i386/x86-64-inval.s +./gas/testsuite/gas/i386/x86-64-opcode.d +./gas/testsuite/gas/i386/x86-64-opcode.s +./gas/testsuite/gas/i386/x86_64.d +./gas/testsuite/gas/i386/x86_64.s +./gas/testsuite/gas/ia64/dependency-1.d +./gas/testsuite/gas/ia64/dependency-1.s +./gas/testsuite/gas/ia64/dv-branch.d +./gas/testsuite/gas/ia64/dv-branch.s +./gas/testsuite/gas/ia64/dv-entry-err.l +./gas/testsuite/gas/ia64/dv-entry-err.s +./gas/testsuite/gas/ia64/dv-imply.d +./gas/testsuite/gas/ia64/dv-imply.s +./gas/testsuite/gas/ia64/dv-mutex-err.l +./gas/testsuite/gas/ia64/dv-mutex-err.s +./gas/testsuite/gas/ia64/dv-mutex.d +./gas/testsuite/gas/ia64/dv-mutex.s +./gas/testsuite/gas/ia64/dv-raw-err.l +./gas/testsuite/gas/ia64/dv-raw-err.s +./gas/testsuite/gas/ia64/dv-safe.d +./gas/testsuite/gas/ia64/dv-safe.s +./gas/testsuite/gas/ia64/dv-srlz.d +./gas/testsuite/gas/ia64/dv-srlz.s +./gas/testsuite/gas/ia64/dv-war-err.l +./gas/testsuite/gas/ia64/dv-war-err.s +./gas/testsuite/gas/ia64/dv-waw-err.l +./gas/testsuite/gas/ia64/dv-waw-err.s +./gas/testsuite/gas/ia64/fixup-dump.pl +./gas/testsuite/gas/ia64/ia64.exp +./gas/testsuite/gas/ia64/ldxmov-1.d +./gas/testsuite/gas/ia64/ldxmov-1.s +./gas/testsuite/gas/ia64/ldxmov-2.l +./gas/testsuite/gas/ia64/ldxmov-2.s +./gas/testsuite/gas/ia64/ltoff22x-1.d +./gas/testsuite/gas/ia64/ltoff22x-1.s +./gas/testsuite/gas/ia64/opc-a-err.l +./gas/testsuite/gas/ia64/opc-a-err.s +./gas/testsuite/gas/ia64/opc-a.d +./gas/testsuite/gas/ia64/opc-a.pl +./gas/testsuite/gas/ia64/opc-a.s +./gas/testsuite/gas/ia64/opc-b.d +./gas/testsuite/gas/ia64/opc-b.pl +./gas/testsuite/gas/ia64/opc-b.s +./gas/testsuite/gas/ia64/opc-f.d +./gas/testsuite/gas/ia64/opc-f.pl +./gas/testsuite/gas/ia64/opc-f.s +./gas/testsuite/gas/ia64/opc-i.d +./gas/testsuite/gas/ia64/opc-i.pl +./gas/testsuite/gas/ia64/opc-i.s +./gas/testsuite/gas/ia64/opc-m.d +./gas/testsuite/gas/ia64/opc-m.pl +./gas/testsuite/gas/ia64/opc-m.s +./gas/testsuite/gas/ia64/opc-x.d +./gas/testsuite/gas/ia64/opc-x.s +./gas/testsuite/gas/ia64/regs.d +./gas/testsuite/gas/ia64/regs.pl +./gas/testsuite/gas/ia64/regs.s +./gas/testsuite/gas/ia64/tls.d +./gas/testsuite/gas/ia64/tls.s +./gas/testsuite/gas/ieee-fp/x930509a.exp +./gas/testsuite/gas/ieee-fp/x930509a.s +./gas/testsuite/gas/iq2000/allinsn.d +./gas/testsuite/gas/iq2000/allinsn.exp +./gas/testsuite/gas/iq2000/allinsn.s +./gas/testsuite/gas/iq2000/hazard0.s +./gas/testsuite/gas/iq2000/hazard1.s +./gas/testsuite/gas/iq2000/hazard2.s +./gas/testsuite/gas/iq2000/hazard3.s +./gas/testsuite/gas/iq2000/hazard4.s +./gas/testsuite/gas/iq2000/hazard5.s +./gas/testsuite/gas/iq2000/load-hazards.exp +./gas/testsuite/gas/iq2000/nohazard.s +./gas/testsuite/gas/iq2000/noyield.s +./gas/testsuite/gas/iq2000/odd-ldw.exp +./gas/testsuite/gas/iq2000/odd-sdw.exp +./gas/testsuite/gas/iq2000/oddldw.s +./gas/testsuite/gas/iq2000/oddsdw.s +./gas/testsuite/gas/iq2000/q10allinsn.d +./gas/testsuite/gas/iq2000/q10allinsn.s +./gas/testsuite/gas/iq2000/q10hazard3.s +./gas/testsuite/gas/iq2000/q10hazard4.s +./gas/testsuite/gas/iq2000/q10hazard5.s +./gas/testsuite/gas/iq2000/q10load-hazards.exp +./gas/testsuite/gas/iq2000/q10nohazard.s +./gas/testsuite/gas/iq2000/q10noyield.s +./gas/testsuite/gas/iq2000/q10test0.d +./gas/testsuite/gas/iq2000/q10test0.s +./gas/testsuite/gas/iq2000/q10test1.d +./gas/testsuite/gas/iq2000/q10test1.s +./gas/testsuite/gas/iq2000/q10test10.d +./gas/testsuite/gas/iq2000/q10test10.s +./gas/testsuite/gas/iq2000/q10test11.d +./gas/testsuite/gas/iq2000/q10test11.s +./gas/testsuite/gas/iq2000/q10test12.d +./gas/testsuite/gas/iq2000/q10test12.s +./gas/testsuite/gas/iq2000/q10test2.d +./gas/testsuite/gas/iq2000/q10test2.s +./gas/testsuite/gas/iq2000/q10test3.d +./gas/testsuite/gas/iq2000/q10test3.s +./gas/testsuite/gas/iq2000/q10test4.d +./gas/testsuite/gas/iq2000/q10test4.s +./gas/testsuite/gas/iq2000/q10test5.d +./gas/testsuite/gas/iq2000/q10test5.s +./gas/testsuite/gas/iq2000/q10test6.d +./gas/testsuite/gas/iq2000/q10test6.s +./gas/testsuite/gas/iq2000/q10test7.d +./gas/testsuite/gas/iq2000/q10test7.s +./gas/testsuite/gas/iq2000/q10test8.d +./gas/testsuite/gas/iq2000/q10test8.s +./gas/testsuite/gas/iq2000/q10test9.d +./gas/testsuite/gas/iq2000/q10test9.s +./gas/testsuite/gas/iq2000/q10yield.exp +./gas/testsuite/gas/iq2000/test.exp +./gas/testsuite/gas/iq2000/yield.exp +./gas/testsuite/gas/iq2000/yield0.s +./gas/testsuite/gas/iq2000/yield1.s +./gas/testsuite/gas/iq2000/yield2.s +./gas/testsuite/gas/m32r/allinsn.d +./gas/testsuite/gas/m32r/allinsn.exp +./gas/testsuite/gas/m32r/allinsn.s +./gas/testsuite/gas/m32r/error.exp +./gas/testsuite/gas/m32r/fslot.d +./gas/testsuite/gas/m32r/fslot.s +./gas/testsuite/gas/m32r/fslotx.d +./gas/testsuite/gas/m32r/fslotx.s +./gas/testsuite/gas/m32r/high-1.d +./gas/testsuite/gas/m32r/high-1.s +./gas/testsuite/gas/m32r/interfere.s +./gas/testsuite/gas/m32r/m32r.exp +./gas/testsuite/gas/m32r/m32rx.d +./gas/testsuite/gas/m32r/m32rx.exp +./gas/testsuite/gas/m32r/m32rx.s +./gas/testsuite/gas/m32r/outofrange.s +./gas/testsuite/gas/m32r/relax-1.d +./gas/testsuite/gas/m32r/relax-1.s +./gas/testsuite/gas/m32r/relax-2.d +./gas/testsuite/gas/m32r/relax-2.s +./gas/testsuite/gas/m32r/signed-relocs.d +./gas/testsuite/gas/m32r/signed-relocs.s +./gas/testsuite/gas/m32r/uppercase.d +./gas/testsuite/gas/m32r/uppercase.s +./gas/testsuite/gas/m32r/wrongsize.s +./gas/testsuite/gas/m68hc11/all_insns.d +./gas/testsuite/gas/m68hc11/all_insns.s +./gas/testsuite/gas/m68hc11/branchs12.d +./gas/testsuite/gas/m68hc11/branchs12.s +./gas/testsuite/gas/m68hc11/bug-1825.d +./gas/testsuite/gas/m68hc11/bug-1825.s +./gas/testsuite/gas/m68hc11/indexed12.d +./gas/testsuite/gas/m68hc11/indexed12.s +./gas/testsuite/gas/m68hc11/insns-dwarf2.d +./gas/testsuite/gas/m68hc11/insns.d +./gas/testsuite/gas/m68hc11/insns.s +./gas/testsuite/gas/m68hc11/insns12.d +./gas/testsuite/gas/m68hc11/insns12.s +./gas/testsuite/gas/m68hc11/lbranch-dwarf2.d +./gas/testsuite/gas/m68hc11/lbranch.d +./gas/testsuite/gas/m68hc11/lbranch.s +./gas/testsuite/gas/m68hc11/m68hc11.exp +./gas/testsuite/gas/m68hc11/malis-include.s +./gas/testsuite/gas/m68hc11/malis.d +./gas/testsuite/gas/m68hc11/malis.s +./gas/testsuite/gas/m68hc11/opers12-dwarf2.d +./gas/testsuite/gas/m68hc11/opers12.d +./gas/testsuite/gas/m68hc11/opers12.s +./gas/testsuite/gas/m68k/bitfield.d +./gas/testsuite/gas/m68k/all.exp +./gas/testsuite/gas/m68k/bitfield.s +./gas/testsuite/gas/m68k/cas.d +./gas/testsuite/gas/m68k/cas.s +./gas/testsuite/gas/m68k/disperr.s +./gas/testsuite/gas/m68k/fmoveml.d +./gas/testsuite/gas/m68k/fmoveml.s +./gas/testsuite/gas/m68k/link.d +./gas/testsuite/gas/m68k/link.s +./gas/testsuite/gas/m68k/op68000.d +./gas/testsuite/gas/m68k/operands.d +./gas/testsuite/gas/m68k/operands.s +./gas/testsuite/gas/m68k/p2410.s +./gas/testsuite/gas/m68k/p2663.s +./gas/testsuite/gas/m68k/pcrel.d +./gas/testsuite/gas/m68k/pcrel.s +./gas/testsuite/gas/m68k/pic1.s +./gas/testsuite/gas/m68k/t2.d +./gas/testsuite/gas/m68k/t2.s +./gas/testsuite/gas/m68k-coff/p2389a.s +./gas/testsuite/gas/m68k-coff/gas.exp +./gas/testsuite/gas/m68k-coff/p2389.s +./gas/testsuite/gas/m68k-coff/p2430a.s +./gas/testsuite/gas/m68k-coff/p2430.s +./gas/testsuite/gas/m68k-coff/t1.s +./gas/testsuite/gas/m88k/allinsn.d +./gas/testsuite/gas/m88k/allinsn.s +./gas/testsuite/gas/m88k/init.d +./gas/testsuite/gas/m88k/init.s +./gas/testsuite/gas/m88k/m88k.exp +./gas/testsuite/gas/macros/macros.exp +./gas/testsuite/gas/macros/err.s +./gas/testsuite/gas/macros/irp.d +./gas/testsuite/gas/macros/irp.s +./gas/testsuite/gas/macros/strings.d +./gas/testsuite/gas/macros/rept.d +./gas/testsuite/gas/macros/rept.s +./gas/testsuite/gas/macros/semi.d +./gas/testsuite/gas/macros/semi.s +./gas/testsuite/gas/macros/strings.s +./gas/testsuite/gas/macros/test1.d +./gas/testsuite/gas/macros/test1.s +./gas/testsuite/gas/macros/test2.d +./gas/testsuite/gas/macros/test2.s +./gas/testsuite/gas/macros/test3.d +./gas/testsuite/gas/macros/test3.s +./gas/testsuite/gas/macros/app1.d +./gas/testsuite/gas/macros/app1.s +./gas/testsuite/gas/macros/app2.d +./gas/testsuite/gas/macros/app2.s +./gas/testsuite/gas/macros/app3.d +./gas/testsuite/gas/macros/app3.s +./gas/testsuite/gas/macros/app4.d +./gas/testsuite/gas/macros/app4.s +./gas/testsuite/gas/macros/app4b.s +./gas/testsuite/gas/mcore/allinsn.d +./gas/testsuite/gas/mcore/allinsn.exp +./gas/testsuite/gas/mcore/allinsn.s +./gas/testsuite/gas/mips/baddata1.l +./gas/testsuite/gas/mips/abs.d +./gas/testsuite/gas/mips/abs.s +./gas/testsuite/gas/mips/add.d +./gas/testsuite/gas/mips/add.s +./gas/testsuite/gas/mips/and.d +./gas/testsuite/gas/mips/and.s +./gas/testsuite/gas/mips/baddata1.s +./gas/testsuite/gas/mips/beq.d +./gas/testsuite/gas/mips/beq.s +./gas/testsuite/gas/mips/bge.d +./gas/testsuite/gas/mips/bge.s +./gas/testsuite/gas/mips/bgeu.d +./gas/testsuite/gas/mips/bgeu.s +./gas/testsuite/gas/mips/blt.d +./gas/testsuite/gas/mips/blt.s +./gas/testsuite/gas/mips/bltu.d +./gas/testsuite/gas/mips/bltu.s +./gas/testsuite/gas/mips/branch-misc-1.d +./gas/testsuite/gas/mips/branch-misc-1.s +./gas/testsuite/gas/mips/branch-misc-2.l +./gas/testsuite/gas/mips/branch-misc-2.s +./gas/testsuite/gas/mips/break20.d +./gas/testsuite/gas/mips/break20.s +./gas/testsuite/gas/mips/cp0-names-mips32.d +./gas/testsuite/gas/mips/cp0-names-mips64.d +./gas/testsuite/gas/mips/cp0-names-mips32r2.d +./gas/testsuite/gas/mips/cp0-names-numeric.d +./gas/testsuite/gas/mips/cp0-names-sb1.d +./gas/testsuite/gas/mips/cp0-names.s +./gas/testsuite/gas/mips/cp0sel-names-mips32.d +./gas/testsuite/gas/mips/cp0sel-names-mips32r2.d +./gas/testsuite/gas/mips/cp0sel-names-mips64.d +./gas/testsuite/gas/mips/cp0sel-names-numeric.d +./gas/testsuite/gas/mips/cp0sel-names-sb1.d +./gas/testsuite/gas/mips/cp0sel-names.s +./gas/testsuite/gas/mips/delay.d +./gas/testsuite/gas/mips/delay.s +./gas/testsuite/gas/mips/div-ilocks.d +./gas/testsuite/gas/mips/div.d +./gas/testsuite/gas/mips/div.s +./gas/testsuite/gas/mips/dli.d +./gas/testsuite/gas/mips/dli.s +./gas/testsuite/gas/mips/e32-rel2.d +./gas/testsuite/gas/mips/e32-rel4.d +./gas/testsuite/gas/mips/e32el-rel2.d +./gas/testsuite/gas/mips/elempic.d +./gas/testsuite/gas/mips/elf-consthilo.d +./gas/testsuite/gas/mips/elf-consthilo.s +./gas/testsuite/gas/mips/elf-jal.d +./gas/testsuite/gas/mips/elf-rel-got-n32.d +./gas/testsuite/gas/mips/elf-rel-got-n32.s +./gas/testsuite/gas/mips/elf-rel-got-n64.d +./gas/testsuite/gas/mips/elf-rel-got-n64.s +./gas/testsuite/gas/mips/elf-rel-xgot-n32.d +./gas/testsuite/gas/mips/elf-rel-xgot-n64.d +./gas/testsuite/gas/mips/elf-rel.d +./gas/testsuite/gas/mips/elf-rel.s +./gas/testsuite/gas/mips/elf-rel10.d +./gas/testsuite/gas/mips/elf-rel10.s +./gas/testsuite/gas/mips/elf-rel11.d +./gas/testsuite/gas/mips/elf-rel11.s +./gas/testsuite/gas/mips/elf-rel12.d +./gas/testsuite/gas/mips/elf-rel12.s +./gas/testsuite/gas/mips/elf-rel13.d +./gas/testsuite/gas/mips/elf-rel13.s +./gas/testsuite/gas/mips/elf-rel14.d +./gas/testsuite/gas/mips/elf-rel14.s +./gas/testsuite/gas/mips/elf-rel2.d +./gas/testsuite/gas/mips/elf-rel2.s +./gas/testsuite/gas/mips/elf-rel3.d +./gas/testsuite/gas/mips/elf-rel3.s +./gas/testsuite/gas/mips/elf-rel4.d +./gas/testsuite/gas/mips/elf-rel4.s +./gas/testsuite/gas/mips/elf-rel5.d +./gas/testsuite/gas/mips/elf-rel5.s +./gas/testsuite/gas/mips/elf-rel6.d +./gas/testsuite/gas/mips/elf-rel6.s +./gas/testsuite/gas/mips/elf-rel7.d +./gas/testsuite/gas/mips/elf-rel7.s +./gas/testsuite/gas/mips/elf-rel8.d +./gas/testsuite/gas/mips/elf-rel8.s +./gas/testsuite/gas/mips/elf-rel9.d +./gas/testsuite/gas/mips/elf-rel9.s +./gas/testsuite/gas/mips/elf_arch_mips1.d +./gas/testsuite/gas/mips/elf_arch_mips2.d +./gas/testsuite/gas/mips/elf_arch_mips3.d +./gas/testsuite/gas/mips/elf_arch_mips32.d +./gas/testsuite/gas/mips/elf_arch_mips32r2.d +./gas/testsuite/gas/mips/elf_arch_mips4.d +./gas/testsuite/gas/mips/elf_arch_mips5.d +./gas/testsuite/gas/mips/elf_arch_mips64.d +./gas/testsuite/gas/mips/elf_ase_mips16.d +./gas/testsuite/gas/mips/elf_e_flags.c +./gas/testsuite/gas/mips/elf_e_flags.s +./gas/testsuite/gas/mips/elf_e_flags1.d +./gas/testsuite/gas/mips/elf_e_flags2.d +./gas/testsuite/gas/mips/elf_e_flags3.d +./gas/testsuite/gas/mips/elf_e_flags4.d +./gas/testsuite/gas/mips/elfel-rel.d +./gas/testsuite/gas/mips/elfel-rel2.d +./gas/testsuite/gas/mips/elfel-rel3.d +./gas/testsuite/gas/mips/empic.d +./gas/testsuite/gas/mips/empic.l +./gas/testsuite/gas/mips/empic.s +./gas/testsuite/gas/mips/empic2.d +./gas/testsuite/gas/mips/empic2.s +./gas/testsuite/gas/mips/empic3_e.d +./gas/testsuite/gas/mips/empic3_e.s +./gas/testsuite/gas/mips/empic3_g1.d +./gas/testsuite/gas/mips/empic3_g1.s +./gas/testsuite/gas/mips/empic3_g2.d +./gas/testsuite/gas/mips/empic3_g2.s +./gas/testsuite/gas/mips/empty.s +./gas/testsuite/gas/mips/expr1.d +./gas/testsuite/gas/mips/expr1.s +./gas/testsuite/gas/mips/fpr-names-32.d +./gas/testsuite/gas/mips/fpr-names.s +./gas/testsuite/gas/mips/fpr-names-64.d +./gas/testsuite/gas/mips/fpr-names-n32.d +./gas/testsuite/gas/mips/fpr-names-numeric.d +./gas/testsuite/gas/mips/gpr-names-32.d +./gas/testsuite/gas/mips/gpr-names-64.d +./gas/testsuite/gas/mips/gpr-names-n32.d +./gas/testsuite/gas/mips/gpr-names-numeric.d +./gas/testsuite/gas/mips/gpr-names.s +./gas/testsuite/gas/mips/hwr-names-mips32r2.d +./gas/testsuite/gas/mips/hwr-names-numeric.d +./gas/testsuite/gas/mips/hwr-names.s +./gas/testsuite/gas/mips/illegal.l +./gas/testsuite/gas/mips/illegal.s +./gas/testsuite/gas/mips/itbl +./gas/testsuite/gas/mips/itbl.s +./gas/testsuite/gas/mips/jal-empic-elf-2.d +./gas/testsuite/gas/mips/jal-empic-elf-2.s +./gas/testsuite/gas/mips/jal-empic-elf-3.d +./gas/testsuite/gas/mips/jal-empic-elf-3.s +./gas/testsuite/gas/mips/jal-empic-elf.d +./gas/testsuite/gas/mips/jal-empic.d +./gas/testsuite/gas/mips/jal-range.l +./gas/testsuite/gas/mips/jal-range.s +./gas/testsuite/gas/mips/jal-svr4pic.d +./gas/testsuite/gas/mips/jal-svr4pic.s +./gas/testsuite/gas/mips/jal-xgot.d +./gas/testsuite/gas/mips/jal.d +./gas/testsuite/gas/mips/jal.s +./gas/testsuite/gas/mips/la-empic.d +./gas/testsuite/gas/mips/la-empic.s +./gas/testsuite/gas/mips/la-svr4pic.d +./gas/testsuite/gas/mips/la-xgot.d +./gas/testsuite/gas/mips/la.d +./gas/testsuite/gas/mips/la.s +./gas/testsuite/gas/mips/lb-empic.d +./gas/testsuite/gas/mips/lb-pic.s +./gas/testsuite/gas/mips/lb-svr4pic.d +./gas/testsuite/gas/mips/lb-xgot-ilocks.d +./gas/testsuite/gas/mips/lb-xgot.d +./gas/testsuite/gas/mips/lb.d +./gas/testsuite/gas/mips/lb.s +./gas/testsuite/gas/mips/ld-empic.d +./gas/testsuite/gas/mips/ld-ilocks-addr32.d +./gas/testsuite/gas/mips/ld-ilocks.d +./gas/testsuite/gas/mips/ld-pic.s +./gas/testsuite/gas/mips/ld-svr4pic.d +./gas/testsuite/gas/mips/ld-xgot.d +./gas/testsuite/gas/mips/ld.d +./gas/testsuite/gas/mips/ld.s +./gas/testsuite/gas/mips/li.d +./gas/testsuite/gas/mips/li.s +./gas/testsuite/gas/mips/lif-empic.d +./gas/testsuite/gas/mips/lif-svr4pic.d +./gas/testsuite/gas/mips/lif-xgot.d +./gas/testsuite/gas/mips/lifloat.d +./gas/testsuite/gas/mips/lifloat.s +./gas/testsuite/gas/mips/lineno.d +./gas/testsuite/gas/mips/lineno.s +./gas/testsuite/gas/mips/mips-abi32-pic.d +./gas/testsuite/gas/mips/mips-abi32-pic.s +./gas/testsuite/gas/mips/mips-abi32-pic2.d +./gas/testsuite/gas/mips/mips-abi32-pic2.s +./gas/testsuite/gas/mips/mips-abi32.d +./gas/testsuite/gas/mips/mips-abi32.s +./gas/testsuite/gas/mips/mips-gp32-fp32-pic.d +./gas/testsuite/gas/mips/mips-gp32-fp32-pic.s +./gas/testsuite/gas/mips/mips-gp32-fp32.d +./gas/testsuite/gas/mips/mips-gp32-fp32.s +./gas/testsuite/gas/mips/mips-gp32-fp64-pic.d +./gas/testsuite/gas/mips/mips-gp32-fp64-pic.s +./gas/testsuite/gas/mips/mips-gp32-fp64.d +./gas/testsuite/gas/mips/mips-gp32-fp64.s +./gas/testsuite/gas/mips/mips-gp64-fp32-pic.d +./gas/testsuite/gas/mips/mips-gp64-fp32.d +./gas/testsuite/gas/mips/mips-gp64-fp32-pic.s +./gas/testsuite/gas/mips/mips-gp64-fp32.l +./gas/testsuite/gas/mips/mips-gp64-fp32.s +./gas/testsuite/gas/mips/mips-gp64-fp64-pic.d +./gas/testsuite/gas/mips/mips-gp64-fp64-pic.s +./gas/testsuite/gas/mips/mips-gp64-fp64.d +./gas/testsuite/gas/mips/mips-gp64-fp64.l +./gas/testsuite/gas/mips/mips-gp64-fp64.s +./gas/testsuite/gas/mips/mips-jalx.d +./gas/testsuite/gas/mips/mips-jalx.s +./gas/testsuite/gas/mips/mips-no-jalx.l +./gas/testsuite/gas/mips/mips-no-jalx.s +./gas/testsuite/gas/mips/mips.exp +./gas/testsuite/gas/mips/mips16-e.d +./gas/testsuite/gas/mips/mips16-e.s +./gas/testsuite/gas/mips/mips16-f.d +./gas/testsuite/gas/mips/mips16-f.s +./gas/testsuite/gas/mips/mips16-jalx.d +./gas/testsuite/gas/mips/mips16-jalx.s +./gas/testsuite/gas/mips/mips16.d +./gas/testsuite/gas/mips/mips16.s +./gas/testsuite/gas/mips/mips32.d +./gas/testsuite/gas/mips/mips32.s +./gas/testsuite/gas/mips/mips32r2-ill.l +./gas/testsuite/gas/mips/mips32r2-ill.s +./gas/testsuite/gas/mips/mips32r2.d +./gas/testsuite/gas/mips/mips32r2.s +./gas/testsuite/gas/mips/mips4.d +./gas/testsuite/gas/mips/mips4.s +./gas/testsuite/gas/mips/mips4010.d +./gas/testsuite/gas/mips/mips4010.s +./gas/testsuite/gas/mips/mips4100.d +./gas/testsuite/gas/mips/mips4100.s +./gas/testsuite/gas/mips/mips4650.d +./gas/testsuite/gas/mips/mips4650.s +./gas/testsuite/gas/mips/mips5.d +./gas/testsuite/gas/mips/mips5.l +./gas/testsuite/gas/mips/mips5.s +./gas/testsuite/gas/mips/mips64-mdmx.d +./gas/testsuite/gas/mips/mips64-mdmx.s +./gas/testsuite/gas/mips/mips64-mips3d-incl.d +./gas/testsuite/gas/mips/mips64-mips3d.d +./gas/testsuite/gas/mips/mips64-mips3d.s +./gas/testsuite/gas/mips/mips64.d +./gas/testsuite/gas/mips/mips64.s +./gas/testsuite/gas/mips/mipsel16-e.d +./gas/testsuite/gas/mips/mipsel16-f.d +./gas/testsuite/gas/mips/mul-ilocks.d +./gas/testsuite/gas/mips/mul.d +./gas/testsuite/gas/mips/mul.s +./gas/testsuite/gas/mips/n32-consec.d +./gas/testsuite/gas/mips/n32-consec.s +./gas/testsuite/gas/mips/nodelay.d +./gas/testsuite/gas/mips/perfcount.d +./gas/testsuite/gas/mips/perfcount.s +./gas/testsuite/gas/mips/relax.d +./gas/testsuite/gas/mips/relax.l +./gas/testsuite/gas/mips/relax.s +./gas/testsuite/gas/mips/rol-hw.d +./gas/testsuite/gas/mips/rol-hw.l +./gas/testsuite/gas/mips/rol.d +./gas/testsuite/gas/mips/rol.l +./gas/testsuite/gas/mips/rol.s +./gas/testsuite/gas/mips/rol64-hw.d +./gas/testsuite/gas/mips/rol64-hw.l +./gas/testsuite/gas/mips/rol64.d +./gas/testsuite/gas/mips/rol64.l +./gas/testsuite/gas/mips/rol64.s +./gas/testsuite/gas/mips/sb.d +./gas/testsuite/gas/mips/sb.s +./gas/testsuite/gas/mips/sb1-ext-mdmx.d +./gas/testsuite/gas/mips/sb1-ext-mdmx.s +./gas/testsuite/gas/mips/sb1-ext-ps.d +./gas/testsuite/gas/mips/sb1-ext-ps.s +./gas/testsuite/gas/mips/sync.d +./gas/testsuite/gas/mips/sync.s +./gas/testsuite/gas/mips/telempic.d +./gas/testsuite/gas/mips/tempic.d +./gas/testsuite/gas/mips/tmips16-e.d +./gas/testsuite/gas/mips/tmips16-f.d +./gas/testsuite/gas/mips/tmipsel16-e.d +./gas/testsuite/gas/mips/tmipsel16-f.d +./gas/testsuite/gas/mips/trap20.d +./gas/testsuite/gas/mips/trap20.s +./gas/testsuite/gas/mips/trunc.d +./gas/testsuite/gas/mips/trunc.s +./gas/testsuite/gas/mips/uld.d +./gas/testsuite/gas/mips/uld.s +./gas/testsuite/gas/mips/uld2-eb.d +./gas/testsuite/gas/mips/uld2-el.d +./gas/testsuite/gas/mips/uld2.l +./gas/testsuite/gas/mips/uld2.s +./gas/testsuite/gas/mips/ulh-empic.d +./gas/testsuite/gas/mips/ulh-pic.s +./gas/testsuite/gas/mips/ulh-svr4pic.d +./gas/testsuite/gas/mips/ulh-xgot.d +./gas/testsuite/gas/mips/ulh.d +./gas/testsuite/gas/mips/ulh.s +./gas/testsuite/gas/mips/ulh2-eb.d +./gas/testsuite/gas/mips/ulh2-el.d +./gas/testsuite/gas/mips/ulh2.l +./gas/testsuite/gas/mips/ulh2.s +./gas/testsuite/gas/mips/ulw.d +./gas/testsuite/gas/mips/ulw.s +./gas/testsuite/gas/mips/ulw2-eb-ilocks.d +./gas/testsuite/gas/mips/ulw2-eb.d +./gas/testsuite/gas/mips/ulw2-el-ilocks.d +./gas/testsuite/gas/mips/ulw2-el.d +./gas/testsuite/gas/mips/ulw2.l +./gas/testsuite/gas/mips/ulw2.s +./gas/testsuite/gas/mips/usd.d +./gas/testsuite/gas/mips/usd.s +./gas/testsuite/gas/mips/ush.d +./gas/testsuite/gas/mips/ush.s +./gas/testsuite/gas/mips/usw.d +./gas/testsuite/gas/mips/usw.s +./gas/testsuite/gas/mips/vr4111.d +./gas/testsuite/gas/mips/vr4111.s +./gas/testsuite/gas/mips/vr4120.d +./gas/testsuite/gas/mips/vr4120.s +./gas/testsuite/gas/mips/vr4122.d +./gas/testsuite/gas/mips/vr4122.s +./gas/testsuite/gas/mips/vr5400.d +./gas/testsuite/gas/mips/vr5400.s +./gas/testsuite/gas/mips/vr5500.d +./gas/testsuite/gas/mips/vr5500.s +./gas/testsuite/gas/mips/jal-newabi.d +./gas/testsuite/gas/mips/jal-newabi.s +./gas/testsuite/gas/mips/elf-rel15.d +./gas/testsuite/gas/mips/elf-rel15.s +./gas/testsuite/gas/mmix/1cjmp1b-n.d +./gas/testsuite/gas/mmix/1cjmp1b-r.d +./gas/testsuite/gas/mmix/1cjmp1b.d +./gas/testsuite/gas/mmix/1cjmp1b.l +./gas/testsuite/gas/mmix/1cjmp1b.s +./gas/testsuite/gas/mmix/1cjmp1brn.d +./gas/testsuite/gas/mmix/1hjmp1b.d +./gas/testsuite/gas/mmix/1hjmp1b.l +./gas/testsuite/gas/mmix/1hjmp1b.s +./gas/testsuite/gas/mmix/align-1.d +./gas/testsuite/gas/mmix/align-1.s +./gas/testsuite/gas/mmix/basep-1.d +./gas/testsuite/gas/mmix/basep-1.s +./gas/testsuite/gas/mmix/basep-10.d +./gas/testsuite/gas/mmix/basep-10.s +./gas/testsuite/gas/mmix/basep-11.d +./gas/testsuite/gas/mmix/basep-11.s +./gas/testsuite/gas/mmix/basep-1b.d +./gas/testsuite/gas/mmix/basep-2.d +./gas/testsuite/gas/mmix/basep-2.s +./gas/testsuite/gas/mmix/basep-2b.d +./gas/testsuite/gas/mmix/basep-3.d +./gas/testsuite/gas/mmix/basep-3.s +./gas/testsuite/gas/mmix/basep-3b.d +./gas/testsuite/gas/mmix/basep-4.d +./gas/testsuite/gas/mmix/basep-5.d +./gas/testsuite/gas/mmix/basep-6.d +./gas/testsuite/gas/mmix/basep-7.d +./gas/testsuite/gas/mmix/basep-8.d +./gas/testsuite/gas/mmix/basep-8.s +./gas/testsuite/gas/mmix/basep-9.d +./gas/testsuite/gas/mmix/basep-9.s +./gas/testsuite/gas/mmix/bspec-1.d +./gas/testsuite/gas/mmix/bspec-1.s +./gas/testsuite/gas/mmix/bspec-2.d +./gas/testsuite/gas/mmix/bspec-2.s +./gas/testsuite/gas/mmix/builtin1.d +./gas/testsuite/gas/mmix/builtin1.s +./gas/testsuite/gas/mmix/builtin2.d +./gas/testsuite/gas/mmix/builtin3.d +./gas/testsuite/gas/mmix/byte-1.d +./gas/testsuite/gas/mmix/byte-1.s +./gas/testsuite/gas/mmix/bz-c.d +./gas/testsuite/gas/mmix/bz-c.s +./gas/testsuite/gas/mmix/comment-1.d +./gas/testsuite/gas/mmix/comment-1.s +./gas/testsuite/gas/mmix/comment-2.d +./gas/testsuite/gas/mmix/comment-2.s +./gas/testsuite/gas/mmix/comment-3.d +./gas/testsuite/gas/mmix/comment-3.s +./gas/testsuite/gas/mmix/cons-1.d +./gas/testsuite/gas/mmix/cons-1.s +./gas/testsuite/gas/mmix/cons-2.d +./gas/testsuite/gas/mmix/cons-2.s +./gas/testsuite/gas/mmix/err-bpo1.s +./gas/testsuite/gas/mmix/err-bpo2.s +./gas/testsuite/gas/mmix/err-bpo3.s +./gas/testsuite/gas/mmix/err-bpo4.s +./gas/testsuite/gas/mmix/err-bpo5.s +./gas/testsuite/gas/mmix/err-bpo6.s +./gas/testsuite/gas/mmix/err-bspec-1.s +./gas/testsuite/gas/mmix/err-bspec-2.s +./gas/testsuite/gas/mmix/err-bspec-3.s +./gas/testsuite/gas/mmix/err-bspec-4.s +./gas/testsuite/gas/mmix/err-bspec-5.s +./gas/testsuite/gas/mmix/err-builtin.s +./gas/testsuite/gas/mmix/err-byte1.s +./gas/testsuite/gas/mmix/err-byte2.s +./gas/testsuite/gas/mmix/err-case.s +./gas/testsuite/gas/mmix/err-fb-1.s +./gas/testsuite/gas/mmix/err-greg1.s +./gas/testsuite/gas/mmix/err-insn.s +./gas/testsuite/gas/mmix/err-is-1.s +./gas/testsuite/gas/mmix/err-loc-1.s +./gas/testsuite/gas/mmix/err-loc-2.s +./gas/testsuite/gas/mmix/err-loc-3.s +./gas/testsuite/gas/mmix/err-loc-4.s +./gas/testsuite/gas/mmix/err-loc-5.s +./gas/testsuite/gas/mmix/err-loc-6.s +./gas/testsuite/gas/mmix/err-loc-7.s +./gas/testsuite/gas/mmix/err-loc-8.s +./gas/testsuite/gas/mmix/err-local1.s +./gas/testsuite/gas/mmix/err-local2.s +./gas/testsuite/gas/mmix/err-ser-1.s +./gas/testsuite/gas/mmix/err-set.s +./gas/testsuite/gas/mmix/expr-1.d +./gas/testsuite/gas/mmix/expr-1.s +./gas/testsuite/gas/mmix/fb-1.d +./gas/testsuite/gas/mmix/fb-1.s +./gas/testsuite/gas/mmix/fb-2.d +./gas/testsuite/gas/mmix/fb-2.s +./gas/testsuite/gas/mmix/get-op-r.d +./gas/testsuite/gas/mmix/get-op.d +./gas/testsuite/gas/mmix/get-op.l +./gas/testsuite/gas/mmix/get-op.s +./gas/testsuite/gas/mmix/geta-c.d +./gas/testsuite/gas/mmix/geta-c.s +./gas/testsuite/gas/mmix/geta-op-r.d +./gas/testsuite/gas/mmix/geta-op.d +./gas/testsuite/gas/mmix/geta-op.l +./gas/testsuite/gas/mmix/geta-op.s +./gas/testsuite/gas/mmix/geta-opn.d +./gas/testsuite/gas/mmix/geta-oprn.d +./gas/testsuite/gas/mmix/greg1.d +./gas/testsuite/gas/mmix/greg1.s +./gas/testsuite/gas/mmix/greg1a.d +./gas/testsuite/gas/mmix/greg2.d +./gas/testsuite/gas/mmix/greg2.s +./gas/testsuite/gas/mmix/greg2a.d +./gas/testsuite/gas/mmix/greg3.d +./gas/testsuite/gas/mmix/greg3.s +./gas/testsuite/gas/mmix/greg4.d +./gas/testsuite/gas/mmix/greg4.s +./gas/testsuite/gas/mmix/greg5.d +./gas/testsuite/gas/mmix/greg5.s +./gas/testsuite/gas/mmix/greg6.d +./gas/testsuite/gas/mmix/greg6.s +./gas/testsuite/gas/mmix/greg7.d +./gas/testsuite/gas/mmix/greg7.s +./gas/testsuite/gas/mmix/greg8.d +./gas/testsuite/gas/mmix/greg8.s +./gas/testsuite/gas/mmix/greg9.d +./gas/testsuite/gas/mmix/greg9.s +./gas/testsuite/gas/mmix/hex-r.d +./gas/testsuite/gas/mmix/hex.d +./gas/testsuite/gas/mmix/hex.l +./gas/testsuite/gas/mmix/hex.s +./gas/testsuite/gas/mmix/is-1.d +./gas/testsuite/gas/mmix/is-1.s +./gas/testsuite/gas/mmix/jmp-op-n.d +./gas/testsuite/gas/mmix/jmp-op-r.d +./gas/testsuite/gas/mmix/jmp-op.d +./gas/testsuite/gas/mmix/jmp-op.l +./gas/testsuite/gas/mmix/jmp-op.s +./gas/testsuite/gas/mmix/jmp-oprn.d +./gas/testsuite/gas/mmix/jump-c.d +./gas/testsuite/gas/mmix/jump-c.s +./gas/testsuite/gas/mmix/list-in-n.d +./gas/testsuite/gas/mmix/list-in-r.d +./gas/testsuite/gas/mmix/list-in-rn.d +./gas/testsuite/gas/mmix/list-insns.d +./gas/testsuite/gas/mmix/list-insns.l +./gas/testsuite/gas/mmix/list-insns.s +./gas/testsuite/gas/mmix/list-pseudoints.l +./gas/testsuite/gas/mmix/list-pseudoints.s +./gas/testsuite/gas/mmix/list-textfirst +./gas/testsuite/gas/mmix/list-textfirst.l +./gas/testsuite/gas/mmix/list-textfirst.s +./gas/testsuite/gas/mmix/loc-1.d +./gas/testsuite/gas/mmix/loc-1.s +./gas/testsuite/gas/mmix/loc-2.d +./gas/testsuite/gas/mmix/loc-2.s +./gas/testsuite/gas/mmix/loc-3.d +./gas/testsuite/gas/mmix/loc-3.s +./gas/testsuite/gas/mmix/loc-4.d +./gas/testsuite/gas/mmix/loc-4.s +./gas/testsuite/gas/mmix/loc-5.d +./gas/testsuite/gas/mmix/loc-5.s +./gas/testsuite/gas/mmix/local-1.d +./gas/testsuite/gas/mmix/local-1.s +./gas/testsuite/gas/mmix/locall1.d +./gas/testsuite/gas/mmix/locall1.s +./gas/testsuite/gas/mmix/mmix-err.exp +./gas/testsuite/gas/mmix/mmix-list.exp +./gas/testsuite/gas/mmix/mmix.exp +./gas/testsuite/gas/mmix/odd-1.d +./gas/testsuite/gas/mmix/odd-1.s +./gas/testsuite/gas/mmix/op-0-1.d +./gas/testsuite/gas/mmix/op-0-1.s +./gas/testsuite/gas/mmix/op-0-2.d +./gas/testsuite/gas/mmix/pop-op-r.d +./gas/testsuite/gas/mmix/pop-op.d +./gas/testsuite/gas/mmix/pop-op.l +./gas/testsuite/gas/mmix/pop-op.s +./gas/testsuite/gas/mmix/prefix1.d +./gas/testsuite/gas/mmix/prefix1.s +./gas/testsuite/gas/mmix/prefix2.d +./gas/testsuite/gas/mmix/prefix2.s +./gas/testsuite/gas/mmix/prefix3.d +./gas/testsuite/gas/mmix/prefix3.s +./gas/testsuite/gas/mmix/pseudo-1.d +./gas/testsuite/gas/mmix/pseudo-1.s +./gas/testsuite/gas/mmix/pushgo-op-r.d +./gas/testsuite/gas/mmix/pushgo-op.d +./gas/testsuite/gas/mmix/pushgo-op.l +./gas/testsuite/gas/mmix/pushgo-op.s +./gas/testsuite/gas/mmix/pushj-c.d +./gas/testsuite/gas/mmix/pushj-c.s +./gas/testsuite/gas/mmix/put-op-r.d +./gas/testsuite/gas/mmix/put-op.d +./gas/testsuite/gas/mmix/put-op.l +./gas/testsuite/gas/mmix/put-op.s +./gas/testsuite/gas/mmix/reg-op-r.d +./gas/testsuite/gas/mmix/reg-op.d +./gas/testsuite/gas/mmix/reg-op.l +./gas/testsuite/gas/mmix/reg-op.s +./gas/testsuite/gas/mmix/reg3-op-r.d +./gas/testsuite/gas/mmix/reg3-op.d +./gas/testsuite/gas/mmix/reg3-op.l +./gas/testsuite/gas/mmix/reg3-op.s +./gas/testsuite/gas/mmix/regt-op-r.d +./gas/testsuite/gas/mmix/regt-op.d +./gas/testsuite/gas/mmix/regt-op.l +./gas/testsuite/gas/mmix/regt-op.s +./gas/testsuite/gas/mmix/regx-op-r.d +./gas/testsuite/gas/mmix/regx-op.d +./gas/testsuite/gas/mmix/regx-op.l +./gas/testsuite/gas/mmix/regx-op.s +./gas/testsuite/gas/mmix/regy-op-r.d +./gas/testsuite/gas/mmix/regy-op.d +./gas/testsuite/gas/mmix/regy-op.l +./gas/testsuite/gas/mmix/regy-op.s +./gas/testsuite/gas/mmix/relax1-n.d +./gas/testsuite/gas/mmix/relax1.d +./gas/testsuite/gas/mmix/relax1-r.d +./gas/testsuite/gas/mmix/relax1-rn.d +./gas/testsuite/gas/mmix/relax1.l +./gas/testsuite/gas/mmix/relax1.s +./gas/testsuite/gas/mmix/reloc16-n.d +./gas/testsuite/gas/mmix/reloc16-r.d +./gas/testsuite/gas/mmix/reloc16.d +./gas/testsuite/gas/mmix/reloc16.l +./gas/testsuite/gas/mmix/reloc16.s +./gas/testsuite/gas/mmix/reloc8-r.d +./gas/testsuite/gas/mmix/reloc8.d +./gas/testsuite/gas/mmix/reloc8.l +./gas/testsuite/gas/mmix/reloc8.s +./gas/testsuite/gas/mmix/relocl-n.d +./gas/testsuite/gas/mmix/reloclab-r.d +./gas/testsuite/gas/mmix/reloclab.d +./gas/testsuite/gas/mmix/reloclab.l +./gas/testsuite/gas/mmix/reloclab.s +./gas/testsuite/gas/mmix/reloclrn.d +./gas/testsuite/gas/mmix/relocxrn.d +./gas/testsuite/gas/mmix/resume-op-r.d +./gas/testsuite/gas/mmix/resume-op.d +./gas/testsuite/gas/mmix/resume-op.l +./gas/testsuite/gas/mmix/resume-op.s +./gas/testsuite/gas/mmix/round2-op-r.d +./gas/testsuite/gas/mmix/round2-op.d +./gas/testsuite/gas/mmix/round2-op.l +./gas/testsuite/gas/mmix/round2-op.s +./gas/testsuite/gas/mmix/roundi-op-r.d +./gas/testsuite/gas/mmix/roundi-op.d +./gas/testsuite/gas/mmix/roundi-op.l +./gas/testsuite/gas/mmix/roundi-op.s +./gas/testsuite/gas/mmix/roundr-op-r.d +./gas/testsuite/gas/mmix/roundr-op.d +./gas/testsuite/gas/mmix/roundr-op.l +./gas/testsuite/gas/mmix/roundr-op.s +./gas/testsuite/gas/mmix/save-op-r.d +./gas/testsuite/gas/mmix/save-op.d +./gas/testsuite/gas/mmix/save-op.l +./gas/testsuite/gas/mmix/save-op.s +./gas/testsuite/gas/mmix/set-r.d +./gas/testsuite/gas/mmix/set.d +./gas/testsuite/gas/mmix/set.l +./gas/testsuite/gas/mmix/set.s +./gas/testsuite/gas/mmix/swym-op-r.d +./gas/testsuite/gas/mmix/swym-op.d +./gas/testsuite/gas/mmix/swym-op.l +./gas/testsuite/gas/mmix/swym-op.s +./gas/testsuite/gas/mmix/sym-1.d +./gas/testsuite/gas/mmix/sym-1.s +./gas/testsuite/gas/mmix/sync-op-r.d +./gas/testsuite/gas/mmix/sync-op.d +./gas/testsuite/gas/mmix/sync-op.l +./gas/testsuite/gas/mmix/sync-op.s +./gas/testsuite/gas/mmix/two-op-r.d +./gas/testsuite/gas/mmix/two-op.d +./gas/testsuite/gas/mmix/two-op.l +./gas/testsuite/gas/mmix/two-op.s +./gas/testsuite/gas/mmix/unsave-op-r.d +./gas/testsuite/gas/mmix/unsave-op.d +./gas/testsuite/gas/mmix/unsave-op.l +./gas/testsuite/gas/mmix/unsave-op.s +./gas/testsuite/gas/mmix/weak1.d +./gas/testsuite/gas/mmix/weak1.s +./gas/testsuite/gas/mmix/zerop-1.d +./gas/testsuite/gas/mmix/zerop-1.s +./gas/testsuite/gas/mn10200/basic.exp +./gas/testsuite/gas/mn10200/add.s +./gas/testsuite/gas/mn10200/logical.s +./gas/testsuite/gas/mn10200/bcc.s +./gas/testsuite/gas/mn10200/bccx.s +./gas/testsuite/gas/mn10200/bit.s +./gas/testsuite/gas/mn10200/cmp.s +./gas/testsuite/gas/mn10200/ext.s +./gas/testsuite/gas/mn10200/muldiv.s +./gas/testsuite/gas/mn10200/mov1.s +./gas/testsuite/gas/mn10200/mov2.s +./gas/testsuite/gas/mn10200/mov3.s +./gas/testsuite/gas/mn10200/mov4.s +./gas/testsuite/gas/mn10200/movb.s +./gas/testsuite/gas/mn10200/movbu.s +./gas/testsuite/gas/mn10200/movx.s +./gas/testsuite/gas/mn10200/other.s +./gas/testsuite/gas/mn10200/shift.s +./gas/testsuite/gas/mn10200/sub.s +./gas/testsuite/gas/mn10300/am33_2.s +./gas/testsuite/gas/mn10300/add.s +./gas/testsuite/gas/mn10300/am33.s +./gas/testsuite/gas/mn10300/am33_3.s +./gas/testsuite/gas/mn10300/am33_4.s +./gas/testsuite/gas/mn10300/am33_5.s +./gas/testsuite/gas/mn10300/am33_6.s +./gas/testsuite/gas/mn10300/am33_7.s +./gas/testsuite/gas/mn10300/am33_8.s +./gas/testsuite/gas/mn10300/basic.exp +./gas/testsuite/gas/mn10300/bcc.s +./gas/testsuite/gas/mn10300/bit.s +./gas/testsuite/gas/mn10300/cmp.s +./gas/testsuite/gas/mn10300/ext.s +./gas/testsuite/gas/mn10300/extend.s +./gas/testsuite/gas/mn10300/logical.s +./gas/testsuite/gas/mn10300/loop.s +./gas/testsuite/gas/mn10300/mov1.s +./gas/testsuite/gas/mn10300/mov2.s +./gas/testsuite/gas/mn10300/mov3.s +./gas/testsuite/gas/mn10300/mov4.s +./gas/testsuite/gas/mn10300/movbu.s +./gas/testsuite/gas/mn10300/movhu.s +./gas/testsuite/gas/mn10300/movm.s +./gas/testsuite/gas/mn10300/movpc.l +./gas/testsuite/gas/mn10300/movpc.s +./gas/testsuite/gas/mn10300/muldiv.s +./gas/testsuite/gas/mn10300/other.s +./gas/testsuite/gas/mn10300/shift.s +./gas/testsuite/gas/mn10300/sub.s +./gas/testsuite/gas/mn10300/udf.s +./gas/testsuite/gas/mri/comment.d +./gas/testsuite/gas/mri/char.d +./gas/testsuite/gas/mri/char.s +./gas/testsuite/gas/mri/comment.s +./gas/testsuite/gas/mri/common.d +./gas/testsuite/gas/mri/common.s +./gas/testsuite/gas/mri/constants.d +./gas/testsuite/gas/mri/constants.s +./gas/testsuite/gas/mri/empty.s +./gas/testsuite/gas/mri/equ.d +./gas/testsuite/gas/mri/equ.s +./gas/testsuite/gas/mri/expr.d +./gas/testsuite/gas/mri/expr.s +./gas/testsuite/gas/mri/float.d +./gas/testsuite/gas/mri/float.s +./gas/testsuite/gas/mri/for.d +./gas/testsuite/gas/mri/for.s +./gas/testsuite/gas/mri/if.d +./gas/testsuite/gas/mri/if.s +./gas/testsuite/gas/mri/immconst.d +./gas/testsuite/gas/mri/label.d +./gas/testsuite/gas/mri/label.s +./gas/testsuite/gas/mri/moveml.d +./gas/testsuite/gas/mri/moveml.s +./gas/testsuite/gas/mri/mri.exp +./gas/testsuite/gas/mri/repeat.d +./gas/testsuite/gas/mri/repeat.s +./gas/testsuite/gas/mri/semi.d +./gas/testsuite/gas/mri/semi.s +./gas/testsuite/gas/mri/while.d +./gas/testsuite/gas/mri/while.s +./gas/testsuite/gas/msp430/msp430.exp +./gas/testsuite/gas/msp430/opcode.d +./gas/testsuite/gas/msp430/opcode.s +./gas/testsuite/gas/pj/ops.d +./gas/testsuite/gas/pj/ops.s +./gas/testsuite/gas/pj/pj.exp +./gas/testsuite/gas/openrisc/allinsn.d +./gas/testsuite/gas/openrisc/addi.d +./gas/testsuite/gas/openrisc/addi.s +./gas/testsuite/gas/openrisc/allinsn.exp +./gas/testsuite/gas/openrisc/allinsn.s +./gas/testsuite/gas/openrisc/lohi.d +./gas/testsuite/gas/openrisc/lohi.s +./gas/testsuite/gas/openrisc/store.d +./gas/testsuite/gas/openrisc/store.s +./gas/testsuite/gas/pdp11/opcode.d +./gas/testsuite/gas/pdp11/opcode.s +./gas/testsuite/gas/pdp11/pdp11.exp +./gas/testsuite/gas/ppc/altivec.d +./gas/testsuite/gas/ppc/aix.exp +./gas/testsuite/gas/ppc/align.s +./gas/testsuite/gas/ppc/altivec.s +./gas/testsuite/gas/ppc/altivec_xcoff.d +./gas/testsuite/gas/ppc/altivec_xcoff.s +./gas/testsuite/gas/ppc/altivec_xcoff64.d +./gas/testsuite/gas/ppc/altivec_xcoff64.s +./gas/testsuite/gas/ppc/astest.d +./gas/testsuite/gas/ppc/astest.s +./gas/testsuite/gas/ppc/astest2.d +./gas/testsuite/gas/ppc/astest2.s +./gas/testsuite/gas/ppc/astest2_64.d +./gas/testsuite/gas/ppc/astest2_64.s +./gas/testsuite/gas/ppc/astest64.d +./gas/testsuite/gas/ppc/astest64.s +./gas/testsuite/gas/ppc/booke.d +./gas/testsuite/gas/ppc/booke.s +./gas/testsuite/gas/ppc/booke_xcoff.d +./gas/testsuite/gas/ppc/booke_xcoff.s +./gas/testsuite/gas/ppc/booke_xcoff64.d +./gas/testsuite/gas/ppc/booke_xcoff64.s +./gas/testsuite/gas/ppc/e500.d +./gas/testsuite/gas/ppc/e500.s +./gas/testsuite/gas/ppc/generate.sh +./gas/testsuite/gas/ppc/ppc.exp +./gas/testsuite/gas/ppc/simpshft.d +./gas/testsuite/gas/ppc/simpshft.s +./gas/testsuite/gas/ppc/test1elf.asm +./gas/testsuite/gas/ppc/test1elf32.d +./gas/testsuite/gas/ppc/test1elf32.s +./gas/testsuite/gas/ppc/test1elf64.d +./gas/testsuite/gas/ppc/test1elf64.s +./gas/testsuite/gas/ppc/test1xcoff.asm +./gas/testsuite/gas/ppc/test1xcoff32.d +./gas/testsuite/gas/ppc/test1xcoff32.s +./gas/testsuite/gas/ppc/textalign-xcoff-001.d +./gas/testsuite/gas/ppc/textalign-xcoff-001.s +./gas/testsuite/gas/ppc/textalign-xcoff-002.d +./gas/testsuite/gas/s390/opcode.d +./gas/testsuite/gas/s390/opcode.s +./gas/testsuite/gas/s390/opcode64.d +./gas/testsuite/gas/s390/opcode64.s +./gas/testsuite/gas/s390/operands.d +./gas/testsuite/gas/s390/operands.s +./gas/testsuite/gas/s390/operands64.d +./gas/testsuite/gas/s390/operands64.s +./gas/testsuite/gas/s390/reloc.d +./gas/testsuite/gas/s390/reloc.s +./gas/testsuite/gas/s390/reloc64.d +./gas/testsuite/gas/s390/reloc64.s +./gas/testsuite/gas/s390/s390.exp +./gas/testsuite/gas/sh/sh64/abi-32.d +./gas/testsuite/gas/sh/sh64/abi-32.s +./gas/testsuite/gas/sh/sh64/abi-64.d +./gas/testsuite/gas/sh/sh64/abi-64.s +./gas/testsuite/gas/sh/sh64/basic-1.d +./gas/testsuite/gas/sh/sh64/basic-1.s +./gas/testsuite/gas/sh/sh64/case-1.d +./gas/testsuite/gas/sh/sh64/case-1.s +./gas/testsuite/gas/sh/sh64/case-noexp-1.d +./gas/testsuite/gas/sh/sh64/crange1-1.d +./gas/testsuite/gas/sh/sh64/crange1-2.d +./gas/testsuite/gas/sh/sh64/crange1.s +./gas/testsuite/gas/sh/sh64/crange2-1.d +./gas/testsuite/gas/sh/sh64/crange2-2.d +./gas/testsuite/gas/sh/sh64/crange2-noexp-1.d +./gas/testsuite/gas/sh/sh64/crange2.s +./gas/testsuite/gas/sh/sh64/crange3-1.d +./gas/testsuite/gas/sh/sh64/crange3.s +./gas/testsuite/gas/sh/sh64/crange4-1.d +./gas/testsuite/gas/sh/sh64/crange4.s +./gas/testsuite/gas/sh/sh64/crange5-1.d +./gas/testsuite/gas/sh/sh64/crange5.s +./gas/testsuite/gas/sh/sh64/creg-1.d +./gas/testsuite/gas/sh/sh64/err-1.s +./gas/testsuite/gas/sh/sh64/creg-1.s +./gas/testsuite/gas/sh/sh64/creg-2.d +./gas/testsuite/gas/sh/sh64/creg-2.s +./gas/testsuite/gas/sh/sh64/datal-1.s +./gas/testsuite/gas/sh/sh64/datal-2.d +./gas/testsuite/gas/sh/sh64/datal-2.s +./gas/testsuite/gas/sh/sh64/datal-3.s +./gas/testsuite/gas/sh/sh64/datal32-1.d +./gas/testsuite/gas/sh/sh64/datal32-3.d +./gas/testsuite/gas/sh/sh64/datal64-1.d +./gas/testsuite/gas/sh/sh64/datal64-3.d +./gas/testsuite/gas/sh/sh64/endian-1.d +./gas/testsuite/gas/sh/sh64/endian-1.s +./gas/testsuite/gas/sh/sh64/endian-2.d +./gas/testsuite/gas/sh/sh64/endian-2.s +./gas/testsuite/gas/sh/sh64/err-2.s +./gas/testsuite/gas/sh/sh64/err-3.s +./gas/testsuite/gas/sh/sh64/err-4.s +./gas/testsuite/gas/sh/sh64/err-abi-32.s +./gas/testsuite/gas/sh/sh64/err-abi-64.s +./gas/testsuite/gas/sh/sh64/err-dsp.s +./gas/testsuite/gas/sh/sh64/err-movi-noexp-1.s +./gas/testsuite/gas/sh/sh64/err-noexp-cmd1.s +./gas/testsuite/gas/sh/sh64/err-pt-1.s +./gas/testsuite/gas/sh/sh64/err-ptb-1.s +./gas/testsuite/gas/sh/sh64/err-pt32-cmd1.s +./gas/testsuite/gas/sh/sh64/err-pt32-cmd2.s +./gas/testsuite/gas/sh/sh64/err-pt32-cmd3.s +./gas/testsuite/gas/sh/sh64/err-ptb-2.s +./gas/testsuite/gas/sh/sh64/err.exp +./gas/testsuite/gas/sh/sh64/immexpr1.s +./gas/testsuite/gas/sh/sh64/immexpr2.s +./gas/testsuite/gas/sh/sh64/immexpr32-1.d +./gas/testsuite/gas/sh/sh64/immexpr32-2.d +./gas/testsuite/gas/sh/sh64/immexpr64-1.d +./gas/testsuite/gas/sh/sh64/immexpr64-2.d +./gas/testsuite/gas/sh/sh64/lineno.d +./gas/testsuite/gas/sh/sh64/lineno.s +./gas/testsuite/gas/sh/sh64/localcom-1.d +./gas/testsuite/gas/sh/sh64/localcom-1.s +./gas/testsuite/gas/sh/sh64/mix-1.d +./gas/testsuite/gas/sh/sh64/mix-1.s +./gas/testsuite/gas/sh/sh64/mix-noexp-1.d +./gas/testsuite/gas/sh/sh64/movi-1.s +./gas/testsuite/gas/sh/sh64/movi-2.s +./gas/testsuite/gas/sh/sh64/movi-3.d +./gas/testsuite/gas/sh/sh64/movi-3.s +./gas/testsuite/gas/sh/sh64/movi32-1.d +./gas/testsuite/gas/sh/sh64/movi32-2.d +./gas/testsuite/gas/sh/sh64/movi32-noexp-2.d +./gas/testsuite/gas/sh/sh64/movi64-1.d +./gas/testsuite/gas/sh/sh64/movi64-2.d +./gas/testsuite/gas/sh/sh64/movi64-2.s +./gas/testsuite/gas/sh/sh64/movi64-3.d +./gas/testsuite/gas/sh/sh64/movi64-noexp-2.d +./gas/testsuite/gas/sh/sh64/pt-1.d +./gas/testsuite/gas/sh/sh64/pt-1.s +./gas/testsuite/gas/sh/sh64/pt-2.s +./gas/testsuite/gas/sh/sh64/pt-noexp-1.d +./gas/testsuite/gas/sh/sh64/pt32-1.d +./gas/testsuite/gas/sh/sh64/pt32-noexp-2.d +./gas/testsuite/gas/sh/sh64/pt64-1.d +./gas/testsuite/gas/sh/sh64/pt64-32-1.d +./gas/testsuite/gas/sh/sh64/pt64-32-2.d +./gas/testsuite/gas/sh/sh64/pt64-noexp-2.d +./gas/testsuite/gas/sh/sh64/ptc-1.s +./gas/testsuite/gas/sh/sh64/ptc32-1.d +./gas/testsuite/gas/sh/sh64/ptc32-noexp-1.d +./gas/testsuite/gas/sh/sh64/ptc64-1.d +./gas/testsuite/gas/sh/sh64/ptc64-32-1.d +./gas/testsuite/gas/sh/sh64/ptc64-noexp-1.d +./gas/testsuite/gas/sh/sh64/ptext-1.s +./gas/testsuite/gas/sh/sh64/ptext32-1.d +./gas/testsuite/gas/sh/sh64/ptext32-noexp-1.d +./gas/testsuite/gas/sh/sh64/ptext64-1.d +./gas/testsuite/gas/sh/sh64/ptext64-32-1.d +./gas/testsuite/gas/sh/sh64/ptext64-noexp-1.d +./gas/testsuite/gas/sh/sh64/rel-1.s +./gas/testsuite/gas/sh/sh64/rel-2.s +./gas/testsuite/gas/sh/sh64/rel-3.s +./gas/testsuite/gas/sh/sh64/rel-4.s +./gas/testsuite/gas/sh/sh64/rel-5.s +./gas/testsuite/gas/sh/sh64/rel32-1.d +./gas/testsuite/gas/sh/sh64/rel32-2.d +./gas/testsuite/gas/sh/sh64/rel32-3.d +./gas/testsuite/gas/sh/sh64/rel32-4.d +./gas/testsuite/gas/sh/sh64/rel32-5.d +./gas/testsuite/gas/sh/sh64/rel64-1.d +./gas/testsuite/gas/sh/sh64/rel64-2.d +./gas/testsuite/gas/sh/sh64/rel64-3.d +./gas/testsuite/gas/sh/sh64/rel64-4.d +./gas/testsuite/gas/sh/sh64/rel64-5.d +./gas/testsuite/gas/sh/sh64/relax-1.d +./gas/testsuite/gas/sh/sh64/relax-1.s +./gas/testsuite/gas/sh/sh64/relax-2.d +./gas/testsuite/gas/sh/sh64/relax-2.s +./gas/testsuite/gas/sh/sh64/relax-3.d +./gas/testsuite/gas/sh/sh64/relax-3.s +./gas/testsuite/gas/sh/sh64/sh64.exp +./gas/testsuite/gas/sh/sh64/shift-1.s +./gas/testsuite/gas/sh/sh64/shift-2.s +./gas/testsuite/gas/sh/sh64/shift-3.s +./gas/testsuite/gas/sh/sh64/shift32-1.d +./gas/testsuite/gas/sh/sh64/shift32-3.d +./gas/testsuite/gas/sh/sh64/shift32-noexp-3.d +./gas/testsuite/gas/sh/sh64/shift64-1.d +./gas/testsuite/gas/sh/sh64/shift64-2.d +./gas/testsuite/gas/sh/sh64/shift64-3.d +./gas/testsuite/gas/sh/sh64/shift64-noexp-3.d +./gas/testsuite/gas/sh/sh64/syntax-1.d +./gas/testsuite/gas/sh/sh64/syntax-1.s +./gas/testsuite/gas/sh/sh64/syntax-2.d +./gas/testsuite/gas/sh/sh64/syntax-2.s +./gas/testsuite/gas/sh/sh64/ua-1.s +./gas/testsuite/gas/sh/sh64/ua32-1.d +./gas/testsuite/gas/sh/sh64/ua64-1.d +./gas/testsuite/gas/sh/basic.exp +./gas/testsuite/gas/sh/dsp.d +./gas/testsuite/gas/sh/dsp.s +./gas/testsuite/gas/sh/err-1.s +./gas/testsuite/gas/sh/err-at.s +./gas/testsuite/gas/sh/err-be.s +./gas/testsuite/gas/sh/err-le.s +./gas/testsuite/gas/sh/err.exp +./gas/testsuite/gas/sh/fp.s +./gas/testsuite/gas/sh/pcrel-coff.d +./gas/testsuite/gas/sh/pcrel-coff.s +./gas/testsuite/gas/sh/pcrel.d +./gas/testsuite/gas/sh/pcrel.l +./gas/testsuite/gas/sh/pcrel.s +./gas/testsuite/gas/sh/pcrel2.d +./gas/testsuite/gas/sh/pcrel2.s +./gas/testsuite/gas/sh/pic.d +./gas/testsuite/gas/sh/pic.s +./gas/testsuite/gas/sh/tlsd.d +./gas/testsuite/gas/sh/tlsd.s +./gas/testsuite/gas/sh/tlsnopic.d +./gas/testsuite/gas/sh/tlsnopic.s +./gas/testsuite/gas/sh/tlspic.d +./gas/testsuite/gas/sh/tlspic.s +./gas/testsuite/gas/sparc/membar.d +./gas/testsuite/gas/sparc/asi.d +./gas/testsuite/gas/sparc/asi.s +./gas/testsuite/gas/sparc/membar.s +./gas/testsuite/gas/sparc/mism-1.s +./gas/testsuite/gas/sparc/mismatch.exp +./gas/testsuite/gas/sparc/pcrel.d +./gas/testsuite/gas/sparc/pcrel.s +./gas/testsuite/gas/sparc/pcrel64.d +./gas/testsuite/gas/sparc/pcrel64.s +./gas/testsuite/gas/sparc/plt.d +./gas/testsuite/gas/sparc/plt.s +./gas/testsuite/gas/sparc/plt64.d +./gas/testsuite/gas/sparc/plt64.s +./gas/testsuite/gas/sparc/prefetch.d +./gas/testsuite/gas/sparc/prefetch.s +./gas/testsuite/gas/sparc/rdpr.d +./gas/testsuite/gas/sparc/rdpr.s +./gas/testsuite/gas/sparc/reloc64.d +./gas/testsuite/gas/sparc/reloc64.s +./gas/testsuite/gas/sparc/set64.d +./gas/testsuite/gas/sparc/set64.s +./gas/testsuite/gas/sparc/sparc.exp +./gas/testsuite/gas/sparc/splet-2.d +./gas/testsuite/gas/sparc/splet-2.s +./gas/testsuite/gas/sparc/splet.d +./gas/testsuite/gas/sparc/splet.s +./gas/testsuite/gas/sparc/synth.d +./gas/testsuite/gas/sparc/synth.s +./gas/testsuite/gas/sparc/synth64.d +./gas/testsuite/gas/sparc/synth64.s +./gas/testsuite/gas/sparc/unalign.d +./gas/testsuite/gas/sparc/unalign.s +./gas/testsuite/gas/sparc/wrpr.d +./gas/testsuite/gas/sparc/wrpr.s +./gas/testsuite/gas/sparc-solaris/addend.exp +./gas/testsuite/gas/sparc-solaris/addend.s +./gas/testsuite/gas/sparc-solaris/gas.exp +./gas/testsuite/gas/sparc-solaris/sol-cc.s +./gas/testsuite/gas/sparc-solaris/sol-gcc.s +./gas/testsuite/gas/sun4/addend.d +./gas/testsuite/gas/sun4/addend.exp +./gas/testsuite/gas/sun4/addend.s +./gas/testsuite/gas/symver/symver.exp +./gas/testsuite/gas/symver/symver0.d +./gas/testsuite/gas/symver/symver0.s +./gas/testsuite/gas/symver/symver1.d +./gas/testsuite/gas/symver/symver1.s +./gas/testsuite/gas/symver/symver2.l +./gas/testsuite/gas/symver/symver2.s +./gas/testsuite/gas/symver/symver3.l +./gas/testsuite/gas/symver/symver3.s +./gas/testsuite/gas/symver/symver4.l +./gas/testsuite/gas/symver/symver4.s +./gas/testsuite/gas/symver/symver5.l +./gas/testsuite/gas/symver/symver5.s +./gas/testsuite/gas/symver/symver6.l +./gas/testsuite/gas/symver/symver6.s +./gas/testsuite/gas/tic4x/addressing.s +./gas/testsuite/gas/tic4x/addressing_c3x.d +./gas/testsuite/gas/tic4x/addressing_c4x.d +./gas/testsuite/gas/tic4x/allopcodes.S +./gas/testsuite/gas/tic4x/data.d +./gas/testsuite/gas/tic4x/data.s +./gas/testsuite/gas/tic4x/float.d +./gas/testsuite/gas/tic4x/float.s +./gas/testsuite/gas/tic4x/opclasses.h +./gas/testsuite/gas/tic4x/opcodes.s +./gas/testsuite/gas/tic4x/opcodes_c3x.d +./gas/testsuite/gas/tic4x/opcodes_c4x.d +./gas/testsuite/gas/tic4x/opcodes_new.d +./gas/testsuite/gas/tic4x/rebuild.sh +./gas/testsuite/gas/tic4x/registers.s +./gas/testsuite/gas/tic4x/registers_c3x.d +./gas/testsuite/gas/tic4x/registers_c4x.d +./gas/testsuite/gas/tic4x/tic4x.exp +./gas/testsuite/gas/tic4x/zeros.d +./gas/testsuite/gas/tic4x/zeros.s +./gas/testsuite/gas/tic54x/address.d +./gas/testsuite/gas/tic54x/address.s +./gas/testsuite/gas/tic54x/addrfar.d +./gas/testsuite/gas/tic54x/align.d +./gas/testsuite/gas/tic54x/align.s +./gas/testsuite/gas/tic54x/all-opcodes.d +./gas/testsuite/gas/tic54x/all-opcodes.s +./gas/testsuite/gas/tic54x/asg.d +./gas/testsuite/gas/tic54x/asg.s +./gas/testsuite/gas/tic54x/cons.d +./gas/testsuite/gas/tic54x/cons.s +./gas/testsuite/gas/tic54x/consfar.d +./gas/testsuite/gas/tic54x/extaddr.d +./gas/testsuite/gas/tic54x/extaddr.s +./gas/testsuite/gas/tic54x/field.d +./gas/testsuite/gas/tic54x/field.s +./gas/testsuite/gas/tic54x/in_mlib.asm +./gas/testsuite/gas/tic54x/labels.d +./gas/testsuite/gas/tic54x/labels.inc +./gas/testsuite/gas/tic54x/labels.s +./gas/testsuite/gas/tic54x/loop.d +./gas/testsuite/gas/tic54x/loop.s +./gas/testsuite/gas/tic54x/lp.d +./gas/testsuite/gas/tic54x/lp.s +./gas/testsuite/gas/tic54x/macro.d +./gas/testsuite/gas/tic54x/macro.s +./gas/testsuite/gas/tic54x/math.d +./gas/testsuite/gas/tic54x/macro1.s +./gas/testsuite/gas/tic54x/macros.lib +./gas/testsuite/gas/tic54x/math.s +./gas/testsuite/gas/tic54x/opcodes.d +./gas/testsuite/gas/tic54x/opcodes.s +./gas/testsuite/gas/tic54x/sections.d +./gas/testsuite/gas/tic54x/sections.s +./gas/testsuite/gas/tic54x/set.d +./gas/testsuite/gas/tic54x/set.s +./gas/testsuite/gas/tic54x/struct.d +./gas/testsuite/gas/tic54x/struct.s +./gas/testsuite/gas/tic54x/subsym.d +./gas/testsuite/gas/tic54x/subsym.s +./gas/testsuite/gas/tic54x/subsym1.s +./gas/testsuite/gas/tic54x/tic54x.exp +./gas/testsuite/gas/tic80/align.lst +./gas/testsuite/gas/tic80/add.d +./gas/testsuite/gas/tic80/add.lst +./gas/testsuite/gas/tic80/add.s +./gas/testsuite/gas/tic80/align.d +./gas/testsuite/gas/tic80/bitnum.d +./gas/testsuite/gas/tic80/align.s +./gas/testsuite/gas/tic80/bitnum.lst +./gas/testsuite/gas/tic80/bitnum.s +./gas/testsuite/gas/tic80/ccode.d +./gas/testsuite/gas/tic80/ccode.lst +./gas/testsuite/gas/tic80/ccode.s +./gas/testsuite/gas/tic80/cregops.d +./gas/testsuite/gas/tic80/cregops.lst +./gas/testsuite/gas/tic80/cregops.s +./gas/testsuite/gas/tic80/endmask.d +./gas/testsuite/gas/tic80/endmask.lst +./gas/testsuite/gas/tic80/endmask.s +./gas/testsuite/gas/tic80/float.d +./gas/testsuite/gas/tic80/float.lst +./gas/testsuite/gas/tic80/float.s +./gas/testsuite/gas/tic80/regops.d +./gas/testsuite/gas/tic80/regops.lst +./gas/testsuite/gas/tic80/regops.s +./gas/testsuite/gas/tic80/regops2.d +./gas/testsuite/gas/tic80/regops2.lst +./gas/testsuite/gas/tic80/regops2.s +./gas/testsuite/gas/tic80/regops3.d +./gas/testsuite/gas/tic80/regops3.lst +./gas/testsuite/gas/tic80/regops3.s +./gas/testsuite/gas/tic80/regops4.d +./gas/testsuite/gas/tic80/regops4.lst +./gas/testsuite/gas/tic80/regops4.s +./gas/testsuite/gas/tic80/relocs1.c +./gas/testsuite/gas/tic80/relocs1.d +./gas/testsuite/gas/tic80/relocs1.lst +./gas/testsuite/gas/tic80/relocs1.s +./gas/testsuite/gas/tic80/relocs1b.d +./gas/testsuite/gas/tic80/relocs2.c +./gas/testsuite/gas/tic80/relocs2.d +./gas/testsuite/gas/tic80/relocs2.lst +./gas/testsuite/gas/tic80/relocs2.s +./gas/testsuite/gas/tic80/relocs2b.d +./gas/testsuite/gas/tic80/tic80.exp +./gas/testsuite/gas/v850/basic.exp +./gas/testsuite/gas/v850/arith.s +./gas/testsuite/gas/v850/branch.s +./gas/testsuite/gas/v850/bit.s +./gas/testsuite/gas/v850/compare.s +./gas/testsuite/gas/v850/fepsw.s +./gas/testsuite/gas/v850/hilo.s +./gas/testsuite/gas/v850/hilo2.s +./gas/testsuite/gas/v850/jumps.s +./gas/testsuite/gas/v850/logical.s +./gas/testsuite/gas/v850/mem.s +./gas/testsuite/gas/v850/misc.s +./gas/testsuite/gas/v850/move.s +./gas/testsuite/gas/v850/range.s +./gas/testsuite/gas/v850/reloc.s +./gas/testsuite/gas/vax/elf-rel.d +./gas/testsuite/gas/vax/elf-rel.s +./gas/testsuite/gas/vax/quad.s +./gas/testsuite/gas/vax/quad_elf.s +./gas/testsuite/gas/vax/vax.exp +./gas/testsuite/gas/vtable/entry0.d +./gas/testsuite/gas/vtable/entry0.s +./gas/testsuite/gas/vtable/entry1.d +./gas/testsuite/gas/vtable/entry1.s +./gas/testsuite/gas/vtable/inherit0.d +./gas/testsuite/gas/vtable/inherit0.s +./gas/testsuite/gas/vtable/inherit1.l +./gas/testsuite/gas/vtable/inherit1.s +./gas/testsuite/gas/vtable/vtable.exp +./gas/testsuite/gas/xstormy16/allinsn.d +./gas/testsuite/gas/xstormy16/allinsn.exp +./gas/testsuite/gas/xstormy16/allinsn.s +./gas/testsuite/gas/xstormy16/allinsn.sh +./gas/testsuite/gas/xstormy16/gcc.d +./gas/testsuite/gas/xstormy16/gcc.s +./gas/testsuite/gas/xstormy16/gcc.sh +./gas/testsuite/gas/xstormy16/reloc-1.d +./gas/testsuite/gas/xstormy16/reloc-1.s +./gas/testsuite/gas/xstormy16/reloc-2.d +./gas/testsuite/gas/xstormy16/reloc-2.s +./gas/testsuite/gas/xtensa/j_too_far.s +./gas/testsuite/gas/xtensa/all.exp +./gas/testsuite/gas/xtensa/entry_align.s +./gas/testsuite/gas/xtensa/entry_misalign.s +./gas/testsuite/gas/xtensa/entry_misalign2.s +./gas/testsuite/gas/xtensa/loop_align.s +./gas/testsuite/gas/xtensa/loop_misalign.s +./gas/testsuite/lib/doobjcmp +./gas/testsuite/lib/doboth +./gas/testsuite/lib/dostriptest +./gas/testsuite/lib/dotest +./gas/testsuite/lib/dounsreloc +./gas/testsuite/lib/dounssym +./gas/testsuite/lib/gas-defs.exp +./gas/testsuite/lib/gas-dg.exp +./gas/testsuite/lib/run +./gas/make-gas.com +./gas/itbl-parse.c +./gas/m68k-parse.c +./gas/itbl-parse.h +./gas/itbl-lex.c +./include/ChangeLog +./include/aout/ChangeLog +./include/aout/adobe.h +./include/aout/dynix3.h +./include/aout/encap.h +./include/aout/host.h +./include/aout/hp.h +./include/aout/hp300hpux.h +./include/aout/hppa.h +./include/aout/reloc.h +./include/aout/sun4.h +./include/coff/ChangeLog +./include/coff/a29k.h +./include/coff/alpha.h +./include/coff/apollo.h +./include/coff/arm.h +./include/coff/aux-coff.h +./include/coff/external.h +./include/coff/go32exe.h +./include/coff/h8300.h +./include/coff/h8500.h +./include/coff/i386.h +./include/coff/i860.h +./include/coff/i960.h +./include/coff/ia64.h +./include/coff/m68k.h +./include/coff/m88k.h +./include/coff/mcore.h +./include/coff/mips.h +./include/coff/mipspe.h +./include/coff/or32.h +./include/coff/pe.h +./include/coff/powerpc.h +./include/coff/rs6000.h +./include/coff/rs6k64.h +./include/coff/sh.h +./include/coff/sparc.h +./include/coff/symconst.h +./include/coff/ti.h +./include/coff/tic30.h +./include/coff/tic4x.h +./include/coff/tic54x.h +./include/coff/tic80.h +./include/coff/w65.h +./include/coff/we32k.h +./include/coff/xcoff.h +./include/coff/z8k.h +./include/alloca-conf.h +./include/bout.h +./include/fibheap.h +./include/fopen-bin.h +./include/fopen-vms.h +./include/gdbm.h +./include/hp-symtab.h +./include/elf/ChangeLog +./include/elf/openrisc.h +./include/md5.h +./include/oasys.h +./include/os9k.h +./include/partition.h +./include/sort.h +./include/splay-tree.h +./include/ternary.h +./include/xregex.h +./include/xregex2.h +./include/xtensa-config.h +./include/xtensa-isa-internal.h +./include/xtensa-isa.h +./include/gdb/ChangeLog +./include/gdb/callback.h +./include/gdb/remote-sim.h +./include/gdb/signals.h +./include/gdb/sim-arm.h +./include/gdb/sim-d10v.h +./include/gdb/sim-h8300.h +./include/gdb/sim-sh.h +./include/mpw/sys/resource.h +./include/mpw/sys/file.h +./include/mpw/sys/param.h +./include/mpw/sys/stat.h +./include/mpw/sys/time.h +./include/mpw/sys/types.h +./include/mpw/ChangeLog +./include/mpw/dir.h +./include/mpw/dirent.h +./include/mpw/fcntl.h +./include/mpw/grp.h +./include/mpw/mpw.h +./include/mpw/pwd.h +./include/mpw/spin.h +./include/mpw/stat.h +./include/mpw/utime.h +./include/mpw/varargs.h +./include/nlm/ChangeLog +./include/nlm/alpha-ext.h +./include/nlm/common.h +./include/nlm/external.h +./include/nlm/i386-ext.h +./include/nlm/internal.h +./include/nlm/ppc-ext.h +./include/nlm/sparc32-ext.h +./include/opcode/ChangeLog +./include/opcode/a29k.h +./include/opcode/alpha.h +./include/opcode/arc.h +./include/opcode/arm.h +./include/opcode/avr.h +./include/opcode/cgen.h +./include/opcode/convex.h +./include/opcode/cris.h +./include/opcode/d10v.h +./include/opcode/d30v.h +./include/opcode/dlx.h +./include/opcode/h8300.h +./include/opcode/hppa.h +./include/opcode/i370.h +./include/opcode/i860.h +./include/opcode/i960.h +./include/opcode/ia64.h +./include/opcode/m68hc11.h +./include/opcode/m68k.h +./include/opcode/m88k.h +./include/opcode/mips.h +./include/opcode/mmix.h +./include/opcode/mn10200.h +./include/opcode/mn10300.h +./include/opcode/msp430.h +./include/opcode/np1.h +./include/opcode/ns32k.h +./include/opcode/or32.h +./include/opcode/pdp11.h +./include/opcode/pj.h +./include/opcode/pn.h +./include/opcode/ppc.h +./include/opcode/pyr.h +./include/opcode/s390.h +./include/opcode/sparc.h +./include/opcode/tahoe.h +./include/opcode/tic30.h +./include/opcode/tic4x.h +./include/opcode/tic54x.h +./include/opcode/tic80.h +./include/opcode/v850.h +./include/opcode/vax.h +./libiberty/config/mh-cxux7 +./libiberty/config/mh-aix +./libiberty/config/mh-fbsd21 +./libiberty/config/mh-openedition +./libiberty/config/mh-windows +./libiberty/ChangeLog +./libiberty/Makefile.in +./libiberty/_doprnt.c +./libiberty/acconfig.h +./libiberty/aclocal.m4 +./libiberty/alloca.c +./libiberty/asprintf.c +./libiberty/atexit.c +./libiberty/bcmp.c +./libiberty/bcopy.c +./libiberty/bsearch.c +./libiberty/bzero.c +./libiberty/calloc.c +./libiberty/clock.c +./libiberty/config.h-vms +./libiberty/config.in +./libiberty/config.table +./libiberty/configure +./libiberty/configure.in +./libiberty/copying-lib.texi +./libiberty/copysign.c +./libiberty/fdmatch.c +./libiberty/ffs.c +./libiberty/fibheap.c +./libiberty/fnmatch.c +./libiberty/fnmatch.txh +./libiberty/functions.texi +./libiberty/gather-docs +./libiberty/getcwd.c +./libiberty/getpagesize.c +./libiberty/index.c +./libiberty/insque.c +./libiberty/libiberty.texi +./libiberty/maint-tool +./libiberty/makefile.vms +./libiberty/md5.c +./libiberty/memchr.c +./libiberty/memcmp.c +./libiberty/memcpy.c +./libiberty/memmove.c +./libiberty/mempcpy.c +./libiberty/memset.c +./libiberty/mkstemps.c +./libiberty/mpw-config.in +./libiberty/mpw-make.sed +./libiberty/mpw.c +./libiberty/msdos.c +./libiberty/obstacks.texi +./libiberty/partition.c +./libiberty/pex-common.h +./libiberty/pex-djgpp.c +./libiberty/pex-mpw.c +./libiberty/pex-msdos.c +./libiberty/pex-os2.c +./libiberty/pex-unix.c +./libiberty/pex-win32.c +./libiberty/pexecute.txh +./libiberty/physmem.c +./libiberty/putenv.c +./libiberty/random.c +./libiberty/regex.c +./libiberty/rename.c +./libiberty/rindex.c +./libiberty/setenv.c +./libiberty/sigsetmask.c +./libiberty/snprintf.c +./libiberty/sort.c +./libiberty/spaces.c +./libiberty/splay-tree.c +./libiberty/stpcpy.c +./libiberty/stpncpy.c +./libiberty/strcasecmp.c +./libiberty/strchr.c +./libiberty/strdup.c +./libiberty/strerror.c +./libiberty/strncasecmp.c +./libiberty/strncmp.c +./libiberty/strrchr.c +./libiberty/strsignal.c +./libiberty/strstr.c +./libiberty/strtod.c +./libiberty/strtol.c +./libiberty/strtoul.c +./libiberty/ternary.c +./libiberty/tmpnam.c +./libiberty/vasprintf.c +./libiberty/vfork.c +./libiberty/vfprintf.c +./libiberty/vmsbuild.com +./libiberty/vprintf.c +./libiberty/vsnprintf.c +./libiberty/vsprintf.c +./libiberty/waitpid.c +./libiberty/xmemdup.c +./libiberty/testsuite/Makefile.in +./libiberty/testsuite/demangle-expected +./libiberty/testsuite/test-demangle.c +./opcodes/po/.cvsignore +./opcodes/po/Make-in +./opcodes/po/POTFILES.in +./opcodes/po/da.po +./opcodes/po/de.po +./opcodes/po/es.po +./opcodes/po/fr.po +./opcodes/po/id.po +./opcodes/po/opcodes.pot +./opcodes/po/pt_BR.po +./opcodes/po/sv.po +./opcodes/po/tr.po +./opcodes/po/da.gmo +./opcodes/po/de.gmo +./opcodes/po/es.gmo +./opcodes/po/fr.gmo +./opcodes/po/id.gmo +./opcodes/po/pt_BR.gmo +./opcodes/po/sv.gmo +./opcodes/po/tr.gmo +./opcodes/po/ro.gmo +./opcodes/po/ro.po +./opcodes/ChangeLog +./opcodes/ChangeLog-9297 +./opcodes/ChangeLog-9899 +./opcodes/Makefile.am +./opcodes/Makefile.in +./opcodes/a29k-dis.c +./opcodes/acinclude.m4 +./opcodes/aclocal.m4 +./opcodes/alpha-dis.c +./opcodes/alpha-opc.c +./opcodes/arc-dis.c +./opcodes/arc-dis.h +./opcodes/arc-ext.c +./opcodes/arc-ext.h +./opcodes/arc-opc.c +./opcodes/arm-dis.c +./opcodes/arm-opc.h +./opcodes/avr-dis.c +./opcodes/cgen-asm.c +./opcodes/cgen-asm.in +./opcodes/cgen-dis.c +./opcodes/cgen-dis.in +./opcodes/cgen-ibld.in +./opcodes/cgen-opc.c +./opcodes/cgen.sh +./opcodes/config.in +./opcodes/configure +./opcodes/configure.in +./opcodes/cris-dis.c +./opcodes/cris-opc.c +./opcodes/d10v-dis.c +./opcodes/d10v-opc.c +./opcodes/d30v-dis.c +./opcodes/d30v-opc.c +./opcodes/dep-in.sed +./opcodes/dlx-dis.c +./opcodes/fr30-asm.c +./opcodes/fr30-desc.c +./opcodes/fr30-desc.h +./opcodes/fr30-dis.c +./opcodes/fr30-ibld.c +./opcodes/fr30-opc.c +./opcodes/fr30-opc.h +./opcodes/frv-asm.c +./opcodes/frv-desc.c +./opcodes/frv-desc.h +./opcodes/frv-dis.c +./opcodes/frv-ibld.c +./opcodes/frv-opc.c +./opcodes/frv-opc.h +./opcodes/h8300-dis.c +./opcodes/h8500-dis.c +./opcodes/h8500-opc.h +./opcodes/hppa-dis.c +./opcodes/i370-dis.c +./opcodes/i370-opc.c +./opcodes/i860-dis.c +./opcodes/i960-dis.c +./opcodes/ia64-asmtab.c +./opcodes/ia64-asmtab.h +./opcodes/ia64-dis.c +./opcodes/ia64-gen.c +./opcodes/ia64-ic.tbl +./opcodes/ia64-opc-a.c +./opcodes/ia64-opc-b.c +./opcodes/ia64-opc-d.c +./opcodes/ia64-opc-f.c +./opcodes/ia64-opc-i.c +./opcodes/ia64-opc-m.c +./opcodes/ia64-opc-x.c +./opcodes/ia64-opc.c +./opcodes/ia64-opc.h +./opcodes/ia64-raw.tbl +./opcodes/ia64-war.tbl +./opcodes/ia64-waw.tbl +./opcodes/ip2k-asm.c +./opcodes/ip2k-desc.c +./opcodes/ip2k-desc.h +./opcodes/ip2k-dis.c +./opcodes/ip2k-ibld.c +./opcodes/ip2k-opc.c +./opcodes/ip2k-opc.h +./opcodes/iq2000-asm.c +./opcodes/iq2000-desc.c +./opcodes/iq2000-desc.h +./opcodes/iq2000-dis.c +./opcodes/iq2000-ibld.c +./opcodes/iq2000-opc.c +./opcodes/iq2000-opc.h +./opcodes/m10200-dis.c +./opcodes/m32r-asm.c +./opcodes/m10200-opc.c +./opcodes/m10300-dis.c +./opcodes/m10300-opc.c +./opcodes/m32r-desc.c +./opcodes/m32r-desc.h +./opcodes/m32r-dis.c +./opcodes/m32r-ibld.c +./opcodes/m32r-opc.c +./opcodes/m32r-opc.h +./opcodes/m32r-opinst.c +./opcodes/m68hc11-dis.c +./opcodes/m68hc11-opc.c +./opcodes/m68k-dis.c +./opcodes/m68k-opc.c +./opcodes/m88k-dis.c +./opcodes/makefile.vms +./opcodes/mcore-dis.c +./opcodes/mcore-opc.h +./opcodes/mips-dis.c +./opcodes/mips-opc.c +./opcodes/mips16-opc.c +./opcodes/mmix-dis.c +./opcodes/mmix-opc.c +./opcodes/ns32k-dis.c +./opcodes/mpw-config.in +./opcodes/mpw-make.sed +./opcodes/msp430-dis.c +./opcodes/openrisc-asm.c +./opcodes/openrisc-desc.c +./opcodes/openrisc-desc.h +./opcodes/openrisc-dis.c +./opcodes/openrisc-ibld.c +./opcodes/openrisc-opc.c +./opcodes/openrisc-opc.h +./opcodes/or32-dis.c +./opcodes/or32-opc.c +./opcodes/pdp11-dis.c +./opcodes/pdp11-opc.c +./opcodes/pj-dis.c +./opcodes/pj-opc.c +./opcodes/ppc-dis.c +./opcodes/ppc-opc.c +./opcodes/s390-dis.c +./opcodes/s390-mkopc.c +./opcodes/s390-opc.c +./opcodes/s390-opc.txt +./opcodes/sh-dis.c +./opcodes/sh-opc.h +./opcodes/sh64-dis.c +./opcodes/sh64-opc.c +./opcodes/sh64-opc.h +./opcodes/sparc-dis.c +./opcodes/sparc-opc.c +./opcodes/stamp-h.in +./opcodes/tic30-dis.c +./opcodes/tic4x-dis.c +./opcodes/tic54x-dis.c +./opcodes/tic54x-opc.c +./opcodes/tic80-dis.c +./opcodes/tic80-opc.c +./opcodes/v850-dis.c +./opcodes/v850-opc.c +./opcodes/vax-dis.c +./opcodes/w65-dis.c +./opcodes/w65-opc.h +./opcodes/xstormy16-asm.c +./opcodes/xstormy16-desc.c +./opcodes/xstormy16-desc.h +./opcodes/xstormy16-dis.c +./opcodes/xstormy16-ibld.c +./opcodes/xstormy16-opc.c +./opcodes/xstormy16-opc.h +./opcodes/xtensa-dis.c +./opcodes/z8k-dis.c +./opcodes/z8k-opc.h +./opcodes/z8kgen.c +./ld/emulparams/aix5ppc.sh +./ld/emulparams/README +./ld/emulparams/a29k.sh +./ld/emulparams/aix5rs6.sh +./ld/emulparams/aixppc.sh +./ld/emulparams/aixrs6.sh +./ld/emulparams/alpha.sh +./ld/emulparams/arcelf.sh +./ld/emulparams/arm_epoc_pe.sh +./ld/emulparams/armaoutb.sh +./ld/emulparams/armaoutl.sh +./ld/emulparams/armcoff.sh +./ld/emulparams/armelf.sh +./ld/emulparams/armelf_fbsd.sh +./ld/emulparams/armelf_linux.sh +./ld/emulparams/armelf_nbsd.sh +./ld/emulparams/armelf_oabi.sh +./ld/emulparams/armelfb_nbsd.sh +./ld/emulparams/armnbsd.sh +./ld/emulparams/armnto.sh +./ld/emulparams/armpe.sh +./ld/emulparams/avr1.sh +./ld/emulparams/avr1200.sh +./ld/emulparams/avr2.sh +./ld/emulparams/avr23xx.sh +./ld/emulparams/avr3.sh +./ld/emulparams/avr4.sh +./ld/emulparams/avr4433.sh +./ld/emulparams/avr44x4.sh +./ld/emulparams/avr5.sh +./ld/emulparams/avr85xx.sh +./ld/emulparams/avrmega103.sh +./ld/emulparams/avrmega161.sh +./ld/emulparams/avrmega603.sh +./ld/emulparams/coff_sparc.sh +./ld/emulparams/crisaout.sh +./ld/emulparams/criself.sh +./ld/emulparams/crislinux.sh +./ld/emulparams/d10velf.sh +./ld/emulparams/d30v_e.sh +./ld/emulparams/d30v_o.sh +./ld/emulparams/d30velf.sh +./ld/emulparams/delta68.sh +./ld/emulparams/ebmon29k.sh +./ld/emulparams/elf32_dlx.sh +./ld/emulparams/elf32_i860.sh +./ld/emulparams/elf32_i960.sh +./ld/emulparams/elf32_sparc.sh +./ld/emulparams/elf32b4300.sh +./ld/emulparams/elf32bmip.sh +./ld/emulparams/elf32bmipn32-defs.sh +./ld/emulparams/elf32bmipn32.sh +./ld/emulparams/elf32bsmip.sh +./ld/emulparams/elf32btsmip.sh +./ld/emulparams/elf32btsmipn32.sh +./ld/emulparams/elf32ebmip.sh +./ld/emulparams/elf32elmip.sh +./ld/emulparams/elf32fr30.sh +./ld/emulparams/elf32frv.sh +./ld/emulparams/elf32i370.sh +./ld/emulparams/elf32ip2k.sh +./ld/emulparams/elf32iq10.sh +./ld/emulparams/elf32iq2000.sh +./ld/emulparams/elf32l4300.sh +./ld/emulparams/elf32lmip.sh +./ld/emulparams/elf32lppc.sh +./ld/emulparams/elf32lppcnto.sh +./ld/emulparams/elf32lppcsim.sh +./ld/emulparams/elf32lsmip.sh +./ld/emulparams/elf32ltsmip.sh +./ld/emulparams/elf32ltsmipn32.sh +./ld/emulparams/elf32mcore.sh +./ld/emulparams/elf32openrisc.sh +./ld/emulparams/elf32ppc.sh +./ld/emulparams/elf32ppc_fbsd.sh +./ld/emulparams/elf32ppclinux.sh +./ld/emulparams/elf32ppcnto.sh +./ld/emulparams/elf32ppcsim.sh +./ld/emulparams/elf32ppcwindiss.sh +./ld/emulparams/elf32vax.sh +./ld/emulparams/elf32xstormy16.sh +./ld/emulparams/elf32xtensa.sh +./ld/emulparams/elf64_aix.sh +./ld/emulparams/elf64_ia64.sh +./ld/emulparams/elf64_ia64_fbsd.sh +./ld/emulparams/elf64_s390.sh +./ld/emulparams/elf64_sparc.sh +./ld/emulparams/elf64_sparc_fbsd.sh +./ld/emulparams/elf64alpha.sh +./ld/emulparams/elf64alpha_fbsd.sh +./ld/emulparams/elf64alpha_nbsd.sh +./ld/emulparams/elf64bmip.sh +./ld/emulparams/elf64btsmip.sh +./ld/emulparams/elf64hppa.sh +./ld/emulparams/elf64lppc.sh +./ld/emulparams/elf64ltsmip.sh +./ld/emulparams/elf64mmix.sh +./ld/emulparams/elf64ppc.sh +./ld/emulparams/elf_fbsd.sh +./ld/emulparams/elf_i386_be.sh +./ld/emulparams/elf_i386_chaos.sh +./ld/emulparams/elf_i386_fbsd.sh +./ld/emulparams/elf_i386_ldso.sh +./ld/emulparams/elf_s390.sh +./ld/emulparams/elf_x86_64_fbsd.sh +./ld/emulparams/gld960.sh +./ld/emulparams/gld960coff.sh +./ld/emulparams/h8300.sh +./ld/emulparams/h8300elf.sh +./ld/emulparams/h8300h.sh +./ld/emulparams/h8300helf.sh +./ld/emulparams/h8300hn.sh +./ld/emulparams/h8300hnelf.sh +./ld/emulparams/h8300s.sh +./ld/emulparams/h8300self.sh +./ld/emulparams/h8300sn.sh +./ld/emulparams/h8300snelf.sh +./ld/emulparams/h8500.sh +./ld/emulparams/h8500b.sh +./ld/emulparams/h8500c.sh +./ld/emulparams/h8500m.sh +./ld/emulparams/h8500s.sh +./ld/emulparams/hp300bsd.sh +./ld/emulparams/hp3hpux.sh +./ld/emulparams/hppa64linux.sh +./ld/emulparams/hppaelf.sh +./ld/emulparams/hppalinux.sh +./ld/emulparams/hppanbsd.sh +./ld/emulparams/hppaobsd.sh +./ld/emulparams/i386aout.sh +./ld/emulparams/i386beos.sh +./ld/emulparams/i386bsd.sh +./ld/emulparams/i386coff.sh +./ld/emulparams/i386go32.sh +./ld/emulparams/i386linux.sh +./ld/emulparams/i386lynx.sh +./ld/emulparams/i386mach.sh +./ld/emulparams/i386moss.sh +./ld/emulparams/i386msdos.sh +./ld/emulparams/i386nbsd.sh +./ld/emulparams/i386nto.sh +./ld/emulparams/i386nw.sh +./ld/emulparams/i386pe.sh +./ld/emulparams/i386pe_posix.sh +./ld/emulparams/lnk960.sh +./ld/emulparams/m32relf.sh +./ld/emulparams/m68hc11elf.sh +./ld/emulparams/m68hc11elfb.sh +./ld/emulparams/m68hc12elf.sh +./ld/emulparams/m68hc12elfb.sh +./ld/emulparams/m68k4knbsd.sh +./ld/emulparams/m68kaout.sh +./ld/emulparams/m68kaux.sh +./ld/emulparams/m68kcoff.sh +./ld/emulparams/m68kelf.sh +./ld/emulparams/m68klynx.sh +./ld/emulparams/m68kelfnbsd.sh +./ld/emulparams/m68klinux.sh +./ld/emulparams/m68knbsd.sh +./ld/emulparams/m68kpsos.sh +./ld/emulparams/m88kbcs.sh +./ld/emulparams/mcorepe.sh +./ld/emulparams/mipsbig.sh +./ld/emulparams/mipsbsd.sh +./ld/emulparams/mipsidt.sh +./ld/emulparams/mipsidtl.sh +./ld/emulparams/mipslit.sh +./ld/emulparams/mipslnews.sh +./ld/emulparams/mipspe.sh +./ld/emulparams/mmo.sh +./ld/emulparams/mn10200.sh +./ld/emulparams/mn10300.sh +./ld/emulparams/msp430x110.sh +./ld/emulparams/msp430x1101.sh +./ld/emulparams/msp430x1111.sh +./ld/emulparams/msp430x112.sh +./ld/emulparams/msp430x1121.sh +./ld/emulparams/msp430x1122.sh +./ld/emulparams/msp430x1132.sh +./ld/emulparams/news.sh +./ld/emulparams/msp430x122.sh +./ld/emulparams/msp430x1222.sh +./ld/emulparams/msp430x123.sh +./ld/emulparams/msp430x1232.sh +./ld/emulparams/msp430x133.sh +./ld/emulparams/msp430x1331.sh +./ld/emulparams/msp430x135.sh +./ld/emulparams/msp430x1351.sh +./ld/emulparams/msp430x147.sh +./ld/emulparams/msp430x148.sh +./ld/emulparams/msp430x149.sh +./ld/emulparams/msp430x155.sh +./ld/emulparams/msp430x156.sh +./ld/emulparams/msp430x157.sh +./ld/emulparams/msp430x167.sh +./ld/emulparams/msp430x168.sh +./ld/emulparams/msp430x169.sh +./ld/emulparams/msp430x311.sh +./ld/emulparams/msp430x312.sh +./ld/emulparams/msp430x313.sh +./ld/emulparams/msp430x314.sh +./ld/emulparams/msp430x315.sh +./ld/emulparams/msp430x323.sh +./ld/emulparams/msp430x325.sh +./ld/emulparams/msp430x336.sh +./ld/emulparams/msp430x337.sh +./ld/emulparams/msp430x412.sh +./ld/emulparams/msp430x413.sh +./ld/emulparams/msp430x435.sh +./ld/emulparams/msp430x436.sh +./ld/emulparams/msp430x437.sh +./ld/emulparams/msp430x447.sh +./ld/emulparams/msp430x448.sh +./ld/emulparams/msp430x449.sh +./ld/emulparams/ns32knbsd.sh +./ld/emulparams/or32.sh +./ld/emulparams/or32elf.sh +./ld/emulparams/pc532macha.sh +./ld/emulparams/pdp11.sh +./ld/emulparams/pjelf.sh +./ld/emulparams/pjlelf.sh +./ld/emulparams/ppcmacos.sh +./ld/emulparams/ppcnw.sh +./ld/emulparams/sh.sh +./ld/emulparams/ppcpe.sh +./ld/emulparams/riscix.sh +./ld/emulparams/sa29200.sh +./ld/emulparams/shelf.sh +./ld/emulparams/shelf32.sh +./ld/emulparams/shelf32_linux.sh +./ld/emulparams/shelf32_nbsd.sh +./ld/emulparams/shelf64.sh +./ld/emulparams/shelf64_nbsd.sh +./ld/emulparams/shelf_linux.sh +./ld/emulparams/shelf_nbsd.sh +./ld/emulparams/shelf_nto.sh +./ld/emulparams/shl.sh +./ld/emulparams/shlelf.sh +./ld/emulparams/shlelf32.sh +./ld/emulparams/shlelf32_linux.sh +./ld/emulparams/shlelf32_nbsd.sh +./ld/emulparams/shlelf64.sh +./ld/emulparams/shlelf64_nbsd.sh +./ld/emulparams/shlelf_linux.sh +./ld/emulparams/shlelf_nbsd.sh +./ld/emulparams/shlelf_nto.sh +./ld/emulparams/shpe.sh +./ld/emulparams/sparcaout.sh +./ld/emulparams/sparclinux.sh +./ld/emulparams/sparclynx.sh +./ld/emulparams/sparcnbsd.sh +./ld/emulparams/st2000.sh +./ld/emulparams/sun3.sh +./ld/emulparams/sun4.sh +./ld/emulparams/tic30aout.sh +./ld/emulparams/tic30coff.sh +./ld/emulparams/tic3xcoff.sh +./ld/emulparams/tic3xcoff_onchip.sh +./ld/emulparams/tic4xcoff.sh +./ld/emulparams/tic54xcoff.sh +./ld/emulparams/tic80coff.sh +./ld/emulparams/v850.sh +./ld/emulparams/vanilla.sh +./ld/emulparams/vax.sh +./ld/emulparams/vaxnbsd.sh +./ld/emulparams/vsta.sh +./ld/emulparams/w65.sh +./ld/emulparams/xtensa-config.sh +./ld/emulparams/z8001.sh +./ld/emulparams/z8002.sh +./ld/ChangeLog +./ld/ChangeLog-9197 +./ld/ChangeLog-9899 +./ld/Makefile.am +./ld/Makefile.in +./ld/acinclude.m4 +./ld/aclocal.m4 +./ld/config.in +./ld/configure +./ld/configure.host +./ld/configure.in +./ld/configure.tgt +./ld/deffile.h +./ld/deffilep.y +./ld/dep-in.sed +./ld/h8-doc.texi +./ld/ldint.texinfo +./ld/mac-ld.r +./ld/mpw-config.in +./ld/mpw-make.sed +./ld/pe-dll.c +./ld/pe-dll.h +./ld/stamp-h.in +./ld/emultempl/alphaelf.em +./ld/emultempl/README +./ld/emultempl/aix.em +./ld/emultempl/armcoff.em +./ld/emultempl/armelf.em +./ld/emultempl/armelf_oabi.em +./ld/emultempl/beos.em +./ld/emultempl/generic.em +./ld/emultempl/gld960.em +./ld/emultempl/gld960c.em +./ld/emultempl/hppaelf.em +./ld/emultempl/linux.em +./ld/emultempl/lnk960.em +./ld/emultempl/m68hc1xelf.em +./ld/emultempl/m68kcoff.em +./ld/emultempl/m68kelf.em +./ld/emultempl/mipsecoff.em +./ld/emultempl/mipself.em +./ld/emultempl/mmix-elfnmmo.em +./ld/emultempl/mmixelf.em +./ld/emultempl/mmo.em +./ld/emultempl/needrelax.em +./ld/emultempl/netbsd.em +./ld/emultempl/ostring.sed +./ld/emultempl/pe.em +./ld/emultempl/ppc32elf.em +./ld/emultempl/ppc64elf.em +./ld/emultempl/sh64elf.em +./ld/emultempl/sunos.em +./ld/emultempl/ticoff.em +./ld/emultempl/vanilla.em +./ld/emultempl/xtensaelf.em +./ld/po/.cvsignore +./ld/po/Make-in +./ld/po/POTFILES.in +./ld/po/da.po +./ld/po/es.po +./ld/po/fr.po +./ld/po/ld.pot +./ld/po/sv.po +./ld/po/tr.po +./ld/po/da.gmo +./ld/po/es.gmo +./ld/po/fr.gmo +./ld/po/sv.gmo +./ld/po/tr.gmo +./ld/scripttempl/alpha.sc +./ld/scripttempl/README +./ld/scripttempl/a29k.sc +./ld/scripttempl/aix.sc +./ld/scripttempl/armaout.sc +./ld/scripttempl/aout.sc +./ld/scripttempl/armcoff.sc +./ld/scripttempl/avr.sc +./ld/scripttempl/crisaout.sc +./ld/scripttempl/delta68.sc +./ld/scripttempl/dlx.sc +./ld/scripttempl/ebmon29k.sc +./ld/scripttempl/elf32avr.sc +./ld/scripttempl/elf32msp430.sc +./ld/scripttempl/elf32msp430_3.sc +./ld/scripttempl/elf_chaos.sc +./ld/scripttempl/elfd10v.sc +./ld/scripttempl/elfd30v.sc +./ld/scripttempl/elfi370.sc +./ld/scripttempl/elfm68hc11.sc +./ld/scripttempl/elfm68hc12.sc +./ld/scripttempl/elfxtensa.sc +./ld/scripttempl/epocpe.sc +./ld/scripttempl/h8300.sc +./ld/scripttempl/h8300h.sc +./ld/scripttempl/h8300hn.sc +./ld/scripttempl/h8300s.sc +./ld/scripttempl/h8300sn.sc +./ld/scripttempl/h8500.sc +./ld/scripttempl/h8500b.sc +./ld/scripttempl/h8500c.sc +./ld/scripttempl/h8500m.sc +./ld/scripttempl/h8500s.sc +./ld/scripttempl/hppaelf.sc +./ld/scripttempl/i386beos.sc +./ld/scripttempl/i386coff.sc +./ld/scripttempl/i386go32.sc +./ld/scripttempl/i386lynx.sc +./ld/scripttempl/i386msdos.sc +./ld/scripttempl/i960.sc +./ld/scripttempl/ip2k.sc +./ld/scripttempl/iq2000.sc +./ld/scripttempl/m68kaux.sc +./ld/scripttempl/m68kcoff.sc +./ld/scripttempl/m68klynx.sc +./ld/scripttempl/m88kbcs.sc +./ld/scripttempl/mcorepe.sc +./ld/scripttempl/mips.sc +./ld/scripttempl/mipsbsd.sc +./ld/scripttempl/mmo.sc +./ld/scripttempl/nw.sc +./ld/scripttempl/or32.sc +./ld/scripttempl/pe.sc +./ld/scripttempl/pj.sc +./ld/scripttempl/ppcpe.sc +./ld/scripttempl/psos.sc +./ld/scripttempl/riscix.sc +./ld/scripttempl/sa29200.sc +./ld/scripttempl/sh.sc +./ld/scripttempl/sparccoff.sc +./ld/scripttempl/sparclynx.sc +./ld/scripttempl/st2000.sc +./ld/scripttempl/tic30aout.sc +./ld/scripttempl/tic30coff.sc +./ld/scripttempl/tic4xcoff.sc +./ld/scripttempl/tic54xcoff.sc +./ld/scripttempl/tic80coff.sc +./ld/scripttempl/v850.sc +./ld/scripttempl/vanilla.sc +./ld/scripttempl/w65.sc +./ld/scripttempl/xstormy16.sc +./ld/scripttempl/z8000.sc +./ld/testsuite/config/default.exp +./ld/testsuite/ChangeLog +./ld/testsuite/ld-alpha/alpha.exp +./ld/testsuite/ld-alpha/align.s +./ld/testsuite/ld-alpha/tlsbin.dd +./ld/testsuite/ld-alpha/tlsbin.rd +./ld/testsuite/ld-alpha/tlsbin.s +./ld/testsuite/ld-alpha/tlsbin.sd +./ld/testsuite/ld-alpha/tlsbin.td +./ld/testsuite/ld-alpha/tlsbinpic.s +./ld/testsuite/ld-alpha/tlsbinr.dd +./ld/testsuite/ld-alpha/tlsbinr.rd +./ld/testsuite/ld-alpha/tlsbinr.sd +./ld/testsuite/ld-alpha/tlsg.s +./ld/testsuite/ld-alpha/tlsg.sd +./ld/testsuite/ld-alpha/tlslib.s +./ld/testsuite/ld-alpha/tlspic.dd +./ld/testsuite/ld-alpha/tlspic.rd +./ld/testsuite/ld-alpha/tlspic.sd +./ld/testsuite/ld-alpha/tlspic.td +./ld/testsuite/ld-alpha/tlspic1.s +./ld/testsuite/ld-alpha/tlspic2.s +./ld/testsuite/ld-auto-import/auto-import.exp +./ld/testsuite/ld-auto-import/client.c +./ld/testsuite/ld-auto-import/dll.c +./ld/testsuite/ld-bootstrap/bootstrap.exp +./ld/testsuite/ld-cdtest/cdtest-bar.cc +./ld/testsuite/ld-cdtest/cdtest-foo.cc +./ld/testsuite/ld-cdtest/cdtest-foo.h +./ld/testsuite/ld-cdtest/cdtest-main.cc +./ld/testsuite/ld-cdtest/cdtest-nrv.dat +./ld/testsuite/ld-cdtest/cdtest.dat +./ld/testsuite/ld-cdtest/cdtest.exp +./ld/testsuite/ld-checks/checks.exp +./ld/testsuite/ld-checks/asm.s +./ld/testsuite/ld-checks/script +./ld/testsuite/ld-cris/badgotr1.d +./ld/testsuite/ld-cris/comref1.s +./ld/testsuite/ld-cris/cris.exp +./ld/testsuite/ld-cris/dso-1.s +./ld/testsuite/ld-cris/dso-2.s +./ld/testsuite/ld-cris/dso-3.s +./ld/testsuite/ld-cris/euwref1.s +./ld/testsuite/ld-cris/expdref1.s +./ld/testsuite/ld-cris/expdyn1.d +./ld/testsuite/ld-cris/expdyn1.s +./ld/testsuite/ld-cris/expdyn2.d +./ld/testsuite/ld-cris/expdyn3.d +./ld/testsuite/ld-cris/expdyn4.d +./ld/testsuite/ld-cris/expdyn5.d +./ld/testsuite/ld-cris/expdyn6.d +./ld/testsuite/ld-cris/expdyn7.d +./ld/testsuite/ld-cris/gotrel1.s +./ld/testsuite/ld-cris/gotrel2.s +./ld/testsuite/ld-cris/hide1 +./ld/testsuite/ld-cris/ldsym1.d +./ld/testsuite/ld-cris/libdso-1.d +./ld/testsuite/ld-cris/libdso-2.d +./ld/testsuite/ld-cris/libdso-3.d +./ld/testsuite/ld-cris/libdso-4.d +./ld/testsuite/ld-cris/nodyn4.d +./ld/testsuite/ld-cris/nodyn5.d +./ld/testsuite/ld-cris/noglob1.d +./ld/testsuite/ld-cris/noglob1.s +./ld/testsuite/ld-cris/undef1.d +./ld/testsuite/ld-cris/weakref1.d +./ld/testsuite/ld-cris/weakref2.d +./ld/testsuite/ld-d10v/d10v.exp +./ld/testsuite/ld-d10v/default_layout.d +./ld/testsuite/ld-d10v/linktest-001.s +./ld/testsuite/ld-d10v/linktest-002.lt +./ld/testsuite/ld-d10v/linktest-002.s +./ld/testsuite/ld-d10v/regression-001.lt +./ld/testsuite/ld-d10v/regression-001.s +./ld/testsuite/ld-d10v/reloc-001.d +./ld/testsuite/ld-d10v/reloc-001.ld +./ld/testsuite/ld-d10v/reloc-001.s +./ld/testsuite/ld-d10v/reloc-002.d +./ld/testsuite/ld-d10v/reloc-002.ld +./ld/testsuite/ld-d10v/reloc-003.d +./ld/testsuite/ld-d10v/reloc-003.ld +./ld/testsuite/ld-d10v/reloc-004.d +./ld/testsuite/ld-d10v/reloc-004.ld +./ld/testsuite/ld-d10v/reloc-005.d +./ld/testsuite/ld-d10v/reloc-005.ld +./ld/testsuite/ld-d10v/reloc-005.s +./ld/testsuite/ld-d10v/reloc-006.d +./ld/testsuite/ld-d10v/reloc-006.ld +./ld/testsuite/ld-d10v/reloc-007.d +./ld/testsuite/ld-d10v/reloc-007.ld +./ld/testsuite/ld-d10v/reloc-008.d +./ld/testsuite/ld-d10v/reloc-008.ld +./ld/testsuite/ld-d10v/reloc-009.d +./ld/testsuite/ld-d10v/reloc-009.ld +./ld/testsuite/ld-d10v/reloc-009.s +./ld/testsuite/ld-d10v/reloc-010.d +./ld/testsuite/ld-d10v/reloc-010.ld +./ld/testsuite/ld-d10v/reloc-011.d +./ld/testsuite/ld-d10v/reloc-011.ld +./ld/testsuite/ld-d10v/reloc-012.d +./ld/testsuite/ld-d10v/reloc-012.ld +./ld/testsuite/ld-d10v/reloc-013.d +./ld/testsuite/ld-d10v/reloc-013.ld +./ld/testsuite/ld-d10v/reloc-014.d +./ld/testsuite/ld-d10v/reloc-014.ld +./ld/testsuite/ld-d10v/reloc-015.d +./ld/testsuite/ld-d10v/reloc-015.ld +./ld/testsuite/ld-d10v/reloc-016.d +./ld/testsuite/ld-d10v/reloc-016.ld +./ld/testsuite/ld-d10v/simple.s +./ld/testsuite/ld-discard/discard.exp +./ld/testsuite/ld-discard/discard.ld +./ld/testsuite/ld-discard/exit.s +./ld/testsuite/ld-discard/extern.d +./ld/testsuite/ld-discard/extern.s +./ld/testsuite/ld-discard/start.d +./ld/testsuite/ld-discard/start.s +./ld/testsuite/ld-discard/static.d +./ld/testsuite/ld-discard/static.s +./ld/testsuite/ld-elf/merge.ld +./ld/testsuite/ld-elf/elf.exp +./ld/testsuite/ld-elf/merge.d +./ld/testsuite/ld-elf/sec64k.exp +./ld/testsuite/ld-elf/merge.s +./ld/testsuite/ld-elfcomm/common1a.c +./ld/testsuite/ld-elfcomm/common1b.c +./ld/testsuite/ld-elfcomm/elfcomm.exp +./ld/testsuite/ld-elfvers/vers.exp +./ld/testsuite/ld-elfvers/vers1.c +./ld/testsuite/ld-elfvers/vers1.dsym +./ld/testsuite/ld-elfvers/vers1.map +./ld/testsuite/ld-elfvers/vers1.sym +./ld/testsuite/ld-elfvers/vers1.ver +./ld/testsuite/ld-elfvers/vers13.asym +./ld/testsuite/ld-elfvers/vers15.c +./ld/testsuite/ld-elfvers/vers15.dsym +./ld/testsuite/ld-elfvers/vers15.sym +./ld/testsuite/ld-elfvers/vers15.ver +./ld/testsuite/ld-elfvers/vers16.c +./ld/testsuite/ld-elfvers/vers16.dsym +./ld/testsuite/ld-elfvers/vers16.map +./ld/testsuite/ld-elfvers/vers16a.c +./ld/testsuite/ld-elfvers/vers16a.dsym +./ld/testsuite/ld-elfvers/vers16a.ver +./ld/testsuite/ld-elfvers/vers17.c +./ld/testsuite/ld-elfvers/vers17.dsym +./ld/testsuite/ld-elfvers/vers17.map +./ld/testsuite/ld-elfvers/vers17.ver +./ld/testsuite/ld-elfvers/vers18.c +./ld/testsuite/ld-elfvers/vers18.dsym +./ld/testsuite/ld-elfvers/vers18.map +./ld/testsuite/ld-elfvers/vers18.sym +./ld/testsuite/ld-elfvers/vers18.ver +./ld/testsuite/ld-elfvers/vers19.c +./ld/testsuite/ld-elfvers/vers19.dsym +./ld/testsuite/ld-elfvers/vers19.ver +./ld/testsuite/ld-elfvers/vers2.c +./ld/testsuite/ld-elfvers/vers2.dsym +./ld/testsuite/ld-elfvers/vers2.map +./ld/testsuite/ld-elfvers/vers2.ver +./ld/testsuite/ld-elfvers/vers20.c +./ld/testsuite/ld-elfvers/vers20.dsym +./ld/testsuite/ld-elfvers/vers20.map +./ld/testsuite/ld-elfvers/vers20.ver +./ld/testsuite/ld-elfvers/vers20a.ver +./ld/testsuite/ld-elfvers/vers21.c +./ld/testsuite/ld-elfvers/vers21.dsym +./ld/testsuite/ld-elfvers/vers21.map +./ld/testsuite/ld-elfvers/vers21.sym +./ld/testsuite/ld-elfvers/vers21.ver +./ld/testsuite/ld-elfvers/vers22.c +./ld/testsuite/ld-elfvers/vers22.dsym +./ld/testsuite/ld-elfvers/vers22.map +./ld/testsuite/ld-elfvers/vers22.ver +./ld/testsuite/ld-elfvers/vers22a.c +./ld/testsuite/ld-elfvers/vers22a.dsym +./ld/testsuite/ld-elfvers/vers22a.sym +./ld/testsuite/ld-elfvers/vers22a.ver +./ld/testsuite/ld-elfvers/vers22b.c +./ld/testsuite/ld-elfvers/vers22b.dsym +./ld/testsuite/ld-elfvers/vers22b.ver +./ld/testsuite/ld-elfvers/vers23.c +./ld/testsuite/ld-elfvers/vers23.dsym +./ld/testsuite/ld-elfvers/vers23.ver +./ld/testsuite/ld-elfvers/vers23a.c +./ld/testsuite/ld-elfvers/vers23a.dsym +./ld/testsuite/ld-elfvers/vers23a.map +./ld/testsuite/ld-elfvers/vers23a.sym +./ld/testsuite/ld-elfvers/vers23a.ver +./ld/testsuite/ld-elfvers/vers23b.c +./ld/testsuite/ld-elfvers/vers23b.dsym +./ld/testsuite/ld-elfvers/vers23b.map +./ld/testsuite/ld-elfvers/vers23b.ver +./ld/testsuite/ld-elfvers/vers23c.ver +./ld/testsuite/ld-elfvers/vers23d.dsym +./ld/testsuite/ld-elfvers/vers24.map +./ld/testsuite/ld-elfvers/vers24.rd +./ld/testsuite/ld-elfvers/vers24a.c +./ld/testsuite/ld-elfvers/vers24b.c +./ld/testsuite/ld-elfvers/vers24c.c +./ld/testsuite/ld-elfvers/vers3.c +./ld/testsuite/ld-elfvers/vers25a.c +./ld/testsuite/ld-elfvers/vers25a.dsym +./ld/testsuite/ld-elfvers/vers25a.map +./ld/testsuite/ld-elfvers/vers25a.ver +./ld/testsuite/ld-elfvers/vers25b.c +./ld/testsuite/ld-elfvers/vers25b.dsym +./ld/testsuite/ld-elfvers/vers25b.ver +./ld/testsuite/ld-elfvers/vers3.dsym +./ld/testsuite/ld-elfvers/vers3.ver +./ld/testsuite/ld-elfvers/vers4.c +./ld/testsuite/ld-elfvers/vers4.sym +./ld/testsuite/ld-elfvers/vers4a.dsym +./ld/testsuite/ld-elfvers/vers4a.sym +./ld/testsuite/ld-elfvers/vers4a.ver +./ld/testsuite/ld-elfvers/vers5.c +./ld/testsuite/ld-elfvers/vers6.c +./ld/testsuite/ld-elfvers/vers6.dsym +./ld/testsuite/ld-elfvers/vers6.sym +./ld/testsuite/ld-elfvers/vers6.ver +./ld/testsuite/ld-elfvers/vers7.c +./ld/testsuite/ld-elfvers/vers7.map +./ld/testsuite/ld-elfvers/vers7a.c +./ld/testsuite/ld-elfvers/vers7a.dsym +./ld/testsuite/ld-elfvers/vers7a.sym +./ld/testsuite/ld-elfvers/vers7a.ver +./ld/testsuite/ld-elfvers/vers8.c +./ld/testsuite/ld-elfvers/vers8.map +./ld/testsuite/ld-elfvers/vers8.ver +./ld/testsuite/ld-elfvers/vers9.c +./ld/testsuite/ld-elfvers/vers9.dsym +./ld/testsuite/ld-elfvers/vers9.sym +./ld/testsuite/ld-elfvers/vers9.ver +./ld/testsuite/ld-elfvers/vers26a.c +./ld/testsuite/ld-elfvers/vers26a.dsym +./ld/testsuite/ld-elfvers/vers26a.map +./ld/testsuite/ld-elfvers/vers26a.ver +./ld/testsuite/ld-elfvers/vers26b.c +./ld/testsuite/ld-elfvers/vers27a.c +./ld/testsuite/ld-elfvers/vers27a.dsym +./ld/testsuite/ld-elfvers/vers27a.map +./ld/testsuite/ld-elfvers/vers27a.ver +./ld/testsuite/ld-elfvers/vers27b.c +./ld/testsuite/ld-elfvers/vers26b.dsym +./ld/testsuite/ld-elfvers/vers26b.ver +./ld/testsuite/ld-elfvers/vers27b.dsym +./ld/testsuite/ld-elfvers/vers27b.ver +./ld/testsuite/ld-elfvers/vers27c.c +./ld/testsuite/ld-elfvers/vers27c.dsym +./ld/testsuite/ld-elfvers/vers27c.ver +./ld/testsuite/ld-elfvers/vers27d.dsym +./ld/testsuite/ld-elfvers/vers27d.sym +./ld/testsuite/ld-elfvers/vers27d.ver +./ld/testsuite/ld-elfvers/vers27d1.c +./ld/testsuite/ld-elfvers/vers27d2.c +./ld/testsuite/ld-elfvers/vers27d3.c +./ld/testsuite/ld-elfvers/vers27d4.dsym +./ld/testsuite/ld-elfvers/vers27d4.ver +./ld/testsuite/ld-elfvsb/define.s +./ld/testsuite/ld-elfvsb/elf-offset.ld +./ld/testsuite/ld-elfvsb/elfvsb.dat +./ld/testsuite/ld-elfvsb/elfvsb.exp +./ld/testsuite/ld-elfvsb/hidden0.d +./ld/testsuite/ld-elfvsb/hidden1.d +./ld/testsuite/ld-elfvsb/internal0.d +./ld/testsuite/ld-elfvsb/internal1.d +./ld/testsuite/ld-elfvsb/main.c +./ld/testsuite/ld-elfvsb/protected0.d +./ld/testsuite/ld-elfvsb/protected1.d +./ld/testsuite/ld-elfvsb/sh1.c +./ld/testsuite/ld-elfvsb/sh2.c +./ld/testsuite/ld-elfvsb/undef.s +./ld/testsuite/ld-elfvsb/common.c +./ld/testsuite/ld-elfvsb/sh3.c +./ld/testsuite/ld-elfvsb/test.c +./ld/testsuite/ld-elfweak/dso.dsym +./ld/testsuite/ld-elfweak/bar.c +./ld/testsuite/ld-elfweak/bar1a.c +./ld/testsuite/ld-elfweak/bar1b.c +./ld/testsuite/ld-elfweak/bar1c.c +./ld/testsuite/ld-elfweak/dsodata.dsym +./ld/testsuite/ld-elfweak/dsow.dsym +./ld/testsuite/ld-elfweak/dsowdata.dsym +./ld/testsuite/ld-elfweak/elfweak.exp +./ld/testsuite/ld-elfweak/foo.c +./ld/testsuite/ld-elfweak/foo1a.c +./ld/testsuite/ld-elfweak/foo1b.c +./ld/testsuite/ld-elfweak/main.c +./ld/testsuite/ld-elfweak/main1.c +./ld/testsuite/ld-elfweak/strong.dat +./ld/testsuite/ld-elfweak/strong.sym +./ld/testsuite/ld-elfweak/strongcomm.sym +./ld/testsuite/ld-elfweak/strongdata.dat +./ld/testsuite/ld-elfweak/strongdata.sym +./ld/testsuite/ld-elfweak/weak.dat +./ld/testsuite/ld-elfweak/weak.dsym +./ld/testsuite/ld-elfweak/weakdata.dat +./ld/testsuite/ld-elfweak/weakdata.dsym +./ld/testsuite/ld-empic/empic.exp +./ld/testsuite/ld-empic/relax.t +./ld/testsuite/ld-empic/relax1.c +./ld/testsuite/ld-empic/relax2.c +./ld/testsuite/ld-empic/relax3.c +./ld/testsuite/ld-empic/relax4.c +./ld/testsuite/ld-empic/run.c +./ld/testsuite/ld-empic/runtest1.c +./ld/testsuite/ld-empic/runtest2.c +./ld/testsuite/ld-empic/runtesti.s +./ld/testsuite/ld-fastcall/export.s +./ld/testsuite/ld-fastcall/fastcall.exp +./ld/testsuite/ld-fastcall/import.s +./ld/testsuite/ld-h8300/h8300.exp +./ld/testsuite/ld-h8300/relax.d +./ld/testsuite/ld-h8300/relax.s +./ld/testsuite/ld-i386/combreloc.d +./ld/testsuite/ld-i386/combreloc.s +./ld/testsuite/ld-i386/i386.exp +./ld/testsuite/ld-i386/reloc.d +./ld/testsuite/ld-i386/reloc.s +./ld/testsuite/ld-i386/tlsbin.dd +./ld/testsuite/ld-i386/tlsbin.rd +./ld/testsuite/ld-i386/tlsbin.s +./ld/testsuite/ld-i386/tlsbin.sd +./ld/testsuite/ld-i386/tlsbin.td +./ld/testsuite/ld-i386/tlsbinpic.s +./ld/testsuite/ld-i386/tlsg.s +./ld/testsuite/ld-i386/tlsg.sd +./ld/testsuite/ld-i386/tlsindntpoff.dd +./ld/testsuite/ld-i386/tlsindntpoff.s +./ld/testsuite/ld-i386/tlslib.s +./ld/testsuite/ld-i386/tlsnopic.dd +./ld/testsuite/ld-i386/tlsnopic.rd +./ld/testsuite/ld-i386/tlsnopic.sd +./ld/testsuite/ld-i386/tlsnopic1.s +./ld/testsuite/ld-i386/tlsnopic2.s +./ld/testsuite/ld-i386/tlspic.dd +./ld/testsuite/ld-i386/tlspic.rd +./ld/testsuite/ld-i386/tlspic.sd +./ld/testsuite/ld-i386/tlspic.td +./ld/testsuite/ld-i386/tlspic1.s +./ld/testsuite/ld-i386/tlspic2.s +./ld/testsuite/ld-ia64/ia64.exp +./ld/testsuite/ld-ia64/tlsbin.dd +./ld/testsuite/ld-ia64/tlsbin.rd +./ld/testsuite/ld-ia64/tlsbin.s +./ld/testsuite/ld-ia64/tlsbin.sd +./ld/testsuite/ld-ia64/tlsbin.td +./ld/testsuite/ld-ia64/tlsbinpic.s +./ld/testsuite/ld-ia64/tlsg.s +./ld/testsuite/ld-ia64/tlsg.sd +./ld/testsuite/ld-ia64/tlslib.s +./ld/testsuite/ld-ia64/tlspic.dd +./ld/testsuite/ld-ia64/tlspic.rd +./ld/testsuite/ld-ia64/tlspic.sd +./ld/testsuite/ld-ia64/tlspic.td +./ld/testsuite/ld-ia64/tlspic1.s +./ld/testsuite/ld-ia64/tlspic2.s +./ld/testsuite/ld-linkonce/linkonce.exp +./ld/testsuite/ld-linkonce/x.s +./ld/testsuite/ld-linkonce/y.s +./ld/testsuite/ld-linkonce/zeroeh.ld +./ld/testsuite/ld-linkonce/zeroehl32.d +./ld/testsuite/ld-m68hc11/adj-brset.d +./ld/testsuite/ld-m68hc11/adj-brset.s +./ld/testsuite/ld-m68hc11/adj-jump.d +./ld/testsuite/ld-m68hc11/adj-jump.s +./ld/testsuite/ld-m68hc11/bug-1403.d +./ld/testsuite/ld-m68hc11/bug-1403.s +./ld/testsuite/ld-m68hc11/bug-1417.d +./ld/testsuite/ld-m68hc11/bug-1417.s +./ld/testsuite/ld-m68hc11/bug-3331.d +./ld/testsuite/ld-m68hc11/bug-3331.s +./ld/testsuite/ld-m68hc11/far-hc11.d +./ld/testsuite/ld-m68hc11/far-hc11.s +./ld/testsuite/ld-m68hc11/far-hc12.d +./ld/testsuite/ld-m68hc11/far-hc12.ld +./ld/testsuite/ld-m68hc11/far-hc12.s +./ld/testsuite/ld-m68hc11/m68hc11.exp +./ld/testsuite/ld-m68hc11/relax-direct.d +./ld/testsuite/ld-m68hc11/relax-direct.s +./ld/testsuite/ld-m68hc11/relax-group.d +./ld/testsuite/ld-m68hc11/relax-group.s +./ld/testsuite/ld-m68hc11/link-hc12.s +./ld/testsuite/ld-m68hc11/link-hcs12.d +./ld/testsuite/ld-m68hc11/link-hcs12.s +./ld/testsuite/ld-mips-elf/branch-misc-1.d +./ld/testsuite/ld-mips-elf/elf-rel-got-n32.d +./ld/testsuite/ld-mips-elf/elf-rel-got-n64.d +./ld/testsuite/ld-mips-elf/elf-rel-xgot-n32.d +./ld/testsuite/ld-mips-elf/elf-rel-xgot-n64.d +./ld/testsuite/ld-mips-elf/empic1-ln.d +./ld/testsuite/ld-mips-elf/empic1-lp.d +./ld/testsuite/ld-mips-elf/empic1-mn.d +./ld/testsuite/ld-mips-elf/empic1-mp.d +./ld/testsuite/ld-mips-elf/empic1-ref.s +./ld/testsuite/ld-mips-elf/empic1-sn.d +./ld/testsuite/ld-mips-elf/empic1-sp.d +./ld/testsuite/ld-mips-elf/empic1-space.s +./ld/testsuite/ld-mips-elf/empic1-tgt.s +./ld/testsuite/ld-mips-elf/empic2-fwd-0.d +./ld/testsuite/ld-mips-elf/empic2-fwd-1.d +./ld/testsuite/ld-mips-elf/empic2-fwd-tgt.s +./ld/testsuite/ld-mips-elf/empic2-ref.s +./ld/testsuite/ld-mips-elf/empic2-rev-0.d +./ld/testsuite/ld-mips-elf/empic2-rev-1.d +./ld/testsuite/ld-mips-elf/empic2-rev-tgt.s +./ld/testsuite/ld-mips-elf/empic2-space.s +./ld/testsuite/ld-mips-elf/emrelocs-eb.d +./ld/testsuite/ld-mips-elf/emrelocs-el.d +./ld/testsuite/ld-mips-elf/emrelocs.ld +./ld/testsuite/ld-mips-elf/emrelocs1.s +./ld/testsuite/ld-mips-elf/emrelocs2.s +./ld/testsuite/ld-mips-elf/jr.s +./ld/testsuite/ld-mips-elf/mips-elf-flags.exp +./ld/testsuite/ld-mips-elf/mips-elf.exp +./ld/testsuite/ld-mips-elf/mips16-1.d +./ld/testsuite/ld-mips-elf/mips16-1a.s +./ld/testsuite/ld-mips-elf/mips16-1b.s +./ld/testsuite/ld-mips-elf/multi-got-1-1.s +./ld/testsuite/ld-mips-elf/multi-got-1-2.s +./ld/testsuite/ld-mips-elf/multi-got-1.d +./ld/testsuite/ld-mips-elf/region1.d +./ld/testsuite/ld-mips-elf/region1.t +./ld/testsuite/ld-mips-elf/region1a.s +./ld/testsuite/ld-mips-elf/region1b.s +./ld/testsuite/ld-mips-elf/rel32-n32.d +./ld/testsuite/ld-mips-elf/rel32-o32.d +./ld/testsuite/ld-mips-elf/rel32.s +./ld/testsuite/ld-mips-elf/rel64.d +./ld/testsuite/ld-mips-elf/rel64.s +./ld/testsuite/ld-mips-elf/relax-jalr-n32-shared.d +./ld/testsuite/ld-mips-elf/relax-jalr-n32.d +./ld/testsuite/ld-mips-elf/relax-jalr-n64-shared.d +./ld/testsuite/ld-mips-elf/relax-jalr-n64.d +./ld/testsuite/ld-mips-elf/relax-jalr.s +./ld/testsuite/ld-mmix/areg-t.s +./ld/testsuite/ld-mmix/a.s +./ld/testsuite/ld-mmix/areg-256.s +./ld/testsuite/ld-mmix/aregm.s +./ld/testsuite/ld-mmix/b-badfil1.d +./ld/testsuite/ld-mmix/b-badfil1.s +./ld/testsuite/ld-mmix/b-badfil2.d +./ld/testsuite/ld-mmix/b-badfil2.s +./ld/testsuite/ld-mmix/b-badfixo.d +./ld/testsuite/ld-mmix/b-badfixo.s +./ld/testsuite/ld-mmix/b-badloc.d +./ld/testsuite/ld-mmix/b-badloc.s +./ld/testsuite/ld-mmix/b-badlop.d +./ld/testsuite/ld-mmix/b-badlop.s +./ld/testsuite/ld-mmix/b-badm.d +./ld/testsuite/ld-mmix/b-badm2.s +./ld/testsuite/ld-mmix/b-badmain.s +./ld/testsuite/ld-mmix/b-badquot.d +./ld/testsuite/ld-mmix/b-badquot.s +./ld/testsuite/ld-mmix/b-badrx1.d +./ld/testsuite/ld-mmix/b-badrx1.s +./ld/testsuite/ld-mmix/b-badrx2.d +./ld/testsuite/ld-mmix/b-badrx2.s +./ld/testsuite/ld-mmix/b-badrx3.d +./ld/testsuite/ld-mmix/b-badrx3.s +./ld/testsuite/ld-mmix/b-bend.s +./ld/testsuite/ld-mmix/b-bend1.d +./ld/testsuite/ld-mmix/b-bend2.d +./ld/testsuite/ld-mmix/b-bend3.d +./ld/testsuite/ld-mmix/b-bstab1.d +./ld/testsuite/ld-mmix/b-bstab1.s +./ld/testsuite/ld-mmix/b-fixo2.d +./ld/testsuite/ld-mmix/b-fixo2.s +./ld/testsuite/ld-mmix/b-goodmain.s +./ld/testsuite/ld-mmix/b-loc64k.d +./ld/testsuite/ld-mmix/b-loc64k.s +./ld/testsuite/ld-mmix/b-nosym.d +./ld/testsuite/ld-mmix/b-nosym.s +./ld/testsuite/ld-mmix/b-post1.s +./ld/testsuite/ld-mmix/b-twoinsn.s +./ld/testsuite/ld-mmix/b-widec.s +./ld/testsuite/ld-mmix/b-widec1.d +./ld/testsuite/ld-mmix/b-widec2.d +./ld/testsuite/ld-mmix/b-widec2.s +./ld/testsuite/ld-mmix/b-widec3.d +./ld/testsuite/ld-mmix/b-widec3.s +./ld/testsuite/ld-mmix/bpo-1.d +./ld/testsuite/ld-mmix/bpo-1.s +./ld/testsuite/ld-mmix/bpo-10.d +./ld/testsuite/ld-mmix/bpo-10.s +./ld/testsuite/ld-mmix/bpo-2.d +./ld/testsuite/ld-mmix/bpo-11.d +./ld/testsuite/ld-mmix/bpo-11.s +./ld/testsuite/ld-mmix/bpo-12.d +./ld/testsuite/ld-mmix/bpo-12m.d +./ld/testsuite/ld-mmix/bpo-13.d +./ld/testsuite/ld-mmix/bpo-13m.d +./ld/testsuite/ld-mmix/bpo-14.d +./ld/testsuite/ld-mmix/bpo-14m.d +./ld/testsuite/ld-mmix/bpo-15.d +./ld/testsuite/ld-mmix/bpo-15m.d +./ld/testsuite/ld-mmix/bpo-16.d +./ld/testsuite/ld-mmix/bpo-16m.d +./ld/testsuite/ld-mmix/bpo-17.d +./ld/testsuite/ld-mmix/bpo-17m.d +./ld/testsuite/ld-mmix/bpo-18.d +./ld/testsuite/ld-mmix/bpo-18m.d +./ld/testsuite/ld-mmix/bpo-19.d +./ld/testsuite/ld-mmix/bpo-19m.d +./ld/testsuite/ld-mmix/bpo-1m.d +./ld/testsuite/ld-mmix/bpo-2.s +./ld/testsuite/ld-mmix/bpo-20.d +./ld/testsuite/ld-mmix/bpo-20m.d +./ld/testsuite/ld-mmix/bpo-21.d +./ld/testsuite/ld-mmix/bpo-21m.d +./ld/testsuite/ld-mmix/bpo-22.d +./ld/testsuite/ld-mmix/bpo-3.d +./ld/testsuite/ld-mmix/bpo-2m.d +./ld/testsuite/ld-mmix/bpo-3.s +./ld/testsuite/ld-mmix/bpo-3m.d +./ld/testsuite/ld-mmix/bpo-4.d +./ld/testsuite/ld-mmix/bpo-4.s +./ld/testsuite/ld-mmix/bpo-4m.d +./ld/testsuite/ld-mmix/bpo-5.d +./ld/testsuite/ld-mmix/bpo-5.s +./ld/testsuite/ld-mmix/bpo-5m.d +./ld/testsuite/ld-mmix/bpo-6.d +./ld/testsuite/ld-mmix/bpo-6.s +./ld/testsuite/ld-mmix/bpo-6m.d +./ld/testsuite/ld-mmix/bpo-7.d +./ld/testsuite/ld-mmix/bpo-7.s +./ld/testsuite/ld-mmix/bpo-7m.d +./ld/testsuite/ld-mmix/bpo-8.d +./ld/testsuite/ld-mmix/bpo-8.s +./ld/testsuite/ld-mmix/bpo-8m.d +./ld/testsuite/ld-mmix/bpo-9.d +./ld/testsuite/ld-mmix/bpo-9.s +./ld/testsuite/ld-mmix/bpo-9m.d +./ld/testsuite/ld-mmix/bpo64addr.ld +./ld/testsuite/ld-mmix/bspec1.d +./ld/testsuite/ld-mmix/bspec1.s +./ld/testsuite/ld-mmix/bspec1m.d +./ld/testsuite/ld-mmix/bspec2.d +./ld/testsuite/ld-mmix/bspec2.s +./ld/testsuite/ld-mmix/bspec2m.d +./ld/testsuite/ld-mmix/bspec801.s +./ld/testsuite/ld-mmix/bspec802.s +./ld/testsuite/ld-mmix/bspec803.s +./ld/testsuite/ld-mmix/bspec804.s +./ld/testsuite/ld-mmix/bspec805.s +./ld/testsuite/ld-mmix/bspec806.s +./ld/testsuite/ld-mmix/bspec807.s +./ld/testsuite/ld-mmix/bspec808.s +./ld/testsuite/ld-mmix/bza-1b.d +./ld/testsuite/ld-mmix/bza-1f.d +./ld/testsuite/ld-mmix/bza-2b.d +./ld/testsuite/ld-mmix/bza-2f.d +./ld/testsuite/ld-mmix/bza-7b.d +./ld/testsuite/ld-mmix/bza-7f.d +./ld/testsuite/ld-mmix/bza-8b.d +./ld/testsuite/ld-mmix/bza-8f.d +./ld/testsuite/ld-mmix/bza.s +./ld/testsuite/ld-mmix/data1.s +./ld/testsuite/ld-mmix/dloc1.s +./ld/testsuite/ld-mmix/dloc2.s +./ld/testsuite/ld-mmix/ext1-254.s +./ld/testsuite/ld-mmix/ext1.s +./ld/testsuite/ld-mmix/ext1g.s +./ld/testsuite/ld-mmix/ext1l.s +./ld/testsuite/ld-mmix/getaa-1b.d +./ld/testsuite/ld-mmix/getaa-1f.d +./ld/testsuite/ld-mmix/getaa-2b.d +./ld/testsuite/ld-mmix/getaa-2f.d +./ld/testsuite/ld-mmix/getaa-4b.d +./ld/testsuite/ld-mmix/getaa-4f.d +./ld/testsuite/ld-mmix/getaa-6b.d +./ld/testsuite/ld-mmix/getaa-6f.d +./ld/testsuite/ld-mmix/getaa-7b.d +./ld/testsuite/ld-mmix/getaa-7f.d +./ld/testsuite/ld-mmix/getaa-8b.d +./ld/testsuite/ld-mmix/getaa-8f.d +./ld/testsuite/ld-mmix/getaa.s +./ld/testsuite/ld-mmix/getaa12b.d +./ld/testsuite/ld-mmix/getaa12f.d +./ld/testsuite/ld-mmix/getaa14b.d +./ld/testsuite/ld-mmix/getaa14f.d +./ld/testsuite/ld-mmix/greg-1.d +./ld/testsuite/ld-mmix/greg-1.s +./ld/testsuite/ld-mmix/greg-10.d +./ld/testsuite/ld-mmix/greg-11.d +./ld/testsuite/ld-mmix/greg-11b.d +./ld/testsuite/ld-mmix/greg-12.d +./ld/testsuite/ld-mmix/greg-13.d +./ld/testsuite/ld-mmix/greg-14.d +./ld/testsuite/ld-mmix/greg-15.d +./ld/testsuite/ld-mmix/greg-16.d +./ld/testsuite/ld-mmix/greg-17.d +./ld/testsuite/ld-mmix/hdr-1.d +./ld/testsuite/ld-mmix/greg-18.d +./ld/testsuite/ld-mmix/greg-19.d +./ld/testsuite/ld-mmix/greg-2.d +./ld/testsuite/ld-mmix/greg-2.s +./ld/testsuite/ld-mmix/greg-20.d +./ld/testsuite/ld-mmix/greg-3.d +./ld/testsuite/ld-mmix/greg-3.s +./ld/testsuite/ld-mmix/greg-4.d +./ld/testsuite/ld-mmix/greg-4.s +./ld/testsuite/ld-mmix/greg-5.d +./ld/testsuite/ld-mmix/greg-5.s +./ld/testsuite/ld-mmix/greg-6.d +./ld/testsuite/ld-mmix/greg-7.d +./ld/testsuite/ld-mmix/greg-8.d +./ld/testsuite/ld-mmix/greg-9.d +./ld/testsuite/ld-mmix/gregbza1.s +./ld/testsuite/ld-mmix/gregget1.s +./ld/testsuite/ld-mmix/gregget2.s +./ld/testsuite/ld-mmix/gregldo1.s +./ld/testsuite/ld-mmix/gregpsj1.s +./ld/testsuite/ld-mmix/jumpa-1b.d +./ld/testsuite/ld-mmix/jumpa-1f.d +./ld/testsuite/ld-mmix/jumpa-2b.d +./ld/testsuite/ld-mmix/jumpa-2f.d +./ld/testsuite/ld-mmix/jumpa-3b.d +./ld/testsuite/ld-mmix/x.s +./ld/testsuite/ld-mmix/jumpa-3f.d +./ld/testsuite/ld-mmix/jumpa-4b.d +./ld/testsuite/ld-mmix/jumpa-4f.d +./ld/testsuite/ld-mmix/jumpa-5b.d +./ld/testsuite/ld-mmix/jumpa-5f.d +./ld/testsuite/ld-mmix/jumpa-6b.d +./ld/testsuite/ld-mmix/jumpa-6f.d +./ld/testsuite/ld-mmix/jumpa-7b.d +./ld/testsuite/ld-mmix/jumpa-7f.d +./ld/testsuite/ld-mmix/jumpa-8b.d +./ld/testsuite/ld-mmix/jumpa-8f.d +./ld/testsuite/ld-mmix/jumpa-9b.d +./ld/testsuite/ld-mmix/jumpa-9f.d +./ld/testsuite/ld-mmix/jumpa.s +./ld/testsuite/ld-mmix/jumpa12b.d +./ld/testsuite/ld-mmix/jumpa12f.d +./ld/testsuite/ld-mmix/jumpa13b.d +./ld/testsuite/ld-mmix/jumpa13f.d +./ld/testsuite/ld-mmix/jumpa14b.d +./ld/testsuite/ld-mmix/jumpa14f.d +./ld/testsuite/ld-mmix/loc1.d +./ld/testsuite/ld-mmix/loc1.s +./ld/testsuite/ld-mmix/loc1m.d +./ld/testsuite/ld-mmix/loc2.d +./ld/testsuite/ld-mmix/loc2.s +./ld/testsuite/ld-mmix/loc2m.d +./ld/testsuite/ld-mmix/loc3.d +./ld/testsuite/ld-mmix/loc3m.d +./ld/testsuite/ld-mmix/loc4.d +./ld/testsuite/ld-mmix/loc4m.d +./ld/testsuite/ld-mmix/loc5.d +./ld/testsuite/ld-mmix/loc5m.d +./ld/testsuite/ld-mmix/loc6.d +./ld/testsuite/ld-mmix/loc6m.d +./ld/testsuite/ld-mmix/loc7.d +./ld/testsuite/ld-mmix/loc7m.d +./ld/testsuite/ld-mmix/local1.d +./ld/testsuite/ld-mmix/local1.s +./ld/testsuite/ld-mmix/local10.d +./ld/testsuite/ld-mmix/local10m.d +./ld/testsuite/ld-mmix/local11.d +./ld/testsuite/ld-mmix/local11m.d +./ld/testsuite/ld-mmix/local12.d +./ld/testsuite/ld-mmix/local12m.d +./ld/testsuite/ld-mmix/local1m.d +./ld/testsuite/ld-mmix/local2.d +./ld/testsuite/ld-mmix/local2.s +./ld/testsuite/ld-mmix/local2m.d +./ld/testsuite/ld-mmix/local3.d +./ld/testsuite/ld-mmix/local3m.d +./ld/testsuite/ld-mmix/local4.d +./ld/testsuite/ld-mmix/local4m.d +./ld/testsuite/ld-mmix/local5.d +./ld/testsuite/ld-mmix/local5m.d +./ld/testsuite/ld-mmix/local6.d +./ld/testsuite/ld-mmix/local6m.d +./ld/testsuite/ld-mmix/local7.d +./ld/testsuite/ld-mmix/local7m.d +./ld/testsuite/ld-mmix/local8.d +./ld/testsuite/ld-mmix/local8m.d +./ld/testsuite/ld-mmix/local9.d +./ld/testsuite/ld-mmix/local9m.d +./ld/testsuite/ld-mmix/locdo-1.d +./ld/testsuite/ld-mmix/locdo.s +./ld/testsuite/ld-mmix/loct-1.d +./ld/testsuite/ld-mmix/loct.s +./ld/testsuite/ld-mmix/locto-1.d +./ld/testsuite/ld-mmix/locto.s +./ld/testsuite/ld-mmix/main1.s +./ld/testsuite/ld-mmix/mmix.exp +./ld/testsuite/ld-mmix/mmohdr1.ld +./ld/testsuite/ld-mmix/mmosec1.ld +./ld/testsuite/ld-mmix/mmosec2.ld +./ld/testsuite/ld-mmix/nop123.s +./ld/testsuite/ld-mmix/pad16.s +./ld/testsuite/ld-mmix/pad2p18m32.s +./ld/testsuite/ld-mmix/pad2p26m32.s +./ld/testsuite/ld-mmix/pad4.s +./ld/testsuite/ld-mmix/pushja.s +./ld/testsuite/ld-mmix/pushja1b.d +./ld/testsuite/ld-mmix/pushja1f.d +./ld/testsuite/ld-mmix/pushja2b.d +./ld/testsuite/ld-mmix/pushja2f.d +./ld/testsuite/ld-mmix/pushja7b.d +./ld/testsuite/ld-mmix/pushja7f.d +./ld/testsuite/ld-mmix/pushja8b.d +./ld/testsuite/ld-mmix/pushja8f.d +./ld/testsuite/ld-mmix/reg-1.d +./ld/testsuite/ld-mmix/reg-1m.d +./ld/testsuite/ld-mmix/reg-2.d +./ld/testsuite/ld-mmix/reg-2m.d +./ld/testsuite/ld-mmix/regext1.s +./ld/testsuite/ld-mmix/sec-1.d +./ld/testsuite/ld-mmix/sec-1.s +./ld/testsuite/ld-mmix/sec-2.d +./ld/testsuite/ld-mmix/sec-2.s +./ld/testsuite/ld-mmix/sec-3.d +./ld/testsuite/ld-mmix/sec-4.d +./ld/testsuite/ld-mmix/sec-5.d +./ld/testsuite/ld-mmix/sec-6.d +./ld/testsuite/ld-mmix/sec-6.s +./ld/testsuite/ld-mmix/sec-6m.d +./ld/testsuite/ld-mmix/sec-7a.s +./ld/testsuite/ld-mmix/sec-7b.s +./ld/testsuite/ld-mmix/sec-7c.s +./ld/testsuite/ld-mmix/sec-7d.s +./ld/testsuite/ld-mmix/sec-7e.s +./ld/testsuite/ld-mmix/start.s +./ld/testsuite/ld-mmix/sec-7m.d +./ld/testsuite/ld-mmix/sec-8a.s +./ld/testsuite/ld-mmix/sec-8b.s +./ld/testsuite/ld-mmix/sec-8d.s +./ld/testsuite/ld-mmix/sec-8m.d +./ld/testsuite/ld-mmix/sec-8m.s +./ld/testsuite/ld-mmix/spec801.d +./ld/testsuite/ld-mmix/spec802.d +./ld/testsuite/ld-mmix/spec803.d +./ld/testsuite/ld-mmix/spec804.d +./ld/testsuite/ld-mmix/spec805.d +./ld/testsuite/ld-mmix/spec806.d +./ld/testsuite/ld-mmix/spec807.d +./ld/testsuite/ld-mmix/spec808.d +./ld/testsuite/ld-mmix/start-1.d +./ld/testsuite/ld-mmix/start-2.d +./ld/testsuite/ld-mmix/start2.s +./ld/testsuite/ld-mmix/start3.s +./ld/testsuite/ld-mmix/start4.s +./ld/testsuite/ld-mmix/sym-1.d +./ld/testsuite/ld-mmix/sym-2.d +./ld/testsuite/ld-mmix/sym-2.s +./ld/testsuite/ld-mmix/undef-1.d +./ld/testsuite/ld-mmix/undef-1.s +./ld/testsuite/ld-mmix/undef-1m.d +./ld/testsuite/ld-mmix/undef-2.d +./ld/testsuite/ld-mmix/undef-2.s +./ld/testsuite/ld-mmix/undef-2m.d +./ld/testsuite/ld-mmix/undef-3.d +./ld/testsuite/ld-mmix/undef-3m.d +./ld/testsuite/ld-mmix/y.s +./ld/testsuite/ld-mmix/zeroeh.ld +./ld/testsuite/ld-mmix/zeroehelf.d +./ld/testsuite/ld-mmix/zeroehmmo.d +./ld/testsuite/ld-powerpc/apuinfo.rd +./ld/testsuite/ld-powerpc/apuinfo1.s +./ld/testsuite/ld-powerpc/apuinfo2.s +./ld/testsuite/ld-powerpc/powerpc.exp +./ld/testsuite/ld-powerpc/reloc.d +./ld/testsuite/ld-powerpc/reloc.s +./ld/testsuite/ld-powerpc/tls.d +./ld/testsuite/ld-powerpc/tls.g +./ld/testsuite/ld-powerpc/tls.s +./ld/testsuite/ld-powerpc/tls.t +./ld/testsuite/ld-powerpc/tls32.d +./ld/testsuite/ld-powerpc/tls32.g +./ld/testsuite/ld-powerpc/tls32.s +./ld/testsuite/ld-powerpc/tls32.t +./ld/testsuite/ld-powerpc/tlsexe.d +./ld/testsuite/ld-powerpc/tlsexe.g +./ld/testsuite/ld-powerpc/tlsexe.r +./ld/testsuite/ld-powerpc/tlsexe.t +./ld/testsuite/ld-powerpc/tlsexe32.d +./ld/testsuite/ld-powerpc/tlsexe32.g +./ld/testsuite/ld-powerpc/tlsexe32.r +./ld/testsuite/ld-powerpc/tlsexe32.t +./ld/testsuite/ld-powerpc/tlsexetoc.d +./ld/testsuite/ld-powerpc/tlsexetoc.g +./ld/testsuite/ld-powerpc/tlsexetoc.r +./ld/testsuite/ld-powerpc/tlsexetoc.t +./ld/testsuite/ld-powerpc/tlslib.s +./ld/testsuite/ld-powerpc/tlslib32.s +./ld/testsuite/ld-powerpc/tlsso.d +./ld/testsuite/ld-powerpc/tlsso.g +./ld/testsuite/ld-powerpc/tlsso.r +./ld/testsuite/ld-powerpc/tlsso.t +./ld/testsuite/ld-powerpc/tlsso32.d +./ld/testsuite/ld-powerpc/tlsso32.g +./ld/testsuite/ld-powerpc/tlsso32.r +./ld/testsuite/ld-powerpc/tlsso32.t +./ld/testsuite/ld-powerpc/tlstoc.d +./ld/testsuite/ld-powerpc/tlstoc.g +./ld/testsuite/ld-powerpc/tlstoc.s +./ld/testsuite/ld-powerpc/tlstoc.t +./ld/testsuite/ld-powerpc/tlstocso.d +./ld/testsuite/ld-powerpc/tlstocso.g +./ld/testsuite/ld-powerpc/tlstocso.r +./ld/testsuite/ld-powerpc/tlstocso.t +./ld/testsuite/ld-s390/s390.exp +./ld/testsuite/ld-s390/tlsbin.dd +./ld/testsuite/ld-s390/tlsbin.rd +./ld/testsuite/ld-s390/tlsbin.s +./ld/testsuite/ld-s390/tlsbin.sd +./ld/testsuite/ld-s390/tlsbin.td +./ld/testsuite/ld-s390/tlsbin_64.dd +./ld/testsuite/ld-s390/tlsbin_64.rd +./ld/testsuite/ld-s390/tlsbin_64.s +./ld/testsuite/ld-s390/tlsbin_64.sd +./ld/testsuite/ld-s390/tlsbin_64.td +./ld/testsuite/ld-s390/tlsbinpic.s +./ld/testsuite/ld-s390/tlsbinpic_64.s +./ld/testsuite/ld-s390/tlslib.s +./ld/testsuite/ld-s390/tlslib_64.s +./ld/testsuite/ld-s390/tlspic.dd +./ld/testsuite/ld-s390/tlspic.rd +./ld/testsuite/ld-s390/tlspic.sd +./ld/testsuite/ld-s390/tlspic.td +./ld/testsuite/ld-s390/tlspic1.s +./ld/testsuite/ld-s390/tlspic1_64.s +./ld/testsuite/ld-s390/tlspic2.s +./ld/testsuite/ld-s390/tlspic2_64.s +./ld/testsuite/ld-s390/tlspic_64.dd +./ld/testsuite/ld-s390/tlspic_64.rd +./ld/testsuite/ld-s390/tlspic_64.sd +./ld/testsuite/ld-s390/tlspic_64.td +./ld/testsuite/ld-scripts/cross1.c +./ld/testsuite/ld-scripts/cross1.t +./ld/testsuite/ld-scripts/cross2.c +./ld/testsuite/ld-scripts/cross2.t +./ld/testsuite/ld-scripts/cross3.c +./ld/testsuite/ld-scripts/crossref.exp +./ld/testsuite/ld-scripts/defined.exp +./ld/testsuite/ld-scripts/defined.s +./ld/testsuite/ld-scripts/defined.t +./ld/testsuite/ld-scripts/dynamic-sections-1.s +./ld/testsuite/ld-scripts/dynamic-sections-2.s +./ld/testsuite/ld-scripts/dynamic-sections.d +./ld/testsuite/ld-scripts/dynamic-sections.exp +./ld/testsuite/ld-scripts/dynamic-sections.t +./ld/testsuite/ld-scripts/map-address.d +./ld/testsuite/ld-scripts/map-address.exp +./ld/testsuite/ld-scripts/map-address.t +./ld/testsuite/ld-scripts/overlay-size-map.d +./ld/testsuite/ld-scripts/overlay-size.d +./ld/testsuite/ld-scripts/overlay-size.exp +./ld/testsuite/ld-scripts/overlay-size.s +./ld/testsuite/ld-scripts/overlay-size.t +./ld/testsuite/ld-scripts/phdrs.exp +./ld/testsuite/ld-scripts/phdrs.s +./ld/testsuite/ld-scripts/phdrs.t +./ld/testsuite/ld-scripts/phdrs2.exp +./ld/testsuite/ld-scripts/phdrs2.s +./ld/testsuite/ld-scripts/phdrs2.t +./ld/testsuite/ld-scripts/script.exp +./ld/testsuite/ld-scripts/script.s +./ld/testsuite/ld-scripts/script.t +./ld/testsuite/ld-scripts/scriptm.t +./ld/testsuite/ld-scripts/sizeof.exp +./ld/testsuite/ld-scripts/sizeof.s +./ld/testsuite/ld-scripts/sizeof.t +./ld/testsuite/ld-scripts/weak.exp +./ld/testsuite/ld-scripts/weak.t +./ld/testsuite/ld-scripts/weak1.s +./ld/testsuite/ld-scripts/weak2.s +./ld/testsuite/ld-selective/3.cc +./ld/testsuite/ld-selective/1.c +./ld/testsuite/ld-selective/2.c +./ld/testsuite/ld-selective/keepdot.d +./ld/testsuite/ld-selective/4.cc +./ld/testsuite/ld-selective/5.cc +./ld/testsuite/ld-selective/keepdot.ld +./ld/testsuite/ld-selective/keepdot.s +./ld/testsuite/ld-selective/keepdot0.d +./ld/testsuite/ld-selective/keepdot0.ld +./ld/testsuite/ld-selective/sel-dump.exp +./ld/testsuite/ld-selective/selective.exp +./ld/testsuite/ld-sh/sh64/abi32.sd +./ld/testsuite/ld-sh/sh64/abi32.xd +./ld/testsuite/ld-sh/sh64/abi64.sd +./ld/testsuite/ld-sh/sh64/abi64.xd +./ld/testsuite/ld-sh/sh64/abixx-noexp.sd +./ld/testsuite/ld-sh/sh64/cmpct1.sd +./ld/testsuite/ld-sh/sh64/cmpct1.xd +./ld/testsuite/ld-sh/sh64/crange-1.s +./ld/testsuite/ld-sh/sh64/crange-2a.s +./ld/testsuite/ld-sh/sh64/crange-2b.s +./ld/testsuite/ld-sh/sh64/crange-2c.s +./ld/testsuite/ld-sh/sh64/crange-2d.s +./ld/testsuite/ld-sh/sh64/crange-2e.s +./ld/testsuite/ld-sh/sh64/crange-2f.s +./ld/testsuite/ld-sh/sh64/crange-2g.s +./ld/testsuite/ld-sh/sh64/crange-2h.s +./ld/testsuite/ld-sh/sh64/crange-2i.s +./ld/testsuite/ld-sh/sh64/crange1.rd +./ld/testsuite/ld-sh/sh64/crange2.rd +./ld/testsuite/ld-sh/sh64/crange3-cmpct.rd +./ld/testsuite/ld-sh/sh64/crange3-media.rd +./ld/testsuite/ld-sh/sh64/crange3.dd +./ld/testsuite/ld-sh/sh64/crange3.rd +./ld/testsuite/ld-sh/sh64/crangerel1.rd +./ld/testsuite/ld-sh/sh64/crangerel2.rd +./ld/testsuite/ld-sh/sh64/dlsection-1.s +./ld/testsuite/ld-sh/sh64/dlsection.sd +./ld/testsuite/ld-sh/sh64/endian.dbd +./ld/testsuite/ld-sh/sh64/endian.dld +./ld/testsuite/ld-sh/sh64/endian.ld +./ld/testsuite/ld-sh/sh64/endian.s +./ld/testsuite/ld-sh/sh64/endian.sbd +./ld/testsuite/ld-sh/sh64/endian.sld +./ld/testsuite/ld-sh/sh64/gotplt.d +./ld/testsuite/ld-sh/sh64/gotplt.map +./ld/testsuite/ld-sh/sh64/gotplt.s +./ld/testsuite/ld-sh/sh64/init-cmpct.d +./ld/testsuite/ld-sh/sh64/init-media.d +./ld/testsuite/ld-sh/sh64/init.s +./ld/testsuite/ld-sh/sh64/init64.d +./ld/testsuite/ld-sh/sh64/mix1-noexp.sd +./ld/testsuite/ld-sh/sh64/mix1.sd +./ld/testsuite/ld-sh/sh64/mix1.xd +./ld/testsuite/ld-sh/sh64/mix2-noexp.sd +./ld/testsuite/ld-sh/sh64/mix2.sd +./ld/testsuite/ld-sh/sh64/mix2.xd +./ld/testsuite/ld-sh/sh64/rd-sh64.exp +./ld/testsuite/ld-sh/sh64/rel-1.s +./ld/testsuite/ld-sh/sh64/rel-2.s +./ld/testsuite/ld-sh/sh64/rel32.xd +./ld/testsuite/ld-sh/sh64/rel64.xd +./ld/testsuite/ld-sh/sh64/relax.exp +./ld/testsuite/ld-sh/sh64/relax1.s +./ld/testsuite/ld-sh/sh64/relax2.s +./ld/testsuite/ld-sh/sh64/relax3.s +./ld/testsuite/ld-sh/sh64/relax4.s +./ld/testsuite/ld-sh/sh64/reldl-1.s +./ld/testsuite/ld-sh/sh64/reldl-2.s +./ld/testsuite/ld-sh/sh64/reldl32.rd +./ld/testsuite/ld-sh/sh64/reldl64.rd +./ld/testsuite/ld-sh/sh64/relfail.exp +./ld/testsuite/ld-sh/sh64/relfail.s +./ld/testsuite/ld-sh/sh64/sh64-1.s +./ld/testsuite/ld-sh/sh64/sh64-2.s +./ld/testsuite/ld-sh/sh64/sh64.exp +./ld/testsuite/ld-sh/sh64/shcmp-1.s +./ld/testsuite/ld-sh/sh64/shdl-1.s +./ld/testsuite/ld-sh/sh64/shdl-2.s +./ld/testsuite/ld-sh/sh64/shdl32.xd +./ld/testsuite/ld-sh/sh64/shdl64.sd +./ld/testsuite/ld-sh/sh64/shdl64.xd +./ld/testsuite/ld-sh/sh64/shmix-1.s +./ld/testsuite/ld-sh/sh64/shmix-2.s +./ld/testsuite/ld-sh/sh64/shmix-3.s +./ld/testsuite/ld-sh/ld-r-1.d +./ld/testsuite/ld-sh/ldr1.s +./ld/testsuite/ld-sh/ldr2.s +./ld/testsuite/ld-sh/rd-sh.exp +./ld/testsuite/ld-sh/refdbg-0-dso.d +./ld/testsuite/ld-sh/refdbg-1.d +./ld/testsuite/ld-sh/refdbg.s +./ld/testsuite/ld-sh/refdbglib.s +./ld/testsuite/ld-sh/sh.exp +./ld/testsuite/ld-sh/sh1.s +./ld/testsuite/ld-sh/sh2.c +./ld/testsuite/ld-sh/shared-1.d +./ld/testsuite/ld-sh/start.s +./ld/testsuite/ld-sh/sub2l-1.d +./ld/testsuite/ld-sh/sub2l.s +./ld/testsuite/ld-sh/tlsbin-0-dso.d +./ld/testsuite/ld-sh/tlsbin-1.d +./ld/testsuite/ld-sh/tlsbin-2.d +./ld/testsuite/ld-sh/tlsbin-3.d +./ld/testsuite/ld-sh/tlsbin-4.d +./ld/testsuite/ld-sh/tlsbin.s +./ld/testsuite/ld-sh/tlsbinpic.s +./ld/testsuite/ld-sh/tlslib.s +./ld/testsuite/ld-sh/tlspic-1.d +./ld/testsuite/ld-sh/tlspic-2.d +./ld/testsuite/ld-sh/tlspic-3.d +./ld/testsuite/ld-sh/tlspic-4.d +./ld/testsuite/ld-sh/tlspic1.s +./ld/testsuite/ld-sh/tlspic2.s +./ld/testsuite/ld-sh/tlstpoff-1.d +./ld/testsuite/ld-sh/tlstpoff-2.d +./ld/testsuite/ld-sh/tlstpoff1.s +./ld/testsuite/ld-sh/tlstpoff2.s +./ld/testsuite/ld-sh/weak1.d +./ld/testsuite/ld-sh/weak1.s +./ld/testsuite/ld-shared/elf-offset.ld +./ld/testsuite/ld-shared/main.c +./ld/testsuite/ld-shared/sh1.c +./ld/testsuite/ld-shared/sh2.c +./ld/testsuite/ld-shared/shared.dat +./ld/testsuite/ld-shared/shared.exp +./ld/testsuite/ld-shared/sun4.dat +./ld/testsuite/ld-shared/symbolic.dat +./ld/testsuite/ld-shared/xcoff.dat +./ld/testsuite/ld-sparc/sparc.exp +./ld/testsuite/ld-sparc/tlsg32.s +./ld/testsuite/ld-sparc/tlsg32.sd +./ld/testsuite/ld-sparc/tlsg64.s +./ld/testsuite/ld-sparc/tlsg64.sd +./ld/testsuite/ld-sparc/tlslib.s +./ld/testsuite/ld-sparc/tlsnopic.s +./ld/testsuite/ld-sparc/tlspic.s +./ld/testsuite/ld-sparc/tlssunbin32.dd +./ld/testsuite/ld-sparc/tlssunbin32.rd +./ld/testsuite/ld-sparc/tlssunbin32.s +./ld/testsuite/ld-sparc/tlssunbin32.sd +./ld/testsuite/ld-sparc/tlssunbin32.td +./ld/testsuite/ld-sparc/tlssunbin64.dd +./ld/testsuite/ld-sparc/tlssunbin64.rd +./ld/testsuite/ld-sparc/tlssunbin64.s +./ld/testsuite/ld-sparc/tlssunbin64.sd +./ld/testsuite/ld-sparc/tlssunbin64.td +./ld/testsuite/ld-sparc/tlssunbinpic32.s +./ld/testsuite/ld-sparc/tlssunbinpic64.s +./ld/testsuite/ld-sparc/tlssunnopic32.dd +./ld/testsuite/ld-sparc/tlssunnopic32.rd +./ld/testsuite/ld-sparc/tlssunnopic32.s +./ld/testsuite/ld-sparc/tlssunnopic32.sd +./ld/testsuite/ld-sparc/tlssunnopic64.dd +./ld/testsuite/ld-sparc/tlssunnopic64.rd +./ld/testsuite/ld-sparc/tlssunnopic64.s +./ld/testsuite/ld-sparc/tlssunnopic64.sd +./ld/testsuite/ld-sparc/tlssunpic32.dd +./ld/testsuite/ld-sparc/tlssunpic32.rd +./ld/testsuite/ld-sparc/tlssunpic32.s +./ld/testsuite/ld-sparc/tlssunpic32.sd +./ld/testsuite/ld-sparc/tlssunpic32.td +./ld/testsuite/ld-sparc/tlssunpic64.dd +./ld/testsuite/ld-sparc/tlssunpic64.rd +./ld/testsuite/ld-sparc/tlssunpic64.s +./ld/testsuite/ld-sparc/tlssunpic64.sd +./ld/testsuite/ld-sparc/tlssunpic64.td +./ld/testsuite/ld-srec/srec.exp +./ld/testsuite/ld-srec/sr1.c +./ld/testsuite/ld-srec/sr2.c +./ld/testsuite/ld-srec/sr3.cc +./ld/testsuite/ld-undefined/undefined.c +./ld/testsuite/ld-undefined/undefined.exp +./ld/testsuite/ld-undefined/weak-undef.exp +./ld/testsuite/ld-undefined/weak-undef.s +./ld/testsuite/ld-undefined/weak-undef.t +./ld/testsuite/ld-versados/versados.exp +./ld/testsuite/ld-versados/t1-1.ro +./ld/testsuite/ld-versados/t1-2.ro +./ld/testsuite/ld-versados/t1.ld +./ld/testsuite/ld-versados/t1.ook +./ld/testsuite/ld-versados/t2-1.ro +./ld/testsuite/ld-versados/t2-2.ro +./ld/testsuite/ld-versados/t2-3.ro +./ld/testsuite/ld-versados/t2.ld +./ld/testsuite/ld-versados/t2.ook +./ld/testsuite/ld-x86-64/tlsbin.dd +./ld/testsuite/ld-x86-64/tlsbin.rd +./ld/testsuite/ld-x86-64/tlsbin.s +./ld/testsuite/ld-x86-64/tlsbin.sd +./ld/testsuite/ld-x86-64/tlsbin.td +./ld/testsuite/ld-x86-64/tlsbinpic.s +./ld/testsuite/ld-x86-64/tlsg.s +./ld/testsuite/ld-x86-64/tlsg.sd +./ld/testsuite/ld-x86-64/tlslib.s +./ld/testsuite/ld-x86-64/tlspic.dd +./ld/testsuite/ld-x86-64/tlspic.rd +./ld/testsuite/ld-x86-64/tlspic.sd +./ld/testsuite/ld-x86-64/tlspic.td +./ld/testsuite/ld-x86-64/tlspic1.s +./ld/testsuite/ld-x86-64/tlspic2.s +./ld/testsuite/ld-x86-64/x86-64.exp +./ld/testsuite/ld-xtensa/coalesce.exp +./ld/testsuite/ld-xtensa/coalesce.t +./ld/testsuite/ld-xtensa/coalesce1.s +./ld/testsuite/ld-xtensa/coalesce2.s +./ld/testsuite/ld-xtensa/lcall.exp +./ld/testsuite/ld-xtensa/lcall.t +./ld/testsuite/ld-xtensa/lcall1.s +./ld/testsuite/ld-xtensa/lcall2.s +./ld/testsuite/lib/ld-lib.exp +./ld/configdoc.texi +./ld/ldver.texi +./ld/ld.info +./ld/ld.info-1 +./ld/ld.info-2 +./ld/ld.info-3 +./ld/ld.info-4 +./ld/ld.info-5 +./ld/ld.info-6 +./ld/ldgram.c +./ld/ldgram.h +./ld/ldlex.c +./gprof/po/.cvsignore +./gprof/po/Make-in +./gprof/po/POTFILES.in +./gprof/po/da.po +./gprof/po/es.po +./gprof/po/fr.po +./gprof/po/gprof.pot +./gprof/po/id.po +./gprof/po/pt_BR.po +./gprof/po/sv.po +./gprof/po/tr.po +./gprof/po/da.gmo +./gprof/po/es.gmo +./gprof/po/fr.gmo +./gprof/po/id.gmo +./gprof/po/pt_BR.gmo +./gprof/po/sv.gmo +./gprof/po/tr.gmo +./gprof/.gdbinit +./gprof/ChangeLog +./gprof/Makefile.am +./gprof/Makefile.in +./gprof/acinclude.m4 +./gprof/aclocal.m4 +./gprof/alpha.c +./gprof/basic_blocks.c +./gprof/basic_blocks.h +./gprof/bb_exit_func.c +./gprof/bbconv.pl +./gprof/bsd_callg_bl.m +./gprof/call_graph.c +./gprof/call_graph.h +./gprof/cg_arcs.c +./gprof/cg_arcs.h +./gprof/cg_dfn.c +./gprof/cg_dfn.h +./gprof/cg_print.c +./gprof/cg_print.h +./gprof/configure +./gprof/configure.in +./gprof/corefile.c +./gprof/corefile.h +./gprof/dep-in.sed +./gprof/flat_bl.m +./gprof/fsf_callg_bl.m +./gprof/gconfig.in +./gprof/gen-c-prog.awk +./gprof/gmon.h +./gprof/gmon_io.c +./gprof/gmon_io.h +./gprof/gmon_out.h +./gprof/gprof.c +./gprof/gprof.h +./gprof/gprof.texi +./gprof/hertz.c +./gprof/hertz.h +./gprof/hist.c +./gprof/hist.h +./gprof/i386.c +./gprof/mips.c +./gprof/search_list.c +./gprof/search_list.h +./gprof/source.c +./gprof/source.h +./gprof/sparc.c +./gprof/stamp-h.in +./gprof/sym_ids.c +./gprof/sym_ids.h +./gprof/symtab.c +./gprof/symtab.h +./gprof/tahoe.c +./gprof/utils.c +./gprof/utils.h +./gprof/vax.c +./gprof/flat_bl.c +./gprof/bsd_callg_bl.c +./gprof/fsf_callg_bl.c +./gprof/gprof.info +./gprof/gprof.info-1 +./gprof/gprof.info-2 +./gprof/gprof.info-3 +./gprof/gprof.1 +./intl/ChangeLog +./intl/Makefile.in +./intl/acconfig.h +./intl/aclocal.m4 +./intl/bindtextdom.c +./intl/cat-compat.c +./intl/config.in +./intl/configure +./intl/configure.in +./intl/dcgettext.c +./intl/dgettext.c +./intl/explodename.c +./intl/finddomain.c +./intl/gettext.c +./intl/gettext.h +./intl/gettextP.h +./intl/hash-string.h +./intl/intl-compat.c +./intl/intlh.inst.in +./intl/l10nflist.c +./intl/libgettext.h +./intl/libintl.glibc +./intl/linux-msg.sed +./intl/loadinfo.h +./intl/loadmsgcat.c +./intl/localealias.c +./intl/po2tbl.sed.in +./intl/textdomain.c +./intl/xopen-msg.sed +./setup.com +./makefile.vms +./mkdep +./etc/Makefile.in +./etc/configure +./etc/configure.in +./etc/standards.texi +./etc/make-stds.texi +./etc/standards.info +./etc/configure.texi +./etc/configure.info +./etc/configure.info-1 +./etc/configure.info-2 +./etc/configure.info-3 +./etc/configbuild.ein +./etc/configbuild.fig +./etc/configbuild.jin +./etc/configbuild.tin +./etc/configdev.ein +./etc/configdev.fig +./etc/configdev.jin +./etc/configdev.tin +./etc/fdl.texi +./etc/texi2pod.pl +./texinfo/texinfo.tex +./md5.sum diff --git a/contrib/binutils-2.14/README.DRAGONFLY b/contrib/binutils-2.14/README.DRAGONFLY new file mode 100644 index 0000000000..6122ece33f --- /dev/null +++ b/contrib/binutils-2.14/README.DRAGONFLY @@ -0,0 +1,60 @@ + + BINUTILS-2.14 AS USED BY DRAGONFLY + + This directory contains a selected set of files from the gnu + binutils-2.14 distribution. The entire distribution is 71MB but + we really only need around 10MB of it. No files have been moved + or modified from their extracted position. + + DO NOT CREATE OR EDIT ANY FILES IN THIS DIRECTORY HIERARCHY! THIS + HIERARCHY REPRESENTS AN EXACT COPY, MINUS UNNEEDED FILES, OF THE GNU + BINUTILS-2.14 DISTRIBUTION. All modifications are made in the + DragonFly build wrapper, in /usr/src/gnu/usr.bin/binutils214, by + creating overrides or performing surgery on the distribution. + The only additional files added to this directory are README.DRAGONFLY + and README.DELETED. The base source was fetched from: + + http://ftp.gnu.org/gnu/binutils/binutils-2.14.tar.gz + MD5 (binutils-2.14.tar.gz) = ba665d0ddcc88313384b79e293ecbbab + + UPGRADE PROCDURE: + + * download a new binutils > 2.14.0 from a gnu download site. + + * extract the archive into this directory, overlaying the + existing files. + + * A 'cvs update' will show you what has changed ('M') relative + to what we had before. There will be hundreds of files marked + '?' which, if not needed, should be deleted and NOT COMMITTED. + If any new files are needed you can cvs add and commit them. + + * Make sure that both buildworld and a crossbuilt buildworld + for supported architectures works before committing the upgrade, + making adjustments within /usr/src/gnu/usr.bin/binutils214. + + DO NOT MAKE ANY EDITS TO THE BINUTILS DISTRIBUTION IN THIS CONTRIB + DIRECTORY! + + binutils is designed to be backwards compatible. When unpacking a + new major rev, e.g. 2.15, it should be placed in a NEW CONTRIB DIRECTORY, + and a new infrastructure in /usr/src/gnu/usr.bin/binutilsXXX should be + created. Be sure to commit only those files that the DragonFly build + actually needs to avoid bloating the cvs repository. + + Do not overlay major rev changes in the contrib directory or + build infrastructure directory for older major revs! The binutils the + compiler subsystem uses is selected in: + + /usr/src/usr.bin/objformat/objformat.c + + That is what you edit to change the system binutils defaults. Eventually + the physical cvs hierarchy representing older major revs of binutils + will be physically removed from the contrib/ hierarchy. Older binutils + can be recovered by manually unpacking older gnu binutils dists in + /usr/src/contrib, without CVS support. Do not physically remove + the DFly build infrastructure for older binutils from + /usr/src/gnu/usr.bin/. cvs delete, sure, but no physical removal. + + The file README.DELETED contains a list of deleted files. + diff --git a/contrib/binutils-2.14/bfd/COPYING b/contrib/binutils-2.14/bfd/COPYING new file mode 100644 index 0000000000..c27986e64c --- /dev/null +++ b/contrib/binutils-2.14/bfd/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright 1989, 1991, 1997 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/binutils-2.14/bfd/MAINTAINERS b/contrib/binutils-2.14/bfd/MAINTAINERS new file mode 100644 index 0000000000..d59a3bd7f8 --- /dev/null +++ b/contrib/binutils-2.14/bfd/MAINTAINERS @@ -0,0 +1 @@ +See ../binutils/MAINTAINERS diff --git a/contrib/binutils-2.14/bfd/PORTING b/contrib/binutils-2.14/bfd/PORTING new file mode 100644 index 0000000000..c8bfd77b96 --- /dev/null +++ b/contrib/binutils-2.14/bfd/PORTING @@ -0,0 +1,83 @@ + Preliminary Notes on Porting BFD + -------------------------------- + +The 'host' is the system a tool runs *on*. +The 'target' is the system a tool runs *for*, i.e. +a tool can read/write the binaries of the target. + +Porting to a new host +--------------------- +Pick a name for your host. Call that . +( might be sun4, ...) +Create a file hosts/.mh. + +Porting to a new target +----------------------- +Pick a name for your target. Call that . +Call the name for your CPU architecture . +You need to create .c and config/.mt, +and add a case for it to a case statements in bfd/configure.host and +bfd/config.bfd, which associates each canonical host type with a BFD +host type (used as the base of the makefile fragment names), and to the +table in bfd/configure.in which associates each target vector with +the .o files it uses. + +config/.mt is a Makefile fragment. +The following is usually enough: +DEFAULT_VECTOR=_vec +SELECT_ARCHITECTURES=bfd__arch + +See the list of cpu types in archures.c, or "ls cpu-*.c". +If your architecture is new, you need to add it to the tables +in bfd/archures.c, opcodes/configure.in, and binutils/objdump.c. + +For more information about .mt and .mh files, see config/README. + +The file .c is the hard part. It implements the +bfd_target _vec, which includes pointers to +functions that do the actual -specific methods. + +Porting to a that uses the a.out binary format +------------------------------------------------------- + +In this case, the include file aout-target.h probaby does most +of what you need. The program gen-aout generates .c for +you automatically for many a.out systems. Do: + make gen-aout + ./gen-aout > .c +(This only works if you are building on the target ("native"). +If you must make a cross-port from scratch, copy the most +similar existing file that includes aout-target.h, and fix what is wrong.) + +Check the parameters in .c, and fix anything that is wrong. +(Also let us know about it; perhaps we can improve gen-aout.c.) + +TARGET_IS_BIG_ENDIAN_P + Should be defined if is big-endian. + +N_HEADER_IN_TEXT(x) + See discussion in ../include/aout/aout64.h. + +BYTES_IN_WORD + Number of bytes per word. (Usually 4 but can be 8.) + +ARCH + Number of bits per word. (Usually 32, but can be 64.) + +ENTRY_CAN_BE_ZERO + Define if the extry point (start address of an + executable program) can be 0x0. + +TEXT_START_ADDR + The address of the start of the text segemnt in + virtual memory. Normally, the same as the entry point. + +TARGET_PAGE_SIZE + +SEGMENT_SIZE + Usually, the same as the TARGET_PAGE_SIZE. + Alignment needed for the data segment. + +TARGETNAME + The name of the target, for run-time lookups. + Usually "a.out-" diff --git a/contrib/binutils-2.14/bfd/README b/contrib/binutils-2.14/bfd/README new file mode 100644 index 0000000000..fe6b6f33c1 --- /dev/null +++ b/contrib/binutils-2.14/bfd/README @@ -0,0 +1,49 @@ +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. diff --git a/contrib/binutils-2.14/bfd/TODO b/contrib/binutils-2.14/bfd/TODO new file mode 100644 index 0000000000..7a12735252 --- /dev/null +++ b/contrib/binutils-2.14/bfd/TODO @@ -0,0 +1,25 @@ +Things that still need to be done: -*- Text -*- + + o - A source of space lossage is that all the target-dependent code + is in a single bfd_target structure. Hence all the code for + *writing* object files is still pulled into all the applications + that only care about *reading* (gdb, nm, objdump), while gas has + to carry along all the unneeded baggage for reading objects. And + so on. This would be a substantial change, and the payoff would + not all that great (essentially none if bfd is used as a shared + library). + + o - The storage needed by BFD data structures is also larger than strictly + needed. This may be difficult to do much about. + + o - implement bfd_abort, which should close the bfd but not alter the + filesystem. + + o - update the bfd doc; write a how-to-write-a-backend doc, take out + the stupid quips and fill in all the blanks. + + o - upgrade the reloc handling as per Steve's suggestion. + + + + diff --git a/contrib/binutils-2.14/bfd/archive.c b/contrib/binutils-2.14/bfd/archive.c new file mode 100644 index 0000000000..ffb0bd4c87 --- /dev/null +++ b/contrib/binutils-2.14/bfd/archive.c @@ -0,0 +1,2237 @@ +/* BFD back-end for archive files (libraries). + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 + 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. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +@setfilename archive-info +SECTION + Archives + +DESCRIPTION + An archive (or library) is just another BFD. It has a symbol + table, although there's not much a user program will do with it. + + The big difference between an archive BFD and an ordinary BFD + is that the archive doesn't have sections. Instead it has a + chain of BFDs that are considered its contents. These BFDs can + be manipulated like any other. The BFDs contained in an + archive opened for reading will all be opened for reading. You + may put either input or output BFDs into an archive opened for + output; they will be handled correctly when the archive is closed. + + Use <> to step through + the contents of an archive opened for input. You don't + have to read the entire archive if you don't want + to! Read it until you find what you want. + + Archive contents of output BFDs are chained through the + <> pointer in a BFD. The first one is findable through + the <> slot of the archive. Set it with + <> (q.v.). A given BFD may be in only one + open output archive at a time. + + As expected, the BFD archive code is more general than the + archive code of any given environment. BFD archives may + contain files of different formats (e.g., a.out and coff) and + even different architectures. You may even place archives + recursively into archives! + + This can cause unexpected confusion, since some archive + formats are more expressive than others. For instance, Intel + COFF archives can preserve long filenames; SunOS a.out archives + cannot. If you move a file from the first to the second + format and back again, the filename may be truncated. + Likewise, different a.out environments have different + conventions as to how they truncate filenames, whether they + preserve directory names in filenames, etc. When + interoperating with native tools, be sure your files are + homogeneous. + + Beware: most of these formats do not react well to the + presence of spaces in filenames. We do the best we can, but + can't always handle this case due to restrictions in the format of + archives. Many Unix utilities are braindead in regards to + spaces and such in filenames anyway, so this shouldn't be much + of a restriction. + + Archives are supported in BFD in <>. + +*/ + +/* Assumes: + o - all archive elements start on an even boundary, newline padded; + o - all arch headers are char *; + o - all arch headers are the same size (across architectures). +*/ + +/* Some formats provide a way to cram a long filename into the short + (16 chars) space provided by a BSD archive. The trick is: make a + special "file" in the front of the archive, sort of like the SYMDEF + entry. If the filename is too long to fit, put it in the extended + name table, and use its index as the filename. To prevent + confusion prepend the index with a space. This means you can't + have filenames that start with a space, but then again, many Unix + utilities can't handle that anyway. + + This scheme unfortunately requires that you stand on your head in + order to write an archive since you need to put a magic file at the + front, and need to touch every entry to do so. C'est la vie. + + We support two variants of this idea: + The SVR4 format (extended name table is named "//"), + and an extended pseudo-BSD variant (extended name table is named + "ARFILENAMES/"). The origin of the latter format is uncertain. + + BSD 4.4 uses a third scheme: It writes a long filename + directly after the header. This allows 'ar q' to work. + We currently can read BSD 4.4 archives, but not write them. +*/ + +/* Summary of archive member names: + + Symbol table (must be first): + "__.SYMDEF " - Symbol table, Berkeley style, produced by ranlib. + "/ " - Symbol table, system 5 style. + + Long name table (must be before regular file members): + "// " - Long name table, System 5 R4 style. + "ARFILENAMES/ " - Long name table, non-standard extended BSD (not BSD 4.4). + + Regular file members with short names: + "filename.o/ " - Regular file, System 5 style (embedded spaces ok). + "filename.o " - Regular file, Berkeley style (no embedded spaces). + + Regular files with long names (or embedded spaces, for BSD variants): + "/18 " - SVR4 style, name at offset 18 in name table. + "#1/23 " - Long name (or embedded paces) 23 characters long, + BSD 4.4 style, full name follows header. + Implemented for reading, not writing. + " 18 " - Long name 18 characters long, extended pseudo-BSD. + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/ar.h" +#include "aout/ranlib.h" +#include "safe-ctype.h" + +#ifndef errno +extern int errno; +#endif + +#ifdef GNU960 +#define BFD_GNU960_ARMAG(abfd) (BFD_COFF_FILE_P((abfd)) ? ARMAG : ARMAGB) +#endif + +/* We keep a cache of archive filepointers to archive elements to + speed up searching the archive by filepos. We only add an entry to + the cache when we actually read one. We also don't sort the cache; + it's generally short enough to search linearly. + Note that the pointers here point to the front of the ar_hdr, not + to the front of the contents! */ +struct ar_cache { + file_ptr ptr; + bfd *arelt; + struct ar_cache *next; +}; + +#define ar_padchar(abfd) ((abfd)->xvec->ar_pad_char) +#define ar_maxnamelen(abfd) ((abfd)->xvec->ar_max_namelen) + +#define arch_eltdata(bfd) ((struct areltdata *) ((bfd)->arelt_data)) +#define arch_hdr(bfd) ((struct ar_hdr *)arch_eltdata(bfd)->arch_header) + +static char *get_extended_arelt_filename + PARAMS ((bfd *arch, const char *name)); +static bfd_boolean do_slurp_bsd_armap + PARAMS ((bfd *abfd)); +static bfd_boolean do_slurp_coff_armap + PARAMS ((bfd *abfd)); +bfd_boolean bfd_elf64_archive_slurp_armap + PARAMS ((bfd *abfd)); +static const char *normalize + PARAMS ((bfd *, const char *file)); +static struct areltdata *bfd_ar_hdr_from_filesystem + PARAMS ((bfd *abfd, const char *, bfd *member)); + +bfd_boolean +_bfd_generic_mkarchive (abfd) + bfd *abfd; +{ + bfd_size_type amt = sizeof (struct artdata); + + abfd->tdata.aout_ar_data = (struct artdata *) bfd_zalloc (abfd, amt); + if (bfd_ardata (abfd) == NULL) + return FALSE; + + bfd_ardata (abfd)->cache = NULL; + bfd_ardata (abfd)->archive_head = NULL; + bfd_ardata (abfd)->symdefs = NULL; + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->tdata = NULL; + + return TRUE; +} + +/* +FUNCTION + bfd_get_next_mapent + +SYNOPSIS + symindex bfd_get_next_mapent(bfd *abfd, symindex previous, carsym **sym); + +DESCRIPTION + Step through archive @var{abfd}'s symbol table (if it + has one). Successively update @var{sym} with the next symbol's + information, returning that symbol's (internal) index into the + symbol table. + + Supply <> as the @var{previous} entry to get + the first one; returns <> when you've already + got the last one. + + A <> is a canonical archive symbol. The only + user-visible element is its name, a null-terminated string. +*/ + +symindex +bfd_get_next_mapent (abfd, prev, entry) + bfd *abfd; + symindex prev; + carsym **entry; +{ + if (!bfd_has_map (abfd)) + { + bfd_set_error (bfd_error_invalid_operation); + return BFD_NO_MORE_SYMBOLS; + } + + if (prev == BFD_NO_MORE_SYMBOLS) + prev = 0; + else + ++prev; + if (prev >= bfd_ardata (abfd)->symdef_count) + return BFD_NO_MORE_SYMBOLS; + + *entry = (bfd_ardata (abfd)->symdefs + prev); + return prev; +} + +/* To be called by backends only */ + +bfd * +_bfd_create_empty_archive_element_shell (obfd) + bfd *obfd; +{ + return _bfd_new_bfd_contained_in (obfd); +} + +/* +FUNCTION + bfd_set_archive_head + +SYNOPSIS + bfd_boolean bfd_set_archive_head(bfd *output, bfd *new_head); + +DESCRIPTION + Set the head of the chain of + BFDs contained in the archive @var{output} to @var{new_head}. +*/ + +bfd_boolean +bfd_set_archive_head (output_archive, new_head) + bfd *output_archive; + bfd *new_head; +{ + + output_archive->archive_head = new_head; + return TRUE; +} + +bfd * +_bfd_look_for_bfd_in_cache (arch_bfd, filepos) + bfd *arch_bfd; + file_ptr filepos; +{ + struct ar_cache *current; + + for (current = bfd_ardata (arch_bfd)->cache; current != NULL; + current = current->next) + if (current->ptr == filepos) + return current->arelt; + + return NULL; +} + +/* Kind of stupid to call cons for each one, but we don't do too many */ +bfd_boolean +_bfd_add_bfd_to_archive_cache (arch_bfd, filepos, new_elt) + bfd *arch_bfd, *new_elt; + file_ptr filepos; +{ + bfd_size_type amt = sizeof (struct ar_cache); + + struct ar_cache *new_cache = (struct ar_cache *) bfd_zalloc (arch_bfd, amt); + if (new_cache == NULL) + return FALSE; + + new_cache->ptr = filepos; + new_cache->arelt = new_elt; + new_cache->next = (struct ar_cache *) NULL; + if (bfd_ardata (arch_bfd)->cache == NULL) + bfd_ardata (arch_bfd)->cache = new_cache; + else + { + struct ar_cache *current = bfd_ardata (arch_bfd)->cache; + + while (current->next != NULL) + current = current->next; + current->next = new_cache; + } + + return TRUE; +} + +/* The name begins with space. Hence the rest of the name is an index into + the string table. */ + +static char * +get_extended_arelt_filename (arch, name) + bfd *arch; + const char *name; +{ + unsigned long index = 0; + + /* Should extract string so that I can guarantee not to overflow into + the next region, but I'm too lazy. */ + errno = 0; + /* Skip first char, which is '/' in SVR4 or ' ' in some other variants. */ + index = strtol (name + 1, NULL, 10); + if (errno != 0) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + + return bfd_ardata (arch)->extended_names + index; +} + +/* This functions reads an arch header and returns an areltdata pointer, or + NULL on error. + + Presumes the file pointer is already in the right place (ie pointing + to the ar_hdr in the file). Moves the file pointer; on success it + should be pointing to the front of the file contents; on failure it + could have been moved arbitrarily. +*/ + +PTR +_bfd_generic_read_ar_hdr (abfd) + bfd *abfd; +{ + return _bfd_generic_read_ar_hdr_mag (abfd, (const char *) NULL); +} + +/* Alpha ECOFF uses an optional different ARFMAG value, so we have a + variant of _bfd_generic_read_ar_hdr which accepts a magic string. */ + +PTR +_bfd_generic_read_ar_hdr_mag (abfd, mag) + bfd *abfd; + const char *mag; +{ + struct ar_hdr hdr; + char *hdrp = (char *) &hdr; + size_t parsed_size; + struct areltdata *ared; + char *filename = NULL; + bfd_size_type namelen = 0; + bfd_size_type allocsize = sizeof (struct areltdata) + sizeof (struct ar_hdr); + char *allocptr = 0; + + if (bfd_bread ((PTR) hdrp, (bfd_size_type) sizeof (struct ar_hdr), abfd) + != sizeof (struct ar_hdr)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_no_more_archived_files); + return NULL; + } + if (strncmp (hdr.ar_fmag, ARFMAG, 2) != 0 + && (mag == NULL + || strncmp (hdr.ar_fmag, mag, 2) != 0)) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + + errno = 0; + parsed_size = strtol (hdr.ar_size, NULL, 10); + if (errno != 0) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + + /* Extract the filename from the archive - there are two ways to + specify an extended name table, either the first char of the + name is a space, or it's a slash. */ + if ((hdr.ar_name[0] == '/' + || (hdr.ar_name[0] == ' ' + && memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)) == NULL)) + && bfd_ardata (abfd)->extended_names != NULL) + { + filename = get_extended_arelt_filename (abfd, hdr.ar_name); + if (filename == NULL) + { + bfd_set_error (bfd_error_malformed_archive); + return NULL; + } + } + /* BSD4.4-style long filename. + Only implemented for reading, so far! */ + else if (hdr.ar_name[0] == '#' + && hdr.ar_name[1] == '1' + && hdr.ar_name[2] == '/' + && ISDIGIT (hdr.ar_name[3])) + { + /* BSD-4.4 extended name */ + namelen = atoi (&hdr.ar_name[3]); + allocsize += namelen + 1; + parsed_size -= namelen; + + allocptr = bfd_zalloc (abfd, allocsize); + if (allocptr == NULL) + return NULL; + filename = (allocptr + + sizeof (struct areltdata) + + sizeof (struct ar_hdr)); + if (bfd_bread (filename, namelen, abfd) != namelen) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_no_more_archived_files); + return NULL; + } + filename[namelen] = '\0'; + } + else + { + /* We judge the end of the name by looking for '/' or ' '. + Note: The SYSV format (terminated by '/') allows embedded + spaces, so only look for ' ' if we don't find '/'. */ + + char *e; + e = (char *) memchr (hdr.ar_name, '\0', ar_maxnamelen (abfd)); + if (e == NULL) + { + e = (char *) memchr (hdr.ar_name, '/', ar_maxnamelen (abfd)); + if (e == NULL) + e = (char *) memchr (hdr.ar_name, ' ', ar_maxnamelen (abfd)); + } + + if (e != NULL) + namelen = e - hdr.ar_name; + else + { + /* If we didn't find a termination character, then the name + must be the entire field. */ + namelen = ar_maxnamelen (abfd); + } + + allocsize += namelen + 1; + } + + if (!allocptr) + { + allocptr = bfd_zalloc (abfd, allocsize); + if (allocptr == NULL) + return NULL; + } + + ared = (struct areltdata *) allocptr; + + ared->arch_header = allocptr + sizeof (struct areltdata); + memcpy ((char *) ared->arch_header, (char *) &hdr, sizeof (struct ar_hdr)); + ared->parsed_size = parsed_size; + + if (filename != NULL) + ared->filename = filename; + else + { + ared->filename = allocptr + (sizeof (struct areltdata) + + sizeof (struct ar_hdr)); + if (namelen) + memcpy (ared->filename, hdr.ar_name, (size_t) namelen); + ared->filename[namelen] = '\0'; + } + + return (PTR) ared; +} + +/* This is an internal function; it's mainly used when indexing + through the archive symbol table, but also used to get the next + element, since it handles the bookkeeping so nicely for us. */ + +bfd * +_bfd_get_elt_at_filepos (archive, filepos) + bfd *archive; + file_ptr filepos; +{ + struct areltdata *new_areldata; + bfd *n_nfd; + + n_nfd = _bfd_look_for_bfd_in_cache (archive, filepos); + if (n_nfd) + return n_nfd; + + if (0 > bfd_seek (archive, filepos, SEEK_SET)) + return NULL; + + if ((new_areldata = (struct areltdata *) _bfd_read_ar_hdr (archive)) == NULL) + return NULL; + + n_nfd = _bfd_create_empty_archive_element_shell (archive); + if (n_nfd == NULL) + { + bfd_release (archive, (PTR) new_areldata); + return NULL; + } + + n_nfd->origin = bfd_tell (archive); + n_nfd->arelt_data = (PTR) new_areldata; + n_nfd->filename = new_areldata->filename; + + if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_nfd)) + return n_nfd; + + /* Huh? */ + bfd_release (archive, (PTR) n_nfd); + bfd_release (archive, (PTR) new_areldata); + return NULL; +} + +/* Return the BFD which is referenced by the symbol in ABFD indexed by + INDEX. INDEX should have been returned by bfd_get_next_mapent. */ + +bfd * +_bfd_generic_get_elt_at_index (abfd, index) + bfd *abfd; + symindex index; +{ + carsym *entry; + + entry = bfd_ardata (abfd)->symdefs + index; + return _bfd_get_elt_at_filepos (abfd, entry->file_offset); +} + +/* +FUNCTION + bfd_openr_next_archived_file + +SYNOPSIS + bfd *bfd_openr_next_archived_file(bfd *archive, bfd *previous); + +DESCRIPTION + Provided a BFD, @var{archive}, containing an archive and NULL, open + an input BFD on the first contained element and returns that. + Subsequent calls should pass + the archive and the previous return value to return a created + BFD to the next contained element. NULL is returned when there + are no more. +*/ + +bfd * +bfd_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + if ((bfd_get_format (archive) != bfd_archive) || + (archive->direction == write_direction)) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + return BFD_SEND (archive, + openr_next_archived_file, + (archive, + last_file)); +} + +bfd * +bfd_generic_openr_next_archived_file (archive, last_file) + bfd *archive; + bfd *last_file; +{ + file_ptr filestart; + + if (!last_file) + filestart = bfd_ardata (archive)->first_file_filepos; + else + { + unsigned int size = arelt_size (last_file); + /* Pad to an even boundary... + Note that last_file->origin can be odd in the case of + BSD-4.4-style element with a long odd size. */ + filestart = last_file->origin + size; + filestart += filestart % 2; + } + + return _bfd_get_elt_at_filepos (archive, filestart); +} + +const bfd_target * +bfd_generic_archive_p (abfd) + bfd *abfd; +{ + struct artdata *tdata_hold; + char armag[SARMAG + 1]; + bfd_size_type amt; + + if (bfd_bread ((PTR) armag, (bfd_size_type) SARMAG, abfd) != SARMAG) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + +#ifdef GNU960 + if (strncmp (armag, BFD_GNU960_ARMAG (abfd), SARMAG) != 0) + return 0; +#else + if (strncmp (armag, ARMAG, SARMAG) != 0 && + strncmp (armag, ARMAGB, SARMAG) != 0) + return 0; +#endif + + tdata_hold = bfd_ardata (abfd); + + amt = sizeof (struct artdata); + bfd_ardata (abfd) = (struct artdata *) bfd_zalloc (abfd, amt); + if (bfd_ardata (abfd) == NULL) + { + bfd_ardata (abfd) = tdata_hold; + return NULL; + } + + bfd_ardata (abfd)->first_file_filepos = SARMAG; + bfd_ardata (abfd)->cache = NULL; + bfd_ardata (abfd)->archive_head = NULL; + bfd_ardata (abfd)->symdefs = NULL; + bfd_ardata (abfd)->extended_names = NULL; + bfd_ardata (abfd)->tdata = NULL; + + if (!BFD_SEND (abfd, _bfd_slurp_armap, (abfd)) + || !BFD_SEND (abfd, _bfd_slurp_extended_name_table, (abfd))) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + bfd_release (abfd, bfd_ardata (abfd)); + bfd_ardata (abfd) = tdata_hold; + return NULL; + } + + if (bfd_has_map (abfd)) + { + bfd *first; + + /* This archive has a map, so we may presume that the contents + are object files. Make sure that if the first file in the + archive can be recognized as an object file, it is for this + target. If not, assume that this is the wrong format. If + the first file is not an object file, somebody is doing + something weird, and we permit it so that ar -t will work. + + This is done because any normal format will recognize any + normal archive, regardless of the format of the object files. + We do accept an empty archive. */ + + first = bfd_openr_next_archived_file (abfd, (bfd *) NULL); + if (first != NULL) + { + bfd_boolean fail; + + first->target_defaulted = FALSE; + fail = FALSE; + if (bfd_check_format (first, bfd_object) + && first->xvec != abfd->xvec) + { +#if 0 + /* We ought to close `first' here, but we can't, because + we have no way to remove it from the archive cache. + It's close to impossible to figure out when we can + release bfd_ardata. FIXME. */ + (void) bfd_close (first); + bfd_release (abfd, bfd_ardata (abfd)); +#endif + bfd_set_error (bfd_error_wrong_object_format); + bfd_ardata (abfd) = tdata_hold; + return NULL; + } + /* And we ought to close `first' here too. */ + } + } + + return abfd->xvec; +} + +/* Some constants for a 32 bit BSD archive structure. We do not + support 64 bit archives presently; so far as I know, none actually + exist. Supporting them would require changing these constants, and + changing some H_GET_32 to H_GET_64. */ + +/* The size of an external symdef structure. */ +#define BSD_SYMDEF_SIZE 8 + +/* The offset from the start of a symdef structure to the file offset. */ +#define BSD_SYMDEF_OFFSET_SIZE 4 + +/* The size of the symdef count. */ +#define BSD_SYMDEF_COUNT_SIZE 4 + +/* The size of the string count. */ +#define BSD_STRING_COUNT_SIZE 4 + +/* Returns FALSE on error, TRUE otherwise */ + +static bfd_boolean +do_slurp_bsd_armap (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + unsigned int counter; + bfd_byte *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + bfd_size_type parsed_size, amt; + carsym *set; + + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return FALSE; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR) mapdata); /* Don't need it any more. */ + + raw_armap = (bfd_byte *) bfd_zalloc (abfd, parsed_size); + if (raw_armap == (bfd_byte *) NULL) + return FALSE; + + if (bfd_bread ((PTR) raw_armap, parsed_size, abfd) != parsed_size) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + byebye: + bfd_release (abfd, (PTR) raw_armap); + return FALSE; + } + + 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) + { + /* Probably we're using the wrong byte ordering. */ + bfd_set_error (bfd_error_wrong_format); + goto byebye; + } + + ardata->cache = 0; + rbase = raw_armap + BSD_SYMDEF_COUNT_SIZE; + stringbase = ((char *) rbase + + ardata->symdef_count * BSD_SYMDEF_SIZE + + BSD_STRING_COUNT_SIZE); + amt = (bfd_size_type) ardata->symdef_count * sizeof (carsym); + ardata->symdefs = (carsym *) bfd_alloc (abfd, amt); + if (!ardata->symdefs) + return FALSE; + + for (counter = 0, set = ardata->symdefs; + counter < ardata->symdef_count; + counter++, set++, rbase += BSD_SYMDEF_SIZE) + { + set->name = H_GET_32 (abfd, rbase) + stringbase; + set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE); + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to. */ + ardata->first_file_filepos += (ardata->first_file_filepos) % 2; + /* FIXME, we should provide some way to free raw_ardata when + we are done using the strings from it. For now, it seems + to be allocated on an objalloc anyway... */ + bfd_has_map (abfd) = TRUE; + return TRUE; +} + +/* Returns FALSE on error, TRUE otherwise. */ + +static bfd_boolean +do_slurp_coff_armap (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + int *raw_armap, *rawptr; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + bfd_size_type stringsize; + unsigned int parsed_size; + carsym *carsyms; + bfd_size_type nsymz; /* Number of symbols in armap. */ + bfd_vma (*swap) PARAMS ((const bfd_byte *)); + char int_buf[sizeof (long)]; + bfd_size_type carsym_size, ptrsize; + unsigned int i; + + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return FALSE; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR) mapdata); /* Don't need it any more. */ + + if (bfd_bread ((PTR) int_buf, (bfd_size_type) 4, abfd) != 4) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + return FALSE; + } + /* It seems that all numeric information in a coff archive is always + in big endian format, nomatter the host or target. */ + swap = bfd_getb32; + nsymz = bfd_getb32 ((PTR) int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + +#if 1 + /* ... except that some archive formats are broken, and it may be our + fault - the i960 little endian coff sometimes has big and sometimes + little, because our tools changed. Here's a horrible hack to clean + up the crap. */ + + if (stringsize > 0xfffff + && bfd_get_arch (abfd) == bfd_arch_i960 + && bfd_get_flavour (abfd) == bfd_target_coff_flavour) + { + /* This looks dangerous, let's do it the other way around. */ + nsymz = bfd_getl32 ((PTR) int_buf); + stringsize = parsed_size - (4 * nsymz) - 4; + swap = bfd_getl32; + } +#endif + + /* The coff armap must be read sequentially. So we construct a + bsd-style one in core all at once, for simplicity. */ + + carsym_size = (nsymz * sizeof (carsym)); + ptrsize = (4 * nsymz); + + ardata->symdefs = (carsym *) bfd_zalloc (abfd, carsym_size + stringsize + 1); + if (ardata->symdefs == NULL) + return FALSE; + carsyms = ardata->symdefs; + stringbase = ((char *) ardata->symdefs) + carsym_size; + + /* Allocate and read in the raw offsets. */ + raw_armap = (int *) bfd_alloc (abfd, ptrsize); + if (raw_armap == NULL) + goto release_symdefs; + if (bfd_bread ((PTR) raw_armap, ptrsize, abfd) != ptrsize + || (bfd_bread ((PTR) stringbase, stringsize, abfd) != stringsize)) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + goto release_raw_armap; + } + + /* OK, build the carsyms. */ + for (i = 0; i < nsymz; i++) + { + rawptr = raw_armap + i; + carsyms->file_offset = swap ((PTR) rawptr); + carsyms->name = stringbase; + stringbase += strlen (stringbase) + 1; + carsyms++; + } + *stringbase = 0; + + ardata->symdef_count = nsymz; + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to. */ + ardata->first_file_filepos += (ardata->first_file_filepos) % 2; + + bfd_has_map (abfd) = TRUE; + bfd_release (abfd, (PTR) raw_armap); + + /* Check for a second archive header (as used by PE). */ + { + struct areltdata *tmp; + + bfd_seek (abfd, ardata->first_file_filepos, SEEK_SET); + tmp = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (tmp != NULL) + { + if (tmp->arch_header[0] == '/' + && tmp->arch_header[1] == ' ') + { + ardata->first_file_filepos += + (tmp->parsed_size + sizeof (struct ar_hdr) + 1) & ~(unsigned) 1; + } + bfd_release (abfd, tmp); + } + } + + return TRUE; + +release_raw_armap: + bfd_release (abfd, (PTR) raw_armap); +release_symdefs: + bfd_release (abfd, (PTR) (ardata)->symdefs); + return FALSE; +} + +/* This routine can handle either coff-style or bsd-style armaps. + Returns FALSE on error, TRUE otherwise */ + +bfd_boolean +bfd_slurp_armap (abfd) + bfd *abfd; +{ + char nextname[17]; + int i = bfd_bread ((PTR) nextname, (bfd_size_type) 16, abfd); + + if (i == 0) + return TRUE; + if (i != 16) + return FALSE; + + if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) + return FALSE; + + if (!strncmp (nextname, "__.SYMDEF ", 16) + || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* old Linux archives */ + return do_slurp_bsd_armap (abfd); + else if (!strncmp (nextname, "/ ", 16)) + return do_slurp_coff_armap (abfd); + else if (!strncmp (nextname, "/SYM64/ ", 16)) + { + /* 64bit ELF (Irix 6) archive. */ +#ifdef BFD64 + return bfd_elf64_archive_slurp_armap (abfd); +#else + bfd_set_error (bfd_error_wrong_format); + return FALSE; +#endif + } + + bfd_has_map (abfd) = FALSE; + return TRUE; +} + +/* Returns FALSE on error, TRUE otherwise */ +/* flavor 2 of a bsd armap, similar to bfd_slurp_bsd_armap except the + header is in a slightly different order and the map name is '/'. + This flavour is used by hp300hpux. */ + +#define HPUX_SYMDEF_COUNT_SIZE 2 + +bfd_boolean +bfd_slurp_bsd_armap_f2 (abfd) + bfd *abfd; +{ + struct areltdata *mapdata; + char nextname[17]; + unsigned int counter; + bfd_byte *raw_armap, *rbase; + struct artdata *ardata = bfd_ardata (abfd); + char *stringbase; + unsigned int stringsize; + bfd_size_type amt; + carsym *set; + int i = bfd_bread ((PTR) nextname, (bfd_size_type) 16, abfd); + + if (i == 0) + return TRUE; + if (i != 16) + return FALSE; + + /* The archive has at least 16 bytes in it. */ + if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) + return FALSE; + + if (!strncmp (nextname, "__.SYMDEF ", 16) + || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* old Linux archives */ + return do_slurp_bsd_armap (abfd); + + if (strncmp (nextname, "/ ", 16)) + { + bfd_has_map (abfd) = FALSE; + return TRUE; + } + + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return FALSE; + + amt = mapdata->parsed_size; + raw_armap = (bfd_byte *) bfd_zalloc (abfd, amt); + if (raw_armap == NULL) + { + byebye: + bfd_release (abfd, (PTR) mapdata); + return FALSE; + } + + if (bfd_bread ((PTR) raw_armap, amt, abfd) != amt) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + byebyebye: + bfd_release (abfd, (PTR) raw_armap); + goto byebye; + } + + ardata->symdef_count = H_GET_16 (abfd, (PTR) raw_armap); + + if (ardata->symdef_count * BSD_SYMDEF_SIZE + > mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE) + { + /* Probably we're using the wrong byte ordering. */ + bfd_set_error (bfd_error_wrong_format); + goto byebyebye; + } + + ardata->cache = 0; + + stringsize = H_GET_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE); + /* Skip sym count and string sz. */ + stringbase = ((char *) raw_armap + + HPUX_SYMDEF_COUNT_SIZE + + BSD_STRING_COUNT_SIZE); + rbase = (bfd_byte *) stringbase + stringsize; + amt = (bfd_size_type) ardata->symdef_count * BSD_SYMDEF_SIZE; + ardata->symdefs = (carsym *) bfd_alloc (abfd, amt); + if (!ardata->symdefs) + return FALSE; + + for (counter = 0, set = ardata->symdefs; + counter < ardata->symdef_count; + counter++, set++, rbase += BSD_SYMDEF_SIZE) + { + set->name = H_GET_32 (abfd, rbase) + stringbase; + set->file_offset = H_GET_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE); + } + + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to. */ + ardata->first_file_filepos += (ardata->first_file_filepos) % 2; + /* FIXME, we should provide some way to free raw_ardata when + we are done using the strings from it. For now, it seems + to be allocated on an objalloc anyway... */ + bfd_has_map (abfd) = TRUE; + return TRUE; +} + +/** Extended name table. + + Normally archives support only 14-character filenames. + + Intel has extended the format: longer names are stored in a special + element (the first in the archive, or second if there is an armap); + the name in the ar_hdr is replaced by . Index is the P.R. of an int (decimal). Data General have + extended the format by using the prefix // for the special element. */ + +/* Returns FALSE on error, TRUE otherwise. */ + +bfd_boolean +_bfd_slurp_extended_name_table (abfd) + bfd *abfd; +{ + char nextname[17]; + struct areltdata *namedata; + bfd_size_type amt; + + /* FIXME: Formatting sucks here, and in case of failure of BFD_READ, + we probably don't want to return TRUE. */ + bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET); + if (bfd_bread ((PTR) nextname, (bfd_size_type) 16, abfd) == 16) + { + if (bfd_seek (abfd, (file_ptr) -16, SEEK_CUR) != 0) + return FALSE; + + if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 && + strncmp (nextname, "// ", 16) != 0) + { + bfd_ardata (abfd)->extended_names = NULL; + return TRUE; + } + + namedata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (namedata == NULL) + return FALSE; + + amt = namedata->parsed_size; + bfd_ardata (abfd)->extended_names = bfd_zalloc (abfd, amt); + if (bfd_ardata (abfd)->extended_names == NULL) + { + byebye: + bfd_release (abfd, (PTR) namedata); + return FALSE; + } + + if (bfd_bread ((PTR) bfd_ardata (abfd)->extended_names, amt, abfd) != amt) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + bfd_release (abfd, (PTR) (bfd_ardata (abfd)->extended_names)); + bfd_ardata (abfd)->extended_names = NULL; + goto byebye; + } + + /* Since the archive is supposed to be printable if it contains + 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.. */ + { + char *temp = bfd_ardata (abfd)->extended_names; + char *limit = temp + namedata->parsed_size; + for (; temp < limit; ++temp) + { + if (*temp == '\012') + temp[temp[-1] == '/' ? -1 : 0] = '\0'; + if (*temp == '\\') + *temp = '/'; + } + } + + /* Pad to an even boundary if you have to. */ + bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd); + bfd_ardata (abfd)->first_file_filepos += + (bfd_ardata (abfd)->first_file_filepos) % 2; + + /* FIXME, we can't release namedata here because it was allocated + below extended_names on the objalloc... */ +#if 0 + bfd_release (abfd, namedata); +#endif + } + return TRUE; +} + +#ifdef VMS + +/* Return a copy of the stuff in the filename between any :]> and a + semicolon. */ + +static const char * +normalize (abfd, file) + bfd *abfd; + const char *file; +{ + const char *first; + const char *last; + char *copy; + + first = file + strlen (file) - 1; + last = first + 1; + + while (first != file) + { + if (*first == ';') + last = first; + if (*first == ':' || *first == ']' || *first == '>') + { + first++; + break; + } + first--; + } + + copy = (char *) bfd_alloc (abfd, (bfd_size_type) (last - first + 1)); + if (copy == NULL) + return NULL; + + memcpy (copy, first, last - first); + copy[last - first] = 0; + + return copy; +} + +#else +static const char * +normalize (abfd, file) + bfd *abfd ATTRIBUTE_UNUSED; + const char *file; +{ + const char *filename = strrchr (file, '/'); + +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ + char *bslash = strrchr (file, '\\'); + if (filename == NULL || (bslash != NULL && bslash > filename)) + filename = bslash; + if (filename == NULL && file[0] != '\0' && file[1] == ':') + filename = file + 1; + } +#endif + if (filename != (char *) NULL) + filename++; + else + filename = file; + return filename; +} +#endif + +/* Build a BFD style extended name table. */ + +bfd_boolean +_bfd_archive_bsd_construct_extended_name_table (abfd, tabloc, tablen, name) + bfd *abfd; + char **tabloc; + bfd_size_type *tablen; + const char **name; +{ + *name = "ARFILENAMES/"; + return _bfd_construct_extended_name_table (abfd, FALSE, tabloc, tablen); +} + +/* Build an SVR4 style extended name table. */ + +bfd_boolean +_bfd_archive_coff_construct_extended_name_table (abfd, tabloc, tablen, name) + bfd *abfd; + char **tabloc; + bfd_size_type *tablen; + const char **name; +{ + *name = "//"; + return _bfd_construct_extended_name_table (abfd, TRUE, tabloc, tablen); +} + +/* Follows archive_head and produces an extended name table if + necessary. Returns (in tabloc) a pointer to an extended name + table, and in tablen the length of the table. If it makes an entry + it clobbers the filename so that the element may be written without + further massage. Returns TRUE if it ran successfully, FALSE if + something went wrong. A successful return may still involve a + zero-length tablen! */ + +bfd_boolean +_bfd_construct_extended_name_table (abfd, trailing_slash, tabloc, tablen) + bfd *abfd; + bfd_boolean trailing_slash; + char **tabloc; + bfd_size_type *tablen; +{ + unsigned int maxname = abfd->xvec->ar_max_namelen; + bfd_size_type total_namelen = 0; + bfd *current; + char *strptr; + + *tablen = 0; + + /* Figure out how long the table should be. */ + for (current = abfd->archive_head; current != NULL; current = current->next) + { + const char *normal; + unsigned int thislen; + + normal = normalize (current, current->filename); + if (normal == NULL) + return FALSE; + + thislen = strlen (normal); + + if (thislen > maxname + && (bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0) + thislen = maxname; + + if (thislen > maxname) + { + /* Add one to leave room for \n. */ + total_namelen += thislen + 1; + if (trailing_slash) + { + /* Leave room for trailing slash. */ + ++total_namelen; + } + } + else + { + struct ar_hdr *hdr = arch_hdr (current); + if (strncmp (normal, hdr->ar_name, thislen) != 0 + || (thislen < sizeof hdr->ar_name + && hdr->ar_name[thislen] != ar_padchar (current))) + { + /* Must have been using extended format even though it + didn't need to. Fix it to use normal format. */ + memcpy (hdr->ar_name, normal, thislen); + if (thislen < maxname + || (thislen == maxname && thislen < sizeof hdr->ar_name)) + hdr->ar_name[thislen] = ar_padchar (current); + } + } + } + + if (total_namelen == 0) + return TRUE; + + *tabloc = bfd_zalloc (abfd, total_namelen); + if (*tabloc == NULL) + return FALSE; + + *tablen = total_namelen; + strptr = *tabloc; + + for (current = abfd->archive_head; current != NULL; current = + current->next) + { + const char *normal; + unsigned int thislen; + + normal = normalize (current, current->filename); + if (normal == NULL) + return FALSE; + + thislen = strlen (normal); + if (thislen > maxname) + { + /* Works for now; may need to be re-engineered if we + encounter an oddball archive format and want to + generalise this hack. */ + struct ar_hdr *hdr = arch_hdr (current); + strcpy (strptr, normal); + if (! trailing_slash) + strptr[thislen] = '\012'; + else + { + strptr[thislen] = '/'; + strptr[thislen + 1] = '\012'; + } + hdr->ar_name[0] = ar_padchar (current); + /* We know there will always be enough room (one of the few + cases where you may safely use sprintf). */ + sprintf ((hdr->ar_name) + 1, "%-d", (unsigned) (strptr - *tabloc)); + /* Kinda Kludgy. We should just use the returned value of + sprintf but not all implementations get this right. */ + { + char *temp = hdr->ar_name + 2; + for (; temp < hdr->ar_name + maxname; temp++) + if (*temp == '\0') + *temp = ' '; + } + strptr += thislen + 1; + if (trailing_slash) + ++strptr; + } + } + + return TRUE; +} + +/** A couple of functions for creating ar_hdrs */ + +#ifdef HPUX_LARGE_AR_IDS +/* Function to encode large UID/GID values according to HP. */ + +static void +hpux_uid_gid_encode (str, id) + char str[6]; + long int id; +{ + int cnt; + + str[5] = '@' + (id & 3); + id >>= 2; + + for (cnt = 4; cnt >= 0; ++cnt, id >>= 6) + str[cnt] = ' ' + (id & 0x3f); +} +#endif /* HPUX_LARGE_AR_IDS */ + +#ifndef HAVE_GETUID +#define getuid() 0 +#endif + +#ifndef HAVE_GETGID +#define getgid() 0 +#endif + +/* Takes a filename, returns an arelt_data for it, or NULL if it can't + make one. The filename must refer to a filename in the filesystem. + The filename field of the ar_hdr will NOT be initialized. If member + is set, and it's an in-memory bfd, we fake it. */ + +static struct areltdata * +bfd_ar_hdr_from_filesystem (abfd, filename, member) + bfd *abfd; + const char *filename; + bfd *member; +{ + struct stat status; + struct areltdata *ared; + struct ar_hdr *hdr; + char *temp, *temp1; + bfd_size_type amt; + + if (member && (member->flags & BFD_IN_MEMORY) != 0) + { + /* Assume we just "made" the member, and fake it. */ + struct bfd_in_memory *bim = (struct bfd_in_memory *) member->iostream; + time (&status.st_mtime); + status.st_uid = getuid (); + status.st_gid = getgid (); + status.st_mode = 0644; + status.st_size = bim->size; + } + else if (stat (filename, &status) != 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + amt = sizeof (struct ar_hdr) + sizeof (struct areltdata); + ared = (struct areltdata *) bfd_zalloc (abfd, amt); + if (ared == NULL) + return NULL; + hdr = (struct ar_hdr *) (((char *) ared) + sizeof (struct areltdata)); + + /* ar headers are space padded, not null padded! */ + memset ((PTR) hdr, ' ', sizeof (struct ar_hdr)); + + strncpy (hdr->ar_fmag, ARFMAG, 2); + + /* Goddamned sprintf doesn't permit MAXIMUM field lengths. */ + sprintf ((hdr->ar_date), "%-12ld", (long) status.st_mtime); +#ifdef HPUX_LARGE_AR_IDS + /* HP has a very "special" way to handle UID/GID's with numeric values + > 99999. */ + if (status.st_uid > 99999) + hpux_uid_gid_encode (hdr->ar_gid, (long) status.st_uid); + else +#endif + sprintf ((hdr->ar_uid), "%ld", (long) status.st_uid); +#ifdef HPUX_LARGE_AR_IDS + /* HP has a very "special" way to handle UID/GID's with numeric values + > 99999. */ + if (status.st_gid > 99999) + hpux_uid_gid_encode (hdr->ar_uid, (long) status.st_gid); + else +#endif + sprintf ((hdr->ar_gid), "%ld", (long) status.st_gid); + sprintf ((hdr->ar_mode), "%-8o", (unsigned int) status.st_mode); + sprintf ((hdr->ar_size), "%-10ld", (long) status.st_size); + /* Correct for a lossage in sprintf whereby it null-terminates. I cannot + understand how these C losers could design such a ramshackle bunch of + IO operations. */ + temp = (char *) hdr; + temp1 = temp + sizeof (struct ar_hdr) - 2; + for (; temp < temp1; temp++) + { + if (*temp == '\0') + *temp = ' '; + } + strncpy (hdr->ar_fmag, ARFMAG, 2); + ared->parsed_size = status.st_size; + ared->arch_header = (char *) hdr; + + return ared; +} + +/* This is magic required by the "ar" program. Since it's + undocumented, it's undocumented. You may think that it would take + a strong stomach to write this, and it does, but it takes even a + stronger stomach to try to code around such a thing! */ + +struct ar_hdr *bfd_special_undocumented_glue + PARAMS ((bfd *, const char *)); + +struct ar_hdr * +bfd_special_undocumented_glue (abfd, filename) + bfd *abfd; + const char *filename; +{ + struct areltdata *ar_elt = bfd_ar_hdr_from_filesystem (abfd, filename, 0); + if (ar_elt == NULL) + return NULL; + return (struct ar_hdr *) ar_elt->arch_header; +} + +/* Analogous to stat call. */ + +int +bfd_generic_stat_arch_elt (abfd, buf) + bfd *abfd; + struct stat *buf; +{ + struct ar_hdr *hdr; + char *aloser; + + if (abfd->arelt_data == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + hdr = arch_hdr (abfd); + +#define foo(arelt, stelt, size) \ + buf->stelt = strtol (hdr->arelt, &aloser, size); \ + if (aloser == hdr->arelt) \ + return -1; + + /* Some platforms support special notations for large IDs. */ +#ifdef HPUX_LARGE_AR_IDS +# define foo2(arelt, stelt, size) \ + if (hdr->arelt[5] == ' ') \ + { \ + foo (arelt, stelt, size); \ + } \ + else \ + { \ + int cnt; \ + for (buf->stelt = cnt = 0; cnt < 5; ++cnt) \ + { \ + if (hdr->arelt[cnt] < ' ' || hdr->arelt[cnt] > ' ' + 0x3f) \ + return -1; \ + buf->stelt <<= 6; \ + buf->stelt += hdr->arelt[cnt] - ' '; \ + } \ + if (hdr->arelt[5] < '@' || hdr->arelt[5] > '@' + 3) \ + return -1; \ + buf->stelt <<= 2; \ + buf->stelt += hdr->arelt[5] - '@'; \ + } +#else +# define foo2(arelt, stelt, size) foo (arelt, stelt, size) +#endif + + foo (ar_date, st_mtime, 10); + foo2 (ar_uid, st_uid, 10); + foo2 (ar_gid, st_gid, 10); + foo (ar_mode, st_mode, 8); + + buf->st_size = arch_eltdata (abfd)->parsed_size; + + return 0; +} + +void +bfd_dont_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + const char *pathname; + char *arhdr; +{ + /* FIXME: This interacts unpleasantly with ar's quick-append option. + Fortunately ic960 users will never use that option. Fixing this + is very hard; fortunately I know how to do it and will do so once + intel's release is out the door. */ + + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + size_t length; + const char *filename; + size_t maxlen = ar_maxnamelen (abfd); + + if ((bfd_get_file_flags (abfd) & BFD_TRADITIONAL_FORMAT) != 0) + { + bfd_bsd_truncate_arname (abfd, pathname, arhdr); + return; + } + + filename = normalize (abfd, pathname); + if (filename == NULL) + { + /* FIXME */ + abort (); + } + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + + /* Add the padding character if there is room for it. */ + if (length < maxlen + || (length == maxlen && length < sizeof hdr->ar_name)) + (hdr->ar_name)[length] = ar_padchar (abfd); +} + +void +bfd_bsd_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + const char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + size_t length; + const char *filename = strrchr (pathname, '/'); + size_t maxlen = ar_maxnamelen (abfd); + +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ + char *bslash = strrchr (pathname, '\\'); + if (filename == NULL || (bslash != NULL && bslash > filename)) + filename = bslash; + if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':') + filename = pathname + 1; + } +#endif + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else + { + /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + length = maxlen; + } + + if (length < maxlen) + (hdr->ar_name)[length] = ar_padchar (abfd); +} + +/* Store name into ar header. Truncates the name to fit. + 1> strip pathname to be just the basename. + 2> if it's short enuf to fit, stuff it in. + 3> If it doesn't end with .o, truncate it to fit + 4> truncate it before the .o, append .o, stuff THAT in. */ + +/* This is what gnu ar does. It's better but incompatible with the + bsd ar. */ + +void +bfd_gnu_truncate_arname (abfd, pathname, arhdr) + bfd *abfd; + const char *pathname; + char *arhdr; +{ + struct ar_hdr *hdr = (struct ar_hdr *) arhdr; + size_t length; + const char *filename = strrchr (pathname, '/'); + size_t maxlen = ar_maxnamelen (abfd); + +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ + char *bslash = strrchr (pathname, '\\'); + if (filename == NULL || (bslash != NULL && bslash > filename)) + filename = bslash; + if (filename == NULL && pathname[0] != '\0' && pathname[1] == ':') + filename = pathname + 1; + } +#endif + + if (filename == NULL) + filename = pathname; + else + ++filename; + + length = strlen (filename); + + if (length <= maxlen) + memcpy (hdr->ar_name, filename, length); + else + { /* pathname: meet procrustes */ + memcpy (hdr->ar_name, filename, maxlen); + if ((filename[length - 2] == '.') && (filename[length - 1] == 'o')) + { + hdr->ar_name[maxlen - 2] = '.'; + hdr->ar_name[maxlen - 1] = 'o'; + } + length = maxlen; + } + + if (length < 16) + (hdr->ar_name)[length] = ar_padchar (abfd); +} + +/* The BFD is open for write and has its format set to bfd_archive. */ + +bfd_boolean +_bfd_write_archive_contents (arch) + bfd *arch; +{ + bfd *current; + char *etable = NULL; + bfd_size_type elength = 0; + const char *ename = NULL; + bfd_boolean makemap = bfd_has_map (arch); + /* If no .o's, don't bother to make a map. */ + bfd_boolean hasobjects = FALSE; + bfd_size_type wrote; + unsigned int i; + int tries; + + /* Verify the viability of all entries; if any of them live in the + filesystem (as opposed to living in an archive open for input) + then construct a fresh ar_hdr for them. */ + for (current = arch->archive_head; current; current = current->next) + { + /* This check is checking the bfds for the objects we're reading + from (which are usually either an object file or archive on + disk), not the archive entries we're writing to. We don't + actually create bfds for the archive members, we just copy + them byte-wise when we write out the archive. */ + if (bfd_write_p (current)) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + if (!current->arelt_data) + { + current->arelt_data = + (PTR) bfd_ar_hdr_from_filesystem (arch, current->filename, current); + if (!current->arelt_data) + return FALSE; + + /* Put in the file name. */ + BFD_SEND (arch, _bfd_truncate_arname, (arch, + current->filename, + (char *) arch_hdr (current))); + } + + if (makemap && ! hasobjects) + { /* Don't bother if we won't make a map! */ + if ((bfd_check_format (current, bfd_object)) +#if 0 /* FIXME -- these are not set correctly */ + && ((bfd_get_file_flags (current) & HAS_SYMS)) +#endif + ) + hasobjects = TRUE; + } + } + + if (!BFD_SEND (arch, _bfd_construct_extended_name_table, + (arch, &etable, &elength, &ename))) + return FALSE; + + if (bfd_seek (arch, (file_ptr) 0, SEEK_SET) != 0) + return FALSE; +#ifdef GNU960 + wrote = bfd_bwrite (BFD_GNU960_ARMAG (arch), (bfd_size_type) SARMAG, arch); +#else + wrote = bfd_bwrite (ARMAG, (bfd_size_type) SARMAG, arch); +#endif + if (wrote != SARMAG) + return FALSE; + + if (makemap && hasobjects) + { + if (! _bfd_compute_and_write_armap (arch, (unsigned int) elength)) + return FALSE; + } + + if (elength != 0) + { + struct ar_hdr hdr; + + memset ((char *) (&hdr), 0, sizeof (struct ar_hdr)); + strcpy (hdr.ar_name, ename); + /* Round size up to even number in archive header. */ + sprintf (&(hdr.ar_size[0]), "%-10d", + (int) ((elength + 1) & ~(bfd_size_type) 1)); + strncpy (hdr.ar_fmag, ARFMAG, 2); + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; + if ((bfd_bwrite ((PTR) &hdr, (bfd_size_type) sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + || bfd_bwrite (etable, elength, arch) != elength) + return FALSE; + if ((elength % 2) == 1) + { + if (bfd_bwrite ("\012", (bfd_size_type) 1, arch) != 1) + return FALSE; + } + } + + for (current = arch->archive_head; current; current = current->next) + { + char buffer[DEFAULT_BUFFERSIZE]; + unsigned int remaining = arelt_size (current); + struct ar_hdr *hdr = arch_hdr (current); + + /* Write ar header. */ + if (bfd_bwrite ((PTR) hdr, (bfd_size_type) sizeof (*hdr), arch) + != sizeof (*hdr)) + return FALSE; + if (bfd_seek (current, (file_ptr) 0, SEEK_SET) != 0) + return FALSE; + while (remaining) + { + unsigned int amt = DEFAULT_BUFFERSIZE; + if (amt > remaining) + amt = remaining; + errno = 0; + if (bfd_bread (buffer, (bfd_size_type) amt, current) != amt) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + return FALSE; + } + if (bfd_bwrite (buffer, (bfd_size_type) amt, arch) != amt) + return FALSE; + remaining -= amt; + } + if ((arelt_size (current) % 2) == 1) + { + if (bfd_bwrite ("\012", (bfd_size_type) 1, arch) != 1) + return FALSE; + } + } + + if (makemap && hasobjects) + { + /* Verify the timestamp in the archive file. If it would not be + accepted by the linker, rewrite it until it would be. If + anything odd happens, break out and just return. (The + Berkeley linker checks the timestamp and refuses to read the + table-of-contents if it is >60 seconds less than the file's + modified-time. That painful hack requires this painful hack. */ + tries = 1; + do + { + if (bfd_update_armap_timestamp (arch)) + break; + (*_bfd_error_handler) + (_("Warning: writing archive was slow: rewriting timestamp\n")); + } + while (++tries < 6); + } + + return TRUE; +} + +/* Note that the namidx for the first symbol is 0. */ + +bfd_boolean +_bfd_compute_and_write_armap (arch, elength) + bfd *arch; + unsigned int elength; +{ + char *first_name = NULL; + bfd *current; + file_ptr elt_no = 0; + struct orl *map = NULL; + unsigned int orl_max = 1024; /* fine initial default */ + unsigned int orl_count = 0; + int stridx = 0; /* string index */ + asymbol **syms = NULL; + long syms_max = 0; + bfd_boolean ret; + bfd_size_type amt; + + /* Dunno if this is the best place for this info... */ + if (elength != 0) + elength += sizeof (struct ar_hdr); + elength += elength % 2; + + amt = (bfd_size_type) orl_max * sizeof (struct orl); + map = (struct orl *) bfd_malloc (amt); + if (map == NULL) + goto error_return; + + /* We put the symbol names on the arch objalloc, and then discard + them when done. */ + first_name = bfd_alloc (arch, (bfd_size_type) 1); + if (first_name == NULL) + goto error_return; + + /* Drop all the files called __.SYMDEF, we're going to make our own. */ + while (arch->archive_head && + strcmp (arch->archive_head->filename, "__.SYMDEF") == 0) + arch->archive_head = arch->archive_head->next; + + /* Map over each element. */ + for (current = arch->archive_head; + current != (bfd *) NULL; + current = current->next, elt_no++) + { + if (bfd_check_format (current, bfd_object) + && (bfd_get_file_flags (current) & HAS_SYMS) != 0) + { + long storage; + long symcount; + long src_count; + + storage = bfd_get_symtab_upper_bound (current); + if (storage < 0) + goto error_return; + + if (storage != 0) + { + if (storage > syms_max) + { + if (syms_max > 0) + free (syms); + syms_max = storage; + syms = (asymbol **) bfd_malloc ((bfd_size_type) syms_max); + if (syms == NULL) + goto error_return; + } + symcount = bfd_canonicalize_symtab (current, syms); + if (symcount < 0) + goto error_return; + + /* Now map over all the symbols, picking out the ones we + want. */ + for (src_count = 0; src_count < symcount; src_count++) + { + flagword flags = (syms[src_count])->flags; + asection *sec = syms[src_count]->section; + + if ((flags & BSF_GLOBAL || + flags & BSF_WEAK || + flags & BSF_INDIRECT || + bfd_is_com_section (sec)) + && ! bfd_is_und_section (sec)) + { + bfd_size_type namelen; + struct orl *new_map; + + /* This symbol will go into the archive header. */ + if (orl_count == orl_max) + { + orl_max *= 2; + amt = (bfd_size_type) orl_max * sizeof (struct orl); + new_map = (struct orl *) bfd_realloc (map, amt); + if (new_map == (struct orl *) NULL) + goto error_return; + + map = new_map; + } + + namelen = strlen (syms[src_count]->name); + amt = sizeof (char *); + map[orl_count].name = (char **) bfd_alloc (arch, amt); + if (map[orl_count].name == NULL) + goto error_return; + *(map[orl_count].name) = bfd_alloc (arch, namelen + 1); + if (*(map[orl_count].name) == NULL) + goto error_return; + strcpy (*(map[orl_count].name), syms[src_count]->name); + map[orl_count].u.abfd = current; + map[orl_count].namidx = stridx; + + stridx += namelen + 1; + ++orl_count; + } + } + } + + /* Now ask the BFD to free up any cached information, so we + don't fill all of memory with symbol tables. */ + if (! bfd_free_cached_info (current)) + goto error_return; + } + } + + /* OK, now we have collected all the data, let's write them out. */ + ret = BFD_SEND (arch, write_armap, + (arch, elength, map, orl_count, stridx)); + + if (syms_max > 0) + free (syms); + if (map != NULL) + free (map); + if (first_name != NULL) + bfd_release (arch, first_name); + + return ret; + + error_return: + if (syms_max > 0) + free (syms); + if (map != NULL) + free (map); + if (first_name != NULL) + bfd_release (arch, first_name); + + return FALSE; +} + +bfd_boolean +bsd_write_armap (arch, elength, map, orl_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int orl_count; + int stridx; +{ + int padit = stridx & 1; + unsigned int ranlibsize = orl_count * BSD_SYMDEF_SIZE; + unsigned int stringsize = stridx + padit; + /* Include 8 bytes to store ranlibsize and stringsize in output. */ + unsigned int mapsize = ranlibsize + stringsize + 8; + file_ptr firstreal; + bfd *current = arch->archive_head; + bfd *last_elt = current; /* last element arch seen */ + bfd_byte temp[4]; + unsigned int count; + struct ar_hdr hdr; + struct stat statbuf; + unsigned int i; + + firstreal = mapsize + elength + sizeof (struct ar_hdr) + SARMAG; + + stat (arch->filename, &statbuf); + memset ((char *) (&hdr), 0, sizeof (struct ar_hdr)); + sprintf (hdr.ar_name, RANLIBMAG); + /* Remember the timestamp, to keep it holy. But fudge it a little. */ + bfd_ardata (arch)->armap_timestamp = statbuf.st_mtime + ARMAP_TIME_OFFSET; + bfd_ardata (arch)->armap_datepos = (SARMAG + + offsetof (struct ar_hdr, ar_date[0])); + sprintf (hdr.ar_date, "%ld", bfd_ardata (arch)->armap_timestamp); + sprintf (hdr.ar_uid, "%ld", (long) getuid ()); + sprintf (hdr.ar_gid, "%ld", (long) getgid ()); + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + strncpy (hdr.ar_fmag, ARFMAG, 2); + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; + if (bfd_bwrite ((PTR) &hdr, (bfd_size_type) sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + return FALSE; + H_PUT_32 (arch, ranlibsize, temp); + if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), arch) != sizeof (temp)) + return FALSE; + + for (count = 0; count < orl_count; count++) + { + bfd_byte buf[BSD_SYMDEF_SIZE]; + + if (map[count].u.abfd != last_elt) + { + do + { + firstreal += arelt_size (current) + sizeof (struct ar_hdr); + firstreal += firstreal % 2; + current = current->next; + } + while (current != map[count].u.abfd); + } /* if new archive element */ + + last_elt = current; + H_PUT_32 (arch, map[count].namidx, buf); + H_PUT_32 (arch, firstreal, buf + BSD_SYMDEF_OFFSET_SIZE); + if (bfd_bwrite (buf, (bfd_size_type) BSD_SYMDEF_SIZE, arch) + != BSD_SYMDEF_SIZE) + return FALSE; + } + + /* Now write the strings themselves. */ + H_PUT_32 (arch, stringsize, temp); + if (bfd_bwrite (temp, (bfd_size_type) sizeof (temp), arch) != sizeof (temp)) + return FALSE; + for (count = 0; count < orl_count; count++) + { + size_t len = strlen (*map[count].name) + 1; + + if (bfd_bwrite (*map[count].name, (bfd_size_type) len, arch) != len) + return FALSE; + } + + /* The spec sez this should be a newline. But in order to be + bug-compatible for sun's ar we use a null. */ + if (padit) + { + if (bfd_bwrite ("", (bfd_size_type) 1, arch) != 1) + return FALSE; + } + + return TRUE; +} + +/* At the end of archive file handling, update the timestamp in the + file, so the linker will accept it. + + Return TRUE if the timestamp was OK, or an unusual problem happened. + Return FALSE if we updated the timestamp. */ + +bfd_boolean +_bfd_archive_bsd_update_armap_timestamp (arch) + bfd *arch; +{ + struct stat archstat; + struct ar_hdr hdr; + unsigned int i; + + /* Flush writes, get last-write timestamp from file, and compare it + to the timestamp IN the file. */ + bfd_flush (arch); + if (bfd_stat (arch, &archstat) == -1) + { + bfd_perror (_("Reading archive file mod timestamp")); + + /* Can't read mod time for some reason. */ + return TRUE; + } + if (archstat.st_mtime <= bfd_ardata (arch)->armap_timestamp) + /* OK by the linker's rules. */ + return TRUE; + + /* Update the timestamp. */ + bfd_ardata (arch)->armap_timestamp = archstat.st_mtime + ARMAP_TIME_OFFSET; + + /* Prepare an ASCII version suitable for writing. */ + memset (hdr.ar_date, 0, sizeof (hdr.ar_date)); + sprintf (hdr.ar_date, "%ld", bfd_ardata (arch)->armap_timestamp); + for (i = 0; i < sizeof (hdr.ar_date); i++) + if (hdr.ar_date[i] == '\0') + (hdr.ar_date)[i] = ' '; + + /* Write it into the file. */ + bfd_ardata (arch)->armap_datepos = (SARMAG + + offsetof (struct ar_hdr, ar_date[0])); + if (bfd_seek (arch, bfd_ardata (arch)->armap_datepos, SEEK_SET) != 0 + || (bfd_bwrite (hdr.ar_date, (bfd_size_type) sizeof (hdr.ar_date), arch) + != sizeof (hdr.ar_date))) + { + bfd_perror (_("Writing updated armap timestamp")); + + /* Some error while writing. */ + return TRUE; + } + + /* We updated the timestamp successfully. */ + return FALSE; +} + +/* A coff armap looks like : + lARMAG + struct ar_hdr with name = '/' + number of symbols + offset of file for symbol 0 + offset of file for symbol 1 + + offset of file for symbol n-1 + symbol name 0 + symbol name 1 + + symbol name n-1 +*/ + +bfd_boolean +coff_write_armap (arch, elength, map, symbol_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int symbol_count; + int stridx; +{ + /* The size of the ranlib is the number of exported symbols in the + archive * the number of bytes in an int, + an int for the count. */ + unsigned int ranlibsize = (symbol_count * 4) + 4; + unsigned int stringsize = stridx; + unsigned int mapsize = stringsize + ranlibsize; + unsigned int archive_member_file_ptr; + bfd *current = arch->archive_head; + unsigned int count; + struct ar_hdr hdr; + unsigned int i; + int padit = mapsize & 1; + + if (padit) + mapsize++; + + /* Work out where the first object file will go in the archive. */ + archive_member_file_ptr = (mapsize + + elength + + sizeof (struct ar_hdr) + + SARMAG); + + memset ((char *) (&hdr), 0, sizeof (struct ar_hdr)); + hdr.ar_name[0] = '/'; + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + sprintf (hdr.ar_date, "%ld", (long) time (NULL)); + /* This, at least, is what Intel coff sets the values to. */ + sprintf ((hdr.ar_uid), "%d", 0); + sprintf ((hdr.ar_gid), "%d", 0); + sprintf ((hdr.ar_mode), "%-7o", (unsigned) 0); + strncpy (hdr.ar_fmag, ARFMAG, 2); + + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; + + /* Write the ar header for this item and the number of symbols. */ + + if (bfd_bwrite ((PTR) &hdr, (bfd_size_type) sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + return FALSE; + + if (!bfd_write_bigendian_4byte_int (arch, symbol_count)) + return FALSE; + + /* Two passes, first write the file offsets for each symbol - + remembering that each offset is on a two byte boundary. */ + + /* Write out the file offset for the file associated with each + symbol, and remember to keep the offsets padded out. */ + + current = arch->archive_head; + count = 0; + while (current != (bfd *) NULL && count < symbol_count) + { + /* For each symbol which is used defined in this object, write + out the object file's address in the archive. */ + + while (count < symbol_count && map[count].u.abfd == current) + { + if (!bfd_write_bigendian_4byte_int (arch, archive_member_file_ptr)) + return FALSE; + count++; + } + /* Add size of this archive entry. */ + archive_member_file_ptr += (arelt_size (current) + + sizeof (struct ar_hdr)); + /* Remember aboout the even alignment. */ + archive_member_file_ptr += archive_member_file_ptr % 2; + current = current->next; + } + + /* Now write the strings themselves. */ + for (count = 0; count < symbol_count; count++) + { + size_t len = strlen (*map[count].name) + 1; + + if (bfd_bwrite (*map[count].name, (bfd_size_type) len, arch) != len) + return FALSE; + } + + /* The spec sez this should be a newline. But in order to be + bug-compatible for arc960 we use a null. */ + if (padit) + { + if (bfd_bwrite ("", (bfd_size_type) 1, arch) != 1) + return FALSE; + } + + return TRUE; +} diff --git a/contrib/binutils-2.14/bfd/archive64.c b/contrib/binutils-2.14/bfd/archive64.c new file mode 100644 index 0000000000..6267e68b3e --- /dev/null +++ b/contrib/binutils-2.14/bfd/archive64.c @@ -0,0 +1,245 @@ +/* MIPS-specific support for 64-bit ELF + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + Ian Lance Taylor, Cygnus Support + Linker support added by Mark Mitchell, CodeSourcery, LLC. + + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file supports the 64-bit (MIPS) ELF archives. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/ar.h" + +/* Irix 6 defines a 64bit archive map format, so that they can + have archives more than 4 GB in size. */ + +bfd_boolean bfd_elf64_archive_slurp_armap PARAMS ((bfd *)); +bfd_boolean bfd_elf64_archive_write_armap + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int)); + +/* Read an Irix 6 armap. */ + +bfd_boolean +bfd_elf64_archive_slurp_armap (abfd) + bfd *abfd; +{ + struct artdata *ardata = bfd_ardata (abfd); + char nextname[17]; + file_ptr arhdrpos; + bfd_size_type i, parsed_size, nsymz, stringsize, carsym_size, ptrsize; + struct areltdata *mapdata; + bfd_byte int_buf[8]; + char *stringbase; + bfd_byte *raw_armap = NULL; + carsym *carsyms; + bfd_size_type amt; + + ardata->symdefs = NULL; + + /* Get the name of the first element. */ + arhdrpos = bfd_tell (abfd); + i = bfd_bread ((PTR) nextname, (bfd_size_type) 16, abfd); + if (i == 0) + return TRUE; + if (i != 16) + return FALSE; + + if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0) + return FALSE; + + /* Archives with traditional armaps are still permitted. */ + if (strncmp (nextname, "/ ", 16) == 0) + return bfd_slurp_armap (abfd); + + if (strncmp (nextname, "/SYM64/ ", 16) != 0) + { + bfd_has_map (abfd) = FALSE; + return TRUE; + } + + mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd); + if (mapdata == NULL) + return FALSE; + parsed_size = mapdata->parsed_size; + bfd_release (abfd, (PTR) mapdata); + + if (bfd_bread (int_buf, (bfd_size_type) 8, abfd) != 8) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + return FALSE; + } + + nsymz = bfd_getb64 (int_buf); + stringsize = parsed_size - 8 * nsymz - 8; + + carsym_size = nsymz * sizeof (carsym); + ptrsize = 8 * nsymz; + + amt = carsym_size + stringsize + 1; + ardata->symdefs = (carsym *) bfd_zalloc (abfd, amt); + if (ardata->symdefs == NULL) + return FALSE; + carsyms = ardata->symdefs; + stringbase = ((char *) ardata->symdefs) + carsym_size; + + raw_armap = (bfd_byte *) bfd_alloc (abfd, ptrsize); + if (raw_armap == NULL) + goto release_symdefs; + + if (bfd_bread (raw_armap, ptrsize, abfd) != ptrsize + || bfd_bread (stringbase, stringsize, abfd) != stringsize) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_malformed_archive); + goto release_raw_armap; + } + + for (i = 0; i < nsymz; i++) + { + carsyms->file_offset = bfd_getb64 (raw_armap + i * 8); + carsyms->name = stringbase; + stringbase += strlen (stringbase) + 1; + ++carsyms; + } + *stringbase = '\0'; + + ardata->symdef_count = nsymz; + ardata->first_file_filepos = bfd_tell (abfd); + /* Pad to an even boundary if you have to. */ + ardata->first_file_filepos += (ardata->first_file_filepos) % 2; + + bfd_has_map (abfd) = TRUE; + bfd_release (abfd, raw_armap); + + return TRUE; + +release_raw_armap: + bfd_release (abfd, raw_armap); +release_symdefs: + bfd_release (abfd, ardata->symdefs); + return FALSE; +} + +/* Write out an Irix 6 armap. The Irix 6 tools are supposed to be + able to handle ordinary ELF armaps, but at least on Irix 6.2 the + linker crashes. */ + +bfd_boolean +bfd_elf64_archive_write_armap (arch, elength, map, symbol_count, stridx) + bfd *arch; + unsigned int elength; + struct orl *map; + unsigned int symbol_count; + int stridx; +{ + unsigned int ranlibsize = (symbol_count * 8) + 8; + unsigned int stringsize = stridx; + unsigned int mapsize = stringsize + ranlibsize; + file_ptr archive_member_file_ptr; + bfd *current = arch->archive_head; + unsigned int count; + struct ar_hdr hdr; + unsigned int i; + int padding; + bfd_byte buf[8]; + + padding = BFD_ALIGN (mapsize, 8) - mapsize; + mapsize += padding; + + /* work out where the first object file will go in the archive */ + archive_member_file_ptr = (mapsize + + elength + + sizeof (struct ar_hdr) + + SARMAG); + + memset ((char *) (&hdr), 0, sizeof (struct ar_hdr)); + strcpy (hdr.ar_name, "/SYM64/"); + sprintf (hdr.ar_size, "%-10d", (int) mapsize); + sprintf (hdr.ar_date, "%ld", (long) time (NULL)); + /* This, at least, is what Intel coff sets the values to.: */ + sprintf ((hdr.ar_uid), "%d", 0); + sprintf ((hdr.ar_gid), "%d", 0); + sprintf ((hdr.ar_mode), "%-7o", (unsigned) 0); + strncpy (hdr.ar_fmag, ARFMAG, 2); + + for (i = 0; i < sizeof (struct ar_hdr); i++) + if (((char *) (&hdr))[i] == '\0') + (((char *) (&hdr))[i]) = ' '; + + /* Write the ar header for this item and the number of symbols */ + + if (bfd_bwrite ((PTR) &hdr, (bfd_size_type) sizeof (struct ar_hdr), arch) + != sizeof (struct ar_hdr)) + return FALSE; + + bfd_putb64 ((bfd_vma) symbol_count, buf); + if (bfd_bwrite (buf, (bfd_size_type) 8, arch) != 8) + return FALSE; + + /* Two passes, first write the file offsets for each symbol - + remembering that each offset is on a two byte boundary. */ + + /* Write out the file offset for the file associated with each + symbol, and remember to keep the offsets padded out. */ + + current = arch->archive_head; + count = 0; + while (current != (bfd *) NULL && count < symbol_count) + { + /* For each symbol which is used defined in this object, write out + the object file's address in the archive */ + + while (map[count].u.abfd == current) + { + bfd_putb64 ((bfd_vma) archive_member_file_ptr, buf); + if (bfd_bwrite (buf, (bfd_size_type) 8, arch) != 8) + return FALSE; + count++; + } + /* Add size of this archive entry */ + archive_member_file_ptr += (arelt_size (current) + + sizeof (struct ar_hdr)); + /* remember about the even alignment */ + archive_member_file_ptr += archive_member_file_ptr % 2; + current = current->next; + } + + /* now write the strings themselves */ + for (count = 0; count < symbol_count; count++) + { + size_t len = strlen (*map[count].name) + 1; + + if (bfd_bwrite (*map[count].name, (bfd_size_type) len, arch) != len) + return FALSE; + } + + /* The spec says that this should be padded to an 8 byte boundary. + However, the Irix 6.2 tools do not appear to do this. */ + while (padding != 0) + { + if (bfd_bwrite ("", (bfd_size_type) 1, arch) != 1) + return FALSE; + --padding; + } + + return TRUE; +} diff --git a/contrib/binutils-2.14/bfd/archures.c b/contrib/binutils-2.14/bfd/archures.c new file mode 100644 index 0000000000..3d473c3b8a --- /dev/null +++ b/contrib/binutils-2.14/bfd/archures.c @@ -0,0 +1,1148 @@ +/* BFD library support routines for architectures. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + 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. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "safe-ctype.h" + +/* + +SECTION + Architectures + + BFD keeps one atom in a BFD describing the + architecture of the data attached to the BFD: a pointer to a + <>. + + Pointers to structures can be requested independently of a BFD + so that an architecture's information can be interrogated + without access to an open BFD. + + The architecture information is provided by each architecture package. + The set of default architectures is selected by the macro + <>. This is normally set up in the + @file{config/@var{target}.mt} file of your choice. If the name is not + defined, then all the architectures supported are included. + + When BFD starts up, all the architectures are called with an + initialize method. It is up to the architecture back end to + insert as many items into the list of architectures as it wants to; + generally this would be one for each machine and one for the + default case (an item with a machine field of 0). + + BFD's idea of an architecture is implemented in @file{archures.c}. +*/ + +/* + +SUBSECTION + bfd_architecture + +DESCRIPTION + This enum gives the object file's CPU architecture, in a + global sense---i.e., what processor family does it belong to? + Another field indicates which processor within + the family is in use. The machine gives a number which + distinguishes different versions of the architecture, + containing, for example, 2 and 3 for Intel i960 KA and i960 KB, + and 68020 and 68030 for Motorola 68020 and 68030. + +.enum bfd_architecture +.{ +. bfd_arch_unknown, {* File arch not known. *} +. bfd_arch_obscure, {* Arch known, not one of these. *} +. bfd_arch_m68k, {* Motorola 68xxx *} +.#define bfd_mach_m68000 1 +.#define bfd_mach_m68008 2 +.#define bfd_mach_m68010 3 +.#define bfd_mach_m68020 4 +.#define bfd_mach_m68030 5 +.#define bfd_mach_m68040 6 +.#define bfd_mach_m68060 7 +.#define bfd_mach_cpu32 8 +.#define bfd_mach_mcf5200 9 +.#define bfd_mach_mcf5206e 10 +.#define bfd_mach_mcf5307 11 +.#define bfd_mach_mcf5407 12 +. bfd_arch_vax, {* DEC Vax *} +. bfd_arch_i960, {* Intel 960 *} +. {* The order of the following is important. +. lower number indicates a machine type that +. only accepts a subset of the instructions +. available to machines with higher numbers. +. The exception is the "ca", which is +. incompatible with all other machines except +. "core". *} +. +.#define bfd_mach_i960_core 1 +.#define bfd_mach_i960_ka_sa 2 +.#define bfd_mach_i960_kb_sb 3 +.#define bfd_mach_i960_mc 4 +.#define bfd_mach_i960_xa 5 +.#define bfd_mach_i960_ca 6 +.#define bfd_mach_i960_jx 7 +.#define bfd_mach_i960_hx 8 +. +. bfd_arch_or32, {* OpenRISC 32 *} +. +. bfd_arch_a29k, {* AMD 29000 *} +. bfd_arch_sparc, {* SPARC *} +.#define bfd_mach_sparc 1 +.{* The difference between v8plus and v9 is that v9 is a true 64 bit env. *} +.#define bfd_mach_sparc_sparclet 2 +.#define bfd_mach_sparc_sparclite 3 +.#define bfd_mach_sparc_v8plus 4 +.#define bfd_mach_sparc_v8plusa 5 {* with ultrasparc add'ns. *} +.#define bfd_mach_sparc_sparclite_le 6 +.#define bfd_mach_sparc_v9 7 +.#define bfd_mach_sparc_v9a 8 {* with ultrasparc add'ns. *} +.#define bfd_mach_sparc_v8plusb 9 {* with cheetah add'ns. *} +.#define bfd_mach_sparc_v9b 10 {* with cheetah add'ns. *} +.{* Nonzero if MACH has the v9 instruction set. *} +.#define bfd_mach_sparc_v9_p(mach) \ +. ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ +. && (mach) != bfd_mach_sparc_sparclite_le) +. bfd_arch_mips, {* MIPS Rxxxx *} +.#define bfd_mach_mips3000 3000 +.#define bfd_mach_mips3900 3900 +.#define bfd_mach_mips4000 4000 +.#define bfd_mach_mips4010 4010 +.#define bfd_mach_mips4100 4100 +.#define bfd_mach_mips4111 4111 +.#define bfd_mach_mips4120 4120 +.#define bfd_mach_mips4300 4300 +.#define bfd_mach_mips4400 4400 +.#define bfd_mach_mips4600 4600 +.#define bfd_mach_mips4650 4650 +.#define bfd_mach_mips5000 5000 +.#define bfd_mach_mips5400 5400 +.#define bfd_mach_mips5500 5500 +.#define bfd_mach_mips6000 6000 +.#define bfd_mach_mips8000 8000 +.#define bfd_mach_mips10000 10000 +.#define bfd_mach_mips12000 12000 +.#define bfd_mach_mips16 16 +.#define bfd_mach_mips5 5 +.#define bfd_mach_mips_sb1 12310201 {* octal 'SB', 01 *} +.#define bfd_mach_mipsisa32 32 +.#define bfd_mach_mipsisa32r2 33 +.#define bfd_mach_mipsisa64 64 +. bfd_arch_i386, {* Intel 386 *} +.#define bfd_mach_i386_i386 1 +.#define bfd_mach_i386_i8086 2 +.#define bfd_mach_i386_i386_intel_syntax 3 +.#define bfd_mach_x86_64 64 +.#define bfd_mach_x86_64_intel_syntax 65 +. bfd_arch_we32k, {* AT&T WE32xxx *} +. bfd_arch_tahoe, {* CCI/Harris Tahoe *} +. bfd_arch_i860, {* Intel 860 *} +. bfd_arch_i370, {* IBM 360/370 Mainframes *} +. bfd_arch_romp, {* IBM ROMP PC/RT *} +. bfd_arch_alliant, {* Alliant *} +. bfd_arch_convex, {* Convex *} +. bfd_arch_m88k, {* Motorola 88xxx *} +. bfd_arch_m98k, {* Motorola 98xxx *} +. bfd_arch_pyramid, {* Pyramid Technology *} +. bfd_arch_h8300, {* Renesas H8/300 (formerly Hitachi H8/300) *} +.#define bfd_mach_h8300 1 +.#define bfd_mach_h8300h 2 +.#define bfd_mach_h8300s 3 +.#define bfd_mach_h8300hn 4 +.#define bfd_mach_h8300sn 5 +. bfd_arch_pdp11, {* DEC PDP-11 *} +. bfd_arch_powerpc, {* PowerPC *} +.#define bfd_mach_ppc 32 +.#define bfd_mach_ppc64 64 +.#define bfd_mach_ppc_403 403 +.#define bfd_mach_ppc_403gc 4030 +.#define bfd_mach_ppc_505 505 +.#define bfd_mach_ppc_601 601 +.#define bfd_mach_ppc_602 602 +.#define bfd_mach_ppc_603 603 +.#define bfd_mach_ppc_ec603e 6031 +.#define bfd_mach_ppc_604 604 +.#define bfd_mach_ppc_620 620 +.#define bfd_mach_ppc_630 630 +.#define bfd_mach_ppc_750 750 +.#define bfd_mach_ppc_860 860 +.#define bfd_mach_ppc_a35 35 +.#define bfd_mach_ppc_rs64ii 642 +.#define bfd_mach_ppc_rs64iii 643 +.#define bfd_mach_ppc_7400 7400 +.#define bfd_mach_ppc_e500 500 +. bfd_arch_rs6000, {* IBM RS/6000 *} +.#define bfd_mach_rs6k 6000 +.#define bfd_mach_rs6k_rs1 6001 +.#define bfd_mach_rs6k_rsc 6003 +.#define bfd_mach_rs6k_rs2 6002 +. bfd_arch_hppa, {* HP PA RISC *} +. bfd_arch_d10v, {* Mitsubishi D10V *} +.#define bfd_mach_d10v 1 +.#define bfd_mach_d10v_ts2 2 +.#define bfd_mach_d10v_ts3 3 +. bfd_arch_d30v, {* Mitsubishi D30V *} +. bfd_arch_dlx, {* DLX *} +. bfd_arch_m68hc11, {* Motorola 68HC11 *} +. bfd_arch_m68hc12, {* Motorola 68HC12 *} +.#define bfd_mach_m6812_default 0 +.#define bfd_mach_m6812 1 +.#define bfd_mach_m6812s 2 +. bfd_arch_z8k, {* Zilog Z8000 *} +.#define bfd_mach_z8001 1 +.#define bfd_mach_z8002 2 +. bfd_arch_h8500, {* Renesas H8/500 (formerly Hitachi H8/500) *} +. bfd_arch_sh, {* Renesas / SuperH SH (formerly Hitachi SH) *} +.#define bfd_mach_sh 1 +.#define bfd_mach_sh2 0x20 +.#define bfd_mach_sh_dsp 0x2d +.#define bfd_mach_sh2e 0x2e +.#define bfd_mach_sh3 0x30 +.#define bfd_mach_sh3_dsp 0x3d +.#define bfd_mach_sh3e 0x3e +.#define bfd_mach_sh4 0x40 +.#define bfd_mach_sh5 0x50 +. bfd_arch_alpha, {* Dec Alpha *} +.#define bfd_mach_alpha_ev4 0x10 +.#define bfd_mach_alpha_ev5 0x20 +.#define bfd_mach_alpha_ev6 0x30 +. bfd_arch_arm, {* Advanced Risc Machines ARM. *} +.#define bfd_mach_arm_unknown 0 +.#define bfd_mach_arm_2 1 +.#define bfd_mach_arm_2a 2 +.#define bfd_mach_arm_3 3 +.#define bfd_mach_arm_3M 4 +.#define bfd_mach_arm_4 5 +.#define bfd_mach_arm_4T 6 +.#define bfd_mach_arm_5 7 +.#define bfd_mach_arm_5T 8 +.#define bfd_mach_arm_5TE 9 +.#define bfd_mach_arm_XScale 10 +.#define bfd_mach_arm_ep9312 11 +.#define bfd_mach_arm_iWMMXt 12 +. bfd_arch_ns32k, {* National Semiconductors ns32000 *} +. bfd_arch_w65, {* WDC 65816 *} +. bfd_arch_tic30, {* Texas Instruments TMS320C30 *} +. bfd_arch_tic4x, {* Texas Instruments TMS320C3X/4X *} +.#define bfd_mach_tic3x 30 +.#define bfd_mach_tic4x 40 +. bfd_arch_tic54x, {* Texas Instruments TMS320C54X *} +. bfd_arch_tic80, {* TI TMS320c80 (MVP) *} +. bfd_arch_v850, {* NEC V850 *} +.#define bfd_mach_v850 1 +.#define bfd_mach_v850e 'E' +. bfd_arch_arc, {* ARC Cores *} +.#define bfd_mach_arc_5 5 +.#define bfd_mach_arc_6 6 +.#define bfd_mach_arc_7 7 +.#define bfd_mach_arc_8 8 +. bfd_arch_m32r, {* Renesas M32R (formerly Mitsubishi M32R/D) *} +.#define bfd_mach_m32r 1 {* For backwards compatibility. *} +.#define bfd_mach_m32rx 'x' +. bfd_arch_mn10200, {* Matsushita MN10200 *} +. bfd_arch_mn10300, {* Matsushita MN10300 *} +.#define bfd_mach_mn10300 300 +.#define bfd_mach_am33 330 +. bfd_arch_fr30, +.#define bfd_mach_fr30 0x46523330 +. bfd_arch_frv, +.#define bfd_mach_frv 1 +.#define bfd_mach_frvsimple 2 +.#define bfd_mach_fr300 300 +.#define bfd_mach_fr400 400 +.#define bfd_mach_frvtomcat 499 {* fr500 prototype *} +.#define bfd_mach_fr500 500 +. bfd_arch_mcore, +. bfd_arch_ia64, {* HP/Intel ia64 *} +.#define bfd_mach_ia64_elf64 64 +.#define bfd_mach_ia64_elf32 32 +. bfd_arch_ip2k, {* Ubicom IP2K microcontrollers. *} +.#define bfd_mach_ip2022 1 +.#define bfd_mach_ip2022ext 2 +. bfd_arch_iq2000, {* Vitesse IQ2000. *} +.#define bfd_mach_iq2000 1 +.#define bfd_mach_iq10 2 +. bfd_arch_pj, +. bfd_arch_avr, {* Atmel AVR microcontrollers. *} +.#define bfd_mach_avr1 1 +.#define bfd_mach_avr2 2 +.#define bfd_mach_avr3 3 +.#define bfd_mach_avr4 4 +.#define bfd_mach_avr5 5 +. bfd_arch_cris, {* Axis CRIS *} +. bfd_arch_s390, {* IBM s390 *} +.#define bfd_mach_s390_31 31 +.#define bfd_mach_s390_64 64 +. bfd_arch_openrisc, {* OpenRISC *} +. bfd_arch_mmix, {* Donald Knuth's educational processor. *} +. bfd_arch_xstormy16, +.#define bfd_mach_xstormy16 1 +. bfd_arch_msp430, {* Texas Instruments MSP430 architecture. *} +.#define bfd_mach_msp110 110 +.#define bfd_mach_msp11 11 +.#define bfd_mach_msp12 12 +.#define bfd_mach_msp13 13 +.#define bfd_mach_msp14 14 +.#define bfd_mach_msp41 41 +.#define bfd_mach_msp31 31 +.#define bfd_mach_msp32 32 +.#define bfd_mach_msp33 33 +.#define bfd_mach_msp43 43 +.#define bfd_mach_msp44 44 +.#define bfd_mach_msp15 15 +.#define bfd_mach_msp16 16 +. bfd_arch_xtensa, {* Tensilica's Xtensa cores. *} +.#define bfd_mach_xtensa 1 +. bfd_arch_last +. }; +*/ + +/* +SUBSECTION + bfd_arch_info + +DESCRIPTION + This structure contains information on architectures for use + within BFD. + +. +.typedef struct bfd_arch_info +.{ +. int bits_per_word; +. int bits_per_address; +. int bits_per_byte; +. enum bfd_architecture arch; +. unsigned long mach; +. const char *arch_name; +. const char *printable_name; +. unsigned int section_align_power; +. {* TRUE if this is the default machine for the architecture. +. The default arch should be the first entry for an arch so that +. all the entries for that arch can be accessed via <>. *} +. bfd_boolean the_default; +. const struct bfd_arch_info * (*compatible) +. PARAMS ((const struct bfd_arch_info *a, +. const struct bfd_arch_info *b)); +. +. bfd_boolean (*scan) PARAMS ((const struct bfd_arch_info *, const char *)); +. +. const struct bfd_arch_info *next; +.} +.bfd_arch_info_type; +. +*/ + +extern const bfd_arch_info_type bfd_a29k_arch; +extern const bfd_arch_info_type bfd_alpha_arch; +extern const bfd_arch_info_type bfd_arc_arch; +extern const bfd_arch_info_type bfd_arm_arch; +extern const bfd_arch_info_type bfd_avr_arch; +extern const bfd_arch_info_type bfd_cris_arch; +extern const bfd_arch_info_type bfd_d10v_arch; +extern const bfd_arch_info_type bfd_d30v_arch; +extern const bfd_arch_info_type bfd_dlx_arch; +extern const bfd_arch_info_type bfd_fr30_arch; +extern const bfd_arch_info_type bfd_frv_arch; +extern const bfd_arch_info_type bfd_h8300_arch; +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_i860_arch; +extern const bfd_arch_info_type bfd_i960_arch; +extern const bfd_arch_info_type bfd_ia64_arch; +extern const bfd_arch_info_type bfd_ip2k_arch; +extern const bfd_arch_info_type bfd_iq2000_arch; +extern const bfd_arch_info_type bfd_m32r_arch; +extern const bfd_arch_info_type bfd_m68hc11_arch; +extern const bfd_arch_info_type bfd_m68hc12_arch; +extern const bfd_arch_info_type bfd_m68k_arch; +extern const bfd_arch_info_type bfd_m88k_arch; +extern const bfd_arch_info_type bfd_mcore_arch; +extern const bfd_arch_info_type bfd_mips_arch; +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_msp430_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_pdp11_arch; +extern const bfd_arch_info_type bfd_pj_arch; +extern const bfd_arch_info_type bfd_powerpc_archs[]; +#define bfd_powerpc_arch bfd_powerpc_archs[0] +extern const bfd_arch_info_type bfd_rs6000_arch; +extern const bfd_arch_info_type bfd_s390_arch; +extern const bfd_arch_info_type bfd_sh_arch; +extern const bfd_arch_info_type bfd_sparc_arch; +extern const bfd_arch_info_type bfd_tic30_arch; +extern const bfd_arch_info_type bfd_tic4x_arch; +extern const bfd_arch_info_type bfd_tic54x_arch; +extern const bfd_arch_info_type bfd_tic80_arch; +extern const bfd_arch_info_type bfd_v850_arch; +extern const bfd_arch_info_type bfd_vax_arch; +extern const bfd_arch_info_type bfd_we32k_arch; +extern const bfd_arch_info_type bfd_w65_arch; +extern const bfd_arch_info_type bfd_xstormy16_arch; +extern const bfd_arch_info_type bfd_xtensa_arch; +extern const bfd_arch_info_type bfd_z8k_arch; + +static const bfd_arch_info_type * const bfd_archures_list[] = + { +#ifdef SELECT_ARCHITECTURES + SELECT_ARCHITECTURES, +#else + &bfd_a29k_arch, + &bfd_alpha_arch, + &bfd_arc_arch, + &bfd_arm_arch, + &bfd_avr_arch, + &bfd_cris_arch, + &bfd_d10v_arch, + &bfd_d30v_arch, + &bfd_dlx_arch, + &bfd_fr30_arch, + &bfd_frv_arch, + &bfd_h8300_arch, + &bfd_h8500_arch, + &bfd_hppa_arch, + &bfd_i370_arch, + &bfd_i386_arch, + &bfd_i860_arch, + &bfd_i960_arch, + &bfd_ia64_arch, + &bfd_ip2k_arch, + &bfd_iq2000_arch, + &bfd_m32r_arch, + &bfd_m68hc11_arch, + &bfd_m68hc12_arch, + &bfd_m68k_arch, + &bfd_m88k_arch, + &bfd_mcore_arch, + &bfd_mips_arch, + &bfd_mmix_arch, + &bfd_mn10200_arch, + &bfd_mn10300_arch, + &bfd_msp430_arch, + &bfd_ns32k_arch, + &bfd_openrisc_arch, + &bfd_or32_arch, + &bfd_pdp11_arch, + &bfd_powerpc_arch, + &bfd_rs6000_arch, + &bfd_s390_arch, + &bfd_sh_arch, + &bfd_sparc_arch, + &bfd_tic30_arch, + &bfd_tic4x_arch, + &bfd_tic54x_arch, + &bfd_tic80_arch, + &bfd_v850_arch, + &bfd_vax_arch, + &bfd_w65_arch, + &bfd_we32k_arch, + &bfd_xstormy16_arch, + &bfd_xtensa_arch, + &bfd_z8k_arch, +#endif + 0 +}; + +/* +FUNCTION + bfd_printable_name + +SYNOPSIS + const char *bfd_printable_name(bfd *abfd); + +DESCRIPTION + Return a printable string representing the architecture and machine + from the pointer to the architecture info structure. + +*/ + +const char * +bfd_printable_name (abfd) + bfd *abfd; +{ + return abfd->arch_info->printable_name; +} + +/* +FUNCTION + bfd_scan_arch + +SYNOPSIS + const bfd_arch_info_type *bfd_scan_arch(const char *string); + +DESCRIPTION + Figure out if BFD supports any cpu which could be described with + the name @var{string}. Return a pointer to an <> + structure if a machine is found, otherwise NULL. +*/ + +const bfd_arch_info_type * +bfd_scan_arch (string) + const char *string; +{ + const bfd_arch_info_type * const *app, *ap; + + /* Look through all the installed architectures. */ + for (app = bfd_archures_list; *app != NULL; app++) + { + for (ap = *app; ap != NULL; ap = ap->next) + { + if (ap->scan (ap, string)) + return ap; + } + } + + return NULL; +} + +/* +FUNCTION + bfd_arch_list + +SYNOPSIS + const char **bfd_arch_list(void); + +DESCRIPTION + Return a freshly malloced NULL-terminated vector of the names + of all the valid BFD architectures. Do not modify the names. +*/ + +const char ** +bfd_arch_list () +{ + int vec_length = 0; + const char **name_ptr; + const char **name_list; + const bfd_arch_info_type * const *app; + bfd_size_type amt; + + /* Determine the number of architectures. */ + vec_length = 0; + for (app = bfd_archures_list; *app != NULL; app++) + { + const bfd_arch_info_type *ap; + for (ap = *app; ap != NULL; ap = ap->next) + { + vec_length++; + } + } + + amt = (vec_length + 1) * sizeof (char **); + name_list = (const char **) bfd_malloc (amt); + if (name_list == NULL) + return NULL; + + /* Point the list at each of the names. */ + name_ptr = name_list; + for (app = bfd_archures_list; *app != NULL; app++) + { + const bfd_arch_info_type *ap; + for (ap = *app; ap != NULL; ap = ap->next) + { + *name_ptr = ap->printable_name; + name_ptr++; + } + } + *name_ptr = NULL; + + return name_list; +} + +/* +FUNCTION + bfd_arch_get_compatible + +SYNOPSIS + const bfd_arch_info_type *bfd_arch_get_compatible( + const bfd *abfd, + const bfd *bbfd, + bfd_boolean accept_unknowns); + +DESCRIPTION + Determine whether two BFDs' architectures and machine types + are compatible. Calculates the lowest common denominator + between the two architectures and machine types implied by + the BFDs and returns a pointer to an <> structure + describing the compatible machine. +*/ + +const bfd_arch_info_type * +bfd_arch_get_compatible (abfd, bbfd, accept_unknowns) + const bfd *abfd; + const bfd *bbfd; + bfd_boolean accept_unknowns; +{ + const bfd * ubfd = NULL; + + /* Look for an unknown architecture. */ + if (((ubfd = abfd) && ubfd->arch_info->arch == bfd_arch_unknown) + || ((ubfd = bbfd) && ubfd->arch_info->arch == bfd_arch_unknown)) + { + /* We can allow an unknown architecture if accept_unknowns + is true, or if the target is the "binary" format, which + has an unknown architecture. Since the binary format can + only be set by explicit request from the user, it is safe + to assume that they know what they are doing. */ + if (accept_unknowns + || strcmp (bfd_get_target (ubfd), "binary") == 0) + return ubfd->arch_info; + return NULL; + } + + /* Otherwise architecture-specific code has to decide. */ + return abfd->arch_info->compatible (abfd->arch_info, bbfd->arch_info); +} + +/* +INTERNAL_DEFINITION + bfd_default_arch_struct + +DESCRIPTION + The <> is an item of + <> which has been initialized to a fairly + generic state. A BFD starts life by pointing to this + structure, until the correct back end has determined the real + architecture of the file. + +.extern const bfd_arch_info_type bfd_default_arch_struct; +*/ + +const bfd_arch_info_type bfd_default_arch_struct = { + 32, 32, 8, bfd_arch_unknown, 0, "unknown", "unknown", 2, TRUE, + bfd_default_compatible, + bfd_default_scan, + 0, +}; + +/* +FUNCTION + bfd_set_arch_info + +SYNOPSIS + void bfd_set_arch_info(bfd *abfd, const bfd_arch_info_type *arg); + +DESCRIPTION + Set the architecture info of @var{abfd} to @var{arg}. +*/ + +void +bfd_set_arch_info (abfd, arg) + bfd *abfd; + const bfd_arch_info_type *arg; +{ + abfd->arch_info = arg; +} + +/* +INTERNAL_FUNCTION + bfd_default_set_arch_mach + +SYNOPSIS + bfd_boolean bfd_default_set_arch_mach(bfd *abfd, + enum bfd_architecture arch, + unsigned long mach); + +DESCRIPTION + Set the architecture and machine type in BFD @var{abfd} + to @var{arch} and @var{mach}. Find the correct + pointer to a structure and insert it into the <> + pointer. +*/ + +bfd_boolean +bfd_default_set_arch_mach (abfd, arch, mach) + bfd *abfd; + enum bfd_architecture arch; + unsigned long mach; +{ + abfd->arch_info = bfd_lookup_arch (arch, mach); + if (abfd->arch_info != NULL) + return TRUE; + + abfd->arch_info = &bfd_default_arch_struct; + bfd_set_error (bfd_error_bad_value); + return FALSE; +} + +/* +FUNCTION + bfd_get_arch + +SYNOPSIS + enum bfd_architecture bfd_get_arch(bfd *abfd); + +DESCRIPTION + Return the enumerated type which describes the BFD @var{abfd}'s + architecture. +*/ + +enum bfd_architecture +bfd_get_arch (abfd) + bfd *abfd; +{ + return abfd->arch_info->arch; +} + +/* +FUNCTION + bfd_get_mach + +SYNOPSIS + unsigned long bfd_get_mach(bfd *abfd); + +DESCRIPTION + Return the long type which describes the BFD @var{abfd}'s + machine. +*/ + +unsigned long +bfd_get_mach (abfd) + bfd *abfd; +{ + return abfd->arch_info->mach; +} + +/* +FUNCTION + bfd_arch_bits_per_byte + +SYNOPSIS + unsigned int bfd_arch_bits_per_byte(bfd *abfd); + +DESCRIPTION + Return the number of bits in one of the BFD @var{abfd}'s + architecture's bytes. +*/ + +unsigned int +bfd_arch_bits_per_byte (abfd) + bfd *abfd; +{ + return abfd->arch_info->bits_per_byte; +} + +/* +FUNCTION + bfd_arch_bits_per_address + +SYNOPSIS + unsigned int bfd_arch_bits_per_address(bfd *abfd); + +DESCRIPTION + Return the number of bits in one of the BFD @var{abfd}'s + architecture's addresses. +*/ + +unsigned int +bfd_arch_bits_per_address (abfd) + bfd *abfd; +{ + return abfd->arch_info->bits_per_address; +} + +/* +INTERNAL_FUNCTION + bfd_default_compatible + +SYNOPSIS + const bfd_arch_info_type *bfd_default_compatible + (const bfd_arch_info_type *a, + const bfd_arch_info_type *b); + +DESCRIPTION + The default function for testing for compatibility. +*/ + +const bfd_arch_info_type * +bfd_default_compatible (a, b) + const bfd_arch_info_type *a; + const bfd_arch_info_type *b; +{ + if (a->arch != b->arch) + return NULL; + + if (a->bits_per_word != b->bits_per_word) + return NULL; + + if (a->mach > b->mach) + return a; + + if (b->mach > a->mach) + return b; + + return a; +} + +/* +INTERNAL_FUNCTION + bfd_default_scan + +SYNOPSIS + bfd_boolean bfd_default_scan(const struct bfd_arch_info *info, const char *string); + +DESCRIPTION + The default function for working out whether this is an + architecture hit and a machine hit. +*/ + +bfd_boolean +bfd_default_scan (info, string) + const bfd_arch_info_type *info; + const char *string; +{ + const char *ptr_src; + const char *ptr_tst; + unsigned long number; + enum bfd_architecture arch; + const char *printable_name_colon; + + /* Exact match of the architecture name (ARCH_NAME) and also the + default architecture? */ + if (strcasecmp (string, info->arch_name) == 0 + && info->the_default) + return TRUE; + + /* Exact match of the machine name (PRINTABLE_NAME)? */ + if (strcasecmp (string, info->printable_name) == 0) + return TRUE; + + /* Given that printable_name contains no colon, attempt to match: + ARCH_NAME [ ":" ] PRINTABLE_NAME? */ + printable_name_colon = strchr (info->printable_name, ':'); + if (printable_name_colon == NULL) + { + size_t strlen_arch_name = strlen (info->arch_name); + if (strncasecmp (string, info->arch_name, strlen_arch_name) == 0) + { + if (string[strlen_arch_name] == ':') + { + if (strcasecmp (string + strlen_arch_name + 1, + info->printable_name) == 0) + return TRUE; + } + else + { + if (strcasecmp (string + strlen_arch_name, + info->printable_name) == 0) + return TRUE; + } + } + } + + /* Given that PRINTABLE_NAME has the form: ":" ; + Attempt to match: ? */ + if (printable_name_colon != NULL) + { + size_t colon_index = printable_name_colon - info->printable_name; + if (strncasecmp (string, info->printable_name, colon_index) == 0 + && strcasecmp (string + colon_index, + info->printable_name + colon_index + 1) == 0) + return TRUE; + } + + /* Given that PRINTABLE_NAME has the form: ":" ; Do not + attempt to match just , it could be ambigious. This test + is left until later. */ + + /* NOTE: The below is retained for compatibility only. Please do + not add to this code. */ + + /* See how much of the supplied string matches with the + architecture, eg the string m68k:68020 would match the 68k entry + up to the :, then we get left with the machine number. */ + + for (ptr_src = string, ptr_tst = info->arch_name; + *ptr_src && *ptr_tst; + ptr_src++, ptr_tst++) + { + if (*ptr_src != *ptr_tst) + break; + } + + /* Chewed up as much of the architecture as will match, skip any + colons. */ + if (*ptr_src == ':') + ptr_src++; + + if (*ptr_src == 0) + { + /* Nothing more, then only keep this one if it is the default + machine for this architecture. */ + return info->the_default; + } + + number = 0; + while (ISDIGIT (*ptr_src)) + { + number = number * 10 + *ptr_src - '0'; + ptr_src++; + } + + /* NOTE: The below is retained for compatibility only. + PLEASE DO NOT ADD TO THIS CODE. */ + + switch (number) + { + /* FIXME: These are needed to parse IEEE objects. */ + /* The following seven case's are here only for compatibility with + older binutils (at least IEEE objects from binutils 2.9.1 require + them). */ + case bfd_mach_m68000: + case bfd_mach_m68010: + case bfd_mach_m68020: + case bfd_mach_m68030: + case bfd_mach_m68040: + case bfd_mach_m68060: + case bfd_mach_cpu32: + arch = bfd_arch_m68k; + break; + case 68000: + arch = bfd_arch_m68k; + number = bfd_mach_m68000; + break; + case 68010: + arch = bfd_arch_m68k; + number = bfd_mach_m68010; + break; + case 68020: + arch = bfd_arch_m68k; + number = bfd_mach_m68020; + break; + case 68030: + arch = bfd_arch_m68k; + number = bfd_mach_m68030; + break; + case 68040: + arch = bfd_arch_m68k; + number = bfd_mach_m68040; + break; + case 68060: + arch = bfd_arch_m68k; + number = bfd_mach_m68060; + break; + case 68332: + arch = bfd_arch_m68k; + number = bfd_mach_cpu32; + break; + case 5200: + arch = bfd_arch_m68k; + number = bfd_mach_mcf5200; + break; + case 5206: + arch = bfd_arch_m68k; + number = bfd_mach_mcf5206e; + break; + case 5307: + arch = bfd_arch_m68k; + number = bfd_mach_mcf5307; + break; + case 5407: + arch = bfd_arch_m68k; + number = bfd_mach_mcf5407; + break; + + case 32000: + arch = bfd_arch_we32k; + break; + + case 3000: + arch = bfd_arch_mips; + number = bfd_mach_mips3000; + break; + + case 4000: + arch = bfd_arch_mips; + number = bfd_mach_mips4000; + break; + + case 6000: + arch = bfd_arch_rs6000; + break; + + case 7410: + arch = bfd_arch_sh; + number = bfd_mach_sh_dsp; + break; + + case 7708: + arch = bfd_arch_sh; + number = bfd_mach_sh3; + break; + + case 7729: + arch = bfd_arch_sh; + number = bfd_mach_sh3_dsp; + break; + + case 7750: + arch = bfd_arch_sh; + number = bfd_mach_sh4; + break; + + default: + return FALSE; + } + + if (arch != info->arch) + return FALSE; + + if (number != info->mach) + return FALSE; + + return TRUE; +} + +/* +FUNCTION + bfd_get_arch_info + +SYNOPSIS + const bfd_arch_info_type * bfd_get_arch_info(bfd *abfd); + +DESCRIPTION + Return the architecture info struct in @var{abfd}. +*/ + +const bfd_arch_info_type * +bfd_get_arch_info (abfd) + bfd *abfd; +{ + return abfd->arch_info; +} + +/* +FUNCTION + bfd_lookup_arch + +SYNOPSIS + const bfd_arch_info_type *bfd_lookup_arch + (enum bfd_architecture + arch, + unsigned long machine); + +DESCRIPTION + Look for the architecure info structure which matches the + arguments @var{arch} and @var{machine}. A machine of 0 matches the + machine/architecture structure which marks itself as the + default. +*/ + +const bfd_arch_info_type * +bfd_lookup_arch (arch, machine) + enum bfd_architecture arch; + unsigned long machine; +{ + const bfd_arch_info_type * const *app, *ap; + + for (app = bfd_archures_list; *app != NULL; app++) + { + for (ap = *app; ap != NULL; ap = ap->next) + { + if (ap->arch == arch + && (ap->mach == machine + || (machine == 0 && ap->the_default))) + return ap; + } + } + + return NULL; +} + +/* +FUNCTION + bfd_printable_arch_mach + +SYNOPSIS + const char *bfd_printable_arch_mach + (enum bfd_architecture arch, unsigned long machine); + +DESCRIPTION + Return a printable string representing the architecture and + machine type. + + This routine is depreciated. +*/ + +const char * +bfd_printable_arch_mach (arch, machine) + enum bfd_architecture arch; + unsigned long machine; +{ + const bfd_arch_info_type *ap = bfd_lookup_arch (arch, machine); + + if (ap) + return ap->printable_name; + return "UNKNOWN!"; +} + +/* +FUNCTION + bfd_octets_per_byte + +SYNOPSIS + unsigned int bfd_octets_per_byte(bfd *abfd); + +DESCRIPTION + Return the number of octets (8-bit quantities) per target byte + (minimum addressable unit). In most cases, this will be one, but some + DSP targets have 16, 32, or even 48 bits per byte. +*/ + +unsigned int +bfd_octets_per_byte (abfd) + bfd *abfd; +{ + return bfd_arch_mach_octets_per_byte (bfd_get_arch (abfd), + bfd_get_mach (abfd)); +} + +/* +FUNCTION + bfd_arch_mach_octets_per_byte + +SYNOPSIS + unsigned int bfd_arch_mach_octets_per_byte(enum bfd_architecture arch, + unsigned long machine); + +DESCRIPTION + See bfd_octets_per_byte. + + This routine is provided for those cases where a bfd * is not + available +*/ + +unsigned int +bfd_arch_mach_octets_per_byte (arch, mach) + enum bfd_architecture arch; + unsigned long mach; +{ + const bfd_arch_info_type *ap = bfd_lookup_arch (arch, mach); + + if (ap) + return ap->bits_per_byte / 8; + return 1; +} diff --git a/contrib/binutils-2.14/bfd/bfd-in2.h b/contrib/binutils-2.14/bfd/bfd-in2.h new file mode 100644 index 0000000000..9b6b5a3937 --- /dev/null +++ b/contrib/binutils-2.14/bfd/bfd-in2.h @@ -0,0 +1,4442 @@ +/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically + generated from "bfd-in.h", "init.c", "opncls.c", "libbfd.c", + "bfdio.c", "bfdwin.c", "section.c", "archures.c", "reloc.c", + "syms.c", "bfd.c", "archive.c", "corefile.c", "targets.c", "format.c", + "linker.c" and "simple.c". + Run "make headers" in your build bfd/ to regenerate. */ + +/* 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 Free Software Foundation, Inc. + + Contributed 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __BFD_H_SEEN__ +#define __BFD_H_SEEN__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ansidecl.h" +#include "symcat.h" +#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) +#ifndef SABER +/* This hack is to avoid a problem with some strict ANSI C preprocessors. + The problem is, "32_" is not a valid preprocessing token, and we don't + want extra underscores (e.g., "nlm_32_"). The XCONCAT2 macro will + cause the inner CONCAT2 macros to be evaluated first, producing + still-valid pp-tokens. Then the final concatenation can be done. */ +#undef CONCAT4 +#define CONCAT4(a,b,c,d) XCONCAT2(CONCAT2(a,b),CONCAT2(c,d)) +#endif +#endif + +/* The word size used by BFD on the host. This may be 64 with a 32 + bit target if the host is 64 bit, or if other 64 bit targets have + been selected with --enable-targets, or if --enable-64-bit-bfd. */ +#define BFD_ARCH_SIZE @wordsize@ + +/* The word size of the default bfd target. */ +#define BFD_DEFAULT_TARGET_SIZE @bfd_default_target_size@ + +#define BFD_HOST_64BIT_LONG @BFD_HOST_64BIT_LONG@ +#if @BFD_HOST_64_BIT_DEFINED@ +#define BFD_HOST_64_BIT @BFD_HOST_64_BIT@ +#define BFD_HOST_U_64_BIT @BFD_HOST_U_64_BIT@ +#endif + +#if BFD_ARCH_SIZE >= 64 +#define BFD64 +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +/* Forward declaration. */ +typedef struct bfd bfd; + +/* Boolean type used in bfd. Too many systems define their own + versions of "boolean" for us to safely typedef a "boolean" of + our own. Using an enum for "bfd_boolean" has its own set of + problems, with strange looking casts required to avoid warnings + on some older compilers. Thus we just use an int. + + General rule: Functions which are bfd_boolean return TRUE on + success and FALSE on failure (unless they're a predicate). */ + +typedef int bfd_boolean; +#undef FALSE +#undef TRUE +#define FALSE 0 +#define TRUE 1 + +#if 0 +/* Poison. */ +#undef false +#undef true +#define false dont_use_false_in_bfd +#define true dont_use_true_in_bfd +#endif + +/* Support for different sizes of target format ints and addresses. + If the type `long' is at least 64 bits, BFD_HOST_64BIT_LONG will be + set to 1 above. Otherwise, if gcc is being used, this code will + use gcc's "long long" type. Otherwise, BFD_HOST_64_BIT must be + defined above. */ + +#ifndef BFD_HOST_64_BIT +# if BFD_HOST_64BIT_LONG +# define BFD_HOST_64_BIT long +# define BFD_HOST_U_64_BIT unsigned long +# else +# ifdef __GNUC__ +# if __GNUC__ >= 2 +# define BFD_HOST_64_BIT long long +# define BFD_HOST_U_64_BIT unsigned long long +# endif /* __GNUC__ >= 2 */ +# endif /* ! defined (__GNUC__) */ +# endif /* ! BFD_HOST_64BIT_LONG */ +#endif /* ! defined (BFD_HOST_64_BIT) */ + +#ifdef BFD64 + +#ifndef BFD_HOST_64_BIT + #error No 64 bit integer type available +#endif /* ! defined (BFD_HOST_64_BIT) */ + +typedef BFD_HOST_U_64_BIT bfd_vma; +typedef BFD_HOST_64_BIT bfd_signed_vma; +typedef BFD_HOST_U_64_BIT bfd_size_type; +typedef BFD_HOST_U_64_BIT symvalue; + +#ifndef fprintf_vma +#if BFD_HOST_64BIT_LONG +#define sprintf_vma(s,x) sprintf (s, "%016lx", x) +#define fprintf_vma(f,x) fprintf (f, "%016lx", x) +#else +#define _bfd_int64_low(x) ((unsigned long) (((x) & 0xffffffff))) +#define _bfd_int64_high(x) ((unsigned long) (((x) >> 32) & 0xffffffff)) +#define fprintf_vma(s,x) \ + fprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#define sprintf_vma(s,x) \ + sprintf ((s), "%08lx%08lx", _bfd_int64_high (x), _bfd_int64_low (x)) +#endif +#endif + +#else /* not BFD64 */ + +/* Represent a target address. Also used as a generic unsigned type + which is guaranteed to be big enough to hold any arithmetic types + we need to deal with. */ +typedef unsigned long bfd_vma; + +/* A generic signed type which is guaranteed to be big enough to hold any + arithmetic types we need to deal with. Can be assumed to be compatible + with bfd_vma in the same way that signed and unsigned ints are compatible + (as parameters, in assignment, etc). */ +typedef long bfd_signed_vma; + +typedef unsigned long symvalue; +typedef unsigned long bfd_size_type; + +/* Print a bfd_vma x on stream s. */ +#define fprintf_vma(s,x) fprintf (s, "%08lx", x) +#define sprintf_vma(s,x) sprintf (s, "%08lx", x) + +#endif /* not BFD64 */ + +/* A pointer to a position in a file. */ +/* FIXME: This should be using off_t from . + For now, try to avoid breaking stuff by not including here. + This will break on systems with 64-bit file offsets (e.g. 4.4BSD). + Probably the best long-term answer is to avoid using file_ptr AND off_t + in this header file, and to handle this in the BFD implementation + rather than in its interface. */ +/* typedef off_t file_ptr; */ +typedef bfd_signed_vma file_ptr; +typedef bfd_vma ufile_ptr; + +extern void bfd_sprintf_vma + PARAMS ((bfd *, char *, bfd_vma)); +extern void bfd_fprintf_vma + PARAMS ((bfd *, PTR, bfd_vma)); + +#define printf_vma(x) fprintf_vma(stdout,x) +#define bfd_printf_vma(abfd,x) bfd_fprintf_vma (abfd,stdout,x) + +typedef unsigned int flagword; /* 32 bits of flags */ +typedef unsigned char bfd_byte; + +/* File formats. */ + +typedef enum bfd_format +{ + bfd_unknown = 0, /* File format is unknown. */ + bfd_object, /* Linker/assember/compiler output. */ + bfd_archive, /* Object archive file. */ + bfd_core, /* Core dump. */ + bfd_type_end /* Marks the end; don't use it! */ +} +bfd_format; + +/* 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 + they indicate the set of flags used by that backend (not all flags + are meaningful for all object file formats) (FIXME: at the moment, + the object_flags values have mostly just been copied from backend + to another, and are not necessarily correct). */ + +/* No flags. */ +#define BFD_NO_FLAGS 0x00 + +/* BFD contains relocation entries. */ +#define HAS_RELOC 0x01 + +/* BFD is directly executable. */ +#define EXEC_P 0x02 + +/* BFD has line number information (basically used for F_LNNO in a + COFF header). */ +#define HAS_LINENO 0x04 + +/* BFD has debugging information. */ +#define HAS_DEBUG 0x08 + +/* BFD has symbols. */ +#define HAS_SYMS 0x10 + +/* BFD has local symbols (basically used for F_LSYMS in a COFF + header). */ +#define HAS_LOCALS 0x20 + +/* BFD is a dynamic object. */ +#define DYNAMIC 0x40 + +/* Text section is write protected (if D_PAGED is not set, this is + like an a.out NMAGIC file) (the linker sets this by default, but + clears it for -r or -N). */ +#define WP_TEXT 0x80 + +/* BFD is dynamically paged (this is like an a.out ZMAGIC file) (the + linker sets this by default, but clears it for -r or -n or -N). */ +#define D_PAGED 0x100 + +/* BFD is relaxable (this means that bfd_relax_section may be able to + do something) (sometimes bfd_relax_section can do something even if + this is not set). */ +#define BFD_IS_RELAXABLE 0x200 + +/* This may be set before writing out a BFD to request using a + traditional format. For example, this is used to request that when + writing out an a.out object the symbols not be hashed to eliminate + duplicates. */ +#define BFD_TRADITIONAL_FORMAT 0x400 + +/* This flag indicates that the BFD contents are actually cached in + memory. If this is set, iostream points to a bfd_in_memory struct. */ +#define BFD_IN_MEMORY 0x800 + +/* The sections in this BFD specify a memory page. */ +#define HAS_LOAD_PAGE 0x1000 + +/* Symbols and relocation. */ + +/* A count of carsyms (canonical archive symbols). */ +typedef unsigned long symindex; + +/* How to perform a relocation. */ +typedef const struct reloc_howto_struct reloc_howto_type; + +#define BFD_NO_MORE_SYMBOLS ((symindex) ~0) + +/* General purpose part of a symbol X; + target specific parts are in libcoff.h, libaout.h, etc. */ + +#define bfd_get_section(x) ((x)->section) +#define bfd_get_output_section(x) ((x)->section->output_section) +#define bfd_set_section(x,y) ((x)->section) = (y) +#define bfd_asymbol_base(x) ((x)->section->vma) +#define bfd_asymbol_value(x) (bfd_asymbol_base(x) + (x)->value) +#define bfd_asymbol_name(x) ((x)->name) +/*Perhaps future: #define bfd_asymbol_bfd(x) ((x)->section->owner)*/ +#define bfd_asymbol_bfd(x) ((x)->the_bfd) +#define bfd_asymbol_flavour(x) (bfd_asymbol_bfd(x)->xvec->flavour) + +/* A canonical archive symbol. */ +/* This is a type pun with struct ranlib on purpose! */ +typedef struct carsym +{ + char *name; + file_ptr file_offset; /* Look here to find the file. */ +} +carsym; /* To make these you call a carsymogen. */ + +/* Used in generating armaps (archive tables of contents). + Perhaps just a forward definition would do? */ +struct orl /* Output ranlib. */ +{ + char **name; /* Symbol name. */ + union + { + file_ptr pos; + bfd *abfd; + } u; /* bfd* or file position. */ + int namidx; /* Index into string table. */ +}; + +/* Linenumber stuff. */ +typedef struct lineno_cache_entry +{ + unsigned int line_number; /* Linenumber from start of function. */ + union + { + struct symbol_cache_entry *sym; /* Function name. */ + bfd_vma offset; /* Offset into section. */ + } u; +} +alent; + +/* Object and core file sections. */ + +#define align_power(addr, align) \ + (((addr) + ((bfd_vma) 1 << (align)) - 1) & ((bfd_vma) -1 << (align))) + +typedef struct sec *sec_ptr; + +#define bfd_get_section_name(bfd, ptr) ((ptr)->name + 0) +#define bfd_get_section_vma(bfd, ptr) ((ptr)->vma + 0) +#define bfd_get_section_lma(bfd, ptr) ((ptr)->lma + 0) +#define bfd_get_section_alignment(bfd, ptr) ((ptr)->alignment_power + 0) +#define bfd_section_name(bfd, ptr) ((ptr)->name) +#define bfd_section_size(bfd, ptr) (bfd_get_section_size_before_reloc(ptr)) +#define bfd_section_vma(bfd, ptr) ((ptr)->vma) +#define bfd_section_lma(bfd, ptr) ((ptr)->lma) +#define bfd_section_alignment(bfd, ptr) ((ptr)->alignment_power) +#define bfd_get_section_flags(bfd, ptr) ((ptr)->flags + 0) +#define bfd_get_section_userdata(bfd, ptr) ((ptr)->userdata) + +#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) + +typedef struct stat stat_type; + +typedef enum bfd_print_symbol +{ + bfd_print_symbol_name, + bfd_print_symbol_more, + bfd_print_symbol_all +} bfd_print_symbol_type; + +/* Information about a symbol that nm needs. */ + +typedef struct _symbol_info +{ + symvalue value; + char type; + const char *name; /* Symbol name. */ + unsigned char stab_type; /* Stab type. */ + char stab_other; /* Stab other. */ + short stab_desc; /* Stab desc. */ + const char *stab_name; /* String for stab type. */ +} symbol_info; + +/* Get the name of a stabs type code. */ + +extern const char *bfd_get_stab_name + PARAMS ((int)); + +/* Hash table routines. There is no way to free up a hash table. */ + +/* An element in the hash table. Most uses will actually use a larger + structure, and an instance of this will be the first field. */ + +struct bfd_hash_entry +{ + /* Next entry for this hash code. */ + struct bfd_hash_entry *next; + /* String being hashed. */ + const char *string; + /* Hash code. This is the full hash code, not the index into the + table. */ + unsigned long hash; +}; + +/* A hash table. */ + +struct bfd_hash_table +{ + /* The hash array. */ + struct bfd_hash_entry **table; + /* The number of slots in the hash table. */ + unsigned int size; + /* A function used to create new elements in the hash table. The + first entry is itself a pointer to an element. When this + function is first invoked, this pointer will be NULL. However, + having the pointer permits a hierarchy of method functions to be + built each of which calls the function in the superclass. Thus + each function should be written to allocate a new block of memory + only if the argument is NULL. */ + struct bfd_hash_entry *(*newfunc) + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + /* An objalloc for this hash table. This is a struct objalloc *, + but we use PTR to avoid requiring the inclusion of objalloc.h. */ + PTR memory; +}; + +/* Initialize a hash table. */ +extern bfd_boolean bfd_hash_table_init + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Initialize a hash table specifying a size. */ +extern bfd_boolean bfd_hash_table_init_n + PARAMS ((struct bfd_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int size)); + +/* Free up a hash table. */ +extern void bfd_hash_table_free + PARAMS ((struct bfd_hash_table *)); + +/* Look up a string in a hash table. If CREATE is TRUE, a new entry + will be created for this string if one does not already exist. The + COPY argument must be TRUE if this routine should copy the string + into newly allocated memory when adding an entry. */ +extern struct bfd_hash_entry *bfd_hash_lookup + PARAMS ((struct bfd_hash_table *, const char *, bfd_boolean create, + bfd_boolean copy)); + +/* Replace an entry in a hash table. */ +extern void bfd_hash_replace + PARAMS ((struct bfd_hash_table *, struct bfd_hash_entry *old, + struct bfd_hash_entry *nw)); + +/* Base method for creating a hash table entry. */ +extern struct bfd_hash_entry *bfd_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); + +/* Grab some space for a hash table entry. */ +extern PTR bfd_hash_allocate + PARAMS ((struct bfd_hash_table *, unsigned int)); + +/* Traverse a hash table in a random order, calling a function on each + element. If the function returns FALSE, the traversal stops. The + INFO argument is passed to the function. */ +extern void bfd_hash_traverse + PARAMS ((struct bfd_hash_table *, + bfd_boolean (*) (struct bfd_hash_entry *, PTR), + PTR info)); + +#define COFF_SWAP_TABLE (PTR) &bfd_coff_std_swap_table + +/* User program access to BFD facilities. */ + +/* Direct I/O routines, for programs which know more about the object + file than BFD does. Use higher level routines if possible. */ + +extern bfd_size_type bfd_bread + PARAMS ((PTR, bfd_size_type, bfd *)); +extern bfd_size_type bfd_bwrite + PARAMS ((const PTR, bfd_size_type, bfd *)); +extern int bfd_seek + PARAMS ((bfd *, file_ptr, int)); +extern ufile_ptr bfd_tell + PARAMS ((bfd *)); +extern int bfd_flush + PARAMS ((bfd *)); +extern int bfd_stat + PARAMS ((bfd *, struct stat *)); + +/* Deprecated old routines. */ +#if __GNUC__ +#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ + (warn_deprecated ("bfd_read", __FILE__, __LINE__, __FUNCTION__), \ + bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) +#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ + (warn_deprecated ("bfd_write", __FILE__, __LINE__, __FUNCTION__), \ + bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) +#else +#define bfd_read(BUF, ELTSIZE, NITEMS, ABFD) \ + (warn_deprecated ("bfd_read", (const char *) 0, 0, (const char *) 0), \ + bfd_bread ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) +#define bfd_write(BUF, ELTSIZE, NITEMS, ABFD) \ + (warn_deprecated ("bfd_write", (const char *) 0, 0, (const char *) 0),\ + bfd_bwrite ((BUF), (ELTSIZE) * (NITEMS), (ABFD))) +#endif +extern void warn_deprecated + PARAMS ((const char *, const char *, int, const char *)); + +/* Cast from const char * to char * so that caller can assign to + a char * without a warning. */ +#define bfd_get_filename(abfd) ((char *) (abfd)->filename) +#define bfd_get_cacheable(abfd) ((abfd)->cacheable) +#define bfd_get_format(abfd) ((abfd)->format) +#define bfd_get_target(abfd) ((abfd)->xvec->name) +#define bfd_get_flavour(abfd) ((abfd)->xvec->flavour) +#define bfd_family_coff(abfd) \ + (bfd_get_flavour (abfd) == bfd_target_coff_flavour || \ + bfd_get_flavour (abfd) == bfd_target_xcoff_flavour) +#define bfd_big_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_BIG) +#define bfd_little_endian(abfd) ((abfd)->xvec->byteorder == BFD_ENDIAN_LITTLE) +#define bfd_header_big_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_BIG) +#define bfd_header_little_endian(abfd) \ + ((abfd)->xvec->header_byteorder == BFD_ENDIAN_LITTLE) +#define bfd_get_file_flags(abfd) ((abfd)->flags) +#define bfd_applicable_file_flags(abfd) ((abfd)->xvec->object_flags) +#define bfd_applicable_section_flags(abfd) ((abfd)->xvec->section_flags) +#define bfd_my_archive(abfd) ((abfd)->my_archive) +#define bfd_has_map(abfd) ((abfd)->has_armap) + +#define bfd_valid_reloc_types(abfd) ((abfd)->xvec->valid_reloc_types) +#define bfd_usrdata(abfd) ((abfd)->usrdata) + +#define bfd_get_start_address(abfd) ((abfd)->start_address) +#define bfd_get_symcount(abfd) ((abfd)->symcount) +#define bfd_get_outsymbols(abfd) ((abfd)->outsymbols) +#define bfd_count_sections(abfd) ((abfd)->section_count) + +#define bfd_get_dynamic_symcount(abfd) ((abfd)->dynsymcount) + +#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 + PARAMS ((bfd *abfd)); +/* NB: This declaration should match the autogenerated one in libbfd.h. */ + +extern bfd_boolean bfd_record_phdr + PARAMS ((bfd *, unsigned long, bfd_boolean, flagword, bfd_boolean, bfd_vma, + bfd_boolean, bfd_boolean, unsigned int, struct sec **)); + +/* Byte swapping routines. */ + +bfd_vma bfd_getb64 + PARAMS ((const unsigned char *)); +bfd_vma bfd_getl64 + PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_64 + PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_64 + PARAMS ((const unsigned char *)); +bfd_vma bfd_getb32 + PARAMS ((const unsigned char *)); +bfd_vma bfd_getl32 + PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_32 + PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_32 + PARAMS ((const unsigned char *)); +bfd_vma bfd_getb16 + PARAMS ((const unsigned char *)); +bfd_vma bfd_getl16 + PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getb_signed_16 + PARAMS ((const unsigned char *)); +bfd_signed_vma bfd_getl_signed_16 + PARAMS ((const unsigned char *)); +void bfd_putb64 + PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl64 + PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb32 + PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl32 + PARAMS ((bfd_vma, unsigned char *)); +void bfd_putb16 + PARAMS ((bfd_vma, unsigned char *)); +void bfd_putl16 + PARAMS ((bfd_vma, unsigned char *)); + +/* Byte swapping routines which take size and endiannes as arguments. */ + +bfd_vma bfd_get_bits + PARAMS ((bfd_byte *, int, bfd_boolean)); +void bfd_put_bits + PARAMS ((bfd_vma, bfd_byte *, int, bfd_boolean)); + +/* Externally visible ECOFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_debug_info; +struct ecoff_debug_swap; +struct ecoff_extr; +struct symbol_cache_entry; +struct bfd_link_info; +struct bfd_link_hash_entry; +struct bfd_elf_version_tree; +#endif +extern bfd_vma bfd_ecoff_get_gp_value + PARAMS ((bfd * abfd)); +extern bfd_boolean bfd_ecoff_set_gp_value + PARAMS ((bfd *abfd, bfd_vma gp_value)); +extern bfd_boolean bfd_ecoff_set_regmasks + PARAMS ((bfd *abfd, unsigned long gprmask, unsigned long fprmask, + unsigned long *cprmask)); +extern PTR bfd_ecoff_debug_init + PARAMS ((bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern void bfd_ecoff_debug_free + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + struct bfd_link_info *)); +extern bfd_boolean bfd_ecoff_debug_accumulate + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, + bfd *input_bfd, struct ecoff_debug_info *input_debug, + const struct ecoff_debug_swap *input_swap, + struct bfd_link_info *)); +extern bfd_boolean bfd_ecoff_debug_accumulate_other + PARAMS ((PTR handle, bfd *output_bfd, struct ecoff_debug_info *output_debug, + const struct ecoff_debug_swap *output_swap, bfd *input_bfd, + struct bfd_link_info *)); +extern bfd_boolean bfd_ecoff_debug_externals + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + bfd_boolean relocateable, + bfd_boolean (*get_extr) (struct symbol_cache_entry *, + struct ecoff_extr *), + void (*set_index) (struct symbol_cache_entry *, + bfd_size_type))); +extern bfd_boolean bfd_ecoff_debug_one_external + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + const char *name, struct ecoff_extr *esym)); +extern bfd_size_type bfd_ecoff_debug_size + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap)); +extern bfd_boolean bfd_ecoff_write_debug + PARAMS ((bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, file_ptr where)); +extern bfd_boolean bfd_ecoff_write_accumulated_debug + PARAMS ((PTR handle, bfd *abfd, struct ecoff_debug_info *debug, + const struct ecoff_debug_swap *swap, + struct bfd_link_info *info, file_ptr where)); +extern bfd_boolean bfd_mips_ecoff_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* Externally visible ELF routines. */ + +struct bfd_link_needed_list +{ + struct bfd_link_needed_list *next; + bfd *by; + const char *name; +}; + +extern bfd_boolean bfd_elf32_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, bfd_boolean)); +extern bfd_boolean bfd_elf64_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *, bfd_boolean)); +extern struct bfd_link_needed_list *bfd_elf_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_elf_get_bfd_needed_list + PARAMS ((bfd *, struct bfd_link_needed_list **)); +extern bfd_boolean bfd_elf32_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, const char *, + const char * const *, struct bfd_link_info *, struct sec **, + struct bfd_elf_version_tree *)); +extern bfd_boolean bfd_elf64_size_dynamic_sections + PARAMS ((bfd *, const char *, const char *, const char *, + const char * const *, struct bfd_link_info *, struct sec **, + struct bfd_elf_version_tree *)); +extern void bfd_elf_set_dt_needed_name + PARAMS ((bfd *, const char *)); +extern void bfd_elf_set_dt_needed_soname + PARAMS ((bfd *, const char *)); +extern const char *bfd_elf_get_dt_soname + PARAMS ((bfd *)); +extern struct bfd_link_needed_list *bfd_elf_get_runpath_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_elf32_discard_info + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_elf64_discard_info + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Return an upper bound on the number of bytes required to store a + copy of ABFD's program header table entries. Return -1 if an error + occurs; bfd_get_error will return an appropriate code. */ +extern long bfd_get_elf_phdr_upper_bound + PARAMS ((bfd *abfd)); + +/* Copy ABFD's program header table entries to *PHDRS. The entries + will be stored as an array of Elf_Internal_Phdr structures, as + defined in include/elf/internal.h. To find out how large the + buffer needs to be, call bfd_get_elf_phdr_upper_bound. + + Return the number of program header table entries read, or -1 if an + error occurs; bfd_get_error will return an appropriate code. */ +extern int bfd_get_elf_phdrs + PARAMS ((bfd *abfd, void *phdrs)); + +/* Return the arch_size field of an elf bfd, or -1 if not elf. */ +extern int bfd_get_arch_size + PARAMS ((bfd *)); + +/* Return TRUE if address "naturally" sign extends, or -1 if not elf. */ +extern int bfd_get_sign_extend_vma + PARAMS ((bfd *)); + +extern bfd_boolean bfd_m68k_elf32_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); +extern bfd_boolean bfd_mips_elf32_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* SunOS shared library support routines for the linker. */ + +extern struct bfd_link_needed_list *bfd_sunos_get_needed_list + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_sunos_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern bfd_boolean bfd_sunos_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, struct sec **, struct sec **, + struct sec **)); + +/* Linux shared library support routines for the linker. */ + +extern bfd_boolean bfd_i386linux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_m68klinux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_sparclinux_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +/* mmap hacks */ + +struct _bfd_window_internal; +typedef struct _bfd_window_internal bfd_window_internal; + +typedef struct _bfd_window +{ + /* What the user asked for. */ + PTR data; + bfd_size_type size; + /* The actual window used by BFD. Small user-requested read-only + regions sharing a page may share a single window into the object + file. Read-write versions shouldn't until I've fixed things to + keep track of which portions have been claimed by the + application; don't want to give the same region back when the + application wants two writable copies! */ + struct _bfd_window_internal *i; +} +bfd_window; + +extern void bfd_init_window + PARAMS ((bfd_window *)); +extern void bfd_free_window + PARAMS ((bfd_window *)); +extern bfd_boolean bfd_get_file_window + PARAMS ((bfd *, file_ptr, bfd_size_type, bfd_window *, bfd_boolean)); + +/* XCOFF support routines for the linker. */ + +extern bfd_boolean bfd_xcoff_link_record_set + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_size_type)); +extern bfd_boolean bfd_xcoff_import_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, + bfd_vma, const char *, const char *, const char *, unsigned int)); +extern bfd_boolean bfd_xcoff_export_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *)); +extern bfd_boolean bfd_xcoff_link_count_reloc + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern bfd_boolean bfd_xcoff_record_link_assignment + PARAMS ((bfd *, struct bfd_link_info *, const char *)); +extern bfd_boolean bfd_xcoff_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *, const char *, const char *, + unsigned long, unsigned long, unsigned long, bfd_boolean, + int, bfd_boolean, bfd_boolean, struct sec **, bfd_boolean)); +extern bfd_boolean bfd_xcoff_link_generate_rtinit + PARAMS ((bfd *, const char *, const char *, bfd_boolean)); + +/* XCOFF support routines for ar. */ +extern bfd_boolean bfd_xcoff_ar_archive_set_magic + PARAMS ((bfd *, char *)); + +/* Externally visible COFF routines. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct internal_syment; +union internal_auxent; +#endif + +extern bfd_boolean bfd_coff_get_syment + PARAMS ((bfd *, struct symbol_cache_entry *, struct internal_syment *)); + +extern bfd_boolean bfd_coff_get_auxent + PARAMS ((bfd *, struct symbol_cache_entry *, int, union internal_auxent *)); + +extern bfd_boolean bfd_coff_set_symbol_class + PARAMS ((bfd *, struct symbol_cache_entry *, unsigned int)); + +extern bfd_boolean bfd_m68k_coff_create_embedded_relocs + PARAMS ((bfd *, struct bfd_link_info *, struct sec *, struct sec *, + char **)); + +/* ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_arm_allocate_interworking_sections + PARAMS ((struct bfd_link_info *)); + +extern bfd_boolean bfd_arm_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *, int)); + +extern bfd_boolean bfd_arm_get_bfd_for_interworking + PARAMS ((bfd *, struct bfd_link_info *)); + +/* PE ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_arm_pe_allocate_interworking_sections + PARAMS ((struct bfd_link_info *)); + +extern bfd_boolean bfd_arm_pe_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *, int)); + +extern bfd_boolean bfd_arm_pe_get_bfd_for_interworking + PARAMS ((bfd *, struct bfd_link_info *)); + +/* ELF ARM Interworking support. Called from linker. */ +extern bfd_boolean bfd_elf32_arm_allocate_interworking_sections + PARAMS ((struct bfd_link_info *)); + +extern bfd_boolean bfd_elf32_arm_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *, int)); + +extern bfd_boolean bfd_elf32_arm_get_bfd_for_interworking + PARAMS ((bfd *, struct bfd_link_info *)); + +extern bfd_boolean bfd_elf32_arm_add_glue_sections_to_bfd + PARAMS ((bfd *, struct bfd_link_info *)); + +/* ARM Note section processing. */ +extern bfd_boolean bfd_arm_merge_machines + PARAMS ((bfd *, bfd *)); + +extern bfd_boolean bfd_arm_update_notes + PARAMS ((bfd *, const char *)); + +extern unsigned int bfd_arm_get_mach_from_notes + PARAMS ((bfd *, const char *)); + +/* TI COFF load page support. */ +extern void bfd_ticoff_set_section_load_page + PARAMS ((struct sec *, int)); + +extern int bfd_ticoff_get_section_load_page + PARAMS ((struct sec *)); + +/* Extracted from init.c. */ +void +bfd_init PARAMS ((void)); + +/* Extracted from opncls.c. */ +bfd * +bfd_openr PARAMS ((const char *filename, const char *target)); + +bfd * +bfd_fdopenr PARAMS ((const char *filename, const char *target, int fd)); + +bfd * +bfd_openstreamr PARAMS ((const char *, const char *, PTR)); + +bfd * +bfd_openw PARAMS ((const char *filename, const char *target)); + +bfd_boolean +bfd_close PARAMS ((bfd *abfd)); + +bfd_boolean +bfd_close_all_done PARAMS ((bfd *)); + +bfd * +bfd_create PARAMS ((const char *filename, bfd *templ)); + +bfd_boolean +bfd_make_writable PARAMS ((bfd *abfd)); + +bfd_boolean +bfd_make_readable PARAMS ((bfd *abfd)); + +char * +bfd_follow_gnu_debuglink PARAMS ((bfd *abfd, const char *dir)); + +/* Extracted from libbfd.c. */ + +/* Byte swapping macros for user section data. */ + +#define bfd_put_8(abfd, val, ptr) \ + ((void) (*((unsigned char *) (ptr)) = (unsigned char) (val))) +#define bfd_put_signed_8 \ + bfd_put_8 +#define bfd_get_8(abfd, ptr) \ + (*(unsigned char *) (ptr) & 0xff) +#define bfd_get_signed_8(abfd, ptr) \ + (((*(unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80) + +#define bfd_put_16(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +#define bfd_put_signed_16 \ + bfd_put_16 +#define bfd_get_16(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx16, (ptr)) +#define bfd_get_signed_16(abfd, ptr) \ + BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) + +#define bfd_put_32(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +#define bfd_put_signed_32 \ + bfd_put_32 +#define bfd_get_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx32, (ptr)) +#define bfd_get_signed_32(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) + +#define bfd_put_64(abfd, val, ptr) \ + BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +#define bfd_put_signed_64 \ + bfd_put_64 +#define bfd_get_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx64, (ptr)) +#define bfd_get_signed_64(abfd, ptr) \ + BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) + +#define bfd_get(bits, abfd, ptr) \ + ( (bits) == 8 ? (bfd_vma) bfd_get_8 (abfd, ptr) \ + : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ + : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ + : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ + : (abort (), (bfd_vma) - 1)) + +#define bfd_put(bits, abfd, val, ptr) \ + ( (bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ + : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ + : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ + : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ + : (abort (), (void) 0)) + + +/* Byte swapping macros for file header data. */ + +#define bfd_h_put_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_put_signed_8(abfd, val, ptr) \ + bfd_put_8 (abfd, val, ptr) +#define bfd_h_get_8(abfd, ptr) \ + bfd_get_8 (abfd, ptr) +#define bfd_h_get_signed_8(abfd, ptr) \ + bfd_get_signed_8 (abfd, ptr) + +#define bfd_h_put_16(abfd, val, ptr) \ + BFD_SEND (abfd, bfd_h_putx16, (val, ptr)) +#define bfd_h_put_signed_16 \ + bfd_h_put_16 +#define bfd_h_get_16(abfd, ptr) \ + BFD_SEND (abfd, bfd_h_getx16, (ptr)) +#define bfd_h_get_signed_16(abfd, ptr) \ + BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr)) + +#define bfd_h_put_32(abfd, val, ptr) \ + BFD_SEND (abfd, bfd_h_putx32, (val, ptr)) +#define bfd_h_put_signed_32 \ + bfd_h_put_32 +#define bfd_h_get_32(abfd, ptr) \ + BFD_SEND (abfd, bfd_h_getx32, (ptr)) +#define bfd_h_get_signed_32(abfd, ptr) \ + BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr)) + +#define bfd_h_put_64(abfd, val, ptr) \ + BFD_SEND (abfd, bfd_h_putx64, (val, ptr)) +#define bfd_h_put_signed_64 \ + bfd_h_put_64 +#define bfd_h_get_64(abfd, ptr) \ + BFD_SEND (abfd, bfd_h_getx64, (ptr)) +#define bfd_h_get_signed_64(abfd, ptr) \ + BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr)) + +/* Refinements on the above, which should eventually go away. Save + cluttering the source with (bfd_vma) and (bfd_byte *) casts. */ + +#define H_PUT_64(abfd, val, where) \ + bfd_h_put_64 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_32(abfd, val, where) \ + bfd_h_put_32 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_16(abfd, val, where) \ + bfd_h_put_16 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_8 bfd_h_put_8 + +#define H_PUT_S64(abfd, val, where) \ + bfd_h_put_signed_64 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_S32(abfd, val, where) \ + bfd_h_put_signed_32 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_S16(abfd, val, where) \ + bfd_h_put_signed_16 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_S8 bfd_h_put_signed_8 + +#define H_GET_64(abfd, where) \ + bfd_h_get_64 ((abfd), (bfd_byte *) (where)) + +#define H_GET_32(abfd, where) \ + bfd_h_get_32 ((abfd), (bfd_byte *) (where)) + +#define H_GET_16(abfd, where) \ + bfd_h_get_16 ((abfd), (bfd_byte *) (where)) + +#define H_GET_8 bfd_h_get_8 + +#define H_GET_S64(abfd, where) \ + bfd_h_get_signed_64 ((abfd), (bfd_byte *) (where)) + +#define H_GET_S32(abfd, where) \ + bfd_h_get_signed_32 ((abfd), (bfd_byte *) (where)) + +#define H_GET_S16(abfd, where) \ + bfd_h_get_signed_16 ((abfd), (bfd_byte *) (where)) + +#define H_GET_S8 bfd_h_get_signed_8 + + +/* Extracted from bfdio.c. */ +long +bfd_get_mtime PARAMS ((bfd *abfd)); + +long +bfd_get_size PARAMS ((bfd *abfd)); + +/* Extracted from bfdwin.c. */ +/* Extracted from section.c. */ +/* 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 bfd_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; +}; + +typedef struct sec +{ + /* The name of the section; the name isn't a copy, the pointer is + the same as that passed to bfd_make_section. */ + const char *name; + + /* A unique sequence number. */ + int id; + + /* Which section in the bfd; 0..n-1 as sections are created in a bfd. */ + int index; + + /* The next section in the list belonging to the BFD, or NULL. */ + struct sec *next; + + /* The field flags contains attributes of the section. Some + flags are read in from the object file, and some are + synthesized from other information. */ + flagword flags; + +#define SEC_NO_FLAGS 0x000 + + /* Tells the OS to allocate space for this section when loading. + This is clear for a section containing debug information only. */ +#define SEC_ALLOC 0x001 + + /* Tells the OS to load the section from the file when loading. + This is clear for a .bss section. */ +#define SEC_LOAD 0x002 + + /* The section contains data still to be relocated, so there is + some relocation information too. */ +#define SEC_RELOC 0x004 + + /* ELF reserves 4 processor specific bits and 8 operating system + specific bits in sh_flags; at present we can get away with just + one in communicating between the assembler and BFD, but this + isn't a good long-term solution. */ +#define SEC_ARCH_BIT_0 0x008 + + /* A signal to the OS that the section contains read only data. */ +#define SEC_READONLY 0x010 + + /* The section contains code only. */ +#define SEC_CODE 0x020 + + /* The section contains data only. */ +#define SEC_DATA 0x040 + + /* The section will reside in ROM. */ +#define SEC_ROM 0x080 + + /* The section contains constructor information. This section + type is used by the linker to create lists of constructors and + destructors used by <>. When a back end sees a symbol + which should be used in a constructor list, it creates a new + section for the type of name (e.g., <<__CTOR_LIST__>>), attaches + the symbol to it, and builds a relocation. To build the lists + of constructors, all the linker has to do is catenate all the + sections called <<__CTOR_LIST__>> and relocate the data + contained within - exactly the operations it would peform on + standard data. */ +#define SEC_CONSTRUCTOR 0x100 + + /* The section has contents - a data section could be + <> | <>; a debug section could be + <> */ +#define SEC_HAS_CONTENTS 0x200 + + /* An instruction to the linker to not output the section + even if it has information which would normally be written. */ +#define SEC_NEVER_LOAD 0x400 + + /* The section is a COFF shared library section. This flag is + only for the linker. If this type of section appears in + the input file, the linker must copy it to the output file + without changing the vma or size. FIXME: Although this + was originally intended to be general, it really is COFF + specific (and the flag was renamed to indicate this). It + might be cleaner to have some more general mechanism to + allow the back end to control what the linker does with + sections. */ +#define SEC_COFF_SHARED_LIBRARY 0x800 + + /* The section contains thread local data. */ +#define SEC_THREAD_LOCAL 0x1000 + + /* The section has GOT references. This flag is only for the + linker, and is currently only used by the elf32-hppa back end. + It will be set if global offset table references were detected + in this section, which indicate to the linker that the section + contains PIC code, and must be handled specially when doing a + static link. */ +#define SEC_HAS_GOT_REF 0x4000 + + /* The section contains common symbols (symbols may be defined + multiple times, the value of a symbol is the amount of + space it requires, and the largest symbol value is the one + used). Most targets have exactly one of these (which we + translate to bfd_com_section_ptr), but ECOFF has two. */ +#define SEC_IS_COMMON 0x8000 + + /* The section contains only debugging information. For + example, this is set for ELF .debug and .stab sections. + strip tests this flag to see if a section can be + discarded. */ +#define SEC_DEBUGGING 0x10000 + + /* The contents of this section are held in memory pointed to + by the contents field. This is checked by bfd_get_section_contents, + and the data is retrieved from memory if appropriate. */ +#define SEC_IN_MEMORY 0x20000 + + /* The contents of this section are to be excluded by the + linker for executable and shared objects unless those + objects are to be further relocated. */ +#define SEC_EXCLUDE 0x40000 + + /* The contents of this section are to be sorted based on the sum of + the symbol and addend values specified by the associated relocation + entries. Entries without associated relocation entries will be + appended to the end of the section in an unspecified order. */ +#define SEC_SORT_ENTRIES 0x80000 + + /* When linking, duplicate sections of the same name should be + discarded, rather than being combined into a single section as + is usually done. This is similar to how common symbols are + handled. See SEC_LINK_DUPLICATES below. */ +#define SEC_LINK_ONCE 0x100000 + + /* If SEC_LINK_ONCE is set, this bitfield describes how the linker + should handle duplicate sections. */ +#define SEC_LINK_DUPLICATES 0x600000 + + /* This value for SEC_LINK_DUPLICATES means that duplicate + sections with the same name should simply be discarded. */ +#define SEC_LINK_DUPLICATES_DISCARD 0x0 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if there are any duplicate sections, although + it should still only link one copy. */ +#define SEC_LINK_DUPLICATES_ONE_ONLY 0x200000 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if any duplicate sections are a different size. */ +#define SEC_LINK_DUPLICATES_SAME_SIZE 0x400000 + + /* This value for SEC_LINK_DUPLICATES means that the linker + should warn if any duplicate sections contain different + contents. */ +#define SEC_LINK_DUPLICATES_SAME_CONTENTS 0x600000 + + /* This section was created by the linker as part of dynamic + relocation or other arcane processing. It is skipped when + going through the first-pass output, trusting that someone + else up the line will take care of it later. */ +#define SEC_LINKER_CREATED 0x800000 + + /* This section should not be subject to garbage collection. */ +#define SEC_KEEP 0x1000000 + + /* This section contains "short" data, and should be placed + "near" the GP. */ +#define SEC_SMALL_DATA 0x2000000 + + /* This section contains data which may be shared with other + executables or shared objects. */ +#define SEC_SHARED 0x4000000 + + /* 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, it + should be aligned on a page boundary. */ +#define SEC_BLOCK 0x8000000 + + /* Conditionally link this section; do not link if there are no + references found to any symbol in the section. */ +#define SEC_CLINK 0x10000000 + + /* Attempt to merge identical entities in the section. + Entity size is given in the entsize field. */ +#define SEC_MERGE 0x20000000 + + /* If given with SEC_MERGE, entities to merge are zero terminated + strings where entsize specifies character size instead of fixed + size entries. */ +#define SEC_STRINGS 0x40000000 + + /* This section contains data about section groups. */ +#define SEC_GROUP 0x80000000 + + /* End of section flags. */ + + /* Some internal packed boolean fields. */ + + /* See the vma field. */ + unsigned int user_set_vma : 1; + + /* Whether relocations have been processed. */ + unsigned int reloc_done : 1; + + /* A mark flag used by some of the linker backends. */ + unsigned int linker_mark : 1; + + /* Another mark flag used by some of the linker backends. Set for + output sections that have an input section. */ + unsigned int linker_has_input : 1; + + /* A mark flag used by some linker backends for garbage collection. */ + unsigned int gc_mark : 1; + + /* The following flags are used by the ELF linker. */ + + /* Mark sections which have been allocated to segments. */ + unsigned int segment_mark : 1; + + /* Type of sec_info information. */ + unsigned int sec_info_type:3; +#define ELF_INFO_TYPE_NONE 0 +#define ELF_INFO_TYPE_STABS 1 +#define ELF_INFO_TYPE_MERGE 2 +#define ELF_INFO_TYPE_EH_FRAME 3 +#define ELF_INFO_TYPE_JUST_SYMS 4 + + /* Nonzero if this section uses RELA relocations, rather than REL. */ + unsigned int use_rela_p:1; + + /* Bits used by various backends. */ + unsigned int has_tls_reloc:1; + + /* Nonzero if this section needs the relax finalize pass. */ + unsigned int need_finalize_relax:1; + + /* Usused bits. */ + unsigned int flag12:1; + unsigned int flag13:1; + unsigned int flag14:1; + unsigned int flag15:1; + unsigned int flag16:4; + unsigned int flag20:4; + unsigned int flag24:8; + + /* End of internal packed boolean fields. */ + + /* The virtual memory address of the section - where it will be + at run time. The symbols are relocated against this. The + user_set_vma flag is maintained by bfd; if it's not set, the + backend can assign addresses (for example, in <>, where + the default address for <<.data>> is dependent on the specific + target and various flags). */ + bfd_vma vma; + + /* The load address of the section - where it would be in a + rom image; really only used for writing section header + information. */ + bfd_vma lma; + + /* The size of the section in octets, as it will be output. + Contains a value even if the section has no contents (e.g., the + size of <<.bss>>). This will be filled in after relocation. */ + bfd_size_type _cooked_size; + + /* The original size on disk of the section, in octets. Normally this + value is the same as the size, but if some relaxing has + been done, then this value will be bigger. */ + bfd_size_type _raw_size; + + /* If this section is going to be output, then this value is the + offset in *bytes* into the output section of the first byte in the + input section (byte ==> smallest addressable unit on the + target). In most cases, if this was going to start at the + 100th octet (8-bit quantity) in the output section, this value + would be 100. However, if the target byte size is 16 bits + (bfd_octets_per_byte is "2"), this value would be 50. */ + bfd_vma output_offset; + + /* The output section through which to map on output. */ + struct sec *output_section; + + /* The alignment requirement of the section, as an exponent of 2 - + e.g., 3 aligns to 2^3 (or 8). */ + unsigned int alignment_power; + + /* If an input section, a pointer to a vector of relocation + records for the data in this section. */ + struct reloc_cache_entry *relocation; + + /* If an output section, a pointer to a vector of pointers to + relocation records for the data in this section. */ + struct reloc_cache_entry **orelocation; + + /* The number of relocation records in one of the above. */ + unsigned reloc_count; + + /* Information below is back end specific - and not always used + or updated. */ + + /* File position of section data. */ + file_ptr filepos; + + /* File position of relocation info. */ + file_ptr rel_filepos; + + /* File position of line data. */ + file_ptr line_filepos; + + /* Pointer to data for applications. */ + PTR userdata; + + /* If the SEC_IN_MEMORY flag is set, this points to the actual + contents. */ + unsigned char *contents; + + /* Attached line number information. */ + alent *lineno; + + /* Number of line number records. */ + unsigned int lineno_count; + + /* Entity size for merging purposes. */ + unsigned int entsize; + + /* Optional information about a COMDAT entry; NULL if not COMDAT. */ + struct bfd_comdat_info *comdat; + + /* When a section is being output, this value changes as more + linenumbers are written out. */ + file_ptr moving_line_filepos; + + /* What the section number is in the target world. */ + int target_index; + + PTR used_by_bfd; + + /* If this is a constructor section then here is a list of the + relocations created to relocate items within it. */ + struct relent_chain *constructor_chain; + + /* The BFD which owns the section. */ + bfd *owner; + + /* A symbol which points at this section only. */ + struct symbol_cache_entry *symbol; + struct symbol_cache_entry **symbol_ptr_ptr; + + struct bfd_link_order *link_order_head; + struct bfd_link_order *link_order_tail; +} asection; + +/* 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. New code should use the section_ptr macros rather + than referring directly to the const sections. The const sections + may eventually vanish. */ +#define BFD_ABS_SECTION_NAME "*ABS*" +#define BFD_UND_SECTION_NAME "*UND*" +#define BFD_COM_SECTION_NAME "*COM*" +#define BFD_IND_SECTION_NAME "*IND*" + +/* The absolute section. */ +extern const asection bfd_abs_section; +#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) +#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) +/* Pointer to the undefined section. */ +extern const asection bfd_und_section; +#define bfd_und_section_ptr ((asection *) &bfd_und_section) +#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) +/* Pointer to the common section. */ +extern const asection bfd_com_section; +#define bfd_com_section_ptr ((asection *) &bfd_com_section) +/* Pointer to the indirect section. */ +extern const asection bfd_ind_section; +#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) +#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) + +#define bfd_is_const_section(SEC) \ + ( ((SEC) == bfd_abs_section_ptr) \ + || ((SEC) == bfd_und_section_ptr) \ + || ((SEC) == bfd_com_section_ptr) \ + || ((SEC) == bfd_ind_section_ptr)) + +extern const struct symbol_cache_entry * const bfd_abs_symbol; +extern const struct symbol_cache_entry * const bfd_com_symbol; +extern const struct symbol_cache_entry * const bfd_und_symbol; +extern const struct symbol_cache_entry * const bfd_ind_symbol; +#define bfd_get_section_size_before_reloc(section) \ + ((section)->reloc_done ? (abort (), (bfd_size_type) 1) \ + : (section)->_raw_size) +#define bfd_get_section_size_after_reloc(section) \ + ((section)->reloc_done ? (section)->_cooked_size \ + : (abort (), (bfd_size_type) 1)) + +/* Macros to handle insertion and deletion of a bfd's sections. These + only handle the list pointers, ie. do not adjust section_count, + target_index etc. */ +#define bfd_section_list_remove(ABFD, PS) \ + do \ + { \ + asection **_ps = PS; \ + asection *_s = *_ps; \ + *_ps = _s->next; \ + if (_s->next == NULL) \ + (ABFD)->section_tail = _ps; \ + } \ + while (0) +#define bfd_section_list_insert(ABFD, PS, S) \ + do \ + { \ + asection **_ps = PS; \ + asection *_s = S; \ + _s->next = *_ps; \ + *_ps = _s; \ + if (_s->next == NULL) \ + (ABFD)->section_tail = &_s->next; \ + } \ + while (0) + +void +bfd_section_list_clear PARAMS ((bfd *)); + +asection * +bfd_get_section_by_name PARAMS ((bfd *abfd, const char *name)); + +char * +bfd_get_unique_section_name PARAMS ((bfd *abfd, + const char *templat, + int *count)); + +asection * +bfd_make_section_old_way PARAMS ((bfd *abfd, const char *name)); + +asection * +bfd_make_section_anyway PARAMS ((bfd *abfd, const char *name)); + +asection * +bfd_make_section PARAMS ((bfd *, const char *name)); + +bfd_boolean +bfd_set_section_flags PARAMS ((bfd *abfd, asection *sec, flagword flags)); + +void +bfd_map_over_sections PARAMS ((bfd *abfd, + void (*func) (bfd *abfd, + asection *sect, + PTR obj), + PTR obj)); + +bfd_boolean +bfd_set_section_size PARAMS ((bfd *abfd, asection *sec, bfd_size_type val)); + +bfd_boolean +bfd_set_section_contents PARAMS ((bfd *abfd, asection *section, + PTR data, file_ptr offset, + bfd_size_type count)); + +bfd_boolean +bfd_get_section_contents PARAMS ((bfd *abfd, asection *section, + PTR location, file_ptr offset, + bfd_size_type count)); + +bfd_boolean +bfd_copy_private_section_data PARAMS ((bfd *ibfd, asection *isec, + bfd *obfd, asection *osec)); + +#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ + BFD_SEND (obfd, _bfd_copy_private_section_data, \ + (ibfd, isection, obfd, osection)) +void +_bfd_strip_section_from_output PARAMS ((struct bfd_link_info *info, asection *section)); + +bfd_boolean +bfd_generic_discard_group PARAMS ((bfd *abfd, asection *group)); + +/* Extracted from archures.c. */ +enum bfd_architecture +{ + bfd_arch_unknown, /* File arch not known. */ + bfd_arch_obscure, /* Arch known, not one of these. */ + bfd_arch_m68k, /* Motorola 68xxx */ +#define bfd_mach_m68000 1 +#define bfd_mach_m68008 2 +#define bfd_mach_m68010 3 +#define bfd_mach_m68020 4 +#define bfd_mach_m68030 5 +#define bfd_mach_m68040 6 +#define bfd_mach_m68060 7 +#define bfd_mach_cpu32 8 +#define bfd_mach_mcf5200 9 +#define bfd_mach_mcf5206e 10 +#define bfd_mach_mcf5307 11 +#define bfd_mach_mcf5407 12 + bfd_arch_vax, /* DEC Vax */ + bfd_arch_i960, /* Intel 960 */ + /* The order of the following is important. + lower number indicates a machine type that + only accepts a subset of the instructions + available to machines with higher numbers. + The exception is the "ca", which is + incompatible with all other machines except + "core". */ + +#define bfd_mach_i960_core 1 +#define bfd_mach_i960_ka_sa 2 +#define bfd_mach_i960_kb_sb 3 +#define bfd_mach_i960_mc 4 +#define bfd_mach_i960_xa 5 +#define bfd_mach_i960_ca 6 +#define bfd_mach_i960_jx 7 +#define bfd_mach_i960_hx 8 + + bfd_arch_or32, /* OpenRISC 32 */ + + bfd_arch_a29k, /* AMD 29000 */ + bfd_arch_sparc, /* SPARC */ +#define bfd_mach_sparc 1 +/* The difference between v8plus and v9 is that v9 is a true 64 bit env. */ +#define bfd_mach_sparc_sparclet 2 +#define bfd_mach_sparc_sparclite 3 +#define bfd_mach_sparc_v8plus 4 +#define bfd_mach_sparc_v8plusa 5 /* with ultrasparc add'ns. */ +#define bfd_mach_sparc_sparclite_le 6 +#define bfd_mach_sparc_v9 7 +#define bfd_mach_sparc_v9a 8 /* with ultrasparc add'ns. */ +#define bfd_mach_sparc_v8plusb 9 /* with cheetah add'ns. */ +#define bfd_mach_sparc_v9b 10 /* with cheetah add'ns. */ +/* Nonzero if MACH has the v9 instruction set. */ +#define bfd_mach_sparc_v9_p(mach) \ + ((mach) >= bfd_mach_sparc_v8plus && (mach) <= bfd_mach_sparc_v9b \ + && (mach) != bfd_mach_sparc_sparclite_le) + bfd_arch_mips, /* MIPS Rxxxx */ +#define bfd_mach_mips3000 3000 +#define bfd_mach_mips3900 3900 +#define bfd_mach_mips4000 4000 +#define bfd_mach_mips4010 4010 +#define bfd_mach_mips4100 4100 +#define bfd_mach_mips4111 4111 +#define bfd_mach_mips4120 4120 +#define bfd_mach_mips4300 4300 +#define bfd_mach_mips4400 4400 +#define bfd_mach_mips4600 4600 +#define bfd_mach_mips4650 4650 +#define bfd_mach_mips5000 5000 +#define bfd_mach_mips5400 5400 +#define bfd_mach_mips5500 5500 +#define bfd_mach_mips6000 6000 +#define bfd_mach_mips8000 8000 +#define bfd_mach_mips10000 10000 +#define bfd_mach_mips12000 12000 +#define bfd_mach_mips16 16 +#define bfd_mach_mips5 5 +#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */ +#define bfd_mach_mipsisa32 32 +#define bfd_mach_mipsisa32r2 33 +#define bfd_mach_mipsisa64 64 + bfd_arch_i386, /* Intel 386 */ +#define bfd_mach_i386_i386 1 +#define bfd_mach_i386_i8086 2 +#define bfd_mach_i386_i386_intel_syntax 3 +#define bfd_mach_x86_64 64 +#define bfd_mach_x86_64_intel_syntax 65 + bfd_arch_we32k, /* AT&T WE32xxx */ + bfd_arch_tahoe, /* CCI/Harris Tahoe */ + bfd_arch_i860, /* Intel 860 */ + bfd_arch_i370, /* IBM 360/370 Mainframes */ + bfd_arch_romp, /* IBM ROMP PC/RT */ + bfd_arch_alliant, /* Alliant */ + bfd_arch_convex, /* Convex */ + bfd_arch_m88k, /* Motorola 88xxx */ + bfd_arch_m98k, /* Motorola 98xxx */ + bfd_arch_pyramid, /* Pyramid Technology */ + bfd_arch_h8300, /* Renesas H8/300 (formerly Hitachi H8/300) */ +#define bfd_mach_h8300 1 +#define bfd_mach_h8300h 2 +#define bfd_mach_h8300s 3 +#define bfd_mach_h8300hn 4 +#define bfd_mach_h8300sn 5 + bfd_arch_pdp11, /* DEC PDP-11 */ + bfd_arch_powerpc, /* PowerPC */ +#define bfd_mach_ppc 32 +#define bfd_mach_ppc64 64 +#define bfd_mach_ppc_403 403 +#define bfd_mach_ppc_403gc 4030 +#define bfd_mach_ppc_505 505 +#define bfd_mach_ppc_601 601 +#define bfd_mach_ppc_602 602 +#define bfd_mach_ppc_603 603 +#define bfd_mach_ppc_ec603e 6031 +#define bfd_mach_ppc_604 604 +#define bfd_mach_ppc_620 620 +#define bfd_mach_ppc_630 630 +#define bfd_mach_ppc_750 750 +#define bfd_mach_ppc_860 860 +#define bfd_mach_ppc_a35 35 +#define bfd_mach_ppc_rs64ii 642 +#define bfd_mach_ppc_rs64iii 643 +#define bfd_mach_ppc_7400 7400 +#define bfd_mach_ppc_e500 500 + bfd_arch_rs6000, /* IBM RS/6000 */ +#define bfd_mach_rs6k 6000 +#define bfd_mach_rs6k_rs1 6001 +#define bfd_mach_rs6k_rsc 6003 +#define bfd_mach_rs6k_rs2 6002 + bfd_arch_hppa, /* HP PA RISC */ + bfd_arch_d10v, /* Mitsubishi D10V */ +#define bfd_mach_d10v 1 +#define bfd_mach_d10v_ts2 2 +#define bfd_mach_d10v_ts3 3 + bfd_arch_d30v, /* Mitsubishi D30V */ + bfd_arch_dlx, /* DLX */ + bfd_arch_m68hc11, /* Motorola 68HC11 */ + bfd_arch_m68hc12, /* Motorola 68HC12 */ +#define bfd_mach_m6812_default 0 +#define bfd_mach_m6812 1 +#define bfd_mach_m6812s 2 + bfd_arch_z8k, /* Zilog Z8000 */ +#define bfd_mach_z8001 1 +#define bfd_mach_z8002 2 + bfd_arch_h8500, /* Renesas H8/500 (formerly Hitachi H8/500) */ + bfd_arch_sh, /* Renesas / SuperH SH (formerly Hitachi SH) */ +#define bfd_mach_sh 1 +#define bfd_mach_sh2 0x20 +#define bfd_mach_sh_dsp 0x2d +#define bfd_mach_sh2e 0x2e +#define bfd_mach_sh3 0x30 +#define bfd_mach_sh3_dsp 0x3d +#define bfd_mach_sh3e 0x3e +#define bfd_mach_sh4 0x40 +#define bfd_mach_sh5 0x50 + bfd_arch_alpha, /* Dec Alpha */ +#define bfd_mach_alpha_ev4 0x10 +#define bfd_mach_alpha_ev5 0x20 +#define bfd_mach_alpha_ev6 0x30 + bfd_arch_arm, /* Advanced Risc Machines ARM. */ +#define bfd_mach_arm_unknown 0 +#define bfd_mach_arm_2 1 +#define bfd_mach_arm_2a 2 +#define bfd_mach_arm_3 3 +#define bfd_mach_arm_3M 4 +#define bfd_mach_arm_4 5 +#define bfd_mach_arm_4T 6 +#define bfd_mach_arm_5 7 +#define bfd_mach_arm_5T 8 +#define bfd_mach_arm_5TE 9 +#define bfd_mach_arm_XScale 10 +#define bfd_mach_arm_ep9312 11 +#define bfd_mach_arm_iWMMXt 12 + bfd_arch_ns32k, /* National Semiconductors ns32000 */ + bfd_arch_w65, /* WDC 65816 */ + bfd_arch_tic30, /* Texas Instruments TMS320C30 */ + bfd_arch_tic4x, /* Texas Instruments TMS320C3X/4X */ +#define bfd_mach_tic3x 30 +#define bfd_mach_tic4x 40 + bfd_arch_tic54x, /* Texas Instruments TMS320C54X */ + bfd_arch_tic80, /* TI TMS320c80 (MVP) */ + bfd_arch_v850, /* NEC V850 */ +#define bfd_mach_v850 1 +#define bfd_mach_v850e 'E' + bfd_arch_arc, /* ARC Cores */ +#define bfd_mach_arc_5 5 +#define bfd_mach_arc_6 6 +#define bfd_mach_arc_7 7 +#define bfd_mach_arc_8 8 + bfd_arch_m32r, /* Renesas M32R (formerly Mitsubishi M32R/D) */ +#define bfd_mach_m32r 1 /* For backwards compatibility. */ +#define bfd_mach_m32rx 'x' + bfd_arch_mn10200, /* Matsushita MN10200 */ + bfd_arch_mn10300, /* Matsushita MN10300 */ +#define bfd_mach_mn10300 300 +#define bfd_mach_am33 330 + bfd_arch_fr30, +#define bfd_mach_fr30 0x46523330 + bfd_arch_frv, +#define bfd_mach_frv 1 +#define bfd_mach_frvsimple 2 +#define bfd_mach_fr300 300 +#define bfd_mach_fr400 400 +#define bfd_mach_frvtomcat 499 /* fr500 prototype */ +#define bfd_mach_fr500 500 + bfd_arch_mcore, + bfd_arch_ia64, /* HP/Intel ia64 */ +#define bfd_mach_ia64_elf64 64 +#define bfd_mach_ia64_elf32 32 + bfd_arch_ip2k, /* Ubicom IP2K microcontrollers. */ +#define bfd_mach_ip2022 1 +#define bfd_mach_ip2022ext 2 + bfd_arch_iq2000, /* Vitesse IQ2000. */ +#define bfd_mach_iq2000 1 +#define bfd_mach_iq10 2 + bfd_arch_pj, + bfd_arch_avr, /* Atmel AVR microcontrollers. */ +#define bfd_mach_avr1 1 +#define bfd_mach_avr2 2 +#define bfd_mach_avr3 3 +#define bfd_mach_avr4 4 +#define bfd_mach_avr5 5 + bfd_arch_cris, /* Axis CRIS */ + bfd_arch_s390, /* IBM s390 */ +#define bfd_mach_s390_31 31 +#define bfd_mach_s390_64 64 + bfd_arch_openrisc, /* OpenRISC */ + bfd_arch_mmix, /* Donald Knuth's educational processor. */ + bfd_arch_xstormy16, +#define bfd_mach_xstormy16 1 + bfd_arch_msp430, /* Texas Instruments MSP430 architecture. */ +#define bfd_mach_msp110 110 +#define bfd_mach_msp11 11 +#define bfd_mach_msp12 12 +#define bfd_mach_msp13 13 +#define bfd_mach_msp14 14 +#define bfd_mach_msp41 41 +#define bfd_mach_msp31 31 +#define bfd_mach_msp32 32 +#define bfd_mach_msp33 33 +#define bfd_mach_msp43 43 +#define bfd_mach_msp44 44 +#define bfd_mach_msp15 15 +#define bfd_mach_msp16 16 + bfd_arch_xtensa, /* Tensilica's Xtensa cores. */ +#define bfd_mach_xtensa 1 + bfd_arch_last + }; + +typedef struct bfd_arch_info +{ + int bits_per_word; + int bits_per_address; + int bits_per_byte; + enum bfd_architecture arch; + unsigned long mach; + const char *arch_name; + const char *printable_name; + unsigned int section_align_power; + /* TRUE if this is the default machine for the architecture. + The default arch should be the first entry for an arch so that + all the entries for that arch can be accessed via <>. */ + bfd_boolean the_default; + const struct bfd_arch_info * (*compatible) + PARAMS ((const struct bfd_arch_info *a, + const struct bfd_arch_info *b)); + + bfd_boolean (*scan) PARAMS ((const struct bfd_arch_info *, const char *)); + + const struct bfd_arch_info *next; +} +bfd_arch_info_type; + +const char * +bfd_printable_name PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_scan_arch PARAMS ((const char *string)); + +const char ** +bfd_arch_list PARAMS ((void)); + +const bfd_arch_info_type * +bfd_arch_get_compatible PARAMS (( + const bfd *abfd, + const bfd *bbfd, + bfd_boolean accept_unknowns)); + +void +bfd_set_arch_info PARAMS ((bfd *abfd, const bfd_arch_info_type *arg)); + +enum bfd_architecture +bfd_get_arch PARAMS ((bfd *abfd)); + +unsigned long +bfd_get_mach PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_byte PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_bits_per_address PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_get_arch_info PARAMS ((bfd *abfd)); + +const bfd_arch_info_type * +bfd_lookup_arch PARAMS ((enum bfd_architecture + arch, + unsigned long machine)); + +const char * +bfd_printable_arch_mach PARAMS ((enum bfd_architecture arch, unsigned long machine)); + +unsigned int +bfd_octets_per_byte PARAMS ((bfd *abfd)); + +unsigned int +bfd_arch_mach_octets_per_byte PARAMS ((enum bfd_architecture arch, + unsigned long machine)); + +/* Extracted from reloc.c. */ +typedef enum bfd_reloc_status +{ + /* No errors detected. */ + bfd_reloc_ok, + + /* The relocation was performed, but there was an overflow. */ + bfd_reloc_overflow, + + /* The address to relocate was not within the section supplied. */ + bfd_reloc_outofrange, + + /* Used by special functions. */ + bfd_reloc_continue, + + /* Unsupported relocation size requested. */ + bfd_reloc_notsupported, + + /* Unused. */ + bfd_reloc_other, + + /* The symbol to relocate against was undefined. */ + bfd_reloc_undefined, + + /* The relocation was performed, but may not be ok - presently + generated only when linking i960 coff files with i960 b.out + symbols. If this type is returned, the error_message argument + to bfd_perform_relocation will be set. */ + bfd_reloc_dangerous + } + bfd_reloc_status_type; + + +typedef struct reloc_cache_entry +{ + /* A pointer into the canonical table of pointers. */ + struct symbol_cache_entry **sym_ptr_ptr; + + /* offset in section. */ + bfd_size_type address; + + /* addend for relocation value. */ + bfd_vma addend; + + /* Pointer to how to perform the required relocation. */ + reloc_howto_type *howto; + +} +arelent; + +enum complain_overflow +{ + /* Do not complain on overflow. */ + complain_overflow_dont, + + /* Complain if the bitfield overflows, whether it is considered + as signed or unsigned. */ + complain_overflow_bitfield, + + /* Complain if the value overflows when considered as signed + number. */ + complain_overflow_signed, + + /* Complain if the value overflows when considered as an + unsigned number. */ + complain_overflow_unsigned +}; + +struct reloc_howto_struct +{ + /* The type field has mainly a documentary use - the back end can + do what it wants with it, though normally the back end's + external idea of what a reloc number is stored + in this field. For example, a PC relative word relocation + in a coff environment has the type 023 - because that's + what the outside world calls a R_PCRWORD reloc. */ + unsigned int type; + + /* The value the final relocation is shifted right by. This drops + unwanted data from the relocation. */ + unsigned int rightshift; + + /* The size of the item to be relocated. This is *not* a + power-of-two measure. To get the number of bytes operated + on by a type of relocation, use bfd_get_reloc_size. */ + int size; + + /* The number of bits in the item to be relocated. This is used + when doing overflow checking. */ + unsigned int bitsize; + + /* Notes that the relocation is relative to the location in the + data section of the addend. The relocation function will + subtract from the relocation value the address of the location + being relocated. */ + bfd_boolean pc_relative; + + /* The bit position of the reloc value in the destination. + The relocated value is left shifted by this amount. */ + unsigned int bitpos; + + /* What type of overflow error should be checked for when + relocating. */ + enum complain_overflow complain_on_overflow; + + /* If this field is non null, then the supplied function is + called rather than the normal function. This allows really + strange relocation methods to be accomodated (e.g., i960 callj + instructions). */ + bfd_reloc_status_type (*special_function) + PARAMS ((bfd *, arelent *, struct symbol_cache_entry *, PTR, asection *, + bfd *, char **)); + + /* The textual name of the relocation type. */ + char *name; + + /* Some formats record a relocation addend in the section contents + rather than with the relocation. For ELF formats this is the + distinction between USE_REL and USE_RELA (though the code checks + for USE_REL == 1/0). The value of this field is TRUE if the + addend is recorded with the section contents; when performing a + partial link (ld -r) the section contents (the data) will be + modified. The value of this field is FALSE if addends are + recorded with the relocation (in arelent.addend); when performing + a partial link the relocation will be modified. + All relocations for all ELF USE_RELA targets should set this field + to FALSE (values of TRUE should be looked on with suspicion). + However, the converse is not true: not all relocations of all ELF + USE_REL targets set this field to TRUE. Why this is so is peculiar + to each particular target. For relocs that aren't used in partial + links (e.g. GOT stuff) it doesn't matter what this is set to. */ + bfd_boolean partial_inplace; + + /* src_mask selects the part of the instruction (or data) to be used + in the relocation sum. If the target relocations don't have an + addend in the reloc, eg. ELF USE_REL, src_mask will normally equal + dst_mask to extract the addend from the section contents. If + relocations do have an addend in the reloc, eg. ELF USE_RELA, this + field should be zero. Non-zero values for ELF USE_RELA targets are + bogus as in those cases the value in the dst_mask part of the + section contents should be treated as garbage. */ + bfd_vma src_mask; + + /* dst_mask selects which parts of the instruction (or data) are + replaced with a relocated value. */ + bfd_vma dst_mask; + + /* When some formats create PC relative instructions, they leave + the value of the pc of the place being relocated in the offset + slot of the instruction, so that a PC relative relocation can + be made just by adding in an ordinary offset (e.g., sun3 a.out). + Some formats leave the displacement part of an instruction + empty (e.g., m88k bcs); this flag signals the fact. */ + bfd_boolean pcrel_offset; +}; + +#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ + { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } +#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ + HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ + NAME, FALSE, 0, 0, IN) + +#define EMPTY_HOWTO(C) \ + HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ + NULL, FALSE, 0, 0, FALSE) + +#define HOWTO_PREPARE(relocation, symbol) \ + { \ + if (symbol != (asymbol *) NULL) \ + { \ + if (bfd_is_com_section (symbol->section)) \ + { \ + relocation = 0; \ + } \ + else \ + { \ + relocation = symbol->value; \ + } \ + } \ + } + +unsigned int +bfd_get_reloc_size PARAMS ((reloc_howto_type *)); + +typedef struct relent_chain +{ + arelent relent; + struct relent_chain *next; +} +arelent_chain; + +bfd_reloc_status_type +bfd_check_overflow PARAMS ((enum complain_overflow how, + unsigned int bitsize, + unsigned int rightshift, + unsigned int addrsize, + bfd_vma relocation)); + +bfd_reloc_status_type +bfd_perform_relocation PARAMS ((bfd *abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message)); + +bfd_reloc_status_type +bfd_install_relocation PARAMS ((bfd *abfd, + arelent *reloc_entry, + PTR data, bfd_vma data_start, + asection *input_section, + char **error_message)); + +enum bfd_reloc_code_real { + _dummy_first_bfd_reloc_code_real, + + +/* Basic absolute relocations of N bits. */ + BFD_RELOC_64, + BFD_RELOC_32, + BFD_RELOC_26, + BFD_RELOC_24, + BFD_RELOC_16, + BFD_RELOC_14, + BFD_RELOC_8, + +/* PC-relative relocations. Sometimes these are relative to the address +of the relocation itself; sometimes they are relative to the start of +the section containing the relocation. It depends on the specific target. + +The 24-bit relocation is used in some Intel 960 configurations. */ + BFD_RELOC_64_PCREL, + BFD_RELOC_32_PCREL, + BFD_RELOC_24_PCREL, + BFD_RELOC_16_PCREL, + BFD_RELOC_12_PCREL, + BFD_RELOC_8_PCREL, + +/* For ELF. */ + BFD_RELOC_32_GOT_PCREL, + BFD_RELOC_16_GOT_PCREL, + BFD_RELOC_8_GOT_PCREL, + BFD_RELOC_32_GOTOFF, + BFD_RELOC_16_GOTOFF, + BFD_RELOC_LO16_GOTOFF, + BFD_RELOC_HI16_GOTOFF, + BFD_RELOC_HI16_S_GOTOFF, + BFD_RELOC_8_GOTOFF, + BFD_RELOC_64_PLT_PCREL, + BFD_RELOC_32_PLT_PCREL, + BFD_RELOC_24_PLT_PCREL, + BFD_RELOC_16_PLT_PCREL, + BFD_RELOC_8_PLT_PCREL, + BFD_RELOC_64_PLTOFF, + BFD_RELOC_32_PLTOFF, + BFD_RELOC_16_PLTOFF, + BFD_RELOC_LO16_PLTOFF, + BFD_RELOC_HI16_PLTOFF, + BFD_RELOC_HI16_S_PLTOFF, + BFD_RELOC_8_PLTOFF, + +/* Relocations used by 68K ELF. */ + BFD_RELOC_68K_GLOB_DAT, + BFD_RELOC_68K_JMP_SLOT, + BFD_RELOC_68K_RELATIVE, + +/* Linkage-table relative. */ + BFD_RELOC_32_BASEREL, + BFD_RELOC_16_BASEREL, + BFD_RELOC_LO16_BASEREL, + BFD_RELOC_HI16_BASEREL, + BFD_RELOC_HI16_S_BASEREL, + BFD_RELOC_8_BASEREL, + BFD_RELOC_RVA, + +/* Absolute 8-bit relocation, but used to form an address like 0xFFnn. */ + BFD_RELOC_8_FFnn, + +/* These PC-relative relocations are stored as word displacements -- +i.e., byte displacements shifted right two bits. The 30-bit word +displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the +SPARC. (SPARC tools generally refer to this as <>.) The +signed 16-bit displacement is used on the MIPS, and the 23-bit +displacement is used on the Alpha. */ + BFD_RELOC_32_PCREL_S2, + BFD_RELOC_16_PCREL_S2, + BFD_RELOC_23_PCREL_S2, + +/* High 22 bits and low 10 bits of 32-bit value, placed into lower bits of +the target word. These are used on the SPARC. */ + BFD_RELOC_HI22, + BFD_RELOC_LO10, + +/* For systems that allocate a Global Pointer register, these are +displacements off that register. These relocation types are +handled specially, because the value the register will have is +decided relatively late. */ + BFD_RELOC_GPREL16, + BFD_RELOC_GPREL32, + +/* Reloc types used for i960/b.out. */ + BFD_RELOC_I960_CALLJ, + +/* SPARC ELF relocations. There is probably some overlap with other +relocation types already defined. */ + BFD_RELOC_NONE, + BFD_RELOC_SPARC_WDISP22, + BFD_RELOC_SPARC22, + BFD_RELOC_SPARC13, + BFD_RELOC_SPARC_GOT10, + BFD_RELOC_SPARC_GOT13, + BFD_RELOC_SPARC_GOT22, + BFD_RELOC_SPARC_PC10, + BFD_RELOC_SPARC_PC22, + BFD_RELOC_SPARC_WPLT30, + BFD_RELOC_SPARC_COPY, + BFD_RELOC_SPARC_GLOB_DAT, + BFD_RELOC_SPARC_JMP_SLOT, + BFD_RELOC_SPARC_RELATIVE, + BFD_RELOC_SPARC_UA16, + BFD_RELOC_SPARC_UA32, + BFD_RELOC_SPARC_UA64, + +/* I think these are specific to SPARC a.out (e.g., Sun 4). */ + BFD_RELOC_SPARC_BASE13, + BFD_RELOC_SPARC_BASE22, + +/* SPARC64 relocations */ +#define BFD_RELOC_SPARC_64 BFD_RELOC_64 + BFD_RELOC_SPARC_10, + BFD_RELOC_SPARC_11, + BFD_RELOC_SPARC_OLO10, + BFD_RELOC_SPARC_HH22, + BFD_RELOC_SPARC_HM10, + BFD_RELOC_SPARC_LM22, + BFD_RELOC_SPARC_PC_HH22, + BFD_RELOC_SPARC_PC_HM10, + BFD_RELOC_SPARC_PC_LM22, + BFD_RELOC_SPARC_WDISP16, + BFD_RELOC_SPARC_WDISP19, + BFD_RELOC_SPARC_7, + BFD_RELOC_SPARC_6, + BFD_RELOC_SPARC_5, +#define BFD_RELOC_SPARC_DISP64 BFD_RELOC_64_PCREL + BFD_RELOC_SPARC_PLT32, + BFD_RELOC_SPARC_PLT64, + BFD_RELOC_SPARC_HIX22, + BFD_RELOC_SPARC_LOX10, + BFD_RELOC_SPARC_H44, + BFD_RELOC_SPARC_M44, + BFD_RELOC_SPARC_L44, + BFD_RELOC_SPARC_REGISTER, + +/* SPARC little endian relocation */ + BFD_RELOC_SPARC_REV32, + +/* SPARC TLS relocations */ + BFD_RELOC_SPARC_TLS_GD_HI22, + BFD_RELOC_SPARC_TLS_GD_LO10, + BFD_RELOC_SPARC_TLS_GD_ADD, + BFD_RELOC_SPARC_TLS_GD_CALL, + BFD_RELOC_SPARC_TLS_LDM_HI22, + BFD_RELOC_SPARC_TLS_LDM_LO10, + BFD_RELOC_SPARC_TLS_LDM_ADD, + BFD_RELOC_SPARC_TLS_LDM_CALL, + BFD_RELOC_SPARC_TLS_LDO_HIX22, + BFD_RELOC_SPARC_TLS_LDO_LOX10, + BFD_RELOC_SPARC_TLS_LDO_ADD, + BFD_RELOC_SPARC_TLS_IE_HI22, + BFD_RELOC_SPARC_TLS_IE_LO10, + BFD_RELOC_SPARC_TLS_IE_LD, + BFD_RELOC_SPARC_TLS_IE_LDX, + BFD_RELOC_SPARC_TLS_IE_ADD, + BFD_RELOC_SPARC_TLS_LE_HIX22, + BFD_RELOC_SPARC_TLS_LE_LOX10, + BFD_RELOC_SPARC_TLS_DTPMOD32, + BFD_RELOC_SPARC_TLS_DTPMOD64, + BFD_RELOC_SPARC_TLS_DTPOFF32, + BFD_RELOC_SPARC_TLS_DTPOFF64, + BFD_RELOC_SPARC_TLS_TPOFF32, + BFD_RELOC_SPARC_TLS_TPOFF64, + +/* Alpha ECOFF and ELF relocations. Some of these treat the symbol or +"addend" in some special way. +For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when +writing; when reading, it will be the absolute section symbol. The +addend is the displacement in bytes of the "lda" instruction from +the "ldah" instruction (which is at the address of this reloc). */ + BFD_RELOC_ALPHA_GPDISP_HI16, + +/* For GPDISP_LO16 ("ignore") relocations, the symbol is handled as +with GPDISP_HI16 relocs. The addend is ignored when writing the +relocations out, and is filled in with the file's GP value on +reading, for convenience. */ + BFD_RELOC_ALPHA_GPDISP_LO16, + +/* The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 +relocation except that there is no accompanying GPDISP_LO16 +relocation. */ + BFD_RELOC_ALPHA_GPDISP, + +/* The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; +the assembler turns it into a LDQ instruction to load the address of +the symbol, and then fills in a register in the real instruction. + +The LITERAL reloc, at the LDQ instruction, refers to the .lita +section symbol. The addend is ignored when writing, but is filled +in with the file's GP value on reading, for convenience, as with the +GPDISP_LO16 reloc. + +The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. +It should refer to the symbol to be referenced, as with 16_GOTOFF, +but it generates output not based on the position within the .got +section, but relative to the GP value chosen for the file during the +final link stage. + +The LITUSE reloc, on the instruction using the loaded address, gives +information to the linker that it might be able to use to optimize +away some literal section references. The symbol is ignored (read +as the absolute section symbol), and the "addend" indicates the type +of instruction using the register: +1 - "memory" fmt insn +2 - byte-manipulation (byte offset reg) +3 - jsr (target of branch) */ + BFD_RELOC_ALPHA_LITERAL, + BFD_RELOC_ALPHA_ELF_LITERAL, + BFD_RELOC_ALPHA_LITUSE, + +/* The HINT relocation indicates a value that should be filled into the +"hint" field of a jmp/jsr/ret instruction, for possible branch- +prediction logic which may be provided on some processors. */ + BFD_RELOC_ALPHA_HINT, + +/* The LINKAGE relocation outputs a linkage pair in the object file, +which is filled by the linker. */ + BFD_RELOC_ALPHA_LINKAGE, + +/* The CODEADDR relocation outputs a STO_CA in the object file, +which is filled by the linker. */ + BFD_RELOC_ALPHA_CODEADDR, + +/* The GPREL_HI/LO relocations together form a 32-bit offset from the +GP register. */ + BFD_RELOC_ALPHA_GPREL_HI16, + BFD_RELOC_ALPHA_GPREL_LO16, + +/* Like BFD_RELOC_23_PCREL_S2, except that the source and target must +share a common GP, and the target address is adjusted for +STO_ALPHA_STD_GPLOAD. */ + BFD_RELOC_ALPHA_BRSGP, + +/* Alpha thread-local storage relocations. */ + BFD_RELOC_ALPHA_TLSGD, + BFD_RELOC_ALPHA_TLSLDM, + BFD_RELOC_ALPHA_DTPMOD64, + BFD_RELOC_ALPHA_GOTDTPREL16, + BFD_RELOC_ALPHA_DTPREL64, + BFD_RELOC_ALPHA_DTPREL_HI16, + BFD_RELOC_ALPHA_DTPREL_LO16, + BFD_RELOC_ALPHA_DTPREL16, + BFD_RELOC_ALPHA_GOTTPREL16, + BFD_RELOC_ALPHA_TPREL64, + BFD_RELOC_ALPHA_TPREL_HI16, + BFD_RELOC_ALPHA_TPREL_LO16, + BFD_RELOC_ALPHA_TPREL16, + +/* Bits 27..2 of the relocation address shifted right 2 bits; +simple reloc otherwise. */ + BFD_RELOC_MIPS_JMP, + +/* The MIPS16 jump instruction. */ + BFD_RELOC_MIPS16_JMP, + +/* MIPS16 GP relative reloc. */ + BFD_RELOC_MIPS16_GPREL, + +/* High 16 bits of 32-bit value; simple reloc. */ + BFD_RELOC_HI16, + +/* High 16 bits of 32-bit value but the low 16 bits will be sign +extended and added to form the final result. If the low 16 +bits form a negative number, we need to add one to the high value +to compensate for the borrow when the low bits are added. */ + BFD_RELOC_HI16_S, + +/* Low 16 bits. */ + BFD_RELOC_LO16, + +/* Like BFD_RELOC_HI16_S, but PC relative. */ + BFD_RELOC_PCREL_HI16_S, + +/* Like BFD_RELOC_LO16, but PC relative. */ + BFD_RELOC_PCREL_LO16, + +/* Relocation against a MIPS literal section. */ + BFD_RELOC_MIPS_LITERAL, + +/* MIPS ELF relocations. */ + BFD_RELOC_MIPS_GOT16, + BFD_RELOC_MIPS_CALL16, + BFD_RELOC_MIPS_GOT_HI16, + BFD_RELOC_MIPS_GOT_LO16, + BFD_RELOC_MIPS_CALL_HI16, + BFD_RELOC_MIPS_CALL_LO16, + BFD_RELOC_MIPS_SUB, + BFD_RELOC_MIPS_GOT_PAGE, + BFD_RELOC_MIPS_GOT_OFST, + BFD_RELOC_MIPS_GOT_DISP, + BFD_RELOC_MIPS_SHIFT5, + BFD_RELOC_MIPS_SHIFT6, + BFD_RELOC_MIPS_INSERT_A, + BFD_RELOC_MIPS_INSERT_B, + BFD_RELOC_MIPS_DELETE, + BFD_RELOC_MIPS_HIGHEST, + BFD_RELOC_MIPS_HIGHER, + BFD_RELOC_MIPS_SCN_DISP, + BFD_RELOC_MIPS_REL16, + BFD_RELOC_MIPS_RELGOT, + BFD_RELOC_MIPS_JALR, + +/* Fujitsu Frv Relocations. */ + BFD_RELOC_FRV_LABEL16, + BFD_RELOC_FRV_LABEL24, + BFD_RELOC_FRV_LO16, + BFD_RELOC_FRV_HI16, + BFD_RELOC_FRV_GPREL12, + BFD_RELOC_FRV_GPRELU12, + BFD_RELOC_FRV_GPREL32, + BFD_RELOC_FRV_GPRELHI, + BFD_RELOC_FRV_GPRELLO, + + +/* i386/elf relocations */ + BFD_RELOC_386_GOT32, + BFD_RELOC_386_PLT32, + BFD_RELOC_386_COPY, + BFD_RELOC_386_GLOB_DAT, + BFD_RELOC_386_JUMP_SLOT, + BFD_RELOC_386_RELATIVE, + BFD_RELOC_386_GOTOFF, + BFD_RELOC_386_GOTPC, + BFD_RELOC_386_TLS_TPOFF, + BFD_RELOC_386_TLS_IE, + BFD_RELOC_386_TLS_GOTIE, + BFD_RELOC_386_TLS_LE, + BFD_RELOC_386_TLS_GD, + BFD_RELOC_386_TLS_LDM, + BFD_RELOC_386_TLS_LDO_32, + BFD_RELOC_386_TLS_IE_32, + BFD_RELOC_386_TLS_LE_32, + BFD_RELOC_386_TLS_DTPMOD32, + BFD_RELOC_386_TLS_DTPOFF32, + BFD_RELOC_386_TLS_TPOFF32, + +/* x86-64/elf relocations */ + BFD_RELOC_X86_64_GOT32, + BFD_RELOC_X86_64_PLT32, + BFD_RELOC_X86_64_COPY, + BFD_RELOC_X86_64_GLOB_DAT, + BFD_RELOC_X86_64_JUMP_SLOT, + BFD_RELOC_X86_64_RELATIVE, + BFD_RELOC_X86_64_GOTPCREL, + BFD_RELOC_X86_64_32S, + BFD_RELOC_X86_64_DTPMOD64, + BFD_RELOC_X86_64_DTPOFF64, + BFD_RELOC_X86_64_TPOFF64, + BFD_RELOC_X86_64_TLSGD, + BFD_RELOC_X86_64_TLSLD, + BFD_RELOC_X86_64_DTPOFF32, + BFD_RELOC_X86_64_GOTTPOFF, + BFD_RELOC_X86_64_TPOFF32, + +/* ns32k relocations */ + BFD_RELOC_NS32K_IMM_8, + BFD_RELOC_NS32K_IMM_16, + BFD_RELOC_NS32K_IMM_32, + BFD_RELOC_NS32K_IMM_8_PCREL, + BFD_RELOC_NS32K_IMM_16_PCREL, + BFD_RELOC_NS32K_IMM_32_PCREL, + BFD_RELOC_NS32K_DISP_8, + BFD_RELOC_NS32K_DISP_16, + BFD_RELOC_NS32K_DISP_32, + BFD_RELOC_NS32K_DISP_8_PCREL, + BFD_RELOC_NS32K_DISP_16_PCREL, + BFD_RELOC_NS32K_DISP_32_PCREL, + +/* PDP11 relocations */ + BFD_RELOC_PDP11_DISP_8_PCREL, + BFD_RELOC_PDP11_DISP_6_PCREL, + +/* Picojava relocs. Not all of these appear in object files. */ + BFD_RELOC_PJ_CODE_HI16, + BFD_RELOC_PJ_CODE_LO16, + BFD_RELOC_PJ_CODE_DIR16, + BFD_RELOC_PJ_CODE_DIR32, + BFD_RELOC_PJ_CODE_REL16, + BFD_RELOC_PJ_CODE_REL32, + +/* Power(rs6000) and PowerPC relocations. */ + BFD_RELOC_PPC_B26, + BFD_RELOC_PPC_BA26, + BFD_RELOC_PPC_TOC16, + BFD_RELOC_PPC_B16, + BFD_RELOC_PPC_B16_BRTAKEN, + BFD_RELOC_PPC_B16_BRNTAKEN, + BFD_RELOC_PPC_BA16, + BFD_RELOC_PPC_BA16_BRTAKEN, + BFD_RELOC_PPC_BA16_BRNTAKEN, + BFD_RELOC_PPC_COPY, + BFD_RELOC_PPC_GLOB_DAT, + BFD_RELOC_PPC_JMP_SLOT, + BFD_RELOC_PPC_RELATIVE, + BFD_RELOC_PPC_LOCAL24PC, + BFD_RELOC_PPC_EMB_NADDR32, + BFD_RELOC_PPC_EMB_NADDR16, + BFD_RELOC_PPC_EMB_NADDR16_LO, + BFD_RELOC_PPC_EMB_NADDR16_HI, + BFD_RELOC_PPC_EMB_NADDR16_HA, + BFD_RELOC_PPC_EMB_SDAI16, + BFD_RELOC_PPC_EMB_SDA2I16, + BFD_RELOC_PPC_EMB_SDA2REL, + BFD_RELOC_PPC_EMB_SDA21, + BFD_RELOC_PPC_EMB_MRKREF, + BFD_RELOC_PPC_EMB_RELSEC16, + BFD_RELOC_PPC_EMB_RELST_LO, + BFD_RELOC_PPC_EMB_RELST_HI, + BFD_RELOC_PPC_EMB_RELST_HA, + BFD_RELOC_PPC_EMB_BIT_FLD, + BFD_RELOC_PPC_EMB_RELSDA, + BFD_RELOC_PPC64_HIGHER, + BFD_RELOC_PPC64_HIGHER_S, + BFD_RELOC_PPC64_HIGHEST, + BFD_RELOC_PPC64_HIGHEST_S, + BFD_RELOC_PPC64_TOC16_LO, + BFD_RELOC_PPC64_TOC16_HI, + BFD_RELOC_PPC64_TOC16_HA, + BFD_RELOC_PPC64_TOC, + BFD_RELOC_PPC64_PLTGOT16, + BFD_RELOC_PPC64_PLTGOT16_LO, + BFD_RELOC_PPC64_PLTGOT16_HI, + BFD_RELOC_PPC64_PLTGOT16_HA, + BFD_RELOC_PPC64_ADDR16_DS, + BFD_RELOC_PPC64_ADDR16_LO_DS, + BFD_RELOC_PPC64_GOT16_DS, + BFD_RELOC_PPC64_GOT16_LO_DS, + BFD_RELOC_PPC64_PLT16_LO_DS, + BFD_RELOC_PPC64_SECTOFF_DS, + BFD_RELOC_PPC64_SECTOFF_LO_DS, + BFD_RELOC_PPC64_TOC16_DS, + BFD_RELOC_PPC64_TOC16_LO_DS, + BFD_RELOC_PPC64_PLTGOT16_DS, + BFD_RELOC_PPC64_PLTGOT16_LO_DS, + +/* PowerPC and PowerPC64 thread-local storage relocations. */ + BFD_RELOC_PPC_TLS, + BFD_RELOC_PPC_DTPMOD, + BFD_RELOC_PPC_TPREL16, + BFD_RELOC_PPC_TPREL16_LO, + BFD_RELOC_PPC_TPREL16_HI, + BFD_RELOC_PPC_TPREL16_HA, + BFD_RELOC_PPC_TPREL, + BFD_RELOC_PPC_DTPREL16, + BFD_RELOC_PPC_DTPREL16_LO, + BFD_RELOC_PPC_DTPREL16_HI, + BFD_RELOC_PPC_DTPREL16_HA, + BFD_RELOC_PPC_DTPREL, + BFD_RELOC_PPC_GOT_TLSGD16, + BFD_RELOC_PPC_GOT_TLSGD16_LO, + BFD_RELOC_PPC_GOT_TLSGD16_HI, + BFD_RELOC_PPC_GOT_TLSGD16_HA, + BFD_RELOC_PPC_GOT_TLSLD16, + BFD_RELOC_PPC_GOT_TLSLD16_LO, + BFD_RELOC_PPC_GOT_TLSLD16_HI, + BFD_RELOC_PPC_GOT_TLSLD16_HA, + BFD_RELOC_PPC_GOT_TPREL16, + BFD_RELOC_PPC_GOT_TPREL16_LO, + BFD_RELOC_PPC_GOT_TPREL16_HI, + BFD_RELOC_PPC_GOT_TPREL16_HA, + BFD_RELOC_PPC_GOT_DTPREL16, + BFD_RELOC_PPC_GOT_DTPREL16_LO, + BFD_RELOC_PPC_GOT_DTPREL16_HI, + BFD_RELOC_PPC_GOT_DTPREL16_HA, + BFD_RELOC_PPC64_TPREL16_DS, + BFD_RELOC_PPC64_TPREL16_LO_DS, + BFD_RELOC_PPC64_TPREL16_HIGHER, + BFD_RELOC_PPC64_TPREL16_HIGHERA, + BFD_RELOC_PPC64_TPREL16_HIGHEST, + BFD_RELOC_PPC64_TPREL16_HIGHESTA, + BFD_RELOC_PPC64_DTPREL16_DS, + BFD_RELOC_PPC64_DTPREL16_LO_DS, + BFD_RELOC_PPC64_DTPREL16_HIGHER, + BFD_RELOC_PPC64_DTPREL16_HIGHERA, + BFD_RELOC_PPC64_DTPREL16_HIGHEST, + BFD_RELOC_PPC64_DTPREL16_HIGHESTA, + +/* IBM 370/390 relocations */ + BFD_RELOC_I370_D12, + +/* The type of reloc used to build a contructor table - at the moment +probably a 32 bit wide absolute relocation, but the target can choose. +It generally does map to one of the other relocation types. */ + BFD_RELOC_CTOR, + +/* ARM 26 bit pc-relative branch. The lowest two bits must be zero and are +not stored in the instruction. */ + BFD_RELOC_ARM_PCREL_BRANCH, + +/* ARM 26 bit pc-relative branch. The lowest bit must be zero and is +not stored in the instruction. The 2nd lowest bit comes from a 1 bit +field in the instruction. */ + BFD_RELOC_ARM_PCREL_BLX, + +/* Thumb 22 bit pc-relative branch. The lowest bit must be zero and is +not stored in the instruction. The 2nd lowest bit comes from a 1 bit +field in the instruction. */ + BFD_RELOC_THUMB_PCREL_BLX, + +/* These relocs are only used within the ARM assembler. They are not +(at present) written to any object files. */ + BFD_RELOC_ARM_IMMEDIATE, + BFD_RELOC_ARM_ADRL_IMMEDIATE, + BFD_RELOC_ARM_OFFSET_IMM, + BFD_RELOC_ARM_SHIFT_IMM, + BFD_RELOC_ARM_SWI, + BFD_RELOC_ARM_MULTI, + BFD_RELOC_ARM_CP_OFF_IMM, + BFD_RELOC_ARM_CP_OFF_IMM_S2, + BFD_RELOC_ARM_ADR_IMM, + BFD_RELOC_ARM_LDR_IMM, + BFD_RELOC_ARM_LITERAL, + BFD_RELOC_ARM_IN_POOL, + BFD_RELOC_ARM_OFFSET_IMM8, + BFD_RELOC_ARM_HWLITERAL, + BFD_RELOC_ARM_THUMB_ADD, + BFD_RELOC_ARM_THUMB_IMM, + BFD_RELOC_ARM_THUMB_SHIFT, + BFD_RELOC_ARM_THUMB_OFFSET, + BFD_RELOC_ARM_GOT12, + BFD_RELOC_ARM_GOT32, + BFD_RELOC_ARM_JUMP_SLOT, + BFD_RELOC_ARM_COPY, + BFD_RELOC_ARM_GLOB_DAT, + BFD_RELOC_ARM_PLT32, + BFD_RELOC_ARM_RELATIVE, + BFD_RELOC_ARM_GOTOFF, + BFD_RELOC_ARM_GOTPC, + +/* Renesas / SuperH SH relocs. Not all of these appear in object files. */ + BFD_RELOC_SH_PCDISP8BY2, + BFD_RELOC_SH_PCDISP12BY2, + BFD_RELOC_SH_IMM4, + BFD_RELOC_SH_IMM4BY2, + BFD_RELOC_SH_IMM4BY4, + BFD_RELOC_SH_IMM8, + BFD_RELOC_SH_IMM8BY2, + BFD_RELOC_SH_IMM8BY4, + BFD_RELOC_SH_PCRELIMM8BY2, + BFD_RELOC_SH_PCRELIMM8BY4, + BFD_RELOC_SH_SWITCH16, + BFD_RELOC_SH_SWITCH32, + BFD_RELOC_SH_USES, + BFD_RELOC_SH_COUNT, + BFD_RELOC_SH_ALIGN, + BFD_RELOC_SH_CODE, + BFD_RELOC_SH_DATA, + BFD_RELOC_SH_LABEL, + BFD_RELOC_SH_LOOP_START, + BFD_RELOC_SH_LOOP_END, + BFD_RELOC_SH_COPY, + BFD_RELOC_SH_GLOB_DAT, + BFD_RELOC_SH_JMP_SLOT, + BFD_RELOC_SH_RELATIVE, + BFD_RELOC_SH_GOTPC, + BFD_RELOC_SH_GOT_LOW16, + BFD_RELOC_SH_GOT_MEDLOW16, + BFD_RELOC_SH_GOT_MEDHI16, + BFD_RELOC_SH_GOT_HI16, + BFD_RELOC_SH_GOTPLT_LOW16, + BFD_RELOC_SH_GOTPLT_MEDLOW16, + BFD_RELOC_SH_GOTPLT_MEDHI16, + BFD_RELOC_SH_GOTPLT_HI16, + BFD_RELOC_SH_PLT_LOW16, + BFD_RELOC_SH_PLT_MEDLOW16, + BFD_RELOC_SH_PLT_MEDHI16, + BFD_RELOC_SH_PLT_HI16, + BFD_RELOC_SH_GOTOFF_LOW16, + BFD_RELOC_SH_GOTOFF_MEDLOW16, + BFD_RELOC_SH_GOTOFF_MEDHI16, + BFD_RELOC_SH_GOTOFF_HI16, + BFD_RELOC_SH_GOTPC_LOW16, + BFD_RELOC_SH_GOTPC_MEDLOW16, + BFD_RELOC_SH_GOTPC_MEDHI16, + BFD_RELOC_SH_GOTPC_HI16, + BFD_RELOC_SH_COPY64, + BFD_RELOC_SH_GLOB_DAT64, + BFD_RELOC_SH_JMP_SLOT64, + BFD_RELOC_SH_RELATIVE64, + BFD_RELOC_SH_GOT10BY4, + BFD_RELOC_SH_GOT10BY8, + BFD_RELOC_SH_GOTPLT10BY4, + BFD_RELOC_SH_GOTPLT10BY8, + BFD_RELOC_SH_GOTPLT32, + BFD_RELOC_SH_SHMEDIA_CODE, + BFD_RELOC_SH_IMMU5, + BFD_RELOC_SH_IMMS6, + BFD_RELOC_SH_IMMS6BY32, + BFD_RELOC_SH_IMMU6, + BFD_RELOC_SH_IMMS10, + BFD_RELOC_SH_IMMS10BY2, + BFD_RELOC_SH_IMMS10BY4, + BFD_RELOC_SH_IMMS10BY8, + BFD_RELOC_SH_IMMS16, + BFD_RELOC_SH_IMMU16, + BFD_RELOC_SH_IMM_LOW16, + BFD_RELOC_SH_IMM_LOW16_PCREL, + BFD_RELOC_SH_IMM_MEDLOW16, + BFD_RELOC_SH_IMM_MEDLOW16_PCREL, + BFD_RELOC_SH_IMM_MEDHI16, + BFD_RELOC_SH_IMM_MEDHI16_PCREL, + BFD_RELOC_SH_IMM_HI16, + BFD_RELOC_SH_IMM_HI16_PCREL, + BFD_RELOC_SH_PT_16, + BFD_RELOC_SH_TLS_GD_32, + BFD_RELOC_SH_TLS_LD_32, + BFD_RELOC_SH_TLS_LDO_32, + BFD_RELOC_SH_TLS_IE_32, + BFD_RELOC_SH_TLS_LE_32, + BFD_RELOC_SH_TLS_DTPMOD32, + BFD_RELOC_SH_TLS_DTPOFF32, + BFD_RELOC_SH_TLS_TPOFF32, + +/* Thumb 23-, 12- and 9-bit pc-relative branches. The lowest bit must +be zero and is not stored in the instruction. */ + BFD_RELOC_THUMB_PCREL_BRANCH9, + BFD_RELOC_THUMB_PCREL_BRANCH12, + BFD_RELOC_THUMB_PCREL_BRANCH23, + +/* ARC Cores relocs. +ARC 22 bit pc-relative branch. The lowest two bits must be zero and are +not stored in the instruction. The high 20 bits are installed in bits 26 +through 7 of the instruction. */ + BFD_RELOC_ARC_B22_PCREL, + +/* ARC 26 bit absolute branch. The lowest two bits must be zero and are not +stored in the instruction. The high 24 bits are installed in bits 23 +through 0. */ + BFD_RELOC_ARC_B26, + +/* Mitsubishi D10V relocs. +This is a 10-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_10_PCREL_R, + +/* Mitsubishi D10V relocs. +This is a 10-bit reloc with the right 2 bits +assumed to be 0. This is the same as the previous reloc +except it is in the left container, i.e., +shifted left 15 bits. */ + BFD_RELOC_D10V_10_PCREL_L, + +/* This is an 18-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_18, + +/* This is an 18-bit reloc with the right 2 bits +assumed to be 0. */ + BFD_RELOC_D10V_18_PCREL, + +/* Mitsubishi D30V relocs. +This is a 6-bit absolute reloc. */ + BFD_RELOC_D30V_6, + +/* This is a 6-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_9_PCREL, + +/* This is a 6-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_9_PCREL_R, + +/* This is a 12-bit absolute reloc with the +right 3 bitsassumed to be 0. */ + BFD_RELOC_D30V_15, + +/* This is a 12-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_15_PCREL, + +/* This is a 12-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_15_PCREL_R, + +/* This is an 18-bit absolute reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_21, + +/* This is an 18-bit pc-relative reloc with +the right 3 bits assumed to be 0. */ + BFD_RELOC_D30V_21_PCREL, + +/* This is an 18-bit pc-relative reloc with +the right 3 bits assumed to be 0. Same +as the previous reloc but on the right side +of the container. */ + BFD_RELOC_D30V_21_PCREL_R, + +/* This is a 32-bit absolute reloc. */ + BFD_RELOC_D30V_32, + +/* This is a 32-bit pc-relative reloc. */ + BFD_RELOC_D30V_32_PCREL, + +/* DLX relocs */ + BFD_RELOC_DLX_HI16_S, + +/* DLX relocs */ + BFD_RELOC_DLX_LO16, + +/* DLX relocs */ + BFD_RELOC_DLX_JMP26, + +/* Renesas M32R (formerly Mitsubishi M32R) relocs. +This is a 24 bit absolute address. */ + BFD_RELOC_M32R_24, + +/* This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_10_PCREL, + +/* This is an 18-bit reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_18_PCREL, + +/* This is a 26-bit reloc with the right 2 bits assumed to be 0. */ + BFD_RELOC_M32R_26_PCREL, + +/* This is a 16-bit reloc containing the high 16 bits of an address +used when the lower 16 bits are treated as unsigned. */ + BFD_RELOC_M32R_HI16_ULO, + +/* This is a 16-bit reloc containing the high 16 bits of an address +used when the lower 16 bits are treated as signed. */ + BFD_RELOC_M32R_HI16_SLO, + +/* This is a 16-bit reloc containing the lower 16 bits of an address. */ + BFD_RELOC_M32R_LO16, + +/* This is a 16-bit reloc containing the small data area offset for use in +add3, load, and store instructions. */ + BFD_RELOC_M32R_SDA16, + +/* This is a 9-bit reloc */ + BFD_RELOC_V850_9_PCREL, + +/* This is a 22-bit reloc */ + BFD_RELOC_V850_22_PCREL, + +/* This is a 16 bit offset from the short data area pointer. */ + BFD_RELOC_V850_SDA_16_16_OFFSET, + +/* This is a 16 bit offset (of which only 15 bits are used) from the +short data area pointer. */ + BFD_RELOC_V850_SDA_15_16_OFFSET, + +/* This is a 16 bit offset from the zero data area pointer. */ + BFD_RELOC_V850_ZDA_16_16_OFFSET, + +/* This is a 16 bit offset (of which only 15 bits are used) from the +zero data area pointer. */ + BFD_RELOC_V850_ZDA_15_16_OFFSET, + +/* This is an 8 bit offset (of which only 6 bits are used) from the +tiny data area pointer. */ + BFD_RELOC_V850_TDA_6_8_OFFSET, + +/* This is an 8bit offset (of which only 7 bits are used) from the tiny +data area pointer. */ + BFD_RELOC_V850_TDA_7_8_OFFSET, + +/* This is a 7 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_7_7_OFFSET, + +/* This is a 16 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_16_16_OFFSET, + +/* This is a 5 bit offset (of which only 4 bits are used) from the tiny +data area pointer. */ + BFD_RELOC_V850_TDA_4_5_OFFSET, + +/* This is a 4 bit offset from the tiny data area pointer. */ + BFD_RELOC_V850_TDA_4_4_OFFSET, + +/* This is a 16 bit offset from the short data area pointer, with the +bits placed non-contigously in the instruction. */ + BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET, + +/* This is a 16 bit offset from the zero data area pointer, with the +bits placed non-contigously in the instruction. */ + BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET, + +/* This is a 6 bit offset from the call table base pointer. */ + BFD_RELOC_V850_CALLT_6_7_OFFSET, + +/* This is a 16 bit offset from the call table base pointer. */ + BFD_RELOC_V850_CALLT_16_16_OFFSET, + +/* Used for relaxing indirect function calls. */ + BFD_RELOC_V850_LONGCALL, + +/* Used for relaxing indirect jumps. */ + BFD_RELOC_V850_LONGJUMP, + +/* Used to maintain alignment whilst relaxing. */ + BFD_RELOC_V850_ALIGN, + +/* This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. */ + BFD_RELOC_MN10300_32_PCREL, + +/* This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the +instruction. */ + BFD_RELOC_MN10300_16_PCREL, + +/* This is a 8bit DP reloc for the tms320c30, where the most +significant 8 bits of a 24 bit word are placed into the least +significant 8 bits of the opcode. */ + BFD_RELOC_TIC30_LDP, + +/* This is a 7bit reloc for the tms320c54x, where the least +significant 7 bits of a 16 bit word are placed into the least +significant 7 bits of the opcode. */ + BFD_RELOC_TIC54X_PARTLS7, + +/* This is a 9bit DP reloc for the tms320c54x, where the most +significant 9 bits of a 16 bit word are placed into the least +significant 9 bits of the opcode. */ + BFD_RELOC_TIC54X_PARTMS9, + +/* This is an extended address 23-bit reloc for the tms320c54x. */ + BFD_RELOC_TIC54X_23, + +/* This is a 16-bit reloc for the tms320c54x, where the least +significant 16 bits of a 23-bit extended address are placed into +the opcode. */ + BFD_RELOC_TIC54X_16_OF_23, + +/* This is a reloc for the tms320c54x, where the most +significant 7 bits of a 23-bit extended address are placed into +the opcode. */ + BFD_RELOC_TIC54X_MS7_OF_23, + +/* This is a 48 bit reloc for the FR30 that stores 32 bits. */ + BFD_RELOC_FR30_48, + +/* This is a 32 bit reloc for the FR30 that stores 20 bits split up into +two sections. */ + BFD_RELOC_FR30_20, + +/* This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in +4 bits. */ + BFD_RELOC_FR30_6_IN_4, + +/* This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset +into 8 bits. */ + BFD_RELOC_FR30_8_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 9 bit short offset +into 8 bits. */ + BFD_RELOC_FR30_9_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 10 bit word offset +into 8 bits. */ + BFD_RELOC_FR30_10_IN_8, + +/* This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative +short offset into 8 bits. */ + BFD_RELOC_FR30_9_PCREL, + +/* This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative +short offset into 11 bits. */ + BFD_RELOC_FR30_12_PCREL, + +/* Motorola Mcore relocations. */ + BFD_RELOC_MCORE_PCREL_IMM8BY4, + BFD_RELOC_MCORE_PCREL_IMM11BY2, + BFD_RELOC_MCORE_PCREL_IMM4BY2, + BFD_RELOC_MCORE_PCREL_32, + BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2, + BFD_RELOC_MCORE_RVA, + +/* These are relocations for the GETA instruction. */ + BFD_RELOC_MMIX_GETA, + BFD_RELOC_MMIX_GETA_1, + BFD_RELOC_MMIX_GETA_2, + BFD_RELOC_MMIX_GETA_3, + +/* These are relocations for a conditional branch instruction. */ + BFD_RELOC_MMIX_CBRANCH, + BFD_RELOC_MMIX_CBRANCH_J, + BFD_RELOC_MMIX_CBRANCH_1, + BFD_RELOC_MMIX_CBRANCH_2, + BFD_RELOC_MMIX_CBRANCH_3, + +/* These are relocations for the PUSHJ instruction. */ + BFD_RELOC_MMIX_PUSHJ, + BFD_RELOC_MMIX_PUSHJ_1, + BFD_RELOC_MMIX_PUSHJ_2, + BFD_RELOC_MMIX_PUSHJ_3, + +/* These are relocations for the JMP instruction. */ + BFD_RELOC_MMIX_JMP, + BFD_RELOC_MMIX_JMP_1, + BFD_RELOC_MMIX_JMP_2, + BFD_RELOC_MMIX_JMP_3, + +/* This is a relocation for a relative address as in a GETA instruction or +a branch. */ + BFD_RELOC_MMIX_ADDR19, + +/* This is a relocation for a relative address as in a JMP instruction. */ + BFD_RELOC_MMIX_ADDR27, + +/* This is a relocation for an instruction field that may be a general +register or a value 0..255. */ + BFD_RELOC_MMIX_REG_OR_BYTE, + +/* This is a relocation for an instruction field that may be a general +register. */ + BFD_RELOC_MMIX_REG, + +/* This is a relocation for two instruction fields holding a register and +an offset, the equivalent of the relocation. */ + BFD_RELOC_MMIX_BASE_PLUS_OFFSET, + +/* This relocation is an assertion that the expression is not allocated as +a global register. It does not modify contents. */ + BFD_RELOC_MMIX_LOCAL, + +/* This is a 16 bit reloc for the AVR that stores 8 bit pc relative +short offset into 7 bits. */ + BFD_RELOC_AVR_7_PCREL, + +/* This is a 16 bit reloc for the AVR that stores 13 bit pc relative +short offset into 12 bits. */ + BFD_RELOC_AVR_13_PCREL, + +/* This is a 16 bit reloc for the AVR that stores 17 bit value (usually +program memory address) into 16 bits. */ + BFD_RELOC_AVR_16_PM, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually +data memory address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_LO8_LDI, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit +of data memory address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_HI8_LDI, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit +of program memory address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_HH8_LDI, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(usually data memory address) into 8 bit immediate value of SUBI insn. */ + BFD_RELOC_AVR_LO8_LDI_NEG, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(high 8 bit of data memory address) into 8 bit immediate value of +SUBI insn. */ + BFD_RELOC_AVR_HI8_LDI_NEG, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(most high 8 bit of program memory address) into 8 bit immediate value +of LDI or SUBI insn. */ + BFD_RELOC_AVR_HH8_LDI_NEG, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (usually +command address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_LO8_LDI_PM, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit +of command address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_HI8_LDI_PM, + +/* This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit +of command address) into 8 bit immediate value of LDI insn. */ + BFD_RELOC_AVR_HH8_LDI_PM, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(usually command address) into 8 bit immediate value of SUBI insn. */ + BFD_RELOC_AVR_LO8_LDI_PM_NEG, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(high 8 bit of 16 bit command address) into 8 bit immediate value +of SUBI insn. */ + BFD_RELOC_AVR_HI8_LDI_PM_NEG, + +/* This is a 16 bit reloc for the AVR that stores negated 8 bit value +(high 6 bit of 22 bit command address) into 8 bit immediate +value of SUBI insn. */ + BFD_RELOC_AVR_HH8_LDI_PM_NEG, + +/* This is a 32 bit reloc for the AVR that stores 23 bit value +into 22 bits. */ + BFD_RELOC_AVR_CALL, + +/* Direct 12 bit. */ + BFD_RELOC_390_12, + +/* 12 bit GOT offset. */ + BFD_RELOC_390_GOT12, + +/* 32 bit PC relative PLT address. */ + BFD_RELOC_390_PLT32, + +/* Copy symbol at runtime. */ + BFD_RELOC_390_COPY, + +/* Create GOT entry. */ + BFD_RELOC_390_GLOB_DAT, + +/* Create PLT entry. */ + BFD_RELOC_390_JMP_SLOT, + +/* Adjust by program base. */ + BFD_RELOC_390_RELATIVE, + +/* 32 bit PC relative offset to GOT. */ + BFD_RELOC_390_GOTPC, + +/* 16 bit GOT offset. */ + BFD_RELOC_390_GOT16, + +/* 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 32 bit shifted by 1. */ + BFD_RELOC_390_PC32DBL, + +/* 32 bit PC rel. PLT shifted by 1. */ + BFD_RELOC_390_PLT32DBL, + +/* 32 bit PC rel. GOT shifted by 1. */ + BFD_RELOC_390_GOTPCDBL, + +/* 64 bit GOT offset. */ + BFD_RELOC_390_GOT64, + +/* 64 bit PC relative PLT address. */ + BFD_RELOC_390_PLT64, + +/* 32 bit rel. offset to GOT entry. */ + BFD_RELOC_390_GOTENT, + +/* 64 bit offset to GOT. */ + BFD_RELOC_390_GOTOFF64, + +/* 12-bit offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_390_GOTPLT12, + +/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_390_GOTPLT16, + +/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_390_GOTPLT32, + +/* 64-bit offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_390_GOTPLT64, + +/* 32-bit rel. offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_390_GOTPLTENT, + +/* 16-bit rel. offset from the GOT to a PLT entry. */ + BFD_RELOC_390_PLTOFF16, + +/* 32-bit rel. offset from the GOT to a PLT entry. */ + BFD_RELOC_390_PLTOFF32, + +/* 64-bit rel. offset from the GOT to a PLT entry. */ + BFD_RELOC_390_PLTOFF64, + +/* s390 tls relocations. */ + BFD_RELOC_390_TLS_LOAD, + BFD_RELOC_390_TLS_GDCALL, + BFD_RELOC_390_TLS_LDCALL, + BFD_RELOC_390_TLS_GD32, + BFD_RELOC_390_TLS_GD64, + BFD_RELOC_390_TLS_GOTIE12, + BFD_RELOC_390_TLS_GOTIE32, + BFD_RELOC_390_TLS_GOTIE64, + BFD_RELOC_390_TLS_LDM32, + BFD_RELOC_390_TLS_LDM64, + BFD_RELOC_390_TLS_IE32, + BFD_RELOC_390_TLS_IE64, + BFD_RELOC_390_TLS_IEENT, + BFD_RELOC_390_TLS_LE32, + BFD_RELOC_390_TLS_LE64, + BFD_RELOC_390_TLS_LDO32, + BFD_RELOC_390_TLS_LDO64, + BFD_RELOC_390_TLS_DTPMOD, + BFD_RELOC_390_TLS_DTPOFF, + BFD_RELOC_390_TLS_TPOFF, + +/* Scenix IP2K - 9-bit register number / data address */ + BFD_RELOC_IP2K_FR9, + +/* Scenix IP2K - 4-bit register/data bank number */ + BFD_RELOC_IP2K_BANK, + +/* Scenix IP2K - low 13 bits of instruction word address */ + BFD_RELOC_IP2K_ADDR16CJP, + +/* Scenix IP2K - high 3 bits of instruction word address */ + BFD_RELOC_IP2K_PAGE3, + +/* Scenix IP2K - ext/low/high 8 bits of data address */ + BFD_RELOC_IP2K_LO8DATA, + BFD_RELOC_IP2K_HI8DATA, + BFD_RELOC_IP2K_EX8DATA, + +/* Scenix IP2K - low/high 8 bits of instruction word address */ + BFD_RELOC_IP2K_LO8INSN, + BFD_RELOC_IP2K_HI8INSN, + +/* Scenix IP2K - even/odd PC modifier to modify snb pcl.0 */ + BFD_RELOC_IP2K_PC_SKIP, + +/* Scenix IP2K - 16 bit word address in text section. */ + BFD_RELOC_IP2K_TEXT, + +/* Scenix IP2K - 7-bit sp or dp offset */ + BFD_RELOC_IP2K_FR_OFFSET, + +/* Scenix VPE4K coprocessor - data/insn-space addressing */ + BFD_RELOC_VPE4KMATH_DATA, + BFD_RELOC_VPE4KMATH_INSN, + +/* These two relocations are used by the linker to determine which of +the entries in a C++ virtual function table are actually used. When +the --gc-sections option is given, the linker will zero out the entries +that are not used, so that the code for those functions need not be +included in the output. + +VTABLE_INHERIT is a zero-space relocation used to describe to the +linker the inheritence tree of a C++ virtual function table. The +relocation's symbol should be the parent class' vtable, and the +relocation should be located at the child vtable. + +VTABLE_ENTRY is a zero-space relocation that describes the use of a +virtual function table entry. The reloc's symbol should refer to the +table of the class mentioned in the code. Off of that base, an offset +describes the entry that is being used. For Rela hosts, this offset +is stored in the reloc's addend. For Rel hosts, we are forced to put +this offset in the reloc's section offset. */ + BFD_RELOC_VTABLE_INHERIT, + BFD_RELOC_VTABLE_ENTRY, + +/* Intel IA64 Relocations. */ + BFD_RELOC_IA64_IMM14, + BFD_RELOC_IA64_IMM22, + BFD_RELOC_IA64_IMM64, + BFD_RELOC_IA64_DIR32MSB, + BFD_RELOC_IA64_DIR32LSB, + BFD_RELOC_IA64_DIR64MSB, + BFD_RELOC_IA64_DIR64LSB, + BFD_RELOC_IA64_GPREL22, + BFD_RELOC_IA64_GPREL64I, + BFD_RELOC_IA64_GPREL32MSB, + BFD_RELOC_IA64_GPREL32LSB, + BFD_RELOC_IA64_GPREL64MSB, + BFD_RELOC_IA64_GPREL64LSB, + BFD_RELOC_IA64_LTOFF22, + BFD_RELOC_IA64_LTOFF64I, + BFD_RELOC_IA64_PLTOFF22, + BFD_RELOC_IA64_PLTOFF64I, + BFD_RELOC_IA64_PLTOFF64MSB, + BFD_RELOC_IA64_PLTOFF64LSB, + BFD_RELOC_IA64_FPTR64I, + BFD_RELOC_IA64_FPTR32MSB, + BFD_RELOC_IA64_FPTR32LSB, + BFD_RELOC_IA64_FPTR64MSB, + BFD_RELOC_IA64_FPTR64LSB, + BFD_RELOC_IA64_PCREL21B, + BFD_RELOC_IA64_PCREL21BI, + BFD_RELOC_IA64_PCREL21M, + BFD_RELOC_IA64_PCREL21F, + BFD_RELOC_IA64_PCREL22, + BFD_RELOC_IA64_PCREL60B, + BFD_RELOC_IA64_PCREL64I, + BFD_RELOC_IA64_PCREL32MSB, + BFD_RELOC_IA64_PCREL32LSB, + BFD_RELOC_IA64_PCREL64MSB, + BFD_RELOC_IA64_PCREL64LSB, + BFD_RELOC_IA64_LTOFF_FPTR22, + BFD_RELOC_IA64_LTOFF_FPTR64I, + BFD_RELOC_IA64_LTOFF_FPTR32MSB, + BFD_RELOC_IA64_LTOFF_FPTR32LSB, + BFD_RELOC_IA64_LTOFF_FPTR64MSB, + BFD_RELOC_IA64_LTOFF_FPTR64LSB, + BFD_RELOC_IA64_SEGREL32MSB, + BFD_RELOC_IA64_SEGREL32LSB, + BFD_RELOC_IA64_SEGREL64MSB, + BFD_RELOC_IA64_SEGREL64LSB, + BFD_RELOC_IA64_SECREL32MSB, + BFD_RELOC_IA64_SECREL32LSB, + BFD_RELOC_IA64_SECREL64MSB, + BFD_RELOC_IA64_SECREL64LSB, + BFD_RELOC_IA64_REL32MSB, + BFD_RELOC_IA64_REL32LSB, + BFD_RELOC_IA64_REL64MSB, + BFD_RELOC_IA64_REL64LSB, + BFD_RELOC_IA64_LTV32MSB, + BFD_RELOC_IA64_LTV32LSB, + BFD_RELOC_IA64_LTV64MSB, + BFD_RELOC_IA64_LTV64LSB, + BFD_RELOC_IA64_IPLTMSB, + BFD_RELOC_IA64_IPLTLSB, + BFD_RELOC_IA64_COPY, + BFD_RELOC_IA64_LTOFF22X, + BFD_RELOC_IA64_LDXMOV, + BFD_RELOC_IA64_TPREL14, + BFD_RELOC_IA64_TPREL22, + BFD_RELOC_IA64_TPREL64I, + BFD_RELOC_IA64_TPREL64MSB, + BFD_RELOC_IA64_TPREL64LSB, + BFD_RELOC_IA64_LTOFF_TPREL22, + BFD_RELOC_IA64_DTPMOD64MSB, + BFD_RELOC_IA64_DTPMOD64LSB, + BFD_RELOC_IA64_LTOFF_DTPMOD22, + BFD_RELOC_IA64_DTPREL14, + BFD_RELOC_IA64_DTPREL22, + BFD_RELOC_IA64_DTPREL64I, + BFD_RELOC_IA64_DTPREL32MSB, + BFD_RELOC_IA64_DTPREL32LSB, + BFD_RELOC_IA64_DTPREL64MSB, + BFD_RELOC_IA64_DTPREL64LSB, + BFD_RELOC_IA64_LTOFF_DTPREL22, + +/* Motorola 68HC11 reloc. +This is the 8 bit high part of an absolute address. */ + BFD_RELOC_M68HC11_HI8, + +/* Motorola 68HC11 reloc. +This is the 8 bit low part of an absolute address. */ + BFD_RELOC_M68HC11_LO8, + +/* Motorola 68HC11 reloc. +This is the 3 bit of a value. */ + BFD_RELOC_M68HC11_3B, + +/* Motorola 68HC11 reloc. +This reloc marks the beginning of a jump/call instruction. +It is used for linker relaxation to correctly identify beginning +of instruction and change some branchs to use PC-relative +addressing mode. */ + BFD_RELOC_M68HC11_RL_JUMP, + +/* Motorola 68HC11 reloc. +This reloc marks a group of several instructions that gcc generates +and for which the linker relaxation pass can modify and/or remove +some of them. */ + BFD_RELOC_M68HC11_RL_GROUP, + +/* Motorola 68HC11 reloc. +This is the 16-bit lower part of an address. It is used for 'call' +instruction to specify the symbol address without any special +transformation (due to memory bank window). */ + BFD_RELOC_M68HC11_LO16, + +/* Motorola 68HC11 reloc. +This is a 8-bit reloc that specifies the page number of an address. +It is used by 'call' instruction to specify the page number of +the symbol. */ + BFD_RELOC_M68HC11_PAGE, + +/* Motorola 68HC11 reloc. +This is a 24-bit reloc that represents the address with a 16-bit +value and a 8-bit page number. The symbol address is transformed +to follow the 16K memory bank of 68HC12 (seen as mapped in the window). */ + BFD_RELOC_M68HC11_24, + +/* These relocs are only used within the CRIS assembler. They are not +(at present) written to any object files. */ + BFD_RELOC_CRIS_BDISP8, + BFD_RELOC_CRIS_UNSIGNED_5, + BFD_RELOC_CRIS_SIGNED_6, + BFD_RELOC_CRIS_UNSIGNED_6, + BFD_RELOC_CRIS_UNSIGNED_4, + +/* Relocs used in ELF shared libraries for CRIS. */ + BFD_RELOC_CRIS_COPY, + BFD_RELOC_CRIS_GLOB_DAT, + BFD_RELOC_CRIS_JUMP_SLOT, + BFD_RELOC_CRIS_RELATIVE, + +/* 32-bit offset to symbol-entry within GOT. */ + BFD_RELOC_CRIS_32_GOT, + +/* 16-bit offset to symbol-entry within GOT. */ + BFD_RELOC_CRIS_16_GOT, + +/* 32-bit offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_CRIS_32_GOTPLT, + +/* 16-bit offset to symbol-entry within GOT, with PLT handling. */ + BFD_RELOC_CRIS_16_GOTPLT, + +/* 32-bit offset to symbol, relative to GOT. */ + BFD_RELOC_CRIS_32_GOTREL, + +/* 32-bit offset to symbol with PLT entry, relative to GOT. */ + BFD_RELOC_CRIS_32_PLT_GOTREL, + +/* 32-bit offset to symbol with PLT entry, relative to this relocation. */ + BFD_RELOC_CRIS_32_PLT_PCREL, + +/* Intel i860 Relocations. */ + BFD_RELOC_860_COPY, + BFD_RELOC_860_GLOB_DAT, + BFD_RELOC_860_JUMP_SLOT, + BFD_RELOC_860_RELATIVE, + BFD_RELOC_860_PC26, + BFD_RELOC_860_PLT26, + BFD_RELOC_860_PC16, + BFD_RELOC_860_LOW0, + BFD_RELOC_860_SPLIT0, + BFD_RELOC_860_LOW1, + BFD_RELOC_860_SPLIT1, + BFD_RELOC_860_LOW2, + BFD_RELOC_860_SPLIT2, + BFD_RELOC_860_LOW3, + BFD_RELOC_860_LOGOT0, + BFD_RELOC_860_SPGOT0, + BFD_RELOC_860_LOGOT1, + BFD_RELOC_860_SPGOT1, + BFD_RELOC_860_LOGOTOFF0, + BFD_RELOC_860_SPGOTOFF0, + BFD_RELOC_860_LOGOTOFF1, + BFD_RELOC_860_SPGOTOFF1, + BFD_RELOC_860_LOGOTOFF2, + BFD_RELOC_860_LOGOTOFF3, + BFD_RELOC_860_LOPC, + BFD_RELOC_860_HIGHADJ, + BFD_RELOC_860_HAGOT, + BFD_RELOC_860_HAGOTOFF, + BFD_RELOC_860_HAPC, + BFD_RELOC_860_HIGH, + BFD_RELOC_860_HIGOT, + BFD_RELOC_860_HIGOTOFF, + +/* OpenRISC Relocations. */ + BFD_RELOC_OPENRISC_ABS_26, + BFD_RELOC_OPENRISC_REL_26, + +/* H8 elf Relocations. */ + BFD_RELOC_H8_DIR16A8, + BFD_RELOC_H8_DIR16R8, + BFD_RELOC_H8_DIR24A8, + BFD_RELOC_H8_DIR24R8, + BFD_RELOC_H8_DIR32A16, + +/* Sony Xstormy16 Relocations. */ + BFD_RELOC_XSTORMY16_REL_12, + BFD_RELOC_XSTORMY16_12, + BFD_RELOC_XSTORMY16_24, + BFD_RELOC_XSTORMY16_FPTR16, + +/* Relocations used by VAX ELF. */ + BFD_RELOC_VAX_GLOB_DAT, + BFD_RELOC_VAX_JMP_SLOT, + BFD_RELOC_VAX_RELATIVE, + +/* msp430 specific relocation codes */ + BFD_RELOC_MSP430_10_PCREL, + BFD_RELOC_MSP430_16_PCREL, + BFD_RELOC_MSP430_16, + BFD_RELOC_MSP430_16_PCREL_BYTE, + BFD_RELOC_MSP430_16_BYTE, + +/* IQ2000 Relocations. */ + BFD_RELOC_IQ2000_OFFSET_16, + BFD_RELOC_IQ2000_OFFSET_21, + BFD_RELOC_IQ2000_UHI16, + +/* Special Xtensa relocation used only by PLT entries in ELF shared +objects to indicate that the runtime linker should set the value +to one of its own internal functions or data structures. */ + BFD_RELOC_XTENSA_RTLD, + +/* Xtensa relocations for ELF shared objects. */ + BFD_RELOC_XTENSA_GLOB_DAT, + BFD_RELOC_XTENSA_JMP_SLOT, + BFD_RELOC_XTENSA_RELATIVE, + +/* Xtensa relocation used in ELF object files for symbols that may require +PLT entries. Otherwise, this is just a generic 32-bit relocation. */ + BFD_RELOC_XTENSA_PLT, + +/* Generic Xtensa relocations. Only the operand number is encoded +in the relocation. The details are determined by extracting the +instruction opcode. */ + BFD_RELOC_XTENSA_OP0, + BFD_RELOC_XTENSA_OP1, + BFD_RELOC_XTENSA_OP2, + +/* Xtensa relocation to mark that the assembler expanded the +instructions from an original target. The expansion size is +encoded in the reloc size. */ + BFD_RELOC_XTENSA_ASM_EXPAND, + +/* Xtensa relocation to mark that the linker should simplify +assembler-expanded instructions. This is commonly used +internally by the linker after analysis of a +BFD_RELOC_XTENSA_ASM_EXPAND. */ + BFD_RELOC_XTENSA_ASM_SIMPLIFY, + BFD_RELOC_UNUSED }; +typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; +reloc_howto_type * +bfd_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + +const char * +bfd_get_reloc_code_name PARAMS ((bfd_reloc_code_real_type code)); + +/* Extracted from syms.c. */ + +typedef struct symbol_cache_entry +{ + /* A pointer to the BFD which owns the symbol. This information + is necessary so that a back end can work out what additional + information (invisible to the application writer) is carried + with the symbol. + + This field is *almost* redundant, since you can use section->owner + instead, except that some symbols point to the global sections + bfd_{abs,com,und}_section. This could be fixed by making + these globals be per-bfd (or per-target-flavor). FIXME. */ + struct bfd *the_bfd; /* Use bfd_asymbol_bfd(sym) to access this field. */ + + /* The text of the symbol. The name is left alone, and not copied; the + application may not alter it. */ + const char *name; + + /* The value of the symbol. This really should be a union of a + numeric value with a pointer, since some flags indicate that + a pointer to another symbol is stored here. */ + symvalue value; + + /* Attributes of a symbol. */ +#define BSF_NO_FLAGS 0x00 + + /* The symbol has local scope; <> in <>. The value + is the offset into the section of the data. */ +#define BSF_LOCAL 0x01 + + /* The symbol has global scope; initialized data in <>. The + value is the offset into the section of the data. */ +#define BSF_GLOBAL 0x02 + + /* The symbol has global scope and is exported. The value is + the offset into the section of the data. */ +#define BSF_EXPORT BSF_GLOBAL /* No real difference. */ + + /* A normal C symbol would be one of: + <>, <>, <> or + <>. */ + + /* The symbol is a debugging record. The value has an arbitary + meaning, unless BSF_DEBUGGING_RELOC is also set. */ +#define BSF_DEBUGGING 0x08 + + /* The symbol denotes a function entry point. Used in ELF, + perhaps others someday. */ +#define BSF_FUNCTION 0x10 + + /* Used by the linker. */ +#define BSF_KEEP 0x20 +#define BSF_KEEP_G 0x40 + + /* A weak global symbol, overridable without warnings by + a regular global symbol of the same name. */ +#define BSF_WEAK 0x80 + + /* This symbol was created to point to a section, e.g. ELF's + STT_SECTION symbols. */ +#define BSF_SECTION_SYM 0x100 + + /* The symbol used to be a common symbol, but now it is + allocated. */ +#define BSF_OLD_COMMON 0x200 + + /* The default value for common data. */ +#define BFD_FORT_COMM_DEFAULT_VALUE 0 + + /* In some files the type of a symbol sometimes alters its + location in an output file - ie in coff a <> symbol + which is also <> symbol appears where it was + declared and not at the end of a section. This bit is set + by the target BFD part to convey this information. */ +#define BSF_NOT_AT_END 0x400 + + /* Signal that the symbol is the label of constructor section. */ +#define BSF_CONSTRUCTOR 0x800 + + /* Signal that the symbol is a warning symbol. The name is a + warning. The name of the next symbol is the one to warn about; + if a reference is made to a symbol with the same name as the next + symbol, a warning is issued by the linker. */ +#define BSF_WARNING 0x1000 + + /* Signal that the symbol is indirect. This symbol is an indirect + pointer to the symbol with the same name as the next symbol. */ +#define BSF_INDIRECT 0x2000 + + /* BSF_FILE marks symbols that contain a file name. This is used + for ELF STT_FILE symbols. */ +#define BSF_FILE 0x4000 + + /* Symbol is from dynamic linking information. */ +#define BSF_DYNAMIC 0x8000 + + /* The symbol denotes a data object. Used in ELF, and perhaps + others someday. */ +#define BSF_OBJECT 0x10000 + + /* This symbol is a debugging symbol. The value is the offset + into the section of the data. BSF_DEBUGGING should be set + as well. */ +#define BSF_DEBUGGING_RELOC 0x20000 + + /* This symbol is thread local. Used in ELF. */ +#define BSF_THREAD_LOCAL 0x40000 + + flagword flags; + + /* A pointer to the section to which this symbol is + relative. This will always be non NULL, there are special + sections for undefined and absolute symbols. */ + struct sec *section; + + /* Back end special data. */ + union + { + PTR p; + bfd_vma i; + } + udata; +} +asymbol; + +#define bfd_get_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) + +bfd_boolean +bfd_is_local_label PARAMS ((bfd *abfd, asymbol *sym)); + +bfd_boolean +bfd_is_local_label_name PARAMS ((bfd *abfd, const char *name)); + +#define bfd_is_local_label_name(abfd, name) \ + BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) + +#define bfd_canonicalize_symtab(abfd, location) \ + BFD_SEND (abfd, _bfd_canonicalize_symtab,\ + (abfd, location)) + +bfd_boolean +bfd_set_symtab PARAMS ((bfd *abfd, asymbol **location, unsigned int count)); + +void +bfd_print_symbol_vandf PARAMS ((bfd *abfd, PTR file, asymbol *symbol)); + +#define bfd_make_empty_symbol(abfd) \ + BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) + +asymbol * +_bfd_generic_make_empty_symbol PARAMS ((bfd *)); + +#define bfd_make_debug_symbol(abfd,ptr,size) \ + BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) + +int +bfd_decode_symclass PARAMS ((asymbol *symbol)); + +bfd_boolean +bfd_is_undefined_symclass PARAMS ((int symclass)); + +void +bfd_symbol_info PARAMS ((asymbol *symbol, symbol_info *ret)); + +bfd_boolean +bfd_copy_private_symbol_data PARAMS ((bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym)); + +#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ + BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ + (ibfd, isymbol, obfd, osymbol)) + +/* Extracted from bfd.c. */ +struct bfd +{ + /* A unique identifier of the BFD */ + unsigned int id; + + /* The filename the application opened the BFD with. */ + const char *filename; + + /* A pointer to the target jump table. */ + const struct bfd_target *xvec; + + /* To avoid dragging too many header files into every file that + includes `<>', IOSTREAM has been declared as a "char *", + and MTIME as a "long". Their correct types, to which they + are cast when used, are "FILE *" and "time_t". The iostream + is the result of an fopen on the filename. However, if the + BFD_IN_MEMORY flag is set, then iostream is actually a pointer + to a bfd_in_memory struct. */ + PTR iostream; + + /* Is the file descriptor being cached? That is, can it be closed as + needed, and re-opened when accessed later? */ + bfd_boolean cacheable; + + /* 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. */ + bfd_boolean target_defaulted; + + /* The caching routines use these to maintain a + least-recently-used list of BFDs. */ + struct bfd *lru_prev, *lru_next; + + /* When a file is closed by the caching routines, BFD retains + state information on the file here... */ + ufile_ptr where; + + /* ... and here: (``once'' means at least once). */ + bfd_boolean opened_once; + + /* Set if we have a locally maintained mtime value, rather than + getting it from the file each time. */ + bfd_boolean mtime_set; + + /* File modified time, if mtime_set is TRUE. */ + long mtime; + + /* Reserved for an unimplemented file locking extension. */ + int ifd; + + /* The format which belongs to the BFD. (object, core, etc.) */ + bfd_format format; + + /* The direction with which the BFD was opened. */ + enum bfd_direction + { + no_direction = 0, + read_direction = 1, + write_direction = 2, + both_direction = 3 + } + direction; + + /* Format_specific flags. */ + flagword flags; + + /* Currently my_archive is tested before adding origin to + anything. I believe that this can become always an add of + origin, with origin set to 0 for non archive files. */ + ufile_ptr origin; + + /* Remember when output has begun, to stop strange things + from happening. */ + bfd_boolean output_has_begun; + + /* A hash table for section names. */ + struct bfd_hash_table section_htab; + + /* Pointer to linked list of sections. */ + struct sec *sections; + + /* The place where we add to the section list. */ + struct sec **section_tail; + + /* The number of sections. */ + unsigned int section_count; + + /* 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). */ + struct symbol_cache_entry **outsymbols; + + /* Used for slurped dynamic symbol tables. */ + unsigned int dynsymcount; + + /* Pointer to structure which contains architecture information. */ + const struct bfd_arch_info *arch_info; + + /* Stuff only useful for archives. */ + PTR arelt_data; + struct bfd *my_archive; /* The containing archive BFD. */ + struct bfd *next; /* The next BFD in the archive. */ + struct bfd *archive_head; /* The first BFD in the archive. */ + bfd_boolean has_armap; + + /* 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; + + /* Used by the back end to hold private data. */ + union + { + struct aout_data_struct *aout_data; + struct artdata *aout_ar_data; + struct _oasys_data *oasys_obj_data; + struct _oasys_ar_data *oasys_ar_data; + struct coff_tdata *coff_obj_data; + struct pe_tdata *pe_obj_data; + struct xcoff_tdata *xcoff_obj_data; + struct ecoff_tdata *ecoff_obj_data; + struct ieee_data_struct *ieee_data; + struct ieee_ar_data_struct *ieee_ar_data; + struct srec_data_struct *srec_data; + struct ihex_data_struct *ihex_data; + struct tekhex_data_struct *tekhex_data; + struct elf_obj_tdata *elf_obj_data; + struct nlm_obj_tdata *nlm_obj_data; + struct bout_data_struct *bout_data; + struct mmo_data_struct *mmo_data; + struct sun_core_struct *sun_core_data; + struct sco5_core_struct *sco5_core_data; + struct trad_core_struct *trad_core_data; + struct som_data_struct *som_data; + struct hpux_core_struct *hpux_core_data; + struct hppabsd_core_struct *hppabsd_core_data; + struct sgi_core_struct *sgi_core_data; + struct lynx_core_struct *lynx_core_data; + struct osf_core_struct *osf_core_data; + struct cisco_core_struct *cisco_core_data; + struct versados_data_struct *versados_data; + struct netbsd_core_struct *netbsd_core_data; + struct mach_o_data_struct *mach_o_data; + struct mach_o_fat_data_struct *mach_o_fat_data; + struct bfd_pef_data_struct *pef_data; + struct bfd_pef_xlib_data_struct *pef_xlib_data; + struct bfd_sym_data_struct *sym_data; + PTR any; + } + tdata; + + /* Used by the application to hold private data. */ + PTR usrdata; + + /* Where all the allocated stuff under this BFD goes. This is a + struct objalloc *, but we use PTR to avoid requiring the inclusion of + objalloc.h. */ + PTR memory; +}; + +typedef enum bfd_error +{ + bfd_error_no_error = 0, + bfd_error_system_call, + bfd_error_invalid_target, + bfd_error_wrong_format, + bfd_error_wrong_object_format, + bfd_error_invalid_operation, + bfd_error_no_memory, + bfd_error_no_symbols, + bfd_error_no_armap, + bfd_error_no_more_archived_files, + bfd_error_malformed_archive, + bfd_error_file_not_recognized, + bfd_error_file_ambiguously_recognized, + bfd_error_no_contents, + bfd_error_nonrepresentable_section, + bfd_error_no_debug_section, + bfd_error_bad_value, + bfd_error_file_truncated, + bfd_error_file_too_big, + bfd_error_invalid_error_code +} +bfd_error_type; + +bfd_error_type +bfd_get_error PARAMS ((void)); + +void +bfd_set_error PARAMS ((bfd_error_type error_tag)); + +const char * +bfd_errmsg PARAMS ((bfd_error_type error_tag)); + +void +bfd_perror PARAMS ((const char *message)); + +typedef void (*bfd_error_handler_type) PARAMS ((const char *, ...)); + +bfd_error_handler_type +bfd_set_error_handler PARAMS ((bfd_error_handler_type)); + +void +bfd_set_error_program_name PARAMS ((const char *)); + +bfd_error_handler_type +bfd_get_error_handler PARAMS ((void)); + +const char * +bfd_archive_filename PARAMS ((bfd *)); + +long +bfd_get_reloc_upper_bound PARAMS ((bfd *abfd, asection *sect)); + +long +bfd_canonicalize_reloc PARAMS ((bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms)); + +void +bfd_set_reloc PARAMS ((bfd *abfd, asection *sec, arelent **rel, unsigned int count)); + +bfd_boolean +bfd_set_file_flags PARAMS ((bfd *abfd, flagword flags)); + +int +bfd_get_arch_size PARAMS ((bfd *abfd)); + +int +bfd_get_sign_extend_vma PARAMS ((bfd *abfd)); + +bfd_boolean +bfd_set_start_address PARAMS ((bfd *abfd, bfd_vma vma)); + +unsigned int +bfd_get_gp_size PARAMS ((bfd *abfd)); + +void +bfd_set_gp_size PARAMS ((bfd *abfd, unsigned int i)); + +bfd_vma +bfd_scan_vma PARAMS ((const char *string, const char **end, int base)); + +bfd_boolean +bfd_copy_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); + +#define bfd_copy_private_bfd_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ + (ibfd, obfd)) +bfd_boolean +bfd_merge_private_bfd_data PARAMS ((bfd *ibfd, bfd *obfd)); + +#define bfd_merge_private_bfd_data(ibfd, obfd) \ + BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ + (ibfd, obfd)) +bfd_boolean +bfd_set_private_flags PARAMS ((bfd *abfd, flagword flags)); + +#define bfd_set_private_flags(abfd, flags) \ + BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) +#define bfd_sizeof_headers(abfd, reloc) \ + BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) + +#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)) + +#define bfd_debug_info_start(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) + +#define bfd_debug_info_end(abfd) \ + BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) + +#define bfd_debug_info_accumulate(abfd, section) \ + BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) + +#define bfd_stat_arch_elt(abfd, stat) \ + BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) + +#define bfd_update_armap_timestamp(abfd) \ + BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) + +#define bfd_set_arch_mach(abfd, arch, mach)\ + BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) + +#define bfd_relax_section(abfd, section, link_info, again) \ + BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) + +#define bfd_gc_sections(abfd, link_info) \ + BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) + +#define bfd_merge_sections(abfd, link_info) \ + BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) + +#define bfd_discard_group(abfd, sec) \ + BFD_SEND (abfd, _bfd_discard_group, (abfd, sec)) + +#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)) + +#define bfd_link_just_syms(sec, info) \ + BFD_SEND (abfd, _bfd_link_just_syms, (sec, info)) + +#define bfd_final_link(abfd, info) \ + BFD_SEND (abfd, _bfd_final_link, (abfd, info)) + +#define bfd_free_cached_info(abfd) \ + BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) + +#define bfd_get_dynamic_symtab_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) + +#define bfd_print_private_bfd_data(abfd, file)\ + BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) + +#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ + BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) + +#define bfd_get_dynamic_reloc_upper_bound(abfd) \ + BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) + +#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ + BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) + +extern bfd_byte *bfd_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, + struct bfd_link_order *, bfd_byte *, + bfd_boolean, asymbol **)); + +bfd_boolean +bfd_alt_mach_code PARAMS ((bfd *abfd, int alternative)); + +struct bfd_preserve +{ + PTR marker; + PTR tdata; + flagword flags; + const struct bfd_arch_info *arch_info; + struct sec *sections; + struct sec **section_tail; + unsigned int section_count; + struct bfd_hash_table section_htab; +}; + +bfd_boolean +bfd_preserve_save PARAMS ((bfd *, struct bfd_preserve *)); + +void +bfd_preserve_restore PARAMS ((bfd *, struct bfd_preserve *)); + +void +bfd_preserve_finish PARAMS ((bfd *, struct bfd_preserve *)); + +/* Extracted from archive.c. */ +symindex +bfd_get_next_mapent PARAMS ((bfd *abfd, symindex previous, carsym **sym)); + +bfd_boolean +bfd_set_archive_head PARAMS ((bfd *output, bfd *new_head)); + +bfd * +bfd_openr_next_archived_file PARAMS ((bfd *archive, bfd *previous)); + +/* Extracted from corefile.c. */ +const char * +bfd_core_file_failing_command PARAMS ((bfd *abfd)); + +int +bfd_core_file_failing_signal PARAMS ((bfd *abfd)); + +bfd_boolean +core_file_matches_executable_p PARAMS ((bfd *core_bfd, bfd *exec_bfd)); + +/* Extracted from targets.c. */ +#define BFD_SEND(bfd, message, arglist) \ + ((*((bfd)->xvec->message)) arglist) + +#ifdef DEBUG_BFD_SEND +#undef BFD_SEND +#define BFD_SEND(bfd, message, arglist) \ + (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ + ((*((bfd)->xvec->message)) arglist) : \ + (bfd_assert (__FILE__,__LINE__), NULL)) +#endif +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) + +#ifdef DEBUG_BFD_SEND +#undef BFD_SEND_FMT +#define BFD_SEND_FMT(bfd, message, arglist) \ + (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ + (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ + (bfd_assert (__FILE__,__LINE__), NULL)) +#endif + +enum bfd_flavour +{ + bfd_target_unknown_flavour, + bfd_target_aout_flavour, + bfd_target_coff_flavour, + bfd_target_ecoff_flavour, + bfd_target_xcoff_flavour, + bfd_target_elf_flavour, + bfd_target_ieee_flavour, + bfd_target_nlm_flavour, + bfd_target_oasys_flavour, + bfd_target_tekhex_flavour, + bfd_target_srec_flavour, + bfd_target_ihex_flavour, + bfd_target_som_flavour, + bfd_target_os9k_flavour, + bfd_target_versados_flavour, + bfd_target_msdos_flavour, + bfd_target_ovax_flavour, + bfd_target_evax_flavour, + bfd_target_mmo_flavour, + bfd_target_mach_o_flavour, + bfd_target_pef_flavour, + bfd_target_pef_xlib_flavour, + bfd_target_sym_flavour +}; + +enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; + +/* Forward declaration. */ +typedef struct bfd_link_info _bfd_link_info; + +typedef struct bfd_target +{ + /* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. */ + char *name; + + /* The "flavour" of a back end is a general indication about + the contents of a file. */ + enum bfd_flavour flavour; + + /* The order of bytes within the data area of a file. */ + enum bfd_endian byteorder; + + /* The order of bytes within the header parts of a file. */ + enum bfd_endian header_byteorder; + + /* A mask of all the flags which an executable may have set - + from the set <>, <>, ...<>. */ + flagword object_flags; + + /* A mask of all the flags which a section may have set - from + the set <>, <>, ...<>. */ + flagword section_flags; + + /* The character normally found at the front of a symbol. + (if any), perhaps `_'. */ + char symbol_leading_char; + + /* The pad character for file names within an archive header. */ + char ar_pad_char; + + /* The maximum number of characters in an archive header. */ + unsigned short ar_max_namelen; + + /* Entries for byte swapping for data. These are different from the + other entry points, since they don't take a BFD asthe first argument. + Certain other handlers could do the same. */ + bfd_vma (*bfd_getx64) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *)); + void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx32) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *)); + void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_getx16) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *)); + void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); + + /* Byte swapping for the headers. */ + bfd_vma (*bfd_h_getx64) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx32) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); + bfd_vma (*bfd_h_getx16) PARAMS ((const bfd_byte *)); + bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *)); + void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); + + /* Format dependent routines: these are vectors of entry points + within the target vector structure, one for each format to check. */ + + /* Check the format of a file being read. Return a <> or zero. */ + const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); + + /* Set the format of a file being written. */ + bfd_boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); + + /* Write cached information into a file being written, at <>. */ + bfd_boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); + + + /* Generic entry points. */ +#define BFD_JUMP_TABLE_GENERIC(NAME) \ +CONCAT2 (NAME,_close_and_cleanup), \ +CONCAT2 (NAME,_bfd_free_cached_info), \ +CONCAT2 (NAME,_new_section_hook), \ +CONCAT2 (NAME,_get_section_contents), \ +CONCAT2 (NAME,_get_section_contents_in_window) + + /* Called when the BFD is being closed to do any necessary cleanup. */ + bfd_boolean (*_close_and_cleanup) PARAMS ((bfd *)); + /* Ask the BFD to free all cached information. */ + bfd_boolean (*_bfd_free_cached_info) PARAMS ((bfd *)); + /* Called when a new section is created. */ + bfd_boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); + /* Read the contents of a section. */ + bfd_boolean (*_bfd_get_section_contents) + PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); + bfd_boolean (*_bfd_get_section_contents_in_window) + PARAMS ((bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type)); + + /* Entry points to copy private data. */ +#define BFD_JUMP_TABLE_COPY(NAME) \ +CONCAT2 (NAME,_bfd_copy_private_bfd_data), \ +CONCAT2 (NAME,_bfd_merge_private_bfd_data), \ +CONCAT2 (NAME,_bfd_copy_private_section_data), \ +CONCAT2 (NAME,_bfd_copy_private_symbol_data), \ +CONCAT2 (NAME,_bfd_set_private_flags), \ +CONCAT2 (NAME,_bfd_print_private_bfd_data) \ + /* Called to copy BFD general private data from one object file + to another. */ + bfd_boolean (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *)); + /* Called to merge BFD general private data from one object file + to a common output file when linking. */ + bfd_boolean (*_bfd_merge_private_bfd_data) PARAMS ((bfd *, bfd *)); + /* Called to copy BFD private section data from one object file + to another. */ + bfd_boolean (*_bfd_copy_private_section_data) + PARAMS ((bfd *, sec_ptr, bfd *, sec_ptr)); + /* Called to copy BFD private symbol data from one symbol + to another. */ + bfd_boolean (*_bfd_copy_private_symbol_data) + PARAMS ((bfd *, asymbol *, bfd *, asymbol *)); + /* Called to set private backend flags. */ + bfd_boolean (*_bfd_set_private_flags) PARAMS ((bfd *, flagword)); + + /* Called to print private BFD data. */ + bfd_boolean (*_bfd_print_private_bfd_data) PARAMS ((bfd *, PTR)); + + /* Core file entry points. */ +#define BFD_JUMP_TABLE_CORE(NAME) \ +CONCAT2 (NAME,_core_file_failing_command), \ +CONCAT2 (NAME,_core_file_failing_signal), \ +CONCAT2 (NAME,_core_file_matches_executable_p) + char * (*_core_file_failing_command) PARAMS ((bfd *)); + int (*_core_file_failing_signal) PARAMS ((bfd *)); + bfd_boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); + + /* Archive entry points. */ +#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ +CONCAT2 (NAME,_slurp_armap), \ +CONCAT2 (NAME,_slurp_extended_name_table), \ +CONCAT2 (NAME,_construct_extended_name_table), \ +CONCAT2 (NAME,_truncate_arname), \ +CONCAT2 (NAME,_write_armap), \ +CONCAT2 (NAME,_read_ar_hdr), \ +CONCAT2 (NAME,_openr_next_archived_file), \ +CONCAT2 (NAME,_get_elt_at_index), \ +CONCAT2 (NAME,_generic_stat_arch_elt), \ +CONCAT2 (NAME,_update_armap_timestamp) + bfd_boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); + bfd_boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); + bfd_boolean (*_bfd_construct_extended_name_table) + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); + void (*_bfd_truncate_arname) PARAMS ((bfd *, const char *, char *)); + bfd_boolean (*write_armap) + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int)); + PTR (*_bfd_read_ar_hdr_fn) PARAMS ((bfd *)); + bfd * (*openr_next_archived_file) PARAMS ((bfd *, bfd *)); +#define bfd_get_elt_at_index(b,i) BFD_SEND(b, _bfd_get_elt_at_index, (b,i)) + bfd * (*_bfd_get_elt_at_index) PARAMS ((bfd *, symindex)); + int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); + bfd_boolean (*_bfd_update_armap_timestamp) PARAMS ((bfd *)); + + /* Entry points used for symbols. */ +#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ +CONCAT2 (NAME,_get_symtab_upper_bound), \ +CONCAT2 (NAME,_get_symtab), \ +CONCAT2 (NAME,_make_empty_symbol), \ +CONCAT2 (NAME,_print_symbol), \ +CONCAT2 (NAME,_get_symbol_info), \ +CONCAT2 (NAME,_bfd_is_local_label_name), \ +CONCAT2 (NAME,_get_lineno), \ +CONCAT2 (NAME,_find_nearest_line), \ +CONCAT2 (NAME,_bfd_make_debug_symbol), \ +CONCAT2 (NAME,_read_minisymbols), \ +CONCAT2 (NAME,_minisymbol_to_symbol) + long (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *)); + long (*_bfd_canonicalize_symtab) PARAMS ((bfd *, + struct symbol_cache_entry **)); + struct symbol_cache_entry * + (*_bfd_make_empty_symbol) PARAMS ((bfd *)); + void (*_bfd_print_symbol) + PARAMS ((bfd *, PTR, struct symbol_cache_entry *, bfd_print_symbol_type)); +#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) + void (*_bfd_get_symbol_info) + PARAMS ((bfd *, struct symbol_cache_entry *, symbol_info *)); +#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) + bfd_boolean (*_bfd_is_local_label_name) PARAMS ((bfd *, const char *)); + + alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); + bfd_boolean (*_bfd_find_nearest_line) + PARAMS ((bfd *, struct sec *, struct symbol_cache_entry **, bfd_vma, + const char **, const char **, unsigned int *)); + /* Back-door to allow format-aware applications to create debug symbols + while using BFD for everything else. Currently used by the assembler + when creating COFF files. */ + asymbol * (*_bfd_make_debug_symbol) + PARAMS ((bfd *, void *, unsigned long size)); +#define bfd_read_minisymbols(b, d, m, s) \ + BFD_SEND (b, _read_minisymbols, (b, d, m, s)) + long (*_read_minisymbols) + PARAMS ((bfd *, bfd_boolean, PTR *, unsigned int *)); +#define bfd_minisymbol_to_symbol(b, d, m, f) \ + BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) + asymbol * (*_minisymbol_to_symbol) + PARAMS ((bfd *, bfd_boolean, const PTR, asymbol *)); + + /* Routines for relocs. */ +#define BFD_JUMP_TABLE_RELOCS(NAME) \ +CONCAT2 (NAME,_get_reloc_upper_bound), \ +CONCAT2 (NAME,_canonicalize_reloc), \ +CONCAT2 (NAME,_bfd_reloc_type_lookup) + long (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); + long (*_bfd_canonicalize_reloc) + PARAMS ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry **)); + /* See documentation on reloc types. */ + reloc_howto_type * + (*reloc_type_lookup) PARAMS ((bfd *, bfd_reloc_code_real_type)); + + /* Routines used when writing an object file. */ +#define BFD_JUMP_TABLE_WRITE(NAME) \ +CONCAT2 (NAME,_set_arch_mach), \ +CONCAT2 (NAME,_set_section_contents) + bfd_boolean (*_bfd_set_arch_mach) + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); + bfd_boolean (*_bfd_set_section_contents) + PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); + + /* Routines used by the linker. */ +#define BFD_JUMP_TABLE_LINK(NAME) \ +CONCAT2 (NAME,_sizeof_headers), \ +CONCAT2 (NAME,_bfd_get_relocated_section_contents), \ +CONCAT2 (NAME,_bfd_relax_section), \ +CONCAT2 (NAME,_bfd_link_hash_table_create), \ +CONCAT2 (NAME,_bfd_link_hash_table_free), \ +CONCAT2 (NAME,_bfd_link_add_symbols), \ +CONCAT2 (NAME,_bfd_link_just_syms), \ +CONCAT2 (NAME,_bfd_final_link), \ +CONCAT2 (NAME,_bfd_link_split_section), \ +CONCAT2 (NAME,_bfd_gc_sections), \ +CONCAT2 (NAME,_bfd_merge_sections), \ +CONCAT2 (NAME,_bfd_discard_group) + int (*_bfd_sizeof_headers) PARAMS ((bfd *, bfd_boolean)); + bfd_byte * (*_bfd_get_relocated_section_contents) + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, bfd_boolean, struct symbol_cache_entry **)); + + bfd_boolean (*_bfd_relax_section) + PARAMS ((bfd *, struct sec *, struct bfd_link_info *, bfd_boolean *)); + + /* Create a hash table for the linker. Different backends store + different information in this table. */ + struct bfd_link_hash_table * + (*_bfd_link_hash_table_create) PARAMS ((bfd *)); + + /* Release the memory associated with the linker hash table. */ + void (*_bfd_link_hash_table_free) + PARAMS ((struct bfd_link_hash_table *)); + + /* Add symbols from this object file into the hash table. */ + bfd_boolean (*_bfd_link_add_symbols) + PARAMS ((bfd *, struct bfd_link_info *)); + + /* Indicate that we are only retrieving symbol values from this section. */ + void (*_bfd_link_just_syms) + PARAMS ((asection *, struct bfd_link_info *)); + + /* Do a link based on the link_order structures attached to each + section of the BFD. */ + bfd_boolean (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Should this section be split up into smaller pieces during linking. */ + bfd_boolean (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *)); + + /* Remove sections that are not referenced from the output. */ + bfd_boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Attempt to merge SEC_MERGE sections. */ + bfd_boolean (*_bfd_merge_sections) PARAMS ((bfd *, struct bfd_link_info *)); + + /* Discard members of a group. */ + bfd_boolean (*_bfd_discard_group) PARAMS ((bfd *, struct sec *)); + + /* Routines to handle dynamic symbols and relocs. */ +#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ +CONCAT2 (NAME,_get_dynamic_symtab_upper_bound), \ +CONCAT2 (NAME,_canonicalize_dynamic_symtab), \ +CONCAT2 (NAME,_get_dynamic_reloc_upper_bound), \ +CONCAT2 (NAME,_canonicalize_dynamic_reloc) + /* Get the amount of memory required to hold the dynamic symbols. */ + long (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *)); + /* Read in the dynamic symbols. */ + long (*_bfd_canonicalize_dynamic_symtab) + PARAMS ((bfd *, struct symbol_cache_entry **)); + /* Get the amount of memory required to hold the dynamic relocs. */ + long (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *)); + /* Read in the dynamic relocs. */ + long (*_bfd_canonicalize_dynamic_reloc) + PARAMS ((bfd *, arelent **, struct symbol_cache_entry **)); + + /* Opposite endian version of this target. */ + const struct bfd_target * alternative_target; + + /* Data for use by back-end routines, which isn't + generic enough to belong in this structure. */ + PTR backend_data; + +} bfd_target; + +bfd_boolean +bfd_set_default_target PARAMS ((const char *name)); + +const bfd_target * +bfd_find_target PARAMS ((const char *target_name, bfd *abfd)); + +const char ** +bfd_target_list PARAMS ((void)); + +const bfd_target * +bfd_search_for_target PARAMS ((int (* search_func) + (const bfd_target *, void *), + void *)); + +/* Extracted from format.c. */ +bfd_boolean +bfd_check_format PARAMS ((bfd *abfd, bfd_format format)); + +bfd_boolean +bfd_check_format_matches PARAMS ((bfd *abfd, bfd_format format, + char ***matching)); + +bfd_boolean +bfd_set_format PARAMS ((bfd *abfd, bfd_format format)); + +const char * +bfd_format_string PARAMS ((bfd_format format)); + +/* Extracted from linker.c. */ +bfd_boolean +bfd_link_split_section PARAMS ((bfd *abfd, asection *sec)); + +#define bfd_link_split_section(abfd, sec) \ + BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) + +/* Extracted from simple.c. */ +bfd_byte * +bfd_simple_get_relocated_section_contents PARAMS ((bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table)); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/contrib/binutils-2.14/bfd/bfd.c b/contrib/binutils-2.14/bfd/bfd.c new file mode 100644 index 0000000000..32250823a1 --- /dev/null +++ b/contrib/binutils-2.14/bfd/bfd.c @@ -0,0 +1,1441 @@ +/* Generic BFD library interface and support routines. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + <> + + A BFD has type <>; objects of this type are the + cornerstone of any application using BFD. Using BFD + consists of making references though the BFD and to data in the BFD. + + Here is the structure that defines the type <>. It + contains the major data about the file and pointers + to the rest of the data. + +CODE_FRAGMENT +. +.struct bfd +.{ +. {* A unique identifier of the BFD *} +. unsigned int id; +. +. {* The filename the application opened the BFD with. *} +. const char *filename; +. +. {* A pointer to the target jump table. *} +. const struct bfd_target *xvec; +. +. {* To avoid dragging too many header files into every file that +. includes `<>', IOSTREAM has been declared as a "char *", +. and MTIME as a "long". Their correct types, to which they +. are cast when used, are "FILE *" and "time_t". The iostream +. is the result of an fopen on the filename. However, if the +. BFD_IN_MEMORY flag is set, then iostream is actually a pointer +. to a bfd_in_memory struct. *} +. PTR iostream; +. +. {* Is the file descriptor being cached? That is, can it be closed as +. needed, and re-opened when accessed later? *} +. bfd_boolean cacheable; +. +. {* 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. *} +. bfd_boolean target_defaulted; +. +. {* The caching routines use these to maintain a +. least-recently-used list of BFDs. *} +. struct bfd *lru_prev, *lru_next; +. +. {* When a file is closed by the caching routines, BFD retains +. state information on the file here... *} +. ufile_ptr where; +. +. {* ... and here: (``once'' means at least once). *} +. bfd_boolean opened_once; +. +. {* Set if we have a locally maintained mtime value, rather than +. getting it from the file each time. *} +. bfd_boolean mtime_set; +. +. {* File modified time, if mtime_set is TRUE. *} +. long mtime; +. +. {* Reserved for an unimplemented file locking extension. *} +. int ifd; +. +. {* The format which belongs to the BFD. (object, core, etc.) *} +. bfd_format format; +. +. {* The direction with which the BFD was opened. *} +. enum bfd_direction +. { +. no_direction = 0, +. read_direction = 1, +. write_direction = 2, +. both_direction = 3 +. } +. direction; +. +. {* Format_specific flags. *} +. flagword flags; +. +. {* Currently my_archive is tested before adding origin to +. anything. I believe that this can become always an add of +. origin, with origin set to 0 for non archive files. *} +. ufile_ptr origin; +. +. {* Remember when output has begun, to stop strange things +. from happening. *} +. bfd_boolean output_has_begun; +. +. {* A hash table for section names. *} +. struct bfd_hash_table section_htab; +. +. {* Pointer to linked list of sections. *} +. struct sec *sections; +. +. {* The place where we add to the section list. *} +. struct sec **section_tail; +. +. {* The number of sections. *} +. unsigned int section_count; +. +. {* 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). *} +. struct symbol_cache_entry **outsymbols; +. +. {* Used for slurped dynamic symbol tables. *} +. unsigned int dynsymcount; +. +. {* Pointer to structure which contains architecture information. *} +. const struct bfd_arch_info *arch_info; +. +. {* Stuff only useful for archives. *} +. PTR arelt_data; +. struct bfd *my_archive; {* The containing archive BFD. *} +. struct bfd *next; {* The next BFD in the archive. *} +. struct bfd *archive_head; {* The first BFD in the archive. *} +. bfd_boolean has_armap; +. +. {* 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; +. +. {* Used by the back end to hold private data. *} +. union +. { +. struct aout_data_struct *aout_data; +. struct artdata *aout_ar_data; +. struct _oasys_data *oasys_obj_data; +. struct _oasys_ar_data *oasys_ar_data; +. struct coff_tdata *coff_obj_data; +. struct pe_tdata *pe_obj_data; +. struct xcoff_tdata *xcoff_obj_data; +. struct ecoff_tdata *ecoff_obj_data; +. struct ieee_data_struct *ieee_data; +. struct ieee_ar_data_struct *ieee_ar_data; +. struct srec_data_struct *srec_data; +. struct ihex_data_struct *ihex_data; +. struct tekhex_data_struct *tekhex_data; +. struct elf_obj_tdata *elf_obj_data; +. struct nlm_obj_tdata *nlm_obj_data; +. struct bout_data_struct *bout_data; +. struct mmo_data_struct *mmo_data; +. struct sun_core_struct *sun_core_data; +. struct sco5_core_struct *sco5_core_data; +. struct trad_core_struct *trad_core_data; +. struct som_data_struct *som_data; +. struct hpux_core_struct *hpux_core_data; +. struct hppabsd_core_struct *hppabsd_core_data; +. struct sgi_core_struct *sgi_core_data; +. struct lynx_core_struct *lynx_core_data; +. struct osf_core_struct *osf_core_data; +. struct cisco_core_struct *cisco_core_data; +. struct versados_data_struct *versados_data; +. struct netbsd_core_struct *netbsd_core_data; +. struct mach_o_data_struct *mach_o_data; +. struct mach_o_fat_data_struct *mach_o_fat_data; +. struct bfd_pef_data_struct *pef_data; +. struct bfd_pef_xlib_data_struct *pef_xlib_data; +. struct bfd_sym_data_struct *sym_data; +. PTR any; +. } +. tdata; +. +. {* Used by the application to hold private data. *} +. PTR usrdata; +. +. {* Where all the allocated stuff under this BFD goes. This is a +. struct objalloc *, but we use PTR to avoid requiring the inclusion of +. objalloc.h. *} +. PTR memory; +.}; +. +*/ + +#include "bfd.h" +#include "bfdver.h" +#include "sysdep.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#include "libiberty.h" +#include "safe-ctype.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "coff/sym.h" +#include "libcoff.h" +#include "libecoff.h" +#undef obj_symbols +#include "elf-bfd.h" + +/* provide storage for subsystem, stack and heap data which may have been + passed in on the command line. Ld puts this data into a bfd_link_info + struct which ultimately gets passed in to the bfd. When it arrives, copy + it to the following struct so that the data will be available in coffcode.h + where it is needed. The typedef's used are defined in bfd.h */ + +/* +SECTION + Error reporting + + Most BFD functions return nonzero on success (check their + individual documentation for precise semantics). On an error, + they call <> to set an error condition that callers + can check by calling <>. + If that returns <>, then check + <>. + + The easiest way to report a BFD error to the user is to + use <>. + +SUBSECTION + Type <> + + The values returned by <> are defined by the + enumerated type <>. + +CODE_FRAGMENT +. +.typedef enum bfd_error +.{ +. bfd_error_no_error = 0, +. bfd_error_system_call, +. bfd_error_invalid_target, +. bfd_error_wrong_format, +. bfd_error_wrong_object_format, +. bfd_error_invalid_operation, +. bfd_error_no_memory, +. bfd_error_no_symbols, +. bfd_error_no_armap, +. bfd_error_no_more_archived_files, +. bfd_error_malformed_archive, +. bfd_error_file_not_recognized, +. bfd_error_file_ambiguously_recognized, +. bfd_error_no_contents, +. bfd_error_nonrepresentable_section, +. bfd_error_no_debug_section, +. bfd_error_bad_value, +. bfd_error_file_truncated, +. bfd_error_file_too_big, +. bfd_error_invalid_error_code +.} +.bfd_error_type; +. +*/ + +static bfd_error_type bfd_error = bfd_error_no_error; + +const char *const bfd_errmsgs[] = +{ + N_("No error"), + N_("System call error"), + N_("Invalid bfd target"), + N_("File in wrong format"), + N_("Archive object file in wrong format"), + N_("Invalid operation"), + N_("Memory exhausted"), + N_("No symbols"), + N_("Archive has no index; run ranlib to add one"), + N_("No more archived files"), + N_("Malformed archive"), + N_("File format not recognized"), + N_("File format is ambiguous"), + N_("Section has no contents"), + N_("Nonrepresentable section on output"), + N_("Symbol needs debug section which does not exist"), + N_("Bad value"), + N_("File truncated"), + N_("File too big"), + N_("#") +}; + +/* +FUNCTION + bfd_get_error + +SYNOPSIS + bfd_error_type bfd_get_error (void); + +DESCRIPTION + Return the current BFD error condition. +*/ + +bfd_error_type +bfd_get_error () +{ + return bfd_error; +} + +/* +FUNCTION + bfd_set_error + +SYNOPSIS + void bfd_set_error (bfd_error_type error_tag); + +DESCRIPTION + Set the BFD error condition to be @var{error_tag}. +*/ + +void +bfd_set_error (error_tag) + bfd_error_type error_tag; +{ + bfd_error = error_tag; +} + +/* +FUNCTION + bfd_errmsg + +SYNOPSIS + const char *bfd_errmsg (bfd_error_type error_tag); + +DESCRIPTION + Return a string describing the error @var{error_tag}, or + the system error if @var{error_tag} is <>. +*/ + +const char * +bfd_errmsg (error_tag) + bfd_error_type error_tag; +{ +#ifndef errno + extern int errno; +#endif + if (error_tag == bfd_error_system_call) + return xstrerror (errno); + + if ((((int) error_tag < (int) bfd_error_no_error) || + ((int) error_tag > (int) bfd_error_invalid_error_code))) + error_tag = bfd_error_invalid_error_code;/* sanity check */ + + return _(bfd_errmsgs [(int)error_tag]); +} + +/* +FUNCTION + bfd_perror + +SYNOPSIS + void bfd_perror (const char *message); + +DESCRIPTION + Print to the standard error stream a string describing the + last BFD error that occurred, or the last system error if + the last BFD error was a system call failure. If @var{message} + is non-NULL and non-empty, the error string printed is preceded + by @var{message}, a colon, and a space. It is followed by a newline. +*/ + +void +bfd_perror (message) + const char *message; +{ + if (bfd_get_error () == bfd_error_system_call) + /* Must be a system error then. */ + perror ((char *)message); + else + { + if (message == NULL || *message == '\0') + fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ())); + else + fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ())); + } +} + +/* +SUBSECTION + BFD error handler + + Some BFD functions want to print messages describing the + problem. They call a BFD error handler function. This + function may be overriden by the program. + + The BFD error handler acts like printf. + +CODE_FRAGMENT +. +.typedef void (*bfd_error_handler_type) PARAMS ((const char *, ...)); +. +*/ + +/* The program name used when printing BFD error messages. */ + +static const char *_bfd_error_program_name; + +/* This is the default routine to handle BFD error messages. */ + +static void _bfd_default_error_handler PARAMS ((const char *s, ...)); + +static void +_bfd_default_error_handler VPARAMS ((const char *s, ...)) +{ + if (_bfd_error_program_name != NULL) + fprintf (stderr, "%s: ", _bfd_error_program_name); + else + fprintf (stderr, "BFD: "); + + VA_OPEN (p, s); + VA_FIXEDARG (p, const char *, s); + vfprintf (stderr, s, p); + VA_CLOSE (p); + + fprintf (stderr, "\n"); +} + +/* This is a function pointer to the routine which should handle BFD + error messages. It is called when a BFD routine encounters an + error for which it wants to print a message. Going through a + function pointer permits a program linked against BFD to intercept + the messages and deal with them itself. */ + +bfd_error_handler_type _bfd_error_handler = _bfd_default_error_handler; + +/* +FUNCTION + bfd_set_error_handler + +SYNOPSIS + bfd_error_handler_type bfd_set_error_handler (bfd_error_handler_type); + +DESCRIPTION + Set the BFD error handler function. Returns the previous + function. +*/ + +bfd_error_handler_type +bfd_set_error_handler (pnew) + bfd_error_handler_type pnew; +{ + bfd_error_handler_type pold; + + pold = _bfd_error_handler; + _bfd_error_handler = pnew; + return pold; +} + +/* +FUNCTION + bfd_set_error_program_name + +SYNOPSIS + void bfd_set_error_program_name (const char *); + +DESCRIPTION + Set the program name to use when printing a BFD error. This + is printed before the error message followed by a colon and + space. The string must not be changed after it is passed to + this function. +*/ + +void +bfd_set_error_program_name (name) + const char *name; +{ + _bfd_error_program_name = name; +} + +/* +FUNCTION + bfd_get_error_handler + +SYNOPSIS + bfd_error_handler_type bfd_get_error_handler (void); + +DESCRIPTION + Return the BFD error handler function. +*/ + +bfd_error_handler_type +bfd_get_error_handler () +{ + return _bfd_error_handler; +} + +/* +FUNCTION + bfd_archive_filename + +SYNOPSIS + const char *bfd_archive_filename (bfd *); + +DESCRIPTION + For a BFD that is a component of an archive, returns a string + with both the archive name and file name. For other BFDs, just + returns the file name. +*/ + +const char * +bfd_archive_filename (abfd) + bfd *abfd; +{ + if (abfd->my_archive) + { + static size_t curr = 0; + static char *buf; + size_t needed; + + needed = (strlen (bfd_get_filename (abfd->my_archive)) + + strlen (bfd_get_filename (abfd)) + 3); + if (needed > curr) + { + if (curr) + free (buf); + curr = needed + (needed >> 1); + buf = bfd_malloc ((bfd_size_type) curr); + /* If we can't malloc, fail safe by returning just the file + name. This function is only used when building error + messages. */ + if (!buf) + { + curr = 0; + return bfd_get_filename (abfd); + } + } + sprintf (buf, "%s(%s)", bfd_get_filename (abfd->my_archive), + bfd_get_filename (abfd)); + return buf; + } + else + return bfd_get_filename (abfd); +} + +/* +SECTION + Symbols +*/ + +/* +FUNCTION + bfd_get_reloc_upper_bound + +SYNOPSIS + long bfd_get_reloc_upper_bound (bfd *abfd, asection *sect); + +DESCRIPTION + Return the number of bytes required to store the + relocation information associated with section @var{sect} + attached to bfd @var{abfd}. If an error occurs, return -1. + +*/ + +long +bfd_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (abfd->format != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + return BFD_SEND (abfd, _get_reloc_upper_bound, (abfd, asect)); +} + +/* +FUNCTION + bfd_canonicalize_reloc + +SYNOPSIS + long bfd_canonicalize_reloc + (bfd *abfd, + asection *sec, + arelent **loc, + asymbol **syms); + +DESCRIPTION + Call the back end associated with the open BFD + @var{abfd} and translate the external form of the relocation + information attached to @var{sec} into the internal canonical + form. Place the table into memory at @var{loc}, which has + been preallocated, usually by a call to + <>. Returns the number of relocs, or + -1 on error. + + The @var{syms} table is also needed for horrible internal magic + reasons. + +*/ +long +bfd_canonicalize_reloc (abfd, asect, location, symbols) + bfd *abfd; + sec_ptr asect; + arelent **location; + asymbol **symbols; +{ + if (abfd->format != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + return BFD_SEND (abfd, _bfd_canonicalize_reloc, + (abfd, asect, location, symbols)); +} + +/* +FUNCTION + bfd_set_reloc + +SYNOPSIS + void bfd_set_reloc + (bfd *abfd, asection *sec, arelent **rel, unsigned int count); + +DESCRIPTION + Set the relocation pointer and count within + section @var{sec} to the values @var{rel} and @var{count}. + The argument @var{abfd} is ignored. + +*/ + +void +bfd_set_reloc (ignore_abfd, asect, location, count) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + sec_ptr asect; + arelent **location; + unsigned int count; +{ + asect->orelocation = location; + asect->reloc_count = count; +} + +/* +FUNCTION + bfd_set_file_flags + +SYNOPSIS + bfd_boolean bfd_set_file_flags (bfd *abfd, flagword flags); + +DESCRIPTION + Set the flag word in the BFD @var{abfd} to the value @var{flags}. + + Possible errors are: + o <> - The target bfd was not of object format. + o <> - The target bfd was open for reading. + o <> - + The flag word contained a bit which was not applicable to the + type of file. E.g., an attempt was made to set the <> bit + on a BFD format which does not support demand paging. + +*/ + +bfd_boolean +bfd_set_file_flags (abfd, flags) + bfd *abfd; + flagword flags; +{ + if (abfd->format != bfd_object) + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + if (bfd_read_p (abfd)) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + bfd_get_file_flags (abfd) = flags; + if ((flags & bfd_applicable_file_flags (abfd)) != flags) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + return TRUE; +} + +void +bfd_assert (file, line) + const char *file; + int line; +{ + (*_bfd_error_handler) (_("BFD %s assertion fail %s:%d"), + BFD_VERSION_STRING, file, line); +} + +/* A more or less friendly abort message. In libbfd.h abort is + defined to call this function. */ + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + +void +_bfd_abort (file, line, fn) + const char *file; + int line; + const char *fn; +{ + if (fn != NULL) + (*_bfd_error_handler) + (_("BFD %s internal error, aborting at %s line %d in %s\n"), + BFD_VERSION_STRING, file, line, fn); + else + (*_bfd_error_handler) + (_("BFD %s internal error, aborting at %s line %d\n"), + BFD_VERSION_STRING, file, line); + (*_bfd_error_handler) (_("Please report this bug.\n")); + xexit (EXIT_FAILURE); +} + +/* +FUNCTION + bfd_get_arch_size + +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 + Returns the arch size in bits if known, <<-1>> otherwise. +*/ + +int +bfd_get_arch_size (abfd) + bfd *abfd; +{ + if (abfd->xvec->flavour == bfd_target_elf_flavour) + return (get_elf_backend_data (abfd))->s->arch_size; + + return -1; +} + +/* +FUNCTION + bfd_get_sign_extend_vma + +SYNOPSIS + int bfd_get_sign_extend_vma (bfd *abfd); + +DESCRIPTION + Indicates if the target architecture "naturally" sign extends + an address. Some architectures implicitly sign extend address + values when they are converted to types larger than the size + of an address. For instance, bfd_get_start_address() will + return an address sign extended to fill a bfd_vma when this is + the case. + +RETURNS + Returns <<1>> if the target architecture is known to sign + extend addresses, <<0>> if the target architecture is known to + not sign extend addresses, and <<-1>> otherwise. +*/ + +int +bfd_get_sign_extend_vma (abfd) + bfd *abfd; +{ + char *name; + + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + return (get_elf_backend_data (abfd)->sign_extend_vma); + + name = bfd_get_target (abfd); + + /* Return a proper value for DJGPP COFF (an x86 COFF variant). + This function is required for DWARF2 support, but there is + no place to store this information in the COFF back end. + Should enough other COFF targets add support for DWARF2, + a place will have to be found. Until then, this hack will do. */ + if (strncmp (name, "coff-go32", sizeof ("coff-go32") - 1) == 0) + return 1; + + bfd_set_error (bfd_error_wrong_format); + return -1; +} + +/* +FUNCTION + bfd_set_start_address + +SYNOPSIS + bfd_boolean bfd_set_start_address (bfd *abfd, bfd_vma vma); + +DESCRIPTION + Make @var{vma} the entry point of output BFD @var{abfd}. + +RETURNS + Returns <> on success, <> otherwise. +*/ + +bfd_boolean +bfd_set_start_address (abfd, vma) + bfd *abfd; + bfd_vma vma; +{ + abfd->start_address = vma; + return TRUE; +} + +/* +FUNCTION + bfd_get_gp_size + +SYNOPSIS + unsigned int bfd_get_gp_size (bfd *abfd); + +DESCRIPTION + Return the maximum size of objects to be optimized using the GP + register under MIPS ECOFF. This is typically set by the <<-G>> + argument to the compiler, assembler or linker. +*/ + +unsigned int +bfd_get_gp_size (abfd) + bfd *abfd; +{ + if (abfd->format == bfd_object) + { + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + return ecoff_data (abfd)->gp_size; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + return elf_gp_size (abfd); + } + return 0; +} + +/* +FUNCTION + bfd_set_gp_size + +SYNOPSIS + void bfd_set_gp_size (bfd *abfd, unsigned int i); + +DESCRIPTION + Set the maximum size of objects to be optimized using the GP + register under ECOFF or MIPS ELF. This is typically set by + the <<-G>> argument to the compiler, assembler or linker. +*/ + +void +bfd_set_gp_size (abfd, i) + bfd *abfd; + unsigned int i; +{ + /* Don't try to set GP size on an archive or core file! */ + if (abfd->format != bfd_object) + return; + + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + ecoff_data (abfd)->gp_size = i; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + elf_gp_size (abfd) = i; +} + +/* Get the GP value. This is an internal function used by some of the + relocation special_function routines on targets which support a GP + register. */ + +bfd_vma +_bfd_get_gp_value (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_object) + return 0; + + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + return ecoff_data (abfd)->gp; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + return elf_gp (abfd); + + return 0; +} + +/* Set the GP value. */ + +void +_bfd_set_gp_value (abfd, v) + bfd *abfd; + bfd_vma v; +{ + if (abfd->format != bfd_object) + return; + + if (abfd->xvec->flavour == bfd_target_ecoff_flavour) + ecoff_data (abfd)->gp = v; + else if (abfd->xvec->flavour == bfd_target_elf_flavour) + elf_gp (abfd) = v; +} + +/* +FUNCTION + bfd_scan_vma + +SYNOPSIS + bfd_vma bfd_scan_vma (const char *string, const char **end, int base); + +DESCRIPTION + Convert, like <>, a numerical expression + @var{string} into a <> integer, and return that integer. + (Though without as many bells and whistles as <>.) + The expression is assumed to be unsigned (i.e., positive). + If given a @var{base}, it is used as the base for conversion. + A base of 0 causes the function to interpret the string + in hex if a leading "0x" or "0X" is found, otherwise + in octal if a leading zero is found, otherwise in decimal. + + If the value would overflow, the maximum <> value is + returned. +*/ + +bfd_vma +bfd_scan_vma (string, end, base) + const char *string; + const char **end; + int base; +{ + bfd_vma value; + bfd_vma cutoff; + unsigned int cutlim; + int overflow; + + /* Let the host do it if possible. */ + if (sizeof (bfd_vma) <= sizeof (unsigned long)) + return (bfd_vma) strtoul (string, (char **) end, base); + + if (base == 0) + { + if (string[0] == '0') + { + if ((string[1] == 'x') || (string[1] == 'X')) + base = 16; + else + base = 8; + } + } + + if ((base < 2) || (base > 36)) + base = 10; + + if (base == 16 + && string[0] == '0' + && (string[1] == 'x' || string[1] == 'X') + && ISXDIGIT (string[2])) + { + string += 2; + } + + cutoff = (~ (bfd_vma) 0) / (bfd_vma) base; + cutlim = (~ (bfd_vma) 0) % (bfd_vma) base; + value = 0; + overflow = 0; + while (1) + { + unsigned int digit; + + digit = *string; + if (ISDIGIT (digit)) + digit = digit - '0'; + else if (ISALPHA (digit)) + digit = TOUPPER (digit) - 'A' + 10; + else + break; + if (digit >= (unsigned int) base) + break; + if (value > cutoff || (value == cutoff && digit > cutlim)) + overflow = 1; + value = value * base + digit; + ++string; + } + + if (overflow) + value = ~ (bfd_vma) 0; + + if (end != NULL) + *end = string; + + return value; +} + +/* +FUNCTION + bfd_copy_private_bfd_data + +SYNOPSIS + bfd_boolean bfd_copy_private_bfd_data (bfd *ibfd, bfd *obfd); + +DESCRIPTION + Copy private BFD information from the BFD @var{ibfd} to the + the BFD @var{obfd}. Return <> on success, <> on error. + Possible error returns are: + + o <> - + Not enough memory exists to create private data for @var{obfd}. + +.#define bfd_copy_private_bfd_data(ibfd, obfd) \ +. BFD_SEND (obfd, _bfd_copy_private_bfd_data, \ +. (ibfd, obfd)) + +*/ + +/* +FUNCTION + bfd_merge_private_bfd_data + +SYNOPSIS + bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd); + +DESCRIPTION + Merge private BFD information from the BFD @var{ibfd} to the + the output file BFD @var{obfd} when linking. Return <> + on success, <> on error. Possible error returns are: + + o <> - + Not enough memory exists to create private data for @var{obfd}. + +.#define bfd_merge_private_bfd_data(ibfd, obfd) \ +. BFD_SEND (obfd, _bfd_merge_private_bfd_data, \ +. (ibfd, obfd)) + +*/ + +/* +FUNCTION + bfd_set_private_flags + +SYNOPSIS + bfd_boolean bfd_set_private_flags (bfd *abfd, flagword flags); + +DESCRIPTION + Set private BFD flag information in the BFD @var{abfd}. + Return <> on success, <> on error. Possible error + returns are: + + o <> - + Not enough memory exists to create private data for @var{obfd}. + +.#define bfd_set_private_flags(abfd, flags) \ +. BFD_SEND (abfd, _bfd_set_private_flags, (abfd, flags)) + +*/ + +/* +FUNCTION + Other functions + +DESCRIPTION + The following functions exist but have not yet been documented. + +.#define bfd_sizeof_headers(abfd, reloc) \ +. BFD_SEND (abfd, _bfd_sizeof_headers, (abfd, reloc)) +. +.#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)) +. +.#define bfd_debug_info_start(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_start, (abfd)) +. +.#define bfd_debug_info_end(abfd) \ +. BFD_SEND (abfd, _bfd_debug_info_end, (abfd)) +. +.#define bfd_debug_info_accumulate(abfd, section) \ +. BFD_SEND (abfd, _bfd_debug_info_accumulate, (abfd, section)) +. +.#define bfd_stat_arch_elt(abfd, stat) \ +. BFD_SEND (abfd, _bfd_stat_arch_elt,(abfd, stat)) +. +.#define bfd_update_armap_timestamp(abfd) \ +. BFD_SEND (abfd, _bfd_update_armap_timestamp, (abfd)) +. +.#define bfd_set_arch_mach(abfd, arch, mach)\ +. BFD_SEND ( abfd, _bfd_set_arch_mach, (abfd, arch, mach)) +. +.#define bfd_relax_section(abfd, section, link_info, again) \ +. BFD_SEND (abfd, _bfd_relax_section, (abfd, section, link_info, again)) +. +.#define bfd_gc_sections(abfd, link_info) \ +. BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info)) +. +.#define bfd_merge_sections(abfd, link_info) \ +. BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info)) +. +.#define bfd_discard_group(abfd, sec) \ +. BFD_SEND (abfd, _bfd_discard_group, (abfd, sec)) +. +.#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)) +. +.#define bfd_link_just_syms(sec, info) \ +. BFD_SEND (abfd, _bfd_link_just_syms, (sec, info)) +. +.#define bfd_final_link(abfd, info) \ +. BFD_SEND (abfd, _bfd_final_link, (abfd, info)) +. +.#define bfd_free_cached_info(abfd) \ +. BFD_SEND (abfd, _bfd_free_cached_info, (abfd)) +. +.#define bfd_get_dynamic_symtab_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_dynamic_symtab_upper_bound, (abfd)) +. +.#define bfd_print_private_bfd_data(abfd, file)\ +. BFD_SEND (abfd, _bfd_print_private_bfd_data, (abfd, file)) +. +.#define bfd_canonicalize_dynamic_symtab(abfd, asymbols) \ +. BFD_SEND (abfd, _bfd_canonicalize_dynamic_symtab, (abfd, asymbols)) +. +.#define bfd_get_dynamic_reloc_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_dynamic_reloc_upper_bound, (abfd)) +. +.#define bfd_canonicalize_dynamic_reloc(abfd, arels, asyms) \ +. BFD_SEND (abfd, _bfd_canonicalize_dynamic_reloc, (abfd, arels, asyms)) +. +.extern bfd_byte *bfd_get_relocated_section_contents +. PARAMS ((bfd *, struct bfd_link_info *, +. struct bfd_link_order *, bfd_byte *, +. bfd_boolean, asymbol **)); +. + +*/ + +bfd_byte * +bfd_get_relocated_section_contents (abfd, link_info, link_order, data, + relocateable, symbols) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + bfd_boolean relocateable; + asymbol **symbols; +{ + bfd *abfd2; + bfd_byte *(*fn) PARAMS ((bfd *, struct bfd_link_info *, + struct bfd_link_order *, bfd_byte *, bfd_boolean, + asymbol **)); + + if (link_order->type == bfd_indirect_link_order) + { + abfd2 = link_order->u.indirect.section->owner; + if (abfd2 == NULL) + abfd2 = abfd; + } + else + abfd2 = abfd; + + fn = abfd2->xvec->_bfd_get_relocated_section_contents; + + return (*fn) (abfd, link_info, link_order, data, relocateable, symbols); +} + +/* Record information about an ELF program header. */ + +bfd_boolean +bfd_record_phdr (abfd, type, flags_valid, flags, at_valid, at, + includes_filehdr, includes_phdrs, count, secs) + bfd *abfd; + unsigned long type; + bfd_boolean flags_valid; + flagword flags; + bfd_boolean at_valid; + bfd_vma at; + bfd_boolean includes_filehdr; + bfd_boolean includes_phdrs; + unsigned int count; + asection **secs; +{ + struct elf_segment_map *m, **pm; + bfd_size_type amt; + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + return TRUE; + + amt = sizeof (struct elf_segment_map); + amt += ((bfd_size_type) count - 1) * sizeof (asection *); + m = (struct elf_segment_map *) bfd_alloc (abfd, amt); + if (m == NULL) + return FALSE; + + m->next = NULL; + m->p_type = type; + m->p_flags = flags; + m->p_paddr = at; + m->p_flags_valid = (unsigned int) flags_valid; + m->p_paddr_valid = (unsigned int) at_valid; + m->includes_filehdr = (unsigned int) includes_filehdr; + m->includes_phdrs = (unsigned int) includes_phdrs; + m->count = count; + if (count > 0) + memcpy (m->sections, secs, count * sizeof (asection *)); + + for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next) + ; + *pm = m; + + return TRUE; +} + +void +bfd_sprintf_vma (abfd, buf, value) + bfd *abfd; + char *buf; + bfd_vma value; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + get_elf_backend_data (abfd)->elf_backend_sprintf_vma (abfd, buf, value); + else + sprintf_vma (buf, value); +} + +void +bfd_fprintf_vma (abfd, stream, value) + bfd *abfd; + PTR stream; + bfd_vma value; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + get_elf_backend_data (abfd)->elf_backend_fprintf_vma (abfd, stream, value); + else + fprintf_vma ((FILE *) stream, value); +} + +/* +FUNCTION + bfd_alt_mach_code + +SYNOPSIS + bfd_boolean bfd_alt_mach_code (bfd *abfd, int alternative); + +DESCRIPTION + + When more than one machine code number is available for the + same machine type, this function can be used to switch between + the preferred one (alternative == 0) and any others. Currently, + only ELF supports this feature, with up to two alternate + machine codes. +*/ + +bfd_boolean +bfd_alt_mach_code (abfd, alternative) + bfd *abfd; + int alternative; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + int code; + + switch (alternative) + { + case 0: + code = get_elf_backend_data (abfd)->elf_machine_code; + break; + + case 1: + code = get_elf_backend_data (abfd)->elf_machine_alt1; + if (code == 0) + return FALSE; + break; + + case 2: + code = get_elf_backend_data (abfd)->elf_machine_alt2; + if (code == 0) + return FALSE; + break; + + default: + return FALSE; + } + + elf_elfheader (abfd)->e_machine = code; + + return TRUE; + } + + return FALSE; +} + +/* +CODE_FRAGMENT + +.struct bfd_preserve +.{ +. PTR marker; +. PTR tdata; +. flagword flags; +. const struct bfd_arch_info *arch_info; +. struct sec *sections; +. struct sec **section_tail; +. unsigned int section_count; +. struct bfd_hash_table section_htab; +.}; +. +*/ + +/* +FUNCTION + bfd_preserve_save + +SYNOPSIS + bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *); + +DESCRIPTION + When testing an object for compatibility with a particular + target back-end, the back-end object_p function needs to set + up certain fields in the bfd on successfully recognizing the + object. This typically happens in a piecemeal fashion, with + failures possible at many points. On failure, the bfd is + supposed to be restored to its initial state, which is + virtually impossible. However, restoring a subset of the bfd + state works in practice. This function stores the subset and + reinitializes the bfd. + +*/ + +bfd_boolean +bfd_preserve_save (abfd, preserve) + bfd *abfd; + struct bfd_preserve *preserve; +{ + preserve->tdata = abfd->tdata.any; + preserve->arch_info = abfd->arch_info; + preserve->flags = abfd->flags; + preserve->sections = abfd->sections; + preserve->section_tail = abfd->section_tail; + preserve->section_count = abfd->section_count; + preserve->section_htab = abfd->section_htab; + + if (! bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc)) + return FALSE; + + abfd->tdata.any = NULL; + abfd->arch_info = &bfd_default_arch_struct; + abfd->flags &= BFD_IN_MEMORY; + abfd->sections = NULL; + abfd->section_tail = &abfd->sections; + abfd->section_count = 0; + + return TRUE; +} + +/* +FUNCTION + bfd_preserve_restore + +SYNOPSIS + void bfd_preserve_restore (bfd *, struct bfd_preserve *); + +DESCRIPTION + This function restores bfd state saved by bfd_preserve_save. + If MARKER is non-NULL in struct bfd_preserve then that block + and all subsequently bfd_alloc'd memory is freed. + +*/ + +void +bfd_preserve_restore (abfd, preserve) + bfd *abfd; + struct bfd_preserve *preserve; +{ + bfd_hash_table_free (&abfd->section_htab); + + abfd->tdata.any = preserve->tdata; + abfd->arch_info = preserve->arch_info; + abfd->flags = preserve->flags; + abfd->section_htab = preserve->section_htab; + abfd->sections = preserve->sections; + abfd->section_tail = preserve->section_tail; + abfd->section_count = preserve->section_count; + + /* bfd_release frees all memory more recently bfd_alloc'd than + its arg, as well as its arg. */ + if (preserve->marker != NULL) + { + bfd_release (abfd, preserve->marker); + preserve->marker = NULL; + } +} + +/* +FUNCTION + bfd_preserve_finish + +SYNOPSIS + void bfd_preserve_finish (bfd *, struct bfd_preserve *); + +DESCRIPTION + This function should be called when the bfd state saved by + bfd_preserve_save is no longer needed. ie. when the back-end + object_p function returns with success. + +*/ + +void +bfd_preserve_finish (abfd, preserve) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_preserve *preserve; +{ + /* It would be nice to be able to free more memory here, eg. old + tdata, but that's not possible since these blocks are sitting + inside bfd_alloc'd memory. The section hash is on a separate + objalloc. */ + bfd_hash_table_free (&preserve->section_htab); +} diff --git a/contrib/binutils-2.14/bfd/bfdio.c b/contrib/binutils-2.14/bfd/bfdio.c new file mode 100644 index 0000000000..3229316236 --- /dev/null +++ b/contrib/binutils-2.14/bfd/bfdio.c @@ -0,0 +1,436 @@ +/* Low-level I/O routines for BFDs. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "sysdep.h" + +#include "bfd.h" +#include "libbfd.h" + +#include + +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 /* Execute by group. */ +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 /* Execute by others. */ +#endif + +/* Note that archive entries don't have streams; they share their parent's. + This allows someone to play with the iostream behind BFD's back. + + Also, note that the origin pointer points to the beginning of a file's + contents (0 for non-archive elements). For archive entries this is the + first octet in the file, NOT the beginning of the archive header. */ + +static size_t real_read PARAMS ((PTR where, size_t a, size_t b, FILE *file)); +static size_t +real_read (where, a, b, file) + PTR where; + size_t a; + size_t b; + FILE *file; +{ + /* FIXME - this looks like an optimization, but it's really to cover + up for a feature of some OSs (not solaris - sigh) that + ld/pe-dll.c takes advantage of (apparently) when it creates BFDs + internally and tries to link against them. BFD seems to be smart + enough to realize there are no symbol records in the "file" that + doesn't exist but attempts to read them anyway. On Solaris, + attempting to read zero bytes from a NULL file results in a core + dump, but on other platforms it just returns zero bytes read. + This makes it to something reasonable. - DJ */ + if (a == 0 || b == 0) + return 0; + + +#if defined (__VAX) && defined (VMS) + /* Apparently fread on Vax VMS does not keep the record length + information. */ + return read (fileno (file), where, a * b); +#else + return fread (where, a, b, file); +#endif +} + +/* Return value is amount read. */ + +bfd_size_type +bfd_bread (ptr, size, abfd) + PTR ptr; + bfd_size_type size; + bfd *abfd; +{ + size_t nread; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + struct bfd_in_memory *bim; + bfd_size_type get; + + bim = (struct bfd_in_memory *) abfd->iostream; + get = size; + if (abfd->where + get > bim->size) + { + if (bim->size < (bfd_size_type) abfd->where) + get = 0; + else + get = bim->size - abfd->where; + bfd_set_error (bfd_error_file_truncated); + } + memcpy (ptr, bim->buffer + abfd->where, (size_t) get); + abfd->where += get; + return get; + } + + nread = real_read (ptr, 1, (size_t) size, bfd_cache_lookup (abfd)); + if (nread != (size_t) -1) + abfd->where += nread; + + /* Set bfd_error if we did not read as much data as we expected. + + If the read failed due to an error set the bfd_error_system_call, + else set bfd_error_file_truncated. + + A BFD backend may wish to override bfd_error_file_truncated to + provide something more useful (eg. no_symbols or wrong_format). */ + if (nread != size) + { + if (ferror (bfd_cache_lookup (abfd))) + bfd_set_error (bfd_error_system_call); + else + bfd_set_error (bfd_error_file_truncated); + } + + return nread; +} + +bfd_size_type +bfd_bwrite (ptr, size, abfd) + const PTR ptr; + bfd_size_type size; + bfd *abfd; +{ + size_t nwrote; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + struct bfd_in_memory *bim = (struct bfd_in_memory *) (abfd->iostream); + size = (size_t) size; + if (abfd->where + size > bim->size) + { + bfd_size_type newsize, oldsize; + + oldsize = (bim->size + 127) & ~(bfd_size_type) 127; + bim->size = abfd->where + size; + /* Round up to cut down on memory fragmentation */ + newsize = (bim->size + 127) & ~(bfd_size_type) 127; + if (newsize > oldsize) + { + bim->buffer = (bfd_byte *) bfd_realloc (bim->buffer, newsize); + if (bim->buffer == 0) + { + bim->size = 0; + return 0; + } + } + } + memcpy (bim->buffer + abfd->where, ptr, (size_t) size); + abfd->where += size; + return size; + } + + nwrote = fwrite (ptr, 1, (size_t) size, bfd_cache_lookup (abfd)); + if (nwrote != (size_t) -1) + abfd->where += nwrote; + if (nwrote != size) + { +#ifdef ENOSPC + errno = ENOSPC; +#endif + bfd_set_error (bfd_error_system_call); + } + return nwrote; +} + +bfd_vma +bfd_tell (abfd) + bfd *abfd; +{ + file_ptr ptr; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return abfd->where; + + ptr = ftell (bfd_cache_lookup (abfd)); + + if (abfd->my_archive) + ptr -= abfd->origin; + abfd->where = ptr; + return ptr; +} + +int +bfd_flush (abfd) + bfd *abfd; +{ + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return 0; + return fflush (bfd_cache_lookup(abfd)); +} + +/* Returns 0 for success, negative value for failure (in which case + bfd_get_error can retrieve the error code). */ +int +bfd_stat (abfd, statbuf) + bfd *abfd; + struct stat *statbuf; +{ + FILE *f; + int result; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + abort (); + + f = bfd_cache_lookup (abfd); + if (f == NULL) + { + bfd_set_error (bfd_error_system_call); + return -1; + } + result = fstat (fileno (f), statbuf); + if (result < 0) + bfd_set_error (bfd_error_system_call); + return result; +} + +/* Returns 0 for success, nonzero for failure (in which case bfd_get_error + can retrieve the error code). */ + +int +bfd_seek (abfd, position, direction) + bfd *abfd; + file_ptr position; + int direction; +{ + int result; + FILE *f; + long file_position; + /* For the time being, a BFD may not seek to it's end. The problem + is that we don't easily have a way to recognize the end of an + element in an archive. */ + + BFD_ASSERT (direction == SEEK_SET || direction == SEEK_CUR); + + if (direction == SEEK_CUR && position == 0) + return 0; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + { + struct bfd_in_memory *bim; + + bim = (struct bfd_in_memory *) abfd->iostream; + + if (direction == SEEK_SET) + abfd->where = position; + else + abfd->where += position; + + if (abfd->where > bim->size) + { + if ((abfd->direction == write_direction) || + (abfd->direction == both_direction)) + { + bfd_size_type newsize, oldsize; + oldsize = (bim->size + 127) & ~(bfd_size_type) 127; + bim->size = abfd->where; + /* Round up to cut down on memory fragmentation */ + newsize = (bim->size + 127) & ~(bfd_size_type) 127; + if (newsize > oldsize) + { + bim->buffer = (bfd_byte *) bfd_realloc (bim->buffer, newsize); + if (bim->buffer == 0) + { + bim->size = 0; + return -1; + } + } + } + else + { + abfd->where = bim->size; + bfd_set_error (bfd_error_file_truncated); + return -1; + } + } + return 0; + } + + if (abfd->format != bfd_archive && abfd->my_archive == 0) + { +#if 0 + /* Explanation for this code: I'm only about 95+% sure that the above + conditions are sufficient and that all i/o calls are properly + adjusting the `where' field. So this is sort of an `assert' + that the `where' field is correct. If we can go a while without + tripping the abort, we can probably safely disable this code, + so that the real optimizations happen. */ + file_ptr where_am_i_now; + where_am_i_now = ftell (bfd_cache_lookup (abfd)); + if (abfd->my_archive) + where_am_i_now -= abfd->origin; + if (where_am_i_now != abfd->where) + abort (); +#endif + if (direction == SEEK_SET && (bfd_vma) position == abfd->where) + return 0; + } + else + { + /* We need something smarter to optimize access to archives. + Currently, anything inside an archive is read via the file + handle for the archive. Which means that a bfd_seek on one + component affects the `current position' in the archive, as + well as in any other component. + + It might be sufficient to put a spike through the cache + abstraction, and look to the archive for the file position, + but I think we should try for something cleaner. + + In the meantime, no optimization for archives. */ + } + + f = bfd_cache_lookup (abfd); + file_position = position; + if (direction == SEEK_SET && abfd->my_archive != NULL) + file_position += abfd->origin; + + result = fseek (f, file_position, direction); + if (result != 0) + { + int hold_errno = errno; + + /* Force redetermination of `where' field. */ + bfd_tell (abfd); + + /* An EINVAL error probably means that the file offset was + absurd. */ + if (hold_errno == EINVAL) + bfd_set_error (bfd_error_file_truncated); + else + { + bfd_set_error (bfd_error_system_call); + errno = hold_errno; + } + } + else + { + /* Adjust `where' field. */ + if (direction == SEEK_SET) + abfd->where = position; + else + abfd->where += position; + } + return result; +} + +/* +FUNCTION + bfd_get_mtime + +SYNOPSIS + long bfd_get_mtime(bfd *abfd); + +DESCRIPTION + Return the file modification time (as read from the file system, or + from the archive header for archive members). + +*/ + +long +bfd_get_mtime (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + if (abfd->mtime_set) + return abfd->mtime; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), &buf)) + return 0; + + abfd->mtime = buf.st_mtime; /* Save value in case anyone wants it */ + return buf.st_mtime; +} + +/* +FUNCTION + bfd_get_size + +SYNOPSIS + long bfd_get_size(bfd *abfd); + +DESCRIPTION + Return the file size (as read from file system) for the file + associated with BFD @var{abfd}. + + The initial motivation for, and use of, this routine is not + so we can get the exact size of the object the BFD applies to, since + that might not be generally possible (archive members for example). + It would be ideal if someone could eventually modify + it so that such results were guaranteed. + + Instead, we want to ask questions like "is this NNN byte sized + object I'm about to try read from file offset YYY reasonable?" + As as example of where we might do this, some object formats + use string tables for which the first <> bytes of the + table contain the size of the table itself, including the size bytes. + If an application tries to read what it thinks is one of these + string tables, without some way to validate the size, and for + some reason the size is wrong (byte swapping error, wrong location + for the string table, etc.), the only clue is likely to be a read + error when it tries to read the table, or a "virtual memory + exhausted" error when it tries to allocate 15 bazillon bytes + of space for the 15 bazillon byte table it is about to read. + This function at least allows us to answer the quesion, "is the + size reasonable?". +*/ + +long +bfd_get_size (abfd) + bfd *abfd; +{ + FILE *fp; + struct stat buf; + + if ((abfd->flags & BFD_IN_MEMORY) != 0) + return ((struct bfd_in_memory *) abfd->iostream)->size; + + fp = bfd_cache_lookup (abfd); + if (0 != fstat (fileno (fp), & buf)) + return 0; + + return buf.st_size; +} diff --git a/contrib/binutils-2.14/bfd/binary.c b/contrib/binutils-2.14/bfd/binary.c new file mode 100644 index 0000000000..a27eb95f59 --- /dev/null +++ b/contrib/binutils-2.14/bfd/binary.c @@ -0,0 +1,400 @@ +/* BFD back-end for binary objects. + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + Written by Ian Lance Taylor, 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is a BFD backend which may be used to write binary objects. + It may only be used for output, not input. The intention is that + this may be used as an output format for objcopy in order to + generate raw binary data. + + This is very simple. The only complication is that the real data + will start at some address X, and in some cases we will not want to + include X zeroes just to get to that point. Since the start + address is not meaningful for this object file format, we use it + instead to indicate the number of zeroes to skip at the start of + the file. objcopy cooperates by specially setting the start + address to zero by default. */ + +#include "bfd.h" +#include "sysdep.h" +#include "safe-ctype.h" +#include "libbfd.h" + +/* Any bfd we create by reading a binary file has three symbols: + a start symbol, an end symbol, and an absolute length symbol. */ +#define BIN_SYMS 3 + +static bfd_boolean binary_mkobject PARAMS ((bfd *)); +static const bfd_target *binary_object_p PARAMS ((bfd *)); +static bfd_boolean binary_get_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static long binary_get_symtab_upper_bound PARAMS ((bfd *)); +static char *mangle_name PARAMS ((bfd *, char *)); +static long binary_get_symtab PARAMS ((bfd *, asymbol **)); +static void binary_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *)); +static bfd_boolean binary_set_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static int binary_sizeof_headers PARAMS ((bfd *, bfd_boolean)); + +/* Set by external programs - specifies the BFD architecture + to use when creating binary BFDs. */ +enum bfd_architecture bfd_external_binary_architecture = bfd_arch_unknown; + +/* Create a binary object. Invoked via bfd_set_format. */ + +static bfd_boolean +binary_mkobject (abfd) + bfd *abfd ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +/* Any file may be considered to be a binary file, provided the target + was not defaulted. That is, it must be explicitly specified as + being binary. */ + +static const bfd_target * +binary_object_p (abfd) + bfd *abfd; +{ + struct stat statbuf; + asection *sec; + + if (abfd->target_defaulted) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + abfd->symcount = BIN_SYMS; + + /* Find the file size. */ + if (bfd_stat (abfd, &statbuf) < 0) + { + bfd_set_error (bfd_error_system_call); + return NULL; + } + + /* One data section. */ + sec = bfd_make_section (abfd, ".data"); + if (sec == NULL) + return NULL; + sec->flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS; + sec->vma = 0; + sec->_raw_size = statbuf.st_size; + sec->filepos = 0; + + abfd->tdata.any = (PTR) sec; + + if (bfd_get_arch_info (abfd) != NULL) + { + if ((bfd_get_arch_info (abfd)->arch == bfd_arch_unknown) + && (bfd_external_binary_architecture != bfd_arch_unknown)) + bfd_set_arch_info (abfd, bfd_lookup_arch (bfd_external_binary_architecture, 0)); + } + + return abfd->xvec; +} + +#define binary_close_and_cleanup _bfd_generic_close_and_cleanup +#define binary_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define binary_new_section_hook _bfd_generic_new_section_hook + +/* Get contents of the only section. */ + +static bfd_boolean +binary_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section ATTRIBUTE_UNUSED; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (bfd_seek (abfd, offset, SEEK_SET) != 0 + || bfd_bread (location, count, abfd) != count) + return FALSE; + return TRUE; +} + +/* Return the amount of memory needed to read the symbol table. */ + +static long +binary_get_symtab_upper_bound (abfd) + bfd *abfd ATTRIBUTE_UNUSED; +{ + return (BIN_SYMS + 1) * sizeof (asymbol *); +} + +/* Create a symbol name based on the bfd's filename. */ + +static char * +mangle_name (abfd, suffix) + bfd *abfd; + char *suffix; +{ + bfd_size_type size; + char *buf; + char *p; + + size = (strlen (bfd_get_filename (abfd)) + + strlen (suffix) + + sizeof "_binary__"); + + buf = (char *) bfd_alloc (abfd, size); + if (buf == NULL) + return ""; + + sprintf (buf, "_binary_%s_%s", bfd_get_filename (abfd), suffix); + + /* Change any non-alphanumeric characters to underscores. */ + for (p = buf; *p; p++) + if (! ISALNUM (*p)) + *p = '_'; + + return buf; +} + +/* Return the symbol table. */ + +static long +binary_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + asection *sec = (asection *) abfd->tdata.any; + asymbol *syms; + unsigned int i; + bfd_size_type amt = BIN_SYMS * sizeof (asymbol); + + syms = (asymbol *) bfd_alloc (abfd, amt); + if (syms == NULL) + return 0; + + /* Start symbol. */ + syms[0].the_bfd = abfd; + syms[0].name = mangle_name (abfd, "start"); + syms[0].value = 0; + syms[0].flags = BSF_GLOBAL; + syms[0].section = sec; + syms[0].udata.p = NULL; + + /* End symbol. */ + syms[1].the_bfd = abfd; + syms[1].name = mangle_name (abfd, "end"); + syms[1].value = sec->_raw_size; + syms[1].flags = BSF_GLOBAL; + syms[1].section = sec; + syms[1].udata.p = NULL; + + /* Size symbol. */ + syms[2].the_bfd = abfd; + syms[2].name = mangle_name (abfd, "size"); + syms[2].value = sec->_raw_size; + syms[2].flags = BSF_GLOBAL; + syms[2].section = bfd_abs_section_ptr; + syms[2].udata.p = NULL; + + for (i = 0; i < BIN_SYMS; i++) + *alocation++ = syms++; + *alocation = NULL; + + return BIN_SYMS; +} + +#define binary_make_empty_symbol _bfd_generic_make_empty_symbol +#define binary_print_symbol _bfd_nosymbols_print_symbol + +/* Get information about a symbol. */ + +static void +binary_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +#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_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define binary_read_minisymbols _bfd_generic_read_minisymbols +#define binary_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define binary_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) bfd_0l) +#define binary_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l) +#define binary_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +/* Set the architecture of a binary file. */ +#define binary_set_arch_mach _bfd_generic_set_arch_mach + +/* Write section contents of a binary file. */ + +static bfd_boolean +binary_set_section_contents (abfd, sec, data, offset, size) + bfd *abfd; + asection *sec; + PTR data; + file_ptr offset; + bfd_size_type size; +{ + if (size == 0) + return TRUE; + + if (! abfd->output_has_begun) + { + bfd_boolean found_low; + bfd_vma low; + asection *s; + + /* The lowest section LMA sets the virtual address of the start + of the file. We use this to set the file position of all the + sections. */ + found_low = FALSE; + low = 0; + for (s = abfd->sections; s != NULL; s = s->next) + if (((s->flags + & (SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_NEVER_LOAD)) + == (SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC)) + && (s->_raw_size > 0) + && (! found_low || s->lma < low)) + { + low = s->lma; + found_low = TRUE; + } + + for (s = abfd->sections; s != NULL; s = s->next) + { + s->filepos = s->lma - low; + + /* Skip following warning check for sections that will not + occupy file space. */ + if ((s->flags + & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_NEVER_LOAD)) + != (SEC_HAS_CONTENTS | SEC_ALLOC) + || (s->_raw_size == 0)) + continue; + + /* If attempting to generate a binary file from a bfd with + LMA's all over the place, huge (sparse?) binary files may + result. This condition attempts to detect this situation + and print a warning. Better heuristics would be nice to + have. */ + + if (s->filepos < 0) + (*_bfd_error_handler) + (_("Warning: Writing section `%s' to huge (ie negative) file offset 0x%lx."), + bfd_get_section_name (abfd, s), + (unsigned long) s->filepos); + } + + abfd->output_has_begun = TRUE; + } + + /* We don't want to output anything for a section that is neither + loaded nor allocated. The contents of such a section are not + meaningful in the binary format. */ + if ((sec->flags & (SEC_LOAD | SEC_ALLOC)) == 0) + return TRUE; + if ((sec->flags & SEC_NEVER_LOAD) != 0) + return TRUE; + + return _bfd_generic_set_section_contents (abfd, sec, data, offset, size); +} + +/* No space is required for header information. */ + +static int +binary_sizeof_headers (abfd, exec) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_boolean exec ATTRIBUTE_UNUSED; +{ + return 0; +} + +#define binary_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define binary_bfd_relax_section bfd_generic_relax_section +#define binary_bfd_gc_sections bfd_generic_gc_sections +#define binary_bfd_merge_sections bfd_generic_merge_sections +#define binary_bfd_discard_group bfd_generic_discard_group +#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_link_add_symbols _bfd_generic_link_add_symbols +#define binary_bfd_final_link _bfd_generic_final_link +#define binary_bfd_link_split_section _bfd_generic_link_split_section +#define binary_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +const bfd_target binary_vec = +{ + "binary", /* name */ + bfd_target_unknown_flavour, /* flavour */ + BFD_ENDIAN_UNKNOWN, /* byteorder */ + BFD_ENDIAN_UNKNOWN, /* header_byteorder */ + EXEC_P, /* object_flags */ + (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA + | SEC_ROM | SEC_HAS_CONTENTS), /* section_flags */ + 0, /* symbol_leading_char */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + { /* bfd_check_format */ + _bfd_dummy_target, + binary_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { /* bfd_set_format */ + bfd_false, + binary_mkobject, + bfd_false, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + bfd_true, + bfd_false, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (binary), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (binary), + BFD_JUMP_TABLE_RELOCS (binary), + BFD_JUMP_TABLE_WRITE (binary), + BFD_JUMP_TABLE_LINK (binary), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + NULL, + + NULL +}; diff --git a/contrib/binutils-2.14/bfd/cache.c b/contrib/binutils-2.14/bfd/cache.c new file mode 100644 index 0000000000..98a1c72e88 --- /dev/null +++ b/contrib/binutils-2.14/bfd/cache.c @@ -0,0 +1,374 @@ +/* BFD library -- caching of file descriptors. + Copyright 1990, 1991, 1992, 1993, 1994, 1996, 2000, 2001, 2002 + Free Software Foundation, Inc. + Hacked by Steve Chamberlain of Cygnus Support (steve@cygnus.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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + File caching + + The file caching mechanism is embedded within BFD and allows + the application to open as many BFDs as it wants without + 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 + <>, 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 + handle. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +static void insert PARAMS ((bfd *)); +static void snip PARAMS ((bfd *)); +static bfd_boolean close_one PARAMS ((void)); +static bfd_boolean bfd_cache_delete PARAMS ((bfd *)); + +/* +INTERNAL_FUNCTION + BFD_CACHE_MAX_OPEN macro + +DESCRIPTION + The maximum number of files which the cache will keep open at + one time. + +.#define BFD_CACHE_MAX_OPEN 10 + +*/ + +/* The number of BFD files we have open. */ + +static int open_files; + +/* +INTERNAL_FUNCTION + bfd_last_cache + +SYNOPSIS + extern bfd *bfd_last_cache; + +DESCRIPTION + Zero, or a pointer to the topmost BFD on the chain. This is + used by the <> macro in @file{libbfd.h} to + determine when it can avoid a function call. +*/ + +bfd *bfd_last_cache; + +/* + INTERNAL_FUNCTION + bfd_cache_lookup + + DESCRIPTION + Check to see if the required BFD is the same as the last one + looked up. If so, then it can use the stream in the BFD with + impunity, since it can't have changed since the last lookup; + otherwise, it has to perform the complicated lookup function. + + .#define bfd_cache_lookup(x) \ + . ((x)==bfd_last_cache? \ + . (FILE*) (bfd_last_cache->iostream): \ + . bfd_cache_lookup_worker(x)) + + */ + +/* Insert a BFD into the cache. */ + +static INLINE void +insert (abfd) + bfd *abfd; +{ + if (bfd_last_cache == NULL) + { + abfd->lru_next = abfd; + abfd->lru_prev = abfd; + } + else + { + abfd->lru_next = bfd_last_cache; + abfd->lru_prev = bfd_last_cache->lru_prev; + abfd->lru_prev->lru_next = abfd; + abfd->lru_next->lru_prev = abfd; + } + bfd_last_cache = abfd; +} + +/* Remove a BFD from the cache. */ + +static INLINE void +snip (abfd) + bfd *abfd; +{ + abfd->lru_prev->lru_next = abfd->lru_next; + abfd->lru_next->lru_prev = abfd->lru_prev; + if (abfd == bfd_last_cache) + { + bfd_last_cache = abfd->lru_next; + if (abfd == bfd_last_cache) + bfd_last_cache = NULL; + } +} + +/* We need to open a new file, and the cache is full. Find the least + recently used cacheable BFD and close it. */ + +static bfd_boolean +close_one () +{ + register bfd *kill; + + if (bfd_last_cache == NULL) + kill = NULL; + else + { + for (kill = bfd_last_cache->lru_prev; + ! kill->cacheable; + kill = kill->lru_prev) + { + if (kill == bfd_last_cache) + { + kill = NULL; + break; + } + } + } + + if (kill == NULL) + { + /* There are no open cacheable BFD's. */ + return TRUE; + } + + kill->where = ftell ((FILE *) kill->iostream); + + return bfd_cache_delete (kill); +} + +/* Close a BFD and remove it from the cache. */ + +static bfd_boolean +bfd_cache_delete (abfd) + bfd *abfd; +{ + bfd_boolean ret; + + if (fclose ((FILE *) abfd->iostream) == 0) + ret = TRUE; + else + { + ret = FALSE; + bfd_set_error (bfd_error_system_call); + } + + snip (abfd); + + abfd->iostream = NULL; + --open_files; + + return ret; +} + +/* +INTERNAL_FUNCTION + bfd_cache_init + +SYNOPSIS + bfd_boolean bfd_cache_init (bfd *abfd); + +DESCRIPTION + Add a newly opened BFD to the cache. +*/ + +bfd_boolean +bfd_cache_init (abfd) + bfd *abfd; +{ + BFD_ASSERT (abfd->iostream != NULL); + if (open_files >= BFD_CACHE_MAX_OPEN) + { + if (! close_one ()) + return FALSE; + } + insert (abfd); + ++open_files; + return TRUE; +} + +/* +INTERNAL_FUNCTION + bfd_cache_close + +SYNOPSIS + bfd_boolean bfd_cache_close (bfd *abfd); + +DESCRIPTION + Remove the BFD @var{abfd} from the cache. If the attached file is open, + then close it too. + +RETURNS + <> is returned if closing the file fails, <> is + returned if all is well. +*/ + +bfd_boolean +bfd_cache_close (abfd) + bfd *abfd; +{ + if (abfd->iostream == NULL + || (abfd->flags & BFD_IN_MEMORY) != 0) + return TRUE; + + return bfd_cache_delete (abfd); +} + +/* +INTERNAL_FUNCTION + bfd_open_file + +SYNOPSIS + FILE* bfd_open_file(bfd *abfd); + +DESCRIPTION + Call the OS to open a file for @var{abfd}. Return the <> + (possibly <>) that results from this operation. Set up the + BFD so that future accesses know the file is open. If the <> + returned is <>, then it won't have been put in the + cache, so it won't have to be removed from it. +*/ + +FILE * +bfd_open_file (abfd) + bfd *abfd; +{ + abfd->cacheable = TRUE; /* Allow it to be closed later. */ + + if (open_files >= BFD_CACHE_MAX_OPEN) + { + if (! close_one ()) + return NULL; + } + + switch (abfd->direction) + { + case read_direction: + case no_direction: + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RB); + break; + case both_direction: + case write_direction: + if (abfd->opened_once) + { + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_RUB); + if (abfd->iostream == NULL) + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB); + } + else + { + /* Create the file. + + Some operating systems won't let us overwrite a running + binary. For them, we want to unlink the file first. + + However, gcc 2.95 will create temporary files using + O_EXCL and tight permissions to prevent other users from + substituting other .o files during the compilation. gcc + will then tell the assembler to use the newly created + file as an output file. If we unlink the file here, we + open a brief window when another user could still + substitute a file. + + So we unlink the output file if and only if it has + non-zero size. */ +#ifndef __MSDOS__ + /* Don't do this for MSDOS: it doesn't care about overwriting + a running binary, but if this file is already open by + another BFD, we will be in deep trouble if we delete an + open file. In fact, objdump does just that if invoked with + the --info option. */ + struct stat s; + + if (stat (abfd->filename, &s) == 0 && s.st_size != 0) + unlink (abfd->filename); +#endif + abfd->iostream = (PTR) fopen (abfd->filename, FOPEN_WUB); + abfd->opened_once = TRUE; + } + break; + } + + if (abfd->iostream != NULL) + { + if (! bfd_cache_init (abfd)) + return NULL; + } + + return (FILE *) abfd->iostream; +} + +/* +INTERNAL_FUNCTION + bfd_cache_lookup_worker + +SYNOPSIS + FILE *bfd_cache_lookup_worker(bfd *abfd); + +DESCRIPTION + 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 + avoid running out of file descriptors. +*/ + +FILE * +bfd_cache_lookup_worker (abfd) + bfd *abfd; +{ + if ((abfd->flags & BFD_IN_MEMORY) != 0) + abort (); + + if (abfd->my_archive) + abfd = abfd->my_archive; + + if (abfd->iostream != NULL) + { + /* Move the file to the start of the cache. */ + if (abfd != bfd_last_cache) + { + snip (abfd); + insert (abfd); + } + } + else + { + if (bfd_open_file (abfd) == NULL) + return NULL; + if (abfd->where != (unsigned long) abfd->where) + return NULL; + if (fseek ((FILE *) abfd->iostream, (long) abfd->where, SEEK_SET) != 0) + return NULL; + } + + return (FILE *) abfd->iostream; +} diff --git a/contrib/binutils-2.14/bfd/coffgen.c b/contrib/binutils-2.14/bfd/coffgen.c new file mode 100644 index 0000000000..fcb00fc473 --- /dev/null +++ b/contrib/binutils-2.14/bfd/coffgen.c @@ -0,0 +1,2498 @@ +/* Support for the generic parts of COFF, for BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Most of this hacked by Steve Chamberlain, sac@cygnus.com. + Split out of coffcode.h by Ian Taylor, ian@cygnus.com. */ + +/* This file contains COFF code that is not dependent on any + particular COFF target. There is only one version of this file in + libbfd.a, so no target specific code may be put in here. Or, to + put it another way, + + ********** DO NOT PUT TARGET SPECIFIC CODE IN THIS FILE ********** + + If you need to add some target specific behaviour, add a new hook + function to bfd_coff_backend_data. + + Some of these functions are also called by the ECOFF routines. + Those functions may not use any COFF specific information, such as + coff_data (abfd). */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "coff/internal.h" +#include "libcoff.h" + +static void coff_fix_symbol_name + PARAMS ((bfd *, asymbol *, combined_entry_type *, bfd_size_type *, + asection **, bfd_size_type *)); +static bfd_boolean coff_write_symbol + PARAMS ((bfd *, asymbol *, combined_entry_type *, bfd_vma *, + bfd_size_type *, asection **, bfd_size_type *)); +static bfd_boolean coff_write_alien_symbol + PARAMS ((bfd *, asymbol *, bfd_vma *, bfd_size_type *, + asection **, bfd_size_type *)); +static bfd_boolean coff_write_native_symbol + PARAMS ((bfd *, coff_symbol_type *, bfd_vma *, bfd_size_type *, + asection **, bfd_size_type *)); +static void coff_pointerize_aux + PARAMS ((bfd *, combined_entry_type *, combined_entry_type *, + unsigned int, combined_entry_type *)); +static bfd_boolean make_a_section_from_file + PARAMS ((bfd *, struct internal_scnhdr *, unsigned int)); +static const bfd_target *coff_real_object_p + PARAMS ((bfd *, unsigned, struct internal_filehdr *, + struct internal_aouthdr *)); +static void fixup_symbol_value + PARAMS ((bfd *, coff_symbol_type *, struct internal_syment *)); +static char *build_debug_section + PARAMS ((bfd *)); +static char *copy_name + PARAMS ((bfd *, char *, size_t)); + +#define STRING_SIZE_SIZE (4) + +/* Take a section header read from a coff file (in HOST byte order), + and make a BFD "section" out of it. This is used by ECOFF. */ +static bfd_boolean +make_a_section_from_file (abfd, hdr, target_index) + bfd *abfd; + struct internal_scnhdr *hdr; + unsigned int target_index; +{ + asection *return_section; + char *name; + bfd_boolean result = TRUE; + flagword flags; + + name = NULL; + + /* Handle long section names as in PE. */ + if (bfd_coff_long_section_names (abfd) + && hdr->s_name[0] == '/') + { + char buf[SCNNMLEN]; + long strindex; + char *p; + const char *strings; + + memcpy (buf, hdr->s_name + 1, SCNNMLEN - 1); + buf[SCNNMLEN - 1] = '\0'; + strindex = strtol (buf, &p, 10); + if (*p == '\0' && strindex >= 0) + { + 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. */ + strings += strindex; + name = bfd_alloc (abfd, (bfd_size_type) strlen (strings) + 1); + if (name == NULL) + return FALSE; + strcpy (name, strings); + } + } + + if (name == NULL) + { + /* Assorted wastage to null-terminate the name, thanks AT&T! */ + name = bfd_alloc (abfd, (bfd_size_type) sizeof (hdr->s_name) + 1); + if (name == NULL) + return FALSE; + strncpy (name, (char *) &hdr->s_name[0], sizeof (hdr->s_name)); + name[sizeof (hdr->s_name)] = 0; + } + + return_section = bfd_make_section_anyway (abfd, name); + if (return_section == NULL) + return FALSE; + + return_section->vma = hdr->s_vaddr; + return_section->lma = hdr->s_paddr; + return_section->_raw_size = hdr->s_size; + return_section->filepos = hdr->s_scnptr; + return_section->rel_filepos = hdr->s_relptr; + return_section->reloc_count = hdr->s_nreloc; + + bfd_coff_set_alignment_hook (abfd, return_section, hdr); + + return_section->line_filepos = hdr->s_lnnoptr; + + return_section->lineno_count = hdr->s_nlnno; + return_section->userdata = NULL; + return_section->next = (asection *) NULL; + return_section->target_index = target_index; + + if (! bfd_coff_styp_to_sec_flags_hook (abfd, hdr, name, return_section, + & flags)) + result = FALSE; + + return_section->flags = flags; + + /* At least on i386-coff, the line number count for a shared library + section must be ignored. */ + if ((return_section->flags & SEC_COFF_SHARED_LIBRARY) != 0) + return_section->lineno_count = 0; + + if (hdr->s_nreloc != 0) + return_section->flags |= SEC_RELOC; + /* FIXME: should this check 'hdr->s_size > 0' */ + if (hdr->s_scnptr != 0) + return_section->flags |= SEC_HAS_CONTENTS; + + return result; +} + +/* Read in a COFF object and make it into a BFD. This is used by + ECOFF as well. */ + +static const bfd_target * +coff_real_object_p (abfd, nscns, internal_f, internal_a) + bfd *abfd; + unsigned nscns; + struct internal_filehdr *internal_f; + struct internal_aouthdr *internal_a; +{ + flagword oflags = abfd->flags; + bfd_vma ostart = bfd_get_start_address (abfd); + PTR tdata; + PTR tdata_save; + bfd_size_type readsize; /* length of file_info */ + unsigned int scnhsz; + char *external_sections; + + if (!(internal_f->f_flags & F_RELFLG)) + abfd->flags |= HAS_RELOC; + if ((internal_f->f_flags & F_EXEC)) + abfd->flags |= EXEC_P; + if (!(internal_f->f_flags & F_LNNO)) + abfd->flags |= HAS_LINENO; + if (!(internal_f->f_flags & F_LSYMS)) + abfd->flags |= HAS_LOCALS; + + /* FIXME: How can we set D_PAGED correctly? */ + if ((internal_f->f_flags & F_EXEC) != 0) + abfd->flags |= D_PAGED; + + bfd_get_symcount (abfd) = internal_f->f_nsyms; + if (internal_f->f_nsyms) + abfd->flags |= HAS_SYMS; + + if (internal_a != (struct internal_aouthdr *) NULL) + bfd_get_start_address (abfd) = internal_a->entry; + else + bfd_get_start_address (abfd) = 0; + + /* Set up the tdata area. ECOFF uses its own routine, and overrides + abfd->flags. */ + tdata_save = abfd->tdata.any; + tdata = bfd_coff_mkobject_hook (abfd, (PTR) internal_f, (PTR) internal_a); + if (tdata == NULL) + goto fail2; + + scnhsz = bfd_coff_scnhsz (abfd); + readsize = (bfd_size_type) nscns * scnhsz; + external_sections = (char *) bfd_alloc (abfd, readsize); + if (!external_sections) + goto fail; + + if (bfd_bread ((PTR) external_sections, readsize, abfd) != readsize) + goto fail; + + /* Set the arch/mach *before* swapping in sections; section header swapping + may depend on arch/mach info. */ + if (! bfd_coff_set_arch_mach_hook (abfd, (PTR) internal_f)) + goto fail; + + /* Now copy data as required; construct all asections etc. */ + if (nscns != 0) + { + unsigned int i; + for (i = 0; i < nscns; i++) + { + struct internal_scnhdr tmp; + bfd_coff_swap_scnhdr_in (abfd, + (PTR) (external_sections + i * scnhsz), + (PTR) & tmp); + if (! make_a_section_from_file (abfd, &tmp, i + 1)) + goto fail; + } + } + + return abfd->xvec; + + fail: + bfd_release (abfd, tdata); + fail2: + abfd->tdata.any = tdata_save; + abfd->flags = oflags; + bfd_get_start_address (abfd) = ostart; + return (const bfd_target *) NULL; +} + +/* Turn a COFF file into a BFD, but fail with bfd_error_wrong_format if it is + not a COFF file. This is also used by ECOFF. */ + +const bfd_target * +coff_object_p (abfd) + bfd *abfd; +{ + bfd_size_type filhsz; + bfd_size_type aoutsz; + unsigned int nscns; + PTR filehdr; + struct internal_filehdr internal_f; + struct internal_aouthdr internal_a; + + /* figure out how much to read */ + filhsz = bfd_coff_filhsz (abfd); + aoutsz = bfd_coff_aoutsz (abfd); + + filehdr = bfd_alloc (abfd, filhsz); + if (filehdr == NULL) + return NULL; + if (bfd_bread (filehdr, filhsz, abfd) != filhsz) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_wrong_format); + bfd_release (abfd, filehdr); + return NULL; + } + bfd_coff_swap_filehdr_in (abfd, filehdr, &internal_f); + bfd_release (abfd, filehdr); + + /* The XCOFF format has two sizes for the f_opthdr. SMALL_AOUTSZ + (less than aoutsz) used in object files and AOUTSZ (equal to + aoutsz) in executables. The bfd_coff_swap_aouthdr_in function + expects this header to be aoutsz bytes in length, so we use that + value in the call to bfd_alloc below. But we must be careful to + only read in f_opthdr bytes in the call to bfd_bread. We should + also attempt to catch corrupt or non-COFF binaries with a strange + value for f_opthdr. */ + if (! bfd_coff_bad_format_hook (abfd, &internal_f) + || internal_f.f_opthdr > aoutsz) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + nscns = internal_f.f_nscns; + + if (internal_f.f_opthdr) + { + PTR opthdr; + + opthdr = bfd_alloc (abfd, aoutsz); + if (opthdr == NULL) + return NULL; + if (bfd_bread (opthdr, (bfd_size_type) internal_f.f_opthdr, abfd) + != internal_f.f_opthdr) + { + bfd_release (abfd, opthdr); + return NULL; + } + bfd_coff_swap_aouthdr_in (abfd, opthdr, (PTR) &internal_a); + bfd_release (abfd, opthdr); + } + + return coff_real_object_p (abfd, nscns, &internal_f, + (internal_f.f_opthdr != 0 + ? &internal_a + : (struct internal_aouthdr *) NULL)); +} + +/* Get the BFD section from a COFF symbol section number. */ + +asection * +coff_section_from_bfd_index (abfd, index) + bfd *abfd; + int index; +{ + struct sec *answer = abfd->sections; + + if (index == N_ABS) + return bfd_abs_section_ptr; + if (index == N_UNDEF) + return bfd_und_section_ptr; + if (index == N_DEBUG) + return bfd_abs_section_ptr; + + while (answer) + { + if (answer->target_index == index) + return answer; + answer = answer->next; + } + + /* We should not reach this point, but the SCO 3.2v4 /lib/libc_s.a + has a bad symbol table in biglitpow.o. */ + return bfd_und_section_ptr; +} + +/* Get the upper bound of a COFF symbol table. */ + +long +coff_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + if (!bfd_coff_slurp_symbol_table (abfd)) + return -1; + + return (bfd_get_symcount (abfd) + 1) * (sizeof (coff_symbol_type *)); +} + +/* Canonicalize a COFF symbol table. */ + +long +coff_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + unsigned int counter; + coff_symbol_type *symbase; + coff_symbol_type **location = (coff_symbol_type **) alocation; + + if (!bfd_coff_slurp_symbol_table (abfd)) + return -1; + + symbase = obj_symbols (abfd); + counter = bfd_get_symcount (abfd); + while (counter-- > 0) + *location++ = symbase++; + + *location = NULL; + + return bfd_get_symcount (abfd); +} + +/* Get the name of a symbol. The caller must pass in a buffer of size + >= SYMNMLEN + 1. */ + +const char * +_bfd_coff_internal_syment_name (abfd, sym, buf) + bfd *abfd; + const struct internal_syment *sym; + char *buf; +{ + /* FIXME: It's not clear this will work correctly if sizeof + (_n_zeroes) != 4. */ + if (sym->_n._n_n._n_zeroes != 0 + || sym->_n._n_n._n_offset == 0) + { + memcpy (buf, sym->_n._n_name, SYMNMLEN); + buf[SYMNMLEN] = '\0'; + return buf; + } + else + { + const char *strings; + + BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE); + strings = obj_coff_strings (abfd); + if (strings == NULL) + { + strings = _bfd_coff_read_string_table (abfd); + if (strings == NULL) + return NULL; + } + return strings + sym->_n._n_n._n_offset; + } +} + +/* Read in and swap the relocs. This returns a buffer holding the + relocs for section SEC in file ABFD. If CACHE is TRUE and + INTERNAL_RELOCS is NULL, the relocs read in will be saved in case + the function is called again. If EXTERNAL_RELOCS is not NULL, it + is a buffer large enough to hold the unswapped relocs. If + INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold + the swapped relocs. If REQUIRE_INTERNAL is TRUE, then the return + value must be INTERNAL_RELOCS. The function returns NULL on error. */ + +struct internal_reloc * +_bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs, + require_internal, internal_relocs) + bfd *abfd; + asection *sec; + bfd_boolean cache; + bfd_byte *external_relocs; + bfd_boolean require_internal; + struct internal_reloc *internal_relocs; +{ + bfd_size_type relsz; + bfd_byte *free_external = NULL; + struct internal_reloc *free_internal = NULL; + bfd_byte *erel; + bfd_byte *erel_end; + struct internal_reloc *irel; + bfd_size_type amt; + + if (coff_section_data (abfd, sec) != NULL + && coff_section_data (abfd, sec)->relocs != NULL) + { + if (! require_internal) + return coff_section_data (abfd, sec)->relocs; + memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs, + sec->reloc_count * sizeof (struct internal_reloc)); + return internal_relocs; + } + + relsz = bfd_coff_relsz (abfd); + + amt = sec->reloc_count * relsz; + if (external_relocs == NULL) + { + free_external = (bfd_byte *) bfd_malloc (amt); + if (free_external == NULL && sec->reloc_count > 0) + goto error_return; + external_relocs = free_external; + } + + if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 + || bfd_bread (external_relocs, amt, abfd) != amt) + goto error_return; + + if (internal_relocs == NULL) + { + amt = sec->reloc_count; + amt *= sizeof (struct internal_reloc); + free_internal = (struct internal_reloc *) bfd_malloc (amt); + if (free_internal == NULL && sec->reloc_count > 0) + goto error_return; + internal_relocs = free_internal; + } + + /* Swap in the relocs. */ + erel = external_relocs; + erel_end = erel + relsz * sec->reloc_count; + irel = internal_relocs; + for (; erel < erel_end; erel += relsz, irel++) + bfd_coff_swap_reloc_in (abfd, (PTR) erel, (PTR) irel); + + if (free_external != NULL) + { + free (free_external); + free_external = NULL; + } + + if (cache && free_internal != NULL) + { + if (coff_section_data (abfd, sec) == NULL) + { + amt = sizeof (struct coff_section_tdata); + sec->used_by_bfd = (PTR) bfd_zalloc (abfd, amt); + if (sec->used_by_bfd == NULL) + goto error_return; + coff_section_data (abfd, sec)->contents = NULL; + } + coff_section_data (abfd, sec)->relocs = free_internal; + } + + return internal_relocs; + + error_return: + if (free_external != NULL) + free (free_external); + if (free_internal != NULL) + free (free_internal); + return NULL; +} + +/* Set lineno_count for the output sections of a COFF file. */ + +int +coff_count_linenumbers (abfd) + bfd *abfd; +{ + unsigned int limit = bfd_get_symcount (abfd); + unsigned int i; + int total = 0; + asymbol **p; + asection *s; + + if (limit == 0) + { + /* This may be from the backend linker, in which case the + lineno_count in the sections is correct. */ + for (s = abfd->sections; s != NULL; s = s->next) + total += s->lineno_count; + return total; + } + + for (s = abfd->sections; s != NULL; s = s->next) + BFD_ASSERT (s->lineno_count == 0); + + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) + { + asymbol *q_maybe = *p; + + if (bfd_family_coff (bfd_asymbol_bfd (q_maybe))) + { + coff_symbol_type *q = coffsymbol (q_maybe); + + /* The AIX 4.1 compiler can sometimes generate line numbers + attached to debugging symbols. We try to simply ignore + those here. */ + if (q->lineno != NULL + && q->symbol.section->owner != NULL) + { + /* This symbol has line numbers. Increment the owning + section's linenumber count. */ + alent *l = q->lineno; + + do + { + asection * sec = q->symbol.section->output_section; + + /* Do not try to update fields in read-only sections. */ + if (! bfd_is_const_section (sec)) + sec->lineno_count ++; + + ++total; + ++l; + } + while (l->line_number != 0); + } + } + } + + 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 (ignore_abfd, symbol) + 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 (abfd, coff_symbol_ptr, syment) + bfd *abfd; + coff_symbol_type *coff_symbol_ptr; + struct internal_syment *syment; +{ + + /* Normalize the symbol flags */ + if (bfd_is_com_section (coff_symbol_ptr->symbol.section)) + { + /* a common symbol is undefined with a value */ + syment->n_scnum = N_UNDEF; + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if ((coff_symbol_ptr->symbol.flags & BSF_DEBUGGING) != 0 + && (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING_RELOC) == 0) + { + syment->n_value = coff_symbol_ptr->symbol.value; + } + else if (bfd_is_und_section (coff_symbol_ptr->symbol.section)) + { + syment->n_scnum = N_UNDEF; + syment->n_value = 0; + } + /* FIXME: Do we need to handle the absolute section here? */ + else + { + if (coff_symbol_ptr->symbol.section) + { + syment->n_scnum = + coff_symbol_ptr->symbol.section->output_section->target_index; + + syment->n_value = (coff_symbol_ptr->symbol.value + + coff_symbol_ptr->symbol.section->output_offset); + if (! obj_pe (abfd)) + { + syment->n_value += (syment->n_sclass == C_STATLAB) + ? coff_symbol_ptr->symbol.section->output_section->lma + : coff_symbol_ptr->symbol.section->output_section->vma; + } + } + else + { + BFD_ASSERT (0); + /* This can happen, but I don't know why yet (steve@cygnus.com) */ + syment->n_scnum = N_ABS; + syment->n_value = coff_symbol_ptr->symbol.value; + } + } +} + +/* Run through all the symbols in the symbol table and work out what + their indexes into the symbol table will be when output. + + Coff requires that each C_FILE symbol points to the next one in the + chain, and that the last one points to the first external symbol. We + do that here too. */ + +bfd_boolean +coff_renumber_symbols (bfd_ptr, first_undef) + bfd *bfd_ptr; + int *first_undef; +{ + unsigned int symbol_count = bfd_get_symcount (bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int native_index = 0; + struct internal_syment *last_file = (struct internal_syment *) NULL; + unsigned int symbol_index; + + /* COFF demands that undefined symbols come after all other symbols. + Since we don't need to impose this extra knowledge on all our + client programs, deal with that here. Sort the symbol table; + just move the undefined symbols to the end, leaving the rest + alone. The O'Reilly book says that defined global symbols come + at the end before the undefined symbols, so we do that here as + well. */ + /* @@ Do we have some condition we could test for, so we don't always + have to do this? I don't think relocatability is quite right, but + I'm not certain. [raeburn:19920508.1711EST] */ + { + asymbol **newsyms; + unsigned int i; + bfd_size_type amt; + + amt = sizeof (asymbol *) * ((bfd_size_type) symbol_count + 1); + newsyms = (asymbol **) bfd_alloc (bfd_ptr, amt); + if (!newsyms) + return FALSE; + bfd_ptr->outsymbols = newsyms; + for (i = 0; i < symbol_count; i++) + if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) != 0 + || (!bfd_is_und_section (symbol_ptr_ptr[i]->section) + && !bfd_is_com_section (symbol_ptr_ptr[i]->section) + && ((symbol_ptr_ptr[i]->flags & BSF_FUNCTION) != 0 + || ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_WEAK)) + == 0)))) + *newsyms++ = symbol_ptr_ptr[i]; + + for (i = 0; i < symbol_count; i++) + if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0 + && !bfd_is_und_section (symbol_ptr_ptr[i]->section) + && (bfd_is_com_section (symbol_ptr_ptr[i]->section) + || ((symbol_ptr_ptr[i]->flags & BSF_FUNCTION) == 0 + && ((symbol_ptr_ptr[i]->flags & (BSF_GLOBAL | BSF_WEAK)) + != 0)))) + *newsyms++ = symbol_ptr_ptr[i]; + + *first_undef = newsyms - bfd_ptr->outsymbols; + + for (i = 0; i < symbol_count; i++) + if ((symbol_ptr_ptr[i]->flags & BSF_NOT_AT_END) == 0 + && bfd_is_und_section (symbol_ptr_ptr[i]->section)) + *newsyms++ = symbol_ptr_ptr[i]; + *newsyms = (asymbol *) NULL; + symbol_ptr_ptr = bfd_ptr->outsymbols; + } + + 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]); + 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; + + if (s->u.syment.n_sclass == C_FILE) + { + if (last_file != (struct internal_syment *) NULL) + last_file->n_value = native_index; + last_file = &(s->u.syment); + } + else + { + + /* Modify the symbol values according to their section and + type */ + + fixup_symbol_value (bfd_ptr, coff_symbol_ptr, &(s->u.syment)); + } + for (i = 0; i < s->u.syment.n_numaux + 1; i++) + s[i].offset = native_index++; + } + else + { + native_index++; + } + } + obj_conv_table_size (bfd_ptr) = native_index; + + return TRUE; +} + +/* Run thorough the symbol table again, and fix it so that all + pointers to entries are changed to the entries' index in the output + symbol table. */ + +void +coff_mangle_symbols (bfd_ptr) + bfd *bfd_ptr; +{ + unsigned int symbol_count = bfd_get_symcount (bfd_ptr); + asymbol **symbol_ptr_ptr = bfd_ptr->outsymbols; + unsigned int symbol_index; + + 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]); + + if (coff_symbol_ptr && coff_symbol_ptr->native) + { + int i; + combined_entry_type *s = coff_symbol_ptr->native; + + if (s->fix_value) + { + /* FIXME: We should use a union here. */ + s->u.syment.n_value = + (bfd_vma)((combined_entry_type *) + ((unsigned long) s->u.syment.n_value))->offset; + s->fix_value = 0; + } + if (s->fix_line) + { + /* The value is the offset into the line number entries + for the symbol's section. On output, the symbol's + section should be N_DEBUG. */ + s->u.syment.n_value = + (coff_symbol_ptr->symbol.section->output_section->line_filepos + + s->u.syment.n_value * bfd_coff_linesz (bfd_ptr)); + coff_symbol_ptr->symbol.section = + coff_section_from_bfd_index (bfd_ptr, N_DEBUG); + BFD_ASSERT (coff_symbol_ptr->symbol.flags & BSF_DEBUGGING); + } + for (i = 0; i < s->u.syment.n_numaux; i++) + { + combined_entry_type *a = s + i + 1; + if (a->fix_tag) + { + a->u.auxent.x_sym.x_tagndx.l = + a->u.auxent.x_sym.x_tagndx.p->offset; + a->fix_tag = 0; + } + if (a->fix_end) + { + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l = + a->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p->offset; + a->fix_end = 0; + } + if (a->fix_scnlen) + { + a->u.auxent.x_csect.x_scnlen.l = + a->u.auxent.x_csect.x_scnlen.p->offset; + a->fix_scnlen = 0; + } + } + } + } +} + +static void +coff_fix_symbol_name (abfd, symbol, native, string_size_p, + debug_string_section_p, debug_string_size_p) + bfd *abfd; + asymbol *symbol; + combined_entry_type *native; + bfd_size_type *string_size_p; + asection **debug_string_section_p; + bfd_size_type *debug_string_size_p; +{ + unsigned int name_length; + union internal_auxent *auxent; + char *name = (char *) (symbol->name); + + if (name == (char *) NULL) + { + /* coff symbols always have names, so we'll make one up */ + symbol->name = "strange"; + name = (char *) symbol->name; + } + name_length = strlen (name); + + if (native->u.syment.n_sclass == C_FILE + && native->u.syment.n_numaux > 0) + { + unsigned int filnmlen; + + if (bfd_coff_force_symnames_in_strings (abfd)) + { + native->u.syment._n._n_n._n_offset = + (*string_size_p + STRING_SIZE_SIZE); + native->u.syment._n._n_n._n_zeroes = 0; + *string_size_p += 6; /* strlen(".file") + 1 */ + } + else + strncpy (native->u.syment._n._n_name, ".file", SYMNMLEN); + + auxent = &(native + 1)->u.auxent; + + filnmlen = bfd_coff_filnmlen (abfd); + + if (bfd_coff_long_filenames (abfd)) + { + if (name_length <= filnmlen) + { + strncpy (auxent->x_file.x_fname, name, filnmlen); + } + else + { + auxent->x_file.x_n.x_offset = *string_size_p + STRING_SIZE_SIZE; + auxent->x_file.x_n.x_zeroes = 0; + *string_size_p += name_length + 1; + } + } + else + { + strncpy (auxent->x_file.x_fname, name, filnmlen); + if (name_length > filnmlen) + name[filnmlen] = '\0'; + } + } + else + { + if (name_length <= SYMNMLEN && !bfd_coff_force_symnames_in_strings (abfd)) + { + /* This name will fit into the symbol neatly */ + strncpy (native->u.syment._n._n_name, symbol->name, SYMNMLEN); + } + else if (!bfd_coff_symname_in_debug (abfd, &native->u.syment)) + { + native->u.syment._n._n_n._n_offset = (*string_size_p + + STRING_SIZE_SIZE); + native->u.syment._n._n_n._n_zeroes = 0; + *string_size_p += name_length + 1; + } + else + { + file_ptr filepos; + bfd_byte buf[4]; + int prefix_len = bfd_coff_debug_string_prefix_length (abfd); + + /* This name should be written into the .debug section. For + some reason each name is preceded by a two byte length + and also followed by a null byte. FIXME: We assume that + the .debug section has already been created, and that it + is large enough. */ + if (*debug_string_section_p == (asection *) NULL) + *debug_string_section_p = bfd_get_section_by_name (abfd, ".debug"); + filepos = bfd_tell (abfd); + if (prefix_len == 4) + bfd_put_32 (abfd, (bfd_vma) (name_length + 1), buf); + else + bfd_put_16 (abfd, (bfd_vma) (name_length + 1), buf); + + if (!bfd_set_section_contents (abfd, + *debug_string_section_p, + (PTR) buf, + (file_ptr) *debug_string_size_p, + (bfd_size_type) prefix_len) + || !bfd_set_section_contents (abfd, + *debug_string_section_p, + (PTR) symbol->name, + (file_ptr) (*debug_string_size_p + + prefix_len), + (bfd_size_type) name_length + 1)) + abort (); + if (bfd_seek (abfd, filepos, SEEK_SET) != 0) + abort (); + native->u.syment._n._n_n._n_offset = + *debug_string_size_p + prefix_len; + native->u.syment._n._n_n._n_zeroes = 0; + *debug_string_size_p += name_length + 1 + prefix_len; + } + } +} + +/* We need to keep track of the symbol index so that when we write out + the relocs we can get the index for a symbol. This method is a + hack. FIXME. */ + +#define set_index(symbol, idx) ((symbol)->udata.i = (idx)) + +/* Write a symbol out to a COFF file. */ + +static bfd_boolean +coff_write_symbol (abfd, symbol, native, written, string_size_p, + debug_string_section_p, debug_string_size_p) + bfd *abfd; + asymbol *symbol; + combined_entry_type *native; + bfd_vma *written; + bfd_size_type *string_size_p; + asection **debug_string_section_p; + bfd_size_type *debug_string_size_p; +{ + unsigned int numaux = native->u.syment.n_numaux; + int type = native->u.syment.n_type; + int class = native->u.syment.n_sclass; + PTR buf; + bfd_size_type symesz; + + if (native->u.syment.n_sclass == C_FILE) + symbol->flags |= BSF_DEBUGGING; + + if (symbol->flags & BSF_DEBUGGING + && bfd_is_abs_section (symbol->section)) + { + native->u.syment.n_scnum = N_DEBUG; + } + else if (bfd_is_abs_section (symbol->section)) + { + native->u.syment.n_scnum = N_ABS; + } + else if (bfd_is_und_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + } + else + { + native->u.syment.n_scnum = + symbol->section->output_section->target_index; + } + + coff_fix_symbol_name (abfd, symbol, native, string_size_p, + debug_string_section_p, debug_string_size_p); + + symesz = bfd_coff_symesz (abfd); + buf = bfd_alloc (abfd, symesz); + if (!buf) + return FALSE; + bfd_coff_swap_sym_out (abfd, &native->u.syment, buf); + if (bfd_bwrite (buf, symesz, abfd) != symesz) + return FALSE; + bfd_release (abfd, buf); + + if (native->u.syment.n_numaux > 0) + { + bfd_size_type auxesz; + unsigned int j; + + auxesz = bfd_coff_auxesz (abfd); + buf = bfd_alloc (abfd, auxesz); + if (!buf) + return FALSE; + for (j = 0; j < native->u.syment.n_numaux; j++) + { + bfd_coff_swap_aux_out (abfd, + &((native + j + 1)->u.auxent), + type, + class, + (int) j, + native->u.syment.n_numaux, + buf); + if (bfd_bwrite (buf, auxesz, abfd) != auxesz) + return FALSE; + } + bfd_release (abfd, buf); + } + + /* Store the index for use when we write out the relocs. */ + set_index (symbol, *written); + + *written += numaux + 1; + return TRUE; +} + +/* Write out a symbol to a COFF file that does not come from a COFF + file originally. This symbol may have been created by the linker, + or we may be linking a non COFF file to a COFF file. */ + +static bfd_boolean +coff_write_alien_symbol (abfd, symbol, written, string_size_p, + debug_string_section_p, debug_string_size_p) + bfd *abfd; + asymbol *symbol; + bfd_vma *written; + bfd_size_type *string_size_p; + asection **debug_string_section_p; + bfd_size_type *debug_string_size_p; +{ + combined_entry_type *native; + combined_entry_type dummy; + + native = &dummy; + native->u.syment.n_type = T_NULL; + native->u.syment.n_flags = 0; + if (bfd_is_und_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else if (bfd_is_com_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else if (symbol->flags & BSF_DEBUGGING) + { + /* There isn't much point to writing out a debugging symbol + unless we are prepared to convert it into COFF debugging + format. So, we just ignore them. We must clobber the symbol + name to keep it from being put in the string table. */ + symbol->name = ""; + return TRUE; + } + else + { + native->u.syment.n_scnum = + symbol->section->output_section->target_index; + native->u.syment.n_value = (symbol->value + + symbol->section->output_offset); + if (! obj_pe (abfd)) + native->u.syment.n_value += symbol->section->output_section->vma; + + /* Copy the any flags from the file header into the symbol. + FIXME: Why? */ + { + coff_symbol_type *c = coff_symbol_from (abfd, symbol); + if (c != (coff_symbol_type *) NULL) + native->u.syment.n_flags = bfd_asymbol_bfd (&c->symbol)->flags; + } + } + + native->u.syment.n_type = 0; + if (symbol->flags & BSF_LOCAL) + native->u.syment.n_sclass = C_STAT; + else if (symbol->flags & BSF_WEAK) + native->u.syment.n_sclass = obj_pe (abfd) ? C_NT_WEAK : C_WEAKEXT; + else + native->u.syment.n_sclass = C_EXT; + native->u.syment.n_numaux = 0; + + return coff_write_symbol (abfd, symbol, native, written, string_size_p, + debug_string_section_p, debug_string_size_p); +} + +/* Write a native symbol to a COFF file. */ + +static bfd_boolean +coff_write_native_symbol (abfd, symbol, written, string_size_p, + debug_string_section_p, debug_string_size_p) + bfd *abfd; + coff_symbol_type *symbol; + bfd_vma *written; + bfd_size_type *string_size_p; + asection **debug_string_section_p; + bfd_size_type *debug_string_size_p; +{ + combined_entry_type *native = symbol->native; + alent *lineno = symbol->lineno; + + /* 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. */ + if (lineno && !symbol->done_lineno && symbol->symbol.section->owner != NULL) + { + unsigned int count = 0; + lineno[count].u.offset = *written; + if (native->u.syment.n_numaux) + { + union internal_auxent *a = &((native + 1)->u.auxent); + + a->x_sym.x_fcnary.x_fcn.x_lnnoptr = + symbol->symbol.section->output_section->moving_line_filepos; + } + + /* Count and relocate all other linenumbers. */ + count++; + while (lineno[count].line_number != 0) + { +#if 0 + /* 13 april 92. sac + I've been told this, but still need proof: + > The second bug is also in `bfd/coffcode.h'. This bug + > causes the linker to screw up the pc-relocations for + > all the line numbers in COFF code. This bug isn't only + > specific to A29K implementations, but affects all + > systems using COFF format binaries. Note that in COFF + > object files, the line number core offsets output by + > the assembler are relative to the start of each + > procedure, not to the start of the .text section. This + > patch relocates the line numbers relative to the + > `native->u.syment.n_value' instead of the section + > virtual address. + > modular!olson@cs.arizona.edu (Jon Olson) + */ + lineno[count].u.offset += native->u.syment.n_value; +#else + lineno[count].u.offset += + (symbol->symbol.section->output_section->vma + + symbol->symbol.section->output_offset); +#endif + count++; + } + symbol->done_lineno = TRUE; + + if (! bfd_is_const_section (symbol->symbol.section->output_section)) + symbol->symbol.section->output_section->moving_line_filepos += + count * bfd_coff_linesz (abfd); + } + + return coff_write_symbol (abfd, &(symbol->symbol), native, written, + string_size_p, debug_string_section_p, + debug_string_size_p); +} + +/* Write out the COFF symbols. */ + +bfd_boolean +coff_write_symbols (abfd) + bfd *abfd; +{ + bfd_size_type string_size; + asection *debug_string_section; + bfd_size_type debug_string_size; + unsigned int i; + unsigned int limit = bfd_get_symcount (abfd); + bfd_signed_vma written = 0; + asymbol **p; + + string_size = 0; + debug_string_section = NULL; + debug_string_size = 0; + + /* If this target supports long section names, they must be put into + the string table. This is supported by PE. This code must + handle section names just as they are handled in + coff_write_object_contents. */ + if (bfd_coff_long_section_names (abfd)) + { + asection *o; + + for (o = abfd->sections; o != NULL; o = o->next) + { + size_t len; + + len = strlen (o->name); + if (len > SCNNMLEN) + string_size += len + 1; + } + } + + /* Seek to the right place */ + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0) + return FALSE; + + /* Output all the symbols we have */ + + written = 0; + for (p = abfd->outsymbols, i = 0; i < limit; i++, p++) + { + asymbol *symbol = *p; + coff_symbol_type *c_symbol = coff_symbol_from (abfd, symbol); + + if (c_symbol == (coff_symbol_type *) NULL + || c_symbol->native == (combined_entry_type *) NULL) + { + if (!coff_write_alien_symbol (abfd, symbol, &written, &string_size, + &debug_string_section, + &debug_string_size)) + return FALSE; + } + else + { + if (!coff_write_native_symbol (abfd, c_symbol, &written, + &string_size, &debug_string_section, + &debug_string_size)) + return FALSE; + } + } + + obj_raw_syment_count (abfd) = written; + + /* Now write out strings */ + + if (string_size != 0) + { + unsigned int size = string_size + STRING_SIZE_SIZE; + bfd_byte buffer[STRING_SIZE_SIZE]; + +#if STRING_SIZE_SIZE == 4 + H_PUT_32 (abfd, size, buffer); +#else + #error Change H_PUT_32 +#endif + if (bfd_bwrite ((PTR) buffer, (bfd_size_type) sizeof (buffer), abfd) + != sizeof (buffer)) + return FALSE; + + /* Handle long section names. This code must handle section + names just as they are handled in coff_write_object_contents. */ + if (bfd_coff_long_section_names (abfd)) + { + asection *o; + + for (o = abfd->sections; o != NULL; o = o->next) + { + size_t len; + + len = strlen (o->name); + if (len > SCNNMLEN) + { + if (bfd_bwrite (o->name, (bfd_size_type) (len + 1), abfd) + != len + 1) + return FALSE; + } + } + } + + for (p = abfd->outsymbols, i = 0; + i < limit; + i++, p++) + { + asymbol *q = *p; + size_t name_length = strlen (q->name); + coff_symbol_type *c_symbol = coff_symbol_from (abfd, q); + size_t maxlen; + + /* Figure out whether the symbol name should go in the string + table. Symbol names that are short enough are stored + directly in the syment structure. File names permit a + different, longer, length in the syment structure. On + XCOFF, some symbol names are stored in the .debug section + rather than in the string table. */ + + if (c_symbol == NULL + || c_symbol->native == NULL) + { + /* This is not a COFF symbol, so it certainly is not a + file name, nor does it go in the .debug section. */ + 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. + Don't write it into the string table. */ + maxlen = name_length; + } + else if (c_symbol->native->u.syment.n_sclass == C_FILE + && c_symbol->native->u.syment.n_numaux > 0) + { + if (bfd_coff_force_symnames_in_strings (abfd)) + { + if (bfd_bwrite (".file", (bfd_size_type) 6, abfd) != 6) + return FALSE; + } + maxlen = bfd_coff_filnmlen (abfd); + } + else + maxlen = bfd_coff_force_symnames_in_strings (abfd) ? 0 : SYMNMLEN; + + if (name_length > maxlen) + { + if (bfd_bwrite ((PTR) (q->name), (bfd_size_type) name_length + 1, + abfd) != name_length + 1) + return FALSE; + } + } + } + else + { + /* We would normally not write anything here, but we'll write + out 4 so that any stupid coff reader which tries to read the + string table even when there isn't one won't croak. */ + unsigned int size = STRING_SIZE_SIZE; + bfd_byte buffer[STRING_SIZE_SIZE]; + +#if STRING_SIZE_SIZE == 4 + H_PUT_32 (abfd, size, buffer); +#else + #error Change H_PUT_32 +#endif + if (bfd_bwrite ((PTR) buffer, (bfd_size_type) STRING_SIZE_SIZE, abfd) + != STRING_SIZE_SIZE) + return FALSE; + } + + /* Make sure the .debug section was created to be the correct size. + We should create it ourselves on the fly, but we don't because + BFD won't let us write to any section until we know how large all + the sections are. We could still do it by making another pass + over the symbols. FIXME. */ + BFD_ASSERT (debug_string_size == 0 + || (debug_string_section != (asection *) NULL + && (BFD_ALIGN (debug_string_size, + 1 << debug_string_section->alignment_power) + == bfd_section_size (abfd, debug_string_section)))); + + return TRUE; +} + +bfd_boolean +coff_write_linenumbers (abfd) + bfd *abfd; +{ + asection *s; + bfd_size_type linesz; + PTR buff; + + linesz = bfd_coff_linesz (abfd); + buff = bfd_alloc (abfd, linesz); + if (!buff) + return FALSE; + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + if (s->lineno_count) + { + asymbol **q = abfd->outsymbols; + if (bfd_seek (abfd, s->line_filepos, SEEK_SET) != 0) + return FALSE; + /* Find all the linenumbers in this section */ + while (*q) + { + asymbol *p = *q; + if (p->section->output_section == s) + { + alent *l = + BFD_SEND (bfd_asymbol_bfd (p), _get_lineno, + (bfd_asymbol_bfd (p), p)); + if (l) + { + /* Found a linenumber entry, output */ + struct internal_lineno out; + memset ((PTR) & out, 0, sizeof (out)); + out.l_lnno = 0; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out (abfd, &out, buff); + if (bfd_bwrite (buff, (bfd_size_type) linesz, abfd) + != linesz) + return FALSE; + l++; + while (l->line_number) + { + out.l_lnno = l->line_number; + out.l_addr.l_symndx = l->u.offset; + bfd_coff_swap_lineno_out (abfd, &out, buff); + if (bfd_bwrite (buff, (bfd_size_type) linesz, abfd) + != linesz) + return FALSE; + l++; + } + } + } + q++; + } + } + } + bfd_release (abfd, buff); + return TRUE; +} + +alent * +coff_get_lineno (ignore_abfd, symbol) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + asymbol *symbol; +{ + return coffsymbol (symbol)->lineno; +} + +#if 0 + +/* This is only called from coff_add_missing_symbols, which has been + disabled. */ + +asymbol * +coff_section_symbol (abfd, name) + bfd *abfd; + char *name; +{ + asection *sec = bfd_make_section_old_way (abfd, name); + asymbol *sym; + combined_entry_type *csym; + + sym = sec->symbol; + csym = coff_symbol_from (abfd, sym)->native; + /* Make sure back-end COFF stuff is there. */ + if (csym == 0) + { + struct foo + { + coff_symbol_type sym; + /* @@FIXME This shouldn't use a fixed size!! */ + combined_entry_type e[10]; + }; + struct foo *f; + + f = (struct foo *) bfd_zalloc (abfd, (bfd_size_type) sizeof (*f)); + if (!f) + { + bfd_set_error (bfd_error_no_error); + return NULL; + } + coff_symbol_from (abfd, sym)->native = csym = f->e; + } + csym[0].u.syment.n_sclass = C_STAT; + csym[0].u.syment.n_numaux = 1; +/* SF_SET_STATICS (sym); @@ ??? */ + csym[1].u.auxent.x_scn.x_scnlen = sec->_raw_size; + csym[1].u.auxent.x_scn.x_nreloc = sec->reloc_count; + csym[1].u.auxent.x_scn.x_nlinno = sec->lineno_count; + + if (sec->output_section == NULL) + { + sec->output_section = sec; + sec->output_offset = 0; + } + + return sym; +} + +#endif /* 0 */ + +/* This function transforms the offsets into the symbol table into + pointers to syments. */ + +static void +coff_pointerize_aux (abfd, table_base, symbol, indaux, auxent) + bfd *abfd; + combined_entry_type *table_base; + combined_entry_type *symbol; + unsigned int indaux; + combined_entry_type *auxent; +{ + unsigned int type = symbol->u.syment.n_type; + unsigned int class = symbol->u.syment.n_sclass; + + if (coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) + { + if ((*coff_backend_info (abfd)->_bfd_coff_pointerize_aux_hook) + (abfd, table_base, symbol, indaux, auxent)) + return; + } + + /* Don't bother if this is a file or a section */ + if (class == C_STAT && type == T_NULL) + return; + if (class == C_FILE) + return; + + /* Otherwise patch up */ +#define N_TMASK coff_data (abfd)->local_n_tmask +#define N_BTSHFT coff_data (abfd)->local_n_btshft + if ((ISFCN (type) || ISTAG (class) || class == C_BLOCK || class == C_FCN) + && auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l > 0) + { + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p = + table_base + auxent->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; + auxent->fix_end = 1; + } + /* A negative tagndx is meaningless, but the SCO 3.2v4 cc can + generate one, so we must be careful to ignore it. */ + if (auxent->u.auxent.x_sym.x_tagndx.l > 0) + { + auxent->u.auxent.x_sym.x_tagndx.p = + table_base + auxent->u.auxent.x_sym.x_tagndx.l; + auxent->fix_tag = 1; + } +} + +/* Allocate space for the ".debug" section, and read it. + We did not read the debug section until now, because + we didn't want to go to the trouble until someone needed it. */ + +static char * +build_debug_section (abfd) + bfd *abfd; +{ + char *debug_section; + file_ptr position; + bfd_size_type sec_size; + + asection *sect = bfd_get_section_by_name (abfd, ".debug"); + + if (!sect) + { + bfd_set_error (bfd_error_no_debug_section); + return NULL; + } + + sec_size = bfd_get_section_size_before_reloc (sect); + debug_section = (PTR) bfd_alloc (abfd, sec_size); + if (debug_section == NULL) + return NULL; + + /* Seek to the beginning of the `.debug' section and read it. + Save the current position first; it is needed by our caller. + Then read debug section and reset the file pointer. */ + + position = bfd_tell (abfd); + if (bfd_seek (abfd, sect->filepos, SEEK_SET) != 0 + || bfd_bread (debug_section, sec_size, abfd) != sec_size + || bfd_seek (abfd, position, SEEK_SET) != 0) + return NULL; + return debug_section; +} + +/* Return a pointer to a malloc'd copy of 'name'. 'name' may not be + \0-terminated, but will not exceed 'maxlen' characters. The copy *will* + be \0-terminated. */ +static char * +copy_name (abfd, name, maxlen) + bfd *abfd; + char *name; + size_t maxlen; +{ + size_t len; + char *newname; + + for (len = 0; len < maxlen; ++len) + { + if (name[len] == '\0') + { + break; + } + } + + if ((newname = (PTR) bfd_alloc (abfd, (bfd_size_type) len + 1)) == NULL) + return (NULL); + strncpy (newname, name, len); + newname[len] = '\0'; + return newname; +} + +/* Read in the external symbols. */ + +bfd_boolean +_bfd_coff_get_external_symbols (abfd) + bfd *abfd; +{ + bfd_size_type symesz; + bfd_size_type size; + PTR syms; + + if (obj_coff_external_syms (abfd) != NULL) + return TRUE; + + symesz = bfd_coff_symesz (abfd); + + size = obj_raw_syment_count (abfd) * symesz; + + syms = (PTR) bfd_malloc (size); + if (syms == NULL && size != 0) + return FALSE; + + if (bfd_seek (abfd, obj_sym_filepos (abfd), SEEK_SET) != 0 + || bfd_bread (syms, size, abfd) != size) + { + if (syms != NULL) + free (syms); + return FALSE; + } + + obj_coff_external_syms (abfd) = syms; + + return TRUE; +} + +/* 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. */ + +const char * +_bfd_coff_read_string_table (abfd) + bfd *abfd; +{ + char extstrsize[STRING_SIZE_SIZE]; + bfd_size_type strsize; + char *strings; + file_ptr pos; + + if (obj_coff_strings (abfd) != NULL) + return obj_coff_strings (abfd); + + if (obj_sym_filepos (abfd) == 0) + { + bfd_set_error (bfd_error_no_symbols); + return NULL; + } + + pos = obj_sym_filepos (abfd); + pos += obj_raw_syment_count (abfd) * bfd_coff_symesz (abfd); + if (bfd_seek (abfd, pos, SEEK_SET) != 0) + return NULL; + + if (bfd_bread (extstrsize, (bfd_size_type) sizeof extstrsize, abfd) + != sizeof extstrsize) + { + if (bfd_get_error () != bfd_error_file_truncated) + return NULL; + + /* There is no string table. */ + strsize = STRING_SIZE_SIZE; + } + else + { +#if STRING_SIZE_SIZE == 4 + strsize = H_GET_32 (abfd, extstrsize); +#else + #error Change H_GET_32 +#endif + } + + if (strsize < STRING_SIZE_SIZE) + { + (*_bfd_error_handler) + (_("%s: bad string table size %lu"), bfd_archive_filename (abfd), + (unsigned long) strsize); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + + strings = (char *) bfd_malloc (strsize); + if (strings == NULL) + return NULL; + + if (bfd_bread (strings + STRING_SIZE_SIZE, strsize - STRING_SIZE_SIZE, abfd) + != strsize - STRING_SIZE_SIZE) + { + free (strings); + return NULL; + } + + obj_coff_strings (abfd) = strings; + + return strings; +} + +/* Free up the external symbols and strings read from a COFF file. */ + +bfd_boolean +_bfd_coff_free_symbols (abfd) + bfd *abfd; +{ + if (obj_coff_external_syms (abfd) != NULL + && ! obj_coff_keep_syms (abfd)) + { + free (obj_coff_external_syms (abfd)); + obj_coff_external_syms (abfd) = NULL; + } + if (obj_coff_strings (abfd) != NULL + && ! obj_coff_keep_strings (abfd)) + { + free (obj_coff_strings (abfd)); + obj_coff_strings (abfd) = NULL; + } + return TRUE; +} + +/* Read a symbol table into freshly bfd_allocated memory, swap it, and + knit the symbol names into a normalized form. By normalized here I + mean that all symbols have an n_offset pointer that points to a null- + terminated string. */ + +combined_entry_type * +coff_get_normalized_symtab (abfd) + bfd *abfd; +{ + combined_entry_type *internal; + combined_entry_type *internal_ptr; + combined_entry_type *symbol_ptr; + combined_entry_type *internal_end; + size_t symesz; + char *raw_src; + char *raw_end; + const char *string_table = NULL; + char *debug_section = NULL; + bfd_size_type size; + + if (obj_raw_syments (abfd) != NULL) + return obj_raw_syments (abfd); + + 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 */ + symesz = bfd_coff_symesz (abfd); + raw_end = (char *) raw_src + obj_raw_syment_count (abfd) * symesz; + + /* FIXME SOMEDAY. A string table size of zero is very weird, but + probably possible. If one shows up, it will probably kill us. */ + + /* Swap all the raw entries */ + for (internal_ptr = internal; + raw_src < raw_end; + raw_src += symesz, internal_ptr++) + { + + unsigned int i; + bfd_coff_swap_sym_in (abfd, (PTR) raw_src, + (PTR) & internal_ptr->u.syment); + symbol_ptr = internal_ptr; + + for (i = 0; + i < symbol_ptr->u.syment.n_numaux; + i++) + { + internal_ptr++; + raw_src += symesz; + bfd_coff_swap_aux_in (abfd, (PTR) 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)); + coff_pointerize_aux (abfd, internal, symbol_ptr, i, + internal_ptr); + } + } + + /* Free the raw symbols, but not the strings (if we have them). */ + obj_coff_keep_strings (abfd) = TRUE; + if (! _bfd_coff_free_symbols (abfd)) + return NULL; + + for (internal_ptr = internal; internal_ptr < internal_end; + internal_ptr++) + { + if (internal_ptr->u.syment.n_sclass == C_FILE + && internal_ptr->u.syment.n_numaux > 0) + { + /* 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) + { + /* the filename is a long one, point into the string table */ + if (string_table == NULL) + { + string_table = _bfd_coff_read_string_table (abfd); + if (string_table == NULL) + return NULL; + } + + internal_ptr->u.syment._n._n_n._n_offset = + ((long) + (string_table + + (internal_ptr + 1)->u.auxent.x_file.x_n.x_offset)); + } + else + { + /* Ordinary short filename, put into memory anyway. The + Microsoft PE tools sometimes store a filename in + multiple AUX entries. */ + if (internal_ptr->u.syment.n_numaux > 1 + && coff_data (abfd)->pe) + { + internal_ptr->u.syment._n._n_n._n_offset = + ((long) + copy_name (abfd, + (internal_ptr + 1)->u.auxent.x_file.x_fname, + internal_ptr->u.syment.n_numaux * symesz)); + } + else + { + internal_ptr->u.syment._n._n_n._n_offset = + ((long) + copy_name (abfd, + (internal_ptr + 1)->u.auxent.x_file.x_fname, + (size_t) bfd_coff_filnmlen (abfd))); + } + } + } + else + { + if (internal_ptr->u.syment._n._n_n._n_zeroes != 0) + { + /* This is a "short" name. Make it long. */ + size_t i; + char *newstring; + + /* find the length of this string without walking into memory + that isn't ours. */ + for (i = 0; i < 8; ++i) + if (internal_ptr->u.syment._n._n_name[i] == '\0') + break; + + newstring = (PTR) bfd_zalloc (abfd, (bfd_size_type) (i + 1)); + if (newstring == NULL) + return (NULL); + strncpy (newstring, internal_ptr->u.syment._n._n_name, i); + internal_ptr->u.syment._n._n_n._n_offset = (long int) newstring; + internal_ptr->u.syment._n._n_n._n_zeroes = 0; + } + else if (internal_ptr->u.syment._n._n_n._n_offset == 0) + internal_ptr->u.syment._n._n_n._n_offset = (long int) ""; + else if (!bfd_coff_symname_in_debug (abfd, &internal_ptr->u.syment)) + { + /* Long name already. Point symbol at the string in the + table. */ + if (string_table == NULL) + { + string_table = _bfd_coff_read_string_table (abfd); + if (string_table == NULL) + return NULL; + } + internal_ptr->u.syment._n._n_n._n_offset = + ((long int) + (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 = (long int) + (debug_section + internal_ptr->u.syment._n._n_n._n_offset); + } + } + internal_ptr += internal_ptr->u.syment.n_numaux; + } + + obj_raw_syments (abfd) = internal; + BFD_ASSERT (obj_raw_syment_count (abfd) + == (unsigned int) (internal_ptr - internal)); + + return (internal); +} /* coff_get_normalized_symtab() */ + +long +coff_get_reloc_upper_bound (abfd, asect) + bfd *abfd; + sec_ptr asect; +{ + if (bfd_get_format (abfd) != bfd_object) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + return (asect->reloc_count + 1) * sizeof (arelent *); +} + +asymbol * +coff_make_empty_symbol (abfd) + bfd *abfd; +{ + bfd_size_type amt = sizeof (coff_symbol_type); + coff_symbol_type *new = (coff_symbol_type *) bfd_zalloc (abfd, amt); + if (new == NULL) + return (NULL); + new->symbol.section = 0; + new->native = 0; + new->lineno = (alent *) NULL; + new->done_lineno = FALSE; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +/* Make a debugging symbol. */ + +asymbol * +coff_bfd_make_debug_symbol (abfd, ptr, sz) + bfd *abfd; + PTR ptr ATTRIBUTE_UNUSED; + unsigned long sz ATTRIBUTE_UNUSED; +{ + bfd_size_type amt = sizeof (coff_symbol_type); + coff_symbol_type *new = (coff_symbol_type *) bfd_alloc (abfd, amt); + if (new == NULL) + return (NULL); + /* @@ The 10 is a guess at a plausible maximum number of aux entries + (but shouldn't be a constant). */ + amt = sizeof (combined_entry_type) * 10; + new->native = (combined_entry_type *) bfd_zalloc (abfd, amt); + if (!new->native) + return (NULL); + new->symbol.section = bfd_abs_section_ptr; + new->symbol.flags = BSF_DEBUGGING; + new->lineno = (alent *) NULL; + new->done_lineno = FALSE; + new->symbol.the_bfd = abfd; + return &new->symbol; +} + +void +coff_get_symbol_info (abfd, symbol, ret) + bfd *abfd; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); + if (coffsymbol (symbol)->native != NULL + && coffsymbol (symbol)->native->fix_value) + { + ret->value = coffsymbol (symbol)->native->u.syment.n_value - + (unsigned long) obj_raw_syments (abfd); + } +} + +/* Return the COFF syment for a symbol. */ + +bfd_boolean +bfd_coff_get_syment (abfd, symbol, psyment) + 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 - + (unsigned long) 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 (abfd, symbol, indx, pauxent) + 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 +coff_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + + case bfd_print_symbol_more: + fprintf (file, "coff %s %s", + coffsymbol (symbol)->native ? "n" : "g", + coffsymbol (symbol)->lineno ? "l" : " "); + break; + + case bfd_print_symbol_all: + if (coffsymbol (symbol)->native) + { + bfd_vma val; + unsigned int aux; + combined_entry_type *combined = coffsymbol (symbol)->native; + combined_entry_type *root = obj_raw_syments (abfd); + struct lineno_cache_entry *l = coffsymbol (symbol)->lineno; + + fprintf (file, "[%3ld]", (long) (combined - root)); + + if (! combined->fix_value) + val = (bfd_vma) combined->u.syment.n_value; + else + val = combined->u.syment.n_value - (unsigned long) root; + +#ifndef XCOFF64 + fprintf (file, + "(sec %2d)(fl 0x%02x)(ty %3x)(scl %3d) (nx %d) 0x%08lx %s", + combined->u.syment.n_scnum, + combined->u.syment.n_flags, + combined->u.syment.n_type, + combined->u.syment.n_sclass, + combined->u.syment.n_numaux, + (unsigned long) val, + symbol->name); +#else + /* Print out the wide, 64 bit, symbol value */ + fprintf (file, + "(sec %2d)(fl 0x%02x)(ty %3x)(scl %3d) (nx %d) 0x%016llx %s", + combined->u.syment.n_scnum, + combined->u.syment.n_flags, + combined->u.syment.n_type, + combined->u.syment.n_sclass, + combined->u.syment.n_numaux, + val, + symbol->name); +#endif + + for (aux = 0; aux < combined->u.syment.n_numaux; aux++) + { + combined_entry_type *auxp = combined + aux + 1; + long tagndx; + + if (auxp->fix_tag) + tagndx = auxp->u.auxent.x_sym.x_tagndx.p - root; + else + tagndx = auxp->u.auxent.x_sym.x_tagndx.l; + + fprintf (file, "\n"); + + if (bfd_coff_print_aux (abfd, file, root, combined, auxp, aux)) + continue; + + switch (combined->u.syment.n_sclass) + { + case C_FILE: + fprintf (file, "File "); + break; + + case C_STAT: + if (combined->u.syment.n_type == T_NULL) + /* probably a section symbol? */ + { + fprintf (file, "AUX scnlen 0x%lx nreloc %d nlnno %d", + (long) auxp->u.auxent.x_scn.x_scnlen, + auxp->u.auxent.x_scn.x_nreloc, + auxp->u.auxent.x_scn.x_nlinno); + if (auxp->u.auxent.x_scn.x_checksum != 0 + || auxp->u.auxent.x_scn.x_associated != 0 + || auxp->u.auxent.x_scn.x_comdat != 0) + fprintf (file, " checksum 0x%lx assoc %d comdat %d", + auxp->u.auxent.x_scn.x_checksum, + auxp->u.auxent.x_scn.x_associated, + auxp->u.auxent.x_scn.x_comdat); + break; + } + /* else fall through */ + case C_EXT: + if (ISFCN (combined->u.syment.n_type)) + { + long next, llnos; + + if (auxp->fix_end) + next = (auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p + - root); + else + next = auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.l; + llnos = auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_lnnoptr; + fprintf (file, + "AUX tagndx %ld ttlsiz 0x%lx lnnos %ld next %ld", + tagndx, auxp->u.auxent.x_sym.x_misc.x_fsize, + llnos, next); + break; + } + /* else fall through */ + default: + fprintf (file, "AUX lnno %d size 0x%x tagndx %ld", + auxp->u.auxent.x_sym.x_misc.x_lnsz.x_lnno, + auxp->u.auxent.x_sym.x_misc.x_lnsz.x_size, + tagndx); + if (auxp->fix_end) + fprintf (file, " endndx %ld", + ((long) + (auxp->u.auxent.x_sym.x_fcnary.x_fcn.x_endndx.p + - root))); + break; + } + } + + if (l) + { + fprintf (file, "\n%s :", l->u.sym->name); + l++; + while (l->line_number) + { + fprintf (file, "\n%4d : 0x%lx", + l->line_number, + ((unsigned long) + (l->u.offset + symbol->section->vma))); + l++; + } + } + } + else + { + bfd_print_symbol_vandf (abfd, (PTR) file, symbol); + fprintf (file, " %-5s %s %s %s", + symbol->section->name, + coffsymbol (symbol)->native ? "n" : "g", + coffsymbol (symbol)->lineno ? "l" : " ", + symbol->name); + } + } +} + +/* Return whether a symbol name implies a local symbol. In COFF, + local symbols generally start with ``.L''. Most targets use this + function for the is_local_label_name entry point, but some may + override it. */ + +bfd_boolean +_bfd_coff_is_local_label_name (abfd, name) + bfd *abfd ATTRIBUTE_UNUSED; + const char *name; +{ + return name[0] == '.' && name[1] == 'L'; +} + +/* Provided a BFD, a section and an offset (in bytes, not octets) into the + section, calculate and return the name of the source file and the line + nearest to the wanted location. */ + +bfd_boolean +coff_find_nearest_line (abfd, section, symbols, offset, filename_ptr, + functionname_ptr, line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *line_ptr; +{ + bfd_boolean found; + unsigned int i; + unsigned int line_base; + coff_data_type *cof = coff_data (abfd); + /* Run through the raw syments if available */ + combined_entry_type *p; + combined_entry_type *pend; + alent *l; + struct coff_section_tdata *sec_data; + bfd_size_type amt; + + /* Before looking through the symbol table, try to use a .stab + section to find the information. */ + if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, + &found, filename_ptr, + functionname_ptr, line_ptr, + &coff_data(abfd)->line_info)) + return FALSE; + + if (found) + return TRUE; + + /* Also try examining DWARF2 debugging information. */ + if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, + line_ptr, 0, + &coff_data(abfd)->dwarf2_find_line_info)) + return TRUE; + + *filename_ptr = 0; + *functionname_ptr = 0; + *line_ptr = 0; + + /* Don't try and find line numbers in a non coff file */ + if (!bfd_family_coff (abfd)) + return FALSE; + + if (cof == NULL) + return FALSE; + + /* Find the first C_FILE symbol. */ + p = cof->raw_syments; + if (!p) + return FALSE; + + pend = p + cof->raw_syment_count; + while (p < pend) + { + if (p->u.syment.n_sclass == C_FILE) + break; + p += 1 + p->u.syment.n_numaux; + } + + if (p < pend) + { + bfd_vma sec_vma; + bfd_vma maxdiff; + + /* Look through the C_FILE symbols to find the best one. */ + sec_vma = bfd_get_section_vma (abfd, section); + *filename_ptr = (char *) p->u.syment._n._n_n._n_offset; + maxdiff = (bfd_vma) 0 - (bfd_vma) 1; + while (1) + { + combined_entry_type *p2; + + for (p2 = p + 1 + p->u.syment.n_numaux; + p2 < pend; + p2 += 1 + p2->u.syment.n_numaux) + { + if (p2->u.syment.n_scnum > 0 + && (section + == coff_section_from_bfd_index (abfd, + p2->u.syment.n_scnum))) + break; + if (p2->u.syment.n_sclass == C_FILE) + { + p2 = pend; + break; + } + } + + /* We use <= MAXDIFF here so that if we get a zero length + file, we actually use the next file entry. */ + if (p2 < pend + && offset + sec_vma >= (bfd_vma) p2->u.syment.n_value + && offset + sec_vma - (bfd_vma) p2->u.syment.n_value <= maxdiff) + { + *filename_ptr = (char *) p->u.syment._n._n_n._n_offset; + maxdiff = offset + sec_vma - p2->u.syment.n_value; + } + + /* Avoid endless loops on erroneous files by ensuring that + we always move forward in the file. */ + if (p >= cof->raw_syments + p->u.syment.n_value) + break; + + p = cof->raw_syments + p->u.syment.n_value; + if (p > pend || p->u.syment.n_sclass != C_FILE) + break; + } + } + + /* Now wander though the raw linenumbers of the section */ + /* If we have been called on this section before, and the offset we + want is further down then we can prime the lookup loop. */ + sec_data = coff_section_data (abfd, section); + if (sec_data != NULL + && sec_data->i > 0 + && offset >= sec_data->offset) + { + i = sec_data->i; + *functionname_ptr = sec_data->function; + line_base = sec_data->line_base; + } + else + { + i = 0; + line_base = 0; + } + + if (section->lineno != NULL) + { + bfd_vma last_value = 0; + + l = §ion->lineno[i]; + + for (; i < section->lineno_count; i++) + { + if (l->line_number == 0) + { + /* Get the symbol this line number points at */ + coff_symbol_type *coff = (coff_symbol_type *) (l->u.sym); + if (coff->symbol.value > offset) + break; + *functionname_ptr = coff->symbol.name; + last_value = coff->symbol.value; + if (coff->native) + { + combined_entry_type *s = coff->native; + s = s + 1 + s->u.syment.n_numaux; + + /* In XCOFF a debugging symbol can follow the + function symbol. */ + if (s->u.syment.n_scnum == N_DEBUG) + s = s + 1 + s->u.syment.n_numaux; + + /* S should now point to the .bf of the function. */ + if (s->u.syment.n_numaux) + { + /* 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; + } + } + } + else + { + if (l->u.offset > offset) + break; + *line_ptr = l->line_number + line_base - 1; + } + l++; + } + + /* If we fell off the end of the loop, then assume that this + symbol has no line number info. Otherwise, symbols with no + line number info get reported with the line number of the + last line of the last symbol which does have line number + info. We use 0x100 as a slop to account for cases where the + last line has executable code. */ + if (i >= section->lineno_count + && last_value != 0 + && offset - last_value > 0x100) + { + *functionname_ptr = NULL; + *line_ptr = 0; + } + } + + /* Cache the results for the next call. */ + if (sec_data == NULL && section->owner == abfd) + { + amt = sizeof (struct coff_section_tdata); + section->used_by_bfd = (PTR) bfd_zalloc (abfd, amt); + sec_data = (struct coff_section_tdata *) section->used_by_bfd; + } + if (sec_data != NULL) + { + sec_data->offset = offset; + sec_data->i = i; + sec_data->function = *functionname_ptr; + sec_data->line_base = line_base; + } + + return TRUE; +} + +int +coff_sizeof_headers (abfd, reloc) + bfd *abfd; + bfd_boolean reloc; +{ + size_t size; + + if (! reloc) + { + size = bfd_coff_filhsz (abfd) + bfd_coff_aoutsz (abfd); + } + else + { + size = bfd_coff_filhsz (abfd); + } + + size += abfd->section_count * bfd_coff_scnhsz (abfd); + return size; +} + +/* Change the class of a coff symbol held by BFD. */ +bfd_boolean +bfd_coff_set_symbol_class (abfd, symbol, class) + bfd * abfd; + asymbol * symbol; + unsigned int class; +{ + coff_symbol_type * csym; + + csym = coff_symbol_from (abfd, symbol); + if (csym == NULL) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + else if (csym->native == NULL) + { + /* This is an alien symbol which no native coff backend data. + We cheat here by creating a fake native entry for it and + then filling in the class. This code is based on that in + coff_write_alien_symbol(). */ + + combined_entry_type * native; + bfd_size_type amt = sizeof (* native); + + native = (combined_entry_type *) bfd_zalloc (abfd, amt); + if (native == NULL) + return FALSE; + + native->u.syment.n_type = T_NULL; + native->u.syment.n_sclass = class; + + if (bfd_is_und_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else if (bfd_is_com_section (symbol->section)) + { + native->u.syment.n_scnum = N_UNDEF; + native->u.syment.n_value = symbol->value; + } + else + { + native->u.syment.n_scnum = + symbol->section->output_section->target_index; + native->u.syment.n_value = (symbol->value + + symbol->section->output_offset); + if (! obj_pe (abfd)) + native->u.syment.n_value += symbol->section->output_section->vma; + + /* Copy the any flags from the file header into the symbol. + FIXME: Why? */ + native->u.syment.n_flags = bfd_asymbol_bfd (& csym->symbol)->flags; + } + + csym->native = native; + } + else + { + csym->native->u.syment.n_sclass = class; + } + + return TRUE; +} diff --git a/contrib/binutils-2.14/bfd/config.bfd b/contrib/binutils-2.14/bfd/config.bfd new file mode 100644 index 0000000000..fa2e9ae479 --- /dev/null +++ b/contrib/binutils-2.14/bfd/config.bfd @@ -0,0 +1,1275 @@ +# config.bfd +# Convert a canonical host type into a BFD host type. +# Set shell variable targ to canonical target name, and run +# using ``. config.bfd''. +# Sets the following shell variables: +# targ_defvec Default vector for this target +# targ_selvecs Vectors to build for this target +# targ64_selvecs Vectors to build if --enable-64-bit-bfd is given +# or if host is 64 bit. +# targ_archs Architectures for this target +# targ_cflags $(CFLAGS) for this target (FIXME: pretty bogus) +# targ_underscore Whether underscores are used: yes or no + +# Part of this file is processed by targmatch.sed to generate the +# targmatch.h file. The #ifdef and #endif lines that appear below are +# copied directly into targmatch.h. + +# The binutils c++filt program wants to know whether underscores are +# stripped or not. That is why we set targ_underscore. c++filt uses +# this information to choose a default. This information is +# duplicated in the symbol_leading_char field of the BFD target +# vector, but c++filt does not deal with object files and is not +# linked against libbfd.a. It is not terribly important that c++filt +# get this right; it is just convenient. + +targ_defvec= +targ_selvecs= +targ64_selvecs= +targ_cflags= +targ_underscore=no + +targ_cpu=`echo $targ | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +case "${targ_cpu}" in +alpha*) targ_archs=bfd_alpha_arch ;; +arm*) targ_archs=bfd_arm_arch ;; +c30*) targ_archs=bfd_tic30_arch ;; +c4x*) targ_archs=bfd_tic4x_arch ;; +c54x*) targ_archs=bfd_tic54x_arch ;; +dlx*) targ_archs=bfd_dlx_arch ;; +hppa*) targ_archs=bfd_hppa_arch ;; +i[3456]86) targ_archs=bfd_i386_arch ;; +i370) targ_archs=bfd_i370_arch ;; +m6811*|m68hc11*) targ_archs="bfd_m68hc11_arch bfd_m68hc12_arch" ;; +m6812*|m68hc12*) targ_archs="bfd_m68hc12_arch bfd_m68hc11_arch" ;; +m68*) targ_archs=bfd_m68k_arch ;; +m88*) targ_archs=bfd_m88k_arch ;; +mips*) targ_archs=bfd_mips_arch ;; +or32*) targ_archs=bfd_or32_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" ;; +rs6000) targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; +s390*) targ_archs=bfd_s390_arch ;; +sh*) targ_archs=bfd_sh_arch ;; +sparc*) targ_archs=bfd_sparc_arch ;; +strongarm*) targ_archs=bfd_arm_arch ;; +thumb*) targ_archs=bfd_arm_arch ;; +v850*) targ_archs=bfd_v850_arch ;; +x86_64) targ_archs=bfd_i386_arch ;; +xscale*) targ_archs=bfd_arm_arch ;; +xtensa*) targ_archs=bfd_xtensa_arch ;; +z8k*) targ_archs=bfd_z8k_arch ;; +*) targ_archs=bfd_${targ_cpu}_arch ;; +esac + + +# WHEN ADDING ENTRIES TO THIS MATRIX: +# Make sure that the left side always has two dashes. Otherwise you +# can get spurious matches. Even for unambiguous cases, do this as a +# convention, else the table becomes a real mess to understand and maintain. +# +# Keep obsolete entries above the START comment, to keep them out of +# targmatch.h. + +case "${targ}" in + mips*-dec-bsd*) + echo "This target is obsolete and has been removed." + exit 1 + ;; + + mips*-*-pe*) + echo "This target is obsolete and has been removed." + exit 1 + ;; + +# START OF targmatch.h +#ifdef BFD64 + alpha*-*-freebsd*) + targ_defvec=bfd_elf64_alpha_freebsd_vec + targ_selvecs=ecoffalpha_little_vec + # FreeBSD <= 4.0 supports only the old nonstandard way of ABI labelling. + case "${targ}" in + alpha*-*-freebsd3* | alpha*-*-freebsd4 | alpha*-*-freebsd4.0*) + targ_cflags=-DOLD_FREEBSD_ABI_LABEL ;; + esac + ;; + alpha*-*-netbsd* | alpha*-*-openbsd*) + targ_defvec=bfd_elf64_alpha_vec + targ_selvecs=ecoffalpha_little_vec + ;; + alpha*-*-netware*) + targ_defvec=ecoffalpha_little_vec + targ_selvecs=nlm32_alpha_vec + ;; + alpha*-*-linuxecoff*) + targ_defvec=ecoffalpha_little_vec + targ_selvecs=bfd_elf64_alpha_vec + ;; + alpha*-*-linux-gnu* | alpha*-*-elf*) + targ_defvec=bfd_elf64_alpha_vec + targ_selvecs=ecoffalpha_little_vec + ;; + alpha*-*-*vms*) + targ_defvec=vms_alpha_vec + ;; + alpha*-*-*) + targ_defvec=ecoffalpha_little_vec + ;; + ia64*-*-aix*) + targ_defvec=bfd_elf64_ia64_aix_little_vec + targ_selvecs="bfd_elf64_ia64_aix_big_vec bfd_efi_app_ia64_vec" + ;; + ia64*-*-freebsd* | ia64*-*-netbsd* | ia64*-*-linux-gnu* | ia64*-*-elf*) + targ_defvec=bfd_elf64_ia64_little_vec + targ_selvecs="bfd_elf64_ia64_big_vec bfd_efi_app_ia64_vec" + ;; + ia64*-*-hpux*) + targ_defvec=bfd_elf32_ia64_hpux_big_vec + targ_selvecs="bfd_elf64_ia64_hpux_big_vec" + ;; + sparc64-*-freebsd* | sparc64-*-netbsd* | sparc64-*-openbsd*) + targ_defvec=bfd_elf64_sparc_vec + targ_selvecs="bfd_elf32_sparc_vec sunos_big_vec" + ;; +#endif /* BFD64 */ + + arc-*-elf*) + targ_defvec=bfd_elf32_littlearc_vec + targ_selvecs=bfd_elf32_bigarc_vec + ;; + + armeb-*-netbsdelf*) + targ_defvec=bfd_elf32_bigarm_vec + targ_selvecs="bfd_elf32_littlearm_vec armnetbsd_vec" + ;; + arm-*-netbsdelf*) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs="bfd_elf32_bigarm_vec armnetbsd_vec" + ;; + arm-*-netbsd* | arm-*-openbsd*) + targ_defvec=armnetbsd_vec + targ_selvecs="bfd_elf32_littlearm_vec bfd_elf32_bigarm_vec" + targ_underscore=yes + ;; + arm-*-nto* | nto*arm*) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + arm-*-riscix*) + targ_defvec=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_underscore=no + targ_cflags=-DARM_COFF_BUGFIX + ;; + arm-wince-pe | arm-*-wince) + targ_defvec=armpe_little_vec + targ_selvecs="armpe_little_vec armpe_big_vec armpei_little_vec armpei_big_vec" + targ_underscore=no + targ_cflags=-DARM_WINCE + ;; + arm-*-pe*) + targ_defvec=armpe_little_vec + targ_selvecs="armpe_little_vec armpe_big_vec armpei_little_vec armpei_big_vec" + targ_underscore=yes + ;; + arm-*-aout | armel-*-aout) + targ_defvec=aout_arm_little_vec + targ_selvecs=aout_arm_big_vec + ;; + armeb-*-aout) + targ_defvec=aout_arm_big_vec + targ_selvecs=aout_arm_little_vec + ;; + arm-*-vxworks*) + targ_defvec=armcoff_little_vec + targ_selvecs=armcoff_big_vec + targ_underscore=yes + targ_cflags=-DARM_COFF_BUGFIX + ;; + arm-*-coff) + targ_defvec=armcoff_little_vec + targ_selvecs=armcoff_big_vec + targ_underscore=yes + ;; + arm-*-rtems*) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + armeb-*-elf | arm*b-*-linux-gnu*) + targ_defvec=bfd_elf32_bigarm_vec + targ_selvecs=bfd_elf32_littlearm_vec + ;; + arm-*-kaos* | strongarm-*-kaos*) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + arm-*-elf | arm-*-freebsd* | arm*-*-linux-gnu* | arm*-*-conix* | arm*-*-uclinux*) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + arm9e-*-elf) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + arm-*-oabi) + targ_defvec=bfd_elf32_littlearm_oabi_vec + targ_selvecs=bfd_elf32_bigarm_oabi_vec + ;; + + thumb-*-coff) + targ_defvec=armcoff_little_vec + targ_selvecs=armcoff_big_vec + targ_underscore=yes + ;; + thumb-*-oabi) + targ_defvec=bfd_elf32_littlearm_oabi_vec + targ_selvecs=bfd_elf32_bigarm_oabi_vec + ;; + thumb-*-elf) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + thumb-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_underscore=no + ;; + thumb-*-pe*) + targ_defvec=armpe_little_vec + targ_selvecs="armpe_little_vec armpe_big_vec armpei_little_vec armpei_big_vec" + targ_underscore=yes + ;; + strongarm-*-elf) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + strongarm-*-coff) + targ_defvec=armcoff_little_vec + targ_selvecs=armcoff_big_vec + targ_underscore=yes + ;; + xscale-*-elf) + targ_defvec=bfd_elf32_littlearm_vec + targ_selvecs=bfd_elf32_bigarm_vec + ;; + xscale-*-coff) + targ_defvec=armcoff_little_vec + targ_selvecs=armcoff_big_vec + targ_underscore=yes + ;; + + a29k-*-ebmon* | a29k-*-udi* | a29k-*-coff* | a29k-*-sym1* | \ + a29k-*-vxworks* | a29k-*-sysv* | a29k-*rtems*) + targ_defvec=a29kcoff_big_vec + targ_selvecs=sunos_big_vec + targ_underscore=yes + ;; + a29k-*-aout* | a29k-*-bsd* | a29k-*-vsta*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + + avr-*-*) + targ_defvec=bfd_elf32_avr_vec + ;; + + c30-*-*aout* | tic30-*-*aout*) + targ_defvec=tic30_aout_vec + ;; + c30-*-*coff* | tic30-*-*coff*) + targ_defvec=tic30_coff_vec + ;; + + c4x-*-*coff* | tic4x-*-*coff*) + targ_defvec=tic4x_coff1_vec + targ_selvecs="tic4x_coff1_beh_vec tic4x_coff2_vec tic4x_coff2_beh_vec tic4x_coff0_vec tic4x_coff0_beh_vec" + targ_underscore=yes + ;; + + c54x*-*-*coff* | tic54x-*-*coff*) + targ_defvec=tic54x_coff1_vec + targ_selvecs="tic54x_coff1_beh_vec tic54x_coff2_vec tic54x_coff2_beh_vec tic54x_coff0_vec tic54x_coff0_beh_vec" + targ_underscore=yes + ;; + + cris-*-*) + 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. + ;; + + d10v-*-*) + targ_defvec=bfd_elf32_d10v_vec + ;; + + dlx-*-elf*) + targ_defvec=bfd_elf32_dlx_big_vec + targ_selvecs="bfd_elf32_dlx_big_vec" + ;; + + d30v-*-*) + targ_defvec=bfd_elf32_d30v_vec + ;; + + fr30-*-elf) + targ_defvec=bfd_elf32_fr30_vec + ;; + + frv-*-elf) + targ_defvec=bfd_elf32_frv_vec + ;; + + + h8300*-*-elf) + targ_defvec=bfd_elf32_h8300_vec + targ_underscore=yes + ;; + + h8300*-*-*) + targ_defvec=h8300coff_vec + targ_underscore=yes + ;; + + h8500-*-*) + targ_defvec=h8500coff_vec + targ_underscore=yes + ;; + +#ifdef BFD64 + hppa*64*-*-linux-gnu*) + targ_defvec=bfd_elf64_hppa_linux_vec + targ_selvecs=bfd_elf64_hppa_vec + ;; + hppa*64*-*-hpux11*) + targ_defvec=bfd_elf64_hppa_vec + targ_selvecs=bfd_elf64_hppa_linux_vec + targ_cflags=-DHPUX_LARGE_AR_IDS + ;; +#endif + + hppa*-*-linux-gnu*) + targ_defvec=bfd_elf32_hppa_linux_vec + targ_selvecs=bfd_elf32_hppa_vec + ;; + hppa*-*-*elf* | hppa*-*-lites* | hppa*-*-netbsd* | hppa*-*-sysv4* | hppa*-*-rtems* | hppa*-*-openbsd*) + targ_defvec=bfd_elf32_hppa_vec + targ_selvecs=bfd_elf32_hppa_linux_vec + ;; + +#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) || defined (HOST_HPPAOSF) || defined (HOST_HPPAMPEIX) + hppa*-*-bsd*) + targ_defvec=som_vec + targ_selvecs=bfd_elf32_hppa_vec + ;; + hppa*-*-hpux* | hppa*-*-hiux* | hppa*-*-mpeix*) + targ_defvec=som_vec + ;; + hppa*-*-osf*) + targ_defvec=som_vec + targ_selvecs=bfd_elf32_hppa_vec + ;; +#endif /* defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) || defined (HOST_HPPAOSF) */ + + i370-*-*) + targ_defvec=bfd_elf32_i370_vec + targ_selvecs="bfd_elf32_i370_vec" + ;; + i[3456]86-*-sco3.2v5*coff) + targ_defvec=i386coff_vec + targ_selvecs=bfd_elf32_i386_vec + ;; + i[3456]86-*-sysv4* | i[3456]86-*-unixware* | i[3456]86-*-solaris2* | \ + i[3456]86-*-elf | i[3456]86-*-sco3.2v5* | \ + i[3456]86-*-dgux* | i[3456]86-*-sysv5*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386coff_vec + ;; + i[3456]86-*-kaos*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=bfd_elf32_i386_vec + ;; + i[3456]86-*-nto*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386coff_vec + ;; + i[3456]86-*-aros*) + targ_defvec=bfd_elf32_i386_vec + ;; + i[3456]86-*-chorus*) + targ_defvec=bfd_elf32_i386_vec + ;; + *-*-msdosdjgpp* | *-*-go32* | *-go32-rtems* ) + targ_defvec=go32coff_vec + targ_selvecs="go32stubbedcoff_vec i386aout_vec" + ;; + i[3456]86-*-sysv* | i[3456]86-*-isc* | i[3456]86-*-sco* | i[3456]86-*-coff | \ + i[3456]86-*-aix*) + targ_defvec=i386coff_vec + ;; + i[3456]86*-*-rtemscoff*) + targ_defvec=i386coff_vec + targ_selvecs="bfd_elf32_i386_vec i386aout_vec" + ;; + i[3456]86-*-rtemself* | i[3456]86-*-rtems*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386coff_vec i386aout_vec" + ;; + i[3456]86-*-darwin* | i[3456]86-*-macos10* | i[3456]86-*-rhapsody*) + targ_defvec=mach_o_le_vec + targ_selvecs="mach_o_le_vec mach_o_be_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" + targ_archs="bfd_i386_arch bfd_powerpc_arch bfd_rs6000_arch" + ;; + i[3456]86-sequent-bsd*) + targ_defvec=i386dynix_vec + targ_underscore=yes + ;; + i[3456]86-*-bsd*) + targ_defvec=i386bsd_vec + targ_underscore=yes + ;; + i[3456]86-*-freebsdaout* | i[3456]86-*-freebsd[12].* | \ + i[3456]86-*-freebsd[12]) + targ_defvec=i386freebsd_vec + targ_selvecs=i386bsd_vec + targ_underscore=yes + ;; + i[3456]86-*-freebsd*) + targ_defvec=bfd_elf32_i386_freebsd_vec + targ_selvecs=i386coff_vec + # FreeBSD <= 4.0 supports only the old nonstandard way of ABI labelling. + case "${targ}" in + i[3456]86-*-freebsd3* | i[3456]86-*-freebsd4 | i[3456]86-*-freebsd4.0*) + targ_cflags=-DOLD_FREEBSD_ABI_LABEL ;; + esac + ;; + i[3456]86-*-netbsdelf*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs=i386netbsd_vec + ;; + i[3456]86-*-netbsdpe*) + targ_defvec=i386pe_vec + targ_selvecs="i386pe_vec i386pei_vec bfd_elf32_i386_vec" + ;; + i[3456]86-*-netbsdaout* | i[3456]86-*-netbsd* | i[3456]86-*-openbsd*) + targ_defvec=i386netbsd_vec + targ_selvecs="bfd_elf32_i386_vec i386bsd_vec" + targ_underscore=yes + ;; + i[3456]86-*-netware*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="nlm32_i386_vec i386coff_vec i386aout_vec" + ;; + i[3456]86-*-linux*aout*) + targ_defvec=i386linux_vec + targ_selvecs=bfd_elf32_i386_vec + targ_underscore=yes + ;; + i[3456]86-*-linux-gnu*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386linux_vec bfd_efi_app_ia32_vec" + targ64_selvecs=bfd_elf64_x86_64_vec + ;; +#ifdef BFD64 + x86_64-*-freebsd*) + targ_defvec=bfd_elf64_x86_64_vec + targ_selvecs="bfd_elf32_i386_vec i386coff_vec bfd_efi_app_ia32_vec" + ;; + x86_64-*-netbsd*) + targ_defvec=bfd_elf64_x86_64_vec + targ_selvecs="bfd_elf32_i386_vec i386netbsd_vec i386coff_vec bfd_efi_app_ia32_vec" + ;; + x86_64-*-linux-gnu*) + targ_defvec=bfd_elf64_x86_64_vec + targ_selvecs="bfd_elf32_i386_vec i386linux_vec bfd_efi_app_ia32_vec" + ;; +#endif + i[3456]86-*-lynxos*) + targ_defvec=i386lynx_coff_vec + targ_selvecs=i386lynx_aout_vec + ;; + i[3456]86-*-gnu*) + targ_defvec=bfd_elf32_i386_vec + ;; + i[3456]86-*-mach* | i[3456]86-*-osf1mk*) + targ_defvec=i386mach3_vec + targ_cflags=-DSTAT_FOR_EXEC + targ_underscore=yes + ;; + i[3456]86-*-os9k) + targ_defvec=i386os9k_vec + ;; + i[3456]86-*-msdos*) + targ_defvec=i386aout_vec + targ_selvecs=i386msdos_vec + ;; + i[3456]86-*-moss*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386msdos_vec i386aout_vec" + ;; + i[3456]86-*-beospe*) + targ_defvec=i386pe_vec + targ_selvecs="i386pe_vec i386pei_vec" + ;; + i[3456]86-*-beoself* | i[3456]86-*-beos*) + targ_defvec=bfd_elf32_i386_vec + targ_selvecs="i386pe_vec i386pei_vec" + ;; + i[3456]86-*-interix*) + targ_defvec=i386pei_vec + targ_selvecs="i386pe_vec" + # FIXME: This should eventually be checked at runtime. + targ_cflags=-DSTRICT_PE_FORMAT + ;; + i[3456]86-*-mingw32* | i[3456]86-*-cygwin* | i[3456]86-*-winnt | i[3456]86-*-pe) + targ_defvec=i386pe_vec + targ_selvecs="i386pe_vec i386pei_vec bfd_elf32_i386_vec" + ;; + i[3456]86-none-*) + targ_defvec=i386coff_vec + ;; + i[3456]86-*-aout* | i[3456]86*-*-vsta*) + targ_defvec=i386aout_vec + ;; + i[3456]86-*-vxworks*) + targ_defvec=i386aout_vec + targ_underscore=yes + ;; + i[3456]86-*-chaos) + targ_defvec=bfd_elf32_i386_vec + targ_selfvecs=i386chaos_vec + ;; + + i860-*-mach3* | i860-*-osf1* | i860-*-coff*) + targ_defvec=i860coff_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" + ;; + i860-*-sysv4* | i860-*-elf*) + targ_defvec=bfd_elf32_i860_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_underscore=yes + ;; + i960-*-vxworks5.* | i960-*-coff* | i960-*-sysv* | i960-*-rtems*) + targ_defvec=icoff_little_vec + targ_selvecs="icoff_big_vec b_out_vec_little_host b_out_vec_big_host 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_underscore=yes + ;; + i960-*-elf*) + targ_defvec=bfd_elf32_i960_vec + targ_selvecs="icoff_little_vec icoff_big_vec" + ;; + + ip2k-*-elf) + targ_defvec=bfd_elf32_ip2k_vec + ;; + + iq2000-*-elf) + targ_defvec=bfd_elf32_iq2000_vec + ;; + + m32r-*-*) + targ_defvec=bfd_elf32_m32r_vec + ;; + + m68hc11-*-* | m6811-*-*) + targ_defvec=bfd_elf32_m68hc11_vec + targ_selvecs="bfd_elf32_m68hc11_vec bfd_elf32_m68hc12_vec" + ;; + m68hc12-*-* | m6812-*-*) + targ_defvec=bfd_elf32_m68hc12_vec + targ_selvecs="bfd_elf32_m68hc11_vec bfd_elf32_m68hc12_vec" + ;; + + m68*-apollo-*) + targ_defvec=apollocoff_vec + ;; + m68*-bull-sysv*) + targ_defvec=m68kcoffun_vec + targ_underscore=yes + ;; + m68*-motorola-sysv*) + targ_defvec=m68ksysvcoff_vec + ;; + m68*-hp-bsd*) + targ_defvec=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 + # configuration, so that cisco-core.c gets routinely tested at + # least for compilation. + targ_selvecs="cisco_core_big_vec ieee_vec" + targ_underscore=yes + ;; + m68*-*-rtemscoff*) + targ_defvec=m68kcoff_vec + targ_selvecs="m68kcoff_vec versados_vec ieee_vec aout0_big_vec" + ;; + m68*-*-elf* | m68*-*-sysv4*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs="m68kcoff_vec ieee_vec" + ;; + m68*-*-rtems*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs="m68kcoff_vec versados_vec ieee_vec aout0_big_vec" + ;; + m68*-*-coff* | m68*-*-sysv*) + targ_defvec=m68kcoff_vec + targ_selvecs="m68kcoff_vec versados_vec ieee_vec" + ;; + m68*-*-hpux*) + targ_defvec=hp300hpux_vec + targ_underscore=yes + ;; + m68*-*-linux*aout*) + targ_defvec=m68klinux_vec + targ_selvecs=bfd_elf32_m68k_vec + targ_underscore=yes + ;; + m68*-*-linux-gnu*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=m68klinux_vec + ;; + m68*-*-gnu*) + targ_defvec=bfd_elf32_m68k_vec + # targ_selvecs=m68kmach3_vec + # targ_cflags=-DSTAT_FOR_EXEC + ;; + m68*-*-lynxos*) + targ_defvec=m68klynx_coff_vec + targ_selvecs=m68klynx_aout_vec + ;; + m68*-hp*-netbsd*) + targ_defvec=m68k4knetbsd_vec + targ_selvecs="m68knetbsd_vec hp300bsd_vec sunos_big_vec" + targ_underscore=yes + ;; + m68*-*-netbsdelf*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs="m68knetbsd_vec m68k4knetbsd_vec hp300bsd_vec sunos_big_vec" + ;; + m68*-*-netbsdaout* | m68*-*-netbsd*) + targ_defvec=m68knetbsd_vec + targ_selvecs="m68k4knetbsd_vec bfd_elf32_m68k_vec hp300bsd_vec sunos_big_vec" + targ_underscore=yes + ;; + m68*-*-openbsd*) + targ_defvec=m68knetbsd_vec + targ_selvecs="m68k4knetbsd_vec hp300bsd_vec sunos_big_vec" + targ_underscore=yes + ;; + m68*-*-sunos* | m68*-*-os68k* | m68*-*-vxworks* | m68*-netx-* | \ + m68*-*-bsd* | m68*-*-vsta*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + m68*-ericsson-*) + targ_defvec=sunos_big_vec + targ_selvecs="m68kcoff_vec versados_vec tekhex_vec" + targ_underscore=yes + ;; + m68*-cbm-*) + targ_defvec=bfd_elf32_m68k_vec + targ_selvecs=m68kcoff_vec + ;; + m68*-apple-aux*) + targ_defvec=m68kaux_coff_vec + ;; + m68*-*-psos*) + targ_defvec=bfd_elf32_m68k_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 + ;; + m88*-*-mach3*) + targ_defvec=m88kmach3_vec + targ_cflags=-DSTAT_FOR_EXEC + ;; + m88*-*-*) + targ_defvec=m88kbcs_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" + ;; + 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" + ;; + + mips*-big-*) + targ_defvec=ecoff_big_vec + targ_selvecs=ecoff_little_vec + ;; + mips*el-*-netbsd*) + 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" + ;; + mips*-*-netbsd*) + 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" + ;; + mips*-dec-mach3*) + targ_defvec=aout_mips_little_vec + targ_cflags=-DSTAT_FOR_EXEC + ;; + mips*-dec-* | mips*el-*-ecoff*) + targ_defvec=ecoff_little_vec + targ_selvecs=ecoff_big_vec + ;; + mips*-*-ecoff*) + targ_defvec=ecoff_big_vec + targ_selvecs=ecoff_little_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" + ;; +#endif + mips*-*-irix5*) + targ_defvec=bfd_elf32_bigmips_vec + targ_selvecs="bfd_elf32_littlemips_vec ecoff_big_vec ecoff_little_vec" + ;; + mips*-sgi-* | mips*-*-bsd*) + targ_defvec=ecoff_big_vec + targ_selvecs=ecoff_little_vec + ;; + mips*-*-lnews*) + targ_defvec=ecoff_biglittle_vec + targ_selvecs="ecoff_little_vec ecoff_big_vec" + ;; + mips*-*-mach3*) + targ_defvec=aout_mips_little_vec + targ_cflags=-DSTAT_FOR_EXEC + ;; + mips*-*-sysv4*) + targ_defvec=bfd_elf32_tradbigmips_vec + targ_selvecs="bfd_elf32_tradlittlemips_vec ecoff_big_vec ecoff_little_vec" + ;; + mips*-*-sysv* | mips*-*-riscos*) + targ_defvec=ecoff_big_vec + targ_selvecs=ecoff_little_vec + ;; + mips*el-*-elf* | mips*el-*-rtems* | 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" + ;; + mips*-*-elf* | mips*-*-rtems* | mips*-*-vxworks*) + targ_defvec=bfd_elf32_bigmips_vec + targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + ;; + mips*-*-none) + targ_defvec=bfd_elf32_bigmips_vec + targ_selvecs="bfd_elf32_littlemips_vec bfd_elf64_bigmips_vec bfd_elf64_littlemips_vec" + ;; + 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" + ;; + 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" + ;; +#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" + ;; + 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" + ;; +#endif + 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 + ;; + 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 + ;; +#ifdef BFD64 + mmix-*-*) + targ_defvec=bfd_elf64_mmix_vec + targ_selvecs=bfd_mmo_vec + ;; +#endif + mn10200-*-*) + targ_defvec=bfd_elf32_mn10200_vec + ;; + + mn10300-*-*) + targ_defvec=bfd_elf32_mn10300_vec + ;; + + msp430-*-*) + targ_defvec=bfd_elf32_msp430_vec + ;; + + ns32k-pc532-mach* | ns32k-pc532-ux*) + targ_defvec=pc532machaout_vec + targ_underscore=yes + ;; + ns32k-*-netbsd* | ns32k-*-lites* | ns32k-*-openbsd*) + targ_defvec=pc532netbsd_vec + targ_underscore=yes + ;; + + openrisc-*-elf) + targ_defvec=bfd_elf32_openrisc_vec + ;; + + or32-*-coff | or32-*-rtems*) + targ_defvec=or32coff_big_vec + targ_underscore=yes + ;; + + or32-*-elf) + targ_defvec=bfd_elf32_or32_big_vec + ;; + + pdp11-*-*) + targ_defvec=pdp11_aout_vec + targ_underscore=yes + ;; + + pj-*-*) + targ_defvec=bfd_elf32_pj_vec + targ_selvecs="bfd_elf32_pj_vec bfd_elf32_pjl_vec" + ;; + + pjl-*-*) + targ_defvec=bfd_elf32_pjl_vec + targ_selvecs="bfd_elf32_pjl_vec bfd_elf32_pj_vec bfd_elf32_i386_vec" + ;; + + powerpc-*-aix5*) + targ_defvec=rs6000coff_vec + targ_selvecs="aix5coff64_vec" + want64=true + ;; +#ifdef BFD64 + powerpc64-*-aix5*) + targ_defvec=aix5coff64_vec + targ_selvecs="rs6000coff_vec" + want64=true + ;; +#endif + + powerpc-*-aix* | powerpc-*-beos* | rs6000-*-*) + targ_defvec=rs6000coff_vec + targ64_selvecs=rs6000coff64_vec + case "${targ}" in + *-*-aix4.[3456789]* | *-*-aix[56789]*) + want64=true;; + + *) + targ_cflags=-DSMALL_ARCHIVE;; + esac + ;; +#ifdef BFD64 + powerpc64-*-aix*) + targ_defvec=rs6000coff64_vec + targ_selvecs=rs6000coff_vec + ;; + 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" + ;; + 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" + ;; +#endif + powerpc-*-*bsd* | powerpc-*-elf* | powerpc-*-sysv4* | powerpc-*-eabi* | \ + powerpc-*-solaris2* | powerpc-*-linux-gnu* | powerpc-*-rtems* | \ + powerpc-*-chorus* | powerpc-*-vxworks* | powerpc-*-windiss*) + 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" + ;; + 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" + ;; + powerpc-*-darwin* | powerpc-*-macos10* | powerpc-*-rhapsody*) + targ_defvec=mach_o_be_vec + targ_selvecs="mach_o_be_vec mach_o_le_vec mach_o_fat_vec pef_vec pef_xlib_vec sym_vec" + targ_archs="bfd_powerpc_arch bfd_rs6000_arch bfd_i386_arch" + ;; + powerpc-*-macos* | powerpc-*-mpw*) + targ_defvec=pmac_xcoff_vec + ;; + powerpc-*-netware*) + targ_defvec=bfd_elf32_powerpc_vec + targ_selvecs="nlm32_powerpc_vec rs6000coff_vec" + ;; + powerpc-*-nto*) + targ_defvec=bfd_elf32_powerpc_vec + targ_selvecs="rs6000coff_vec bfd_elf32_powerpcle_vec ppcboot_vec" + ;; + powerpcle-*-nto*) + targ_defvec=bfd_elf32_powerpcle_vec + targ_selvecs="rs6000coff_vec bfd_elf32_powerpc_vec ppcboot_vec" + ;; + powerpcle-*-elf* | powerpcle-*-sysv4* | powerpcle-*-eabi* | \ + powerpcle-*-solaris2* | powerpcle-*-linux-gnu* | powerpcle-*-vxworks* |\ + powerpcle-*-rtems*) + 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" + ;; + + 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" + ;; + + s390-*-linux*) + targ_defvec=bfd_elf32_s390_vec + targ64_selvecs=bfd_elf64_s390_vec + ;; +#ifdef BFD64 + s390x-*-linux*) + targ_defvec=bfd_elf64_s390_vec + targ_selvecs=bfd_elf32_s390_vec + ;; +#endif + +#ifdef BFD64 + 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_underscore=yes + ;; + 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_underscore=yes + ;; + 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" + ;; + 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" + ;; +#endif /* BFD64 */ + + sh-*-linux*) + targ_defvec=bfd_elf32_shblin_vec + targ_selvecs=bfd_elf32_shlin_vec +#ifdef BFD64 + targ_selvecs="${targ_selvecs} bfd_elf32_sh64lin_vec bfd_elf32_sh64blin_vec bfd_elf64_sh64lin_vec bfd_elf64_sh64blin_vec" +#endif + ;; + sh*eb-*-linux*) + targ_defvec=bfd_elf32_shblin_vec + targ_selvecs=bfd_elf32_shlin_vec + ;; + sh*-*-linux*) + targ_defvec=bfd_elf32_shlin_vec + targ_selvecs=bfd_elf32_shblin_vec + ;; + +#ifdef BFD64 + sh5le-*-netbsd*) + targ_defvec=bfd_elf32_sh64lnbsd_vec + targ_selvecs="bfd_elf32_sh64nbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec" + ;; + sh5-*-netbsd*) + targ_defvec=bfd_elf32_sh64nbsd_vec + targ_selvecs="bfd_elf32_sh64lnbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec" + ;; + + sh64le-*-netbsd*) + targ_defvec=bfd_elf64_sh64lnbsd_vec + targ_selvecs="bfd_elf64_sh64nbsd_vec bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec" + ;; + sh64-*-netbsd*) + targ_defvec=bfd_elf64_sh64nbsd_vec + targ_selvecs="bfd_elf64_sh64lnbsd_vec bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec" + ;; +#endif + + shle-*-netbsdelf*) + targ_defvec=bfd_elf32_shlnbsd_vec + targ_selvecs="bfd_elf32_shnbsd_vec shcoff_vec shlcoff_vec" +#ifdef BFD64 + targ_selvecs="${targ_selvecs} bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec" +#endif + ;; + sh*le-*-netbsdelf*) + targ_defvec=bfd_elf32_shlnbsd_vec + targ_selvecs="bfd_elf32_shnbsd_vec shcoff_vec shlcoff_vec" + ;; + sh-*-netbsdelf*) + targ_defvec=bfd_elf32_shnbsd_vec + targ_selvecs="bfd_elf32_shlnbsd_vec shcoff_vec shlcoff_vec" +#ifdef BFD64 + targ_selvecs="${targ_selvecs} bfd_elf32_sh64lnbsd_vec bfd_elf32_sh64nbsd_vec bfd_elf64_sh64lnbsd_vec bfd_elf64_sh64nbsd_vec" +#endif + ;; + sh*-*-netbsdelf*) + targ_defvec=bfd_elf32_shnbsd_vec + targ_selvecs="bfd_elf32_shlnbsd_vec shcoff_vec shlcoff_vec" + ;; + + 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" +#ifdef BFD64 + targ_selvecs="${targ_selvecs} bfd_elf32_sh64_vec bfd_elf32_sh64l_vec bfd_elf64_sh64_vec bfd_elf64_sh64l_vec" +#endif + targ_underscore=yes + ;; + sh-*-elf* | sh[1234]*-elf* | sh-*-rtemself* | sh-*-kaos*) + targ_defvec=bfd_elf32_sh_vec + targ_selvecs="bfd_elf32_shl_vec shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" +#ifdef BFD64 + targ_selvecs="${targ_selvecs} bfd_elf32_sh64_vec bfd_elf32_sh64l_vec bfd_elf64_sh64_vec bfd_elf64_sh64l_vec" +#endif + targ_underscore=yes + ;; + 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_underscore=yes + ;; + sh-*-pe) + targ_defvec=shlpe_vec + targ_selvecs="shlpe_vec shlpei_vec" + targ_underscore=yes + ;; + sh-*-* | sh-*-rtems*) + targ_defvec=shcoff_vec + targ_selvecs="shcoff_vec shlcoff_vec shcoff_small_vec shlcoff_small_vec" + targ_underscore=yes + ;; + + sparclet-*-aout*) + targ_defvec=sunos_big_vec + targ_selvecs=sparcle_aout_vec + targ_underscore=yes + ;; + sparc86x-*-aout*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + sparclite-*-elf* | sparc86x-*-elf*) + targ_defvec=bfd_elf32_sparc_vec + ;; + sparc*-*-chorus*) + targ_defvec=bfd_elf32_sparc_vec + ;; + sparc-*-linux*aout*) + targ_defvec=sparclinux_vec + targ_selvecs="bfd_elf32_sparc_vec sunos_big_vec" + targ_underscore=yes + ;; + sparc-*-linux-gnu*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs="sparclinux_vec bfd_elf64_sparc_vec sunos_big_vec" + ;; + sparc-*-lynxos*) + targ_defvec=sparclynx_coff_vec + targ_selvecs=sparclynx_aout_vec + ;; + sparc-*-netbsdelf*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs=sparcnetbsd_vec + ;; + sparc-*-netbsdaout* | sparc-*-netbsd*) + targ_defvec=sparcnetbsd_vec + targ_selvecs=bfd_elf32_sparc_vec + targ_underscore=yes + ;; + sparc-*-openbsd*) + targ_defvec=sparcnetbsd_vec + targ_underscore=yes + ;; + sparc-*-elf* | sparc-*-solaris2.[0-6] | sparc-*-solaris2.[0-6].*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs=sunos_big_vec + ;; +#ifdef BFD64 + sparc-*-solaris2* | sparcv9-*-solaris2* | sparc64-*-solaris2*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs="bfd_elf64_sparc_vec sunos_big_vec" + ;; +#endif + sparc-*-sysv4*) + targ_defvec=bfd_elf32_sparc_vec + ;; + sparc-*-netware*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs="nlm32_sparc_vec sunos_big_vec" + ;; +#ifdef BFD64 + sparc64-*-aout*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + sparc64-*-linux-gnu*) + targ_defvec=bfd_elf64_sparc_vec + targ_selvecs="bfd_elf32_sparc_vec sparclinux_vec sunos_big_vec" + ;; + sparc64-*-elf*) + targ_defvec=bfd_elf64_sparc_vec + targ_selvecs=bfd_elf32_sparc_vec + ;; +#endif /* BFD64 */ + sparc*-*-coff*) + targ_defvec=sparccoff_vec + ;; + sparc*-*-rtemsaout*) + targ_defvec=sunos_big_vec + targ_selvecs="bfd_elf32_sparc_vec sparccoff_vec" + targ_underscore=yes + ;; + sparc*-*-rtems* | sparc*-*-rtemself*) + targ_defvec=bfd_elf32_sparc_vec + targ_selvecs="sunos_big_vec sparccoff_vec" + ;; + sparc*-*-* | sparc*-*-rtems*) + targ_defvec=sunos_big_vec + targ_underscore=yes + ;; + +#if HAVE_host_aout_vec + tahoe-*-*) + targ_defvec=host_aout_vec + targ_underscore=yes + ;; +#endif + + tic80*-*-*) + targ_defvec=tic80coff_vec + targ_underscore=yes + ;; + + + v850-*-*) + targ_defvec=bfd_elf32_v850_vec + ;; + v850e-*-*) + targ_defvec=bfd_elf32_v850_vec + ;; + v850ea-*-*) + targ_defvec=bfd_elf32_v850_vec + ;; + + vax-*-netbsdelf*) + targ_defvec=bfd_elf32_vax_vec + targ_selvecs="vaxnetbsd_vec vax1knetbsd_vec" + ;; + + vax-*-netbsdaout* | vax-*-netbsd*) + targ_defvec=vaxnetbsd_vec + targ_selvecs="bfd_elf32_vax_vec vax1knetbsd_vec" + targ_underscore=yes + ;; + + vax-*-bsd* | vax-*-ultrix*) + targ_defvec=vaxbsd_vec + targ_underscore=yes + ;; + + vax*-*-*vms*) + targ_defvec=vms_vax_vec + ;; + + we32k-*-*) + targ_defvec=we32kcoff_vec + ;; + + w65-*-*) + targ_defvec=w65_vec + ;; + + xstormy16-*-elf) + targ_defvec=bfd_elf32_xstormy16_vec + ;; + + xtensa-*-*) + targ_defvec=bfd_elf32_xtensa_le_vec + targ_selvecs=bfd_elf32_xtensa_be_vec + ;; + + z8k*-*-*) + targ_defvec=z8kcoff_vec + targ_underscore=yes + ;; + + *-*-ieee*) + targ_defvec=ieee_vec + ;; + + *-adobe-*) + targ_defvec=a_out_adobe_vec + targ_underscore=yes + ;; + + *-sony-*) + targ_defvec=newsos3_vec + targ_underscore=yes + ;; + + *-tandem-*) + targ_defvec=m68kcoff_vec + targ_selvecs=ieee_vec + ;; +# END OF targmatch.h + *) + echo 1>&2 "*** BFD does not support target ${targ}." + echo 1>&2 "*** Look in bfd/config.bfd for supported targets." + exit 1 + ;; +esac + +case "${host64}${want64}" in + *true*) + targ_selvecs="${targ_selvecs} ${targ64_selvecs}" + ;; +esac + +# If we support any ELF target, then automatically add support for the +# generic ELF targets. This permits an objdump with some ELF support +# 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" + ;; + *bfd_elf32*) + targ_selvecs="${targ_selvecs} bfd_elf32_little_generic_vec bfd_elf32_big_generic_vec" + ;; +esac diff --git a/contrib/binutils-2.14/bfd/corefile.c b/contrib/binutils-2.14/bfd/corefile.c new file mode 100644 index 0000000000..da9d4d739d --- /dev/null +++ b/contrib/binutils-2.14/bfd/corefile.c @@ -0,0 +1,105 @@ +/* Core file generic interface routines for BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2002 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + Core files + +DESCRIPTION + These are functions pertaining to core files. +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +FUNCTION + bfd_core_file_failing_command + +SYNOPSIS + const char *bfd_core_file_failing_command(bfd *abfd); + +DESCRIPTION + Return a read-only string explaining which program was running + when it failed and produced the core file @var{abfd}. + +*/ + +const char * +bfd_core_file_failing_command (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_core) { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + return BFD_SEND (abfd, _core_file_failing_command, (abfd)); +} + +/* +FUNCTION + bfd_core_file_failing_signal + +SYNOPSIS + int bfd_core_file_failing_signal(bfd *abfd); + +DESCRIPTION + Returns the signal number which caused the core dump which + generated the file the BFD @var{abfd} is attached to. +*/ + +int +bfd_core_file_failing_signal (abfd) + bfd *abfd; +{ + if (abfd->format != bfd_core) { + bfd_set_error (bfd_error_invalid_operation); + return 0; + } + return BFD_SEND (abfd, _core_file_failing_signal, (abfd)); +} + +/* +FUNCTION + core_file_matches_executable_p + +SYNOPSIS + bfd_boolean core_file_matches_executable_p + (bfd *core_bfd, bfd *exec_bfd); + +DESCRIPTION + Return <> if the core file attached to @var{core_bfd} + was generated by a run of the executable file attached to + @var{exec_bfd}, <> otherwise. +*/ +bfd_boolean +core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd, *exec_bfd; +{ + if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + return BFD_SEND (core_bfd, _core_file_matches_executable_p, + (core_bfd, exec_bfd)); +} diff --git a/contrib/binutils-2.14/bfd/cpu-i386.c b/contrib/binutils-2.14/bfd/cpu-i386.c new file mode 100644 index 0000000000..272c719624 --- /dev/null +++ b/contrib/binutils-2.14/bfd/cpu-i386.c @@ -0,0 +1,101 @@ +/* BFD support for the Intel 386 architecture. + Copyright 1992, 1994, 1995, 1996, 1998, 2000, 2001, 2002 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +const bfd_arch_info_type bfd_i386_arch_intel_syntax = +{ + 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_intel_syntax, + "i386:intel", + "i386:intel", + 3, + TRUE, + bfd_default_compatible, + bfd_default_scan , + 0, +}; +const bfd_arch_info_type bfd_x86_64_arch_intel_syntax = +{ + 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_intel_syntax, + "i386:intel", + "i386:x86-64:intel", + 3, + TRUE, + bfd_default_compatible, + bfd_default_scan , + &bfd_i386_arch_intel_syntax, +}; +static const bfd_arch_info_type i8086_arch = +{ + 32, /* 32 bits in a word */ + 32, /* 32 bits in an address (well, not really) */ + 8, /* 8 bits in a byte */ + bfd_arch_i386, + bfd_mach_i386_i8086, + "i8086", + "i8086", + 3, + FALSE, + bfd_default_compatible, + bfd_default_scan , + &bfd_x86_64_arch_intel_syntax, +}; + +const bfd_arch_info_type bfd_x86_64_arch = +{ + 64, /* 32 bits in a word */ + 64, /* 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_i386, + bfd_mach_x86_64, + "i386", + "i386:x86-64", + 3, + TRUE, + bfd_default_compatible, + bfd_default_scan , + &i8086_arch, +}; + +const bfd_arch_info_type bfd_i386_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, + "i386", + "i386", + 3, + TRUE, + bfd_default_compatible, + bfd_default_scan , + &bfd_x86_64_arch +}; diff --git a/contrib/binutils-2.14/bfd/doc/bfdsumm.texi b/contrib/binutils-2.14/bfd/doc/bfdsumm.texi new file mode 100644 index 0000000000..77a5f09e51 --- /dev/null +++ b/contrib/binutils-2.14/bfd/doc/bfdsumm.texi @@ -0,0 +1,148 @@ +@c This summary of BFD is shared by the BFD and LD docs. +When an object file is opened, BFD subroutines automatically determine +the format of the input object file. They then build a descriptor in +memory with pointers to routines that will be used to access elements of +the object file's data structures. + +As different information from the object files is required, +BFD reads from different sections of the file and processes them. +For example, a very common operation for the linker is processing symbol +tables. Each BFD back end provides a routine for converting +between the object file's representation of symbols and an internal +canonical format. When the linker asks for the symbol table of an object +file, it calls through a memory pointer to the routine from the +relevant BFD back end which reads and converts the table into a canonical +form. The linker then operates upon the canonical form. When the link is +finished and the linker writes the output file's symbol table, +another BFD back end routine is called to take the newly +created symbol table and convert it into the chosen output format. + +@menu +* BFD information loss:: Information Loss +* Canonical format:: The BFD canonical object-file format +@end menu + +@node BFD information loss +@subsection Information Loss + +@emph{Information can be lost during output.} The output formats +supported by BFD do not provide identical facilities, and +information which can be described in one form has nowhere to go in +another format. One example of this is alignment information in +@code{b.out}. There is nowhere in an @code{a.out} format file to store +alignment information on the contained data, so when a file is linked +from @code{b.out} and an @code{a.out} image is produced, alignment +information will not propagate to the output file. (The linker will +still use the alignment information internally, so the link is performed +correctly). + +Another example is COFF section names. COFF files may contain an +unlimited number of sections, each one with a textual section name. If +the target of the link is a format which does not have many sections (e.g., +@code{a.out}) or has sections without names (e.g., the Oasys format), the +link cannot be done simply. You can circumvent this problem by +describing the desired input-to-output section mapping with the linker command +language. + +@emph{Information can be lost during canonicalization.} The BFD +internal canonical form of the external formats is not exhaustive; there +are structures in input formats for which there is no direct +representation internally. This means that the BFD back ends +cannot maintain all possible data richness through the transformation +between external to internal and back to external formats. + +This limitation is only a problem when an application reads one +format and writes another. Each BFD back end is responsible for +maintaining as much data as possible, and the internal BFD +canonical form has structures which are opaque to the BFD core, +and exported only to the back ends. When a file is read in one format, +the canonical form is generated for BFD and the application. At the +same time, the back end saves away any information which may otherwise +be lost. If the data is then written back in the same format, the back +end routine will be able to use the canonical form provided by the +BFD core as well as the information it prepared earlier. Since +there is a great deal of commonality between back ends, +there is no information lost when +linking or copying big endian COFF to little endian COFF, or @code{a.out} to +@code{b.out}. When a mixture of formats is linked, the information is +only lost from the files whose format differs from the destination. + +@node Canonical format +@subsection The BFD canonical object-file format + +The greatest potential for loss of information occurs when there is the least +overlap between the information provided by the source format, that +stored by the canonical format, and that needed by the +destination format. A brief description of the canonical form may help +you understand which kinds of data you can count on preserving across +conversions. +@cindex BFD canonical format +@cindex internal object-file format + +@table @emph +@item files +Information stored on a per-file basis includes target machine +architecture, particular implementation format type, a demand pageable +bit, and a write protected bit. Information like Unix magic numbers is +not stored here---only the magic numbers' meaning, so a @code{ZMAGIC} +file would have both the demand pageable bit and the write protected +text bit set. The byte order of the target is stored on a per-file +basis, so that big- and little-endian object files may be used with one +another. + +@item sections +Each section in the input file contains the name of the section, the +section's original address in the object file, size and alignment +information, various flags, and pointers into other BFD data +structures. + +@item symbols +Each symbol contains a pointer to the information for the object file +which originally defined it, its name, its value, and various flag +bits. When a BFD back end reads in a symbol table, it relocates all +symbols to make them relative to the base of the section where they were +defined. Doing this ensures that each symbol points to its containing +section. Each symbol also has a varying amount of hidden private data +for the BFD back end. Since the symbol points to the original file, the +private data format for that symbol is accessible. @code{ld} can +operate on a collection of symbols of wildly different formats without +problems. + +Normal global and simple local symbols are maintained on output, so an +output file (no matter its format) will retain symbols pointing to +functions and to global, static, and common variables. Some symbol +information is not worth retaining; in @code{a.out}, type information is +stored in the symbol table as long symbol names. This information would +be useless to most COFF debuggers; the linker has command line switches +to allow users to throw it away. + +There is one word of type information within the symbol, so if the +format supports symbol type information within symbols (for example, COFF, +IEEE, Oasys) and the type is simple enough to fit within one word +(nearly everything but aggregates), the information will be preserved. + +@item relocation level +Each canonical BFD relocation record contains a pointer to the symbol to +relocate to, the offset of the data to relocate, the section the data +is in, and a pointer to a relocation type descriptor. Relocation is +performed by passing messages through the relocation type +descriptor and the symbol pointer. Therefore, relocations can be performed +on output data using a relocation method that is only available in one of the +input formats. For instance, Oasys provides a byte relocation format. +A relocation record requesting this relocation type would point +indirectly to a routine to perform this, so the relocation may be +performed on a byte being written to a 68k COFF file, even though 68k COFF +has no such relocation type. + +@item line numbers +Object formats can contain, for debugging purposes, some form of mapping +between symbols, source line numbers, and addresses in the output file. +These addresses have to be relocated along with the symbol information. +Each symbol with an associated list of line number records points to the +first record of the list. The head of a line number list consists of a +pointer to the symbol, which allows finding out the address of the +function whose line number is being described. The rest of the list is +made up of pairs: offsets into the section and line numbers. Any format +which can simply derive this information can pass it successfully +between formats (COFF, IEEE and Oasys). +@end table diff --git a/contrib/binutils-2.14/bfd/dwarf1.c b/contrib/binutils-2.14/bfd/dwarf1.c new file mode 100644 index 0000000000..1047ebfc2e --- /dev/null +++ b/contrib/binutils-2.14/bfd/dwarf1.c @@ -0,0 +1,586 @@ +/* DWARF 1 find nearest line (_bfd_dwarf1_find_nearest_line). + Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + +Written by Gavin Romig-Koch of Cygnus Solutions (gavin@cygnus.com). + +This file is part of BFD. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libiberty.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/dwarf.h" + +/* dwarf1_debug is the starting point for all dwarf1 info. */ + +struct dwarf1_debug { + + /* The bfd we are working with. */ + bfd* abfd; + + /* List of already parsed compilation units. */ + struct dwarf1_unit* lastUnit; + + /* The buffer for the .debug section. + Zero indicates that the .debug section failed to load. */ + char* debug_section; + + /* Pointer to the end of the .debug_info section memory buffer. */ + char* debug_section_end; + + /* The buffer for the .line section. */ + char* line_section; + + /* End of that buffer. */ + char* line_section_end; + + /* The current or next unread die within the .debug section. */ + char* currentDie; +}; + +/* One dwarf1_unit for each parsed compilation unit die. */ + +struct dwarf1_unit { + /* Linked starting from stash->lastUnit. */ + struct dwarf1_unit* prev; + + /* Name of the compilation unit. */ + char* name; + + /* The highest and lowest address used in the compilation unit. */ + unsigned long low_pc; + unsigned long high_pc; + + /* Does this unit have a statement list? */ + int has_stmt_list; + + /* If any, the offset of the line number table in the .line section. */ + unsigned long stmt_list_offset; + + /* If non-zero, a pointer to the first child of this unit. */ + char* first_child; + + /* How many line entries? */ + unsigned long line_count; + + /* The decoded line number table (line_count entries). */ + struct linenumber* linenumber_table; + + /* The list of functions in this unit. */ + struct dwarf1_func* func_list; +}; + +/* One dwarf1_func for each parsed function die. */ + +struct dwarf1_func { + /* Linked starting from aUnit->func_list. */ + struct dwarf1_func* prev; + + /* Name of function. */ + char* name; + + /* The highest and lowest address used in the compilation unit. */ + unsigned long low_pc; + unsigned long high_pc; +}; + +/* Used to return info about a parsed die. */ +struct die_info { + unsigned long length; + unsigned long sibling; + unsigned long low_pc; + unsigned long high_pc; + unsigned long stmt_list_offset; + + char* name; + + int has_stmt_list; + + unsigned short tag; +}; + +/* Parsed line number information. */ +struct linenumber { + /* First address in the line. */ + unsigned long addr; + + /* The line number. */ + unsigned long linenumber; +}; + +/* Find the form of an attr, from the attr field. */ +#define FORM_FROM_ATTR(attr) ((attr) & 0xF) /* Implicitly specified */ + +static struct dwarf1_unit *alloc_dwarf1_unit + PARAMS ((struct dwarf1_debug *)); +static struct dwarf1_func *alloc_dwarf1_func + PARAMS ((struct dwarf1_debug *, struct dwarf1_unit *)); +static bfd_boolean parse_die + PARAMS ((bfd *, struct die_info *, char *, char *)); +static bfd_boolean parse_line_table + PARAMS ((struct dwarf1_debug *, struct dwarf1_unit *)); +static bfd_boolean parse_functions_in_unit + PARAMS ((struct dwarf1_debug *, struct dwarf1_unit *)); +static bfd_boolean dwarf1_unit_find_nearest_line + PARAMS ((struct dwarf1_debug *, struct dwarf1_unit *, unsigned long, + const char **, const char **, unsigned int *)); + +/* Return a newly allocated dwarf1_unit. It should be cleared and + then attached into the 'stash' at 'stash->lastUnit'. */ + +static struct dwarf1_unit* +alloc_dwarf1_unit (stash) + struct dwarf1_debug* stash; +{ + bfd_size_type amt = sizeof (struct dwarf1_unit); + + struct dwarf1_unit* x = (struct dwarf1_unit*) bfd_zalloc (stash->abfd, amt); + x->prev = stash->lastUnit; + stash->lastUnit = x; + + return x; +} + +/* Return a newly allocated dwarf1_func. It must be cleared and + attached into 'aUnit' at 'aUnit->func_list'. */ + +static struct dwarf1_func* +alloc_dwarf1_func (stash, aUnit) + struct dwarf1_debug* stash; + struct dwarf1_unit* aUnit; +{ + bfd_size_type amt = sizeof (struct dwarf1_func); + + struct dwarf1_func* x = (struct dwarf1_func*) bfd_zalloc (stash->abfd, amt); + x->prev = aUnit->func_list; + aUnit->func_list = x; + + return x; +} + +/* parse_die - parse a Dwarf1 die. + Parse the die starting at 'aDiePtr' into 'aDieInfo'. + 'abfd' must be the bfd from which the section that 'aDiePtr' + points to was pulled from. + + Return FALSE if the die is invalidly formatted; TRUE otherwise. */ + +static bfd_boolean +parse_die (abfd, aDieInfo, aDiePtr, aDiePtrEnd) + bfd* abfd; + struct die_info* aDieInfo; + char* aDiePtr; + char* aDiePtrEnd; +{ + char* this_die = aDiePtr; + char* xptr = this_die; + + memset (aDieInfo,0,sizeof (*aDieInfo)); + + /* First comes the length. */ + aDieInfo->length = bfd_get_32 (abfd, (bfd_byte *) xptr); + xptr += 4; + if (aDieInfo->length == 0 + || (this_die + aDieInfo->length) >= aDiePtrEnd) + return FALSE; + if (aDieInfo->length < 6) + { + /* Just padding bytes. */ + aDieInfo->tag = TAG_padding; + return TRUE; + } + + /* Then the tag. */ + aDieInfo->tag = bfd_get_16 (abfd, (bfd_byte *) xptr); + xptr += 2; + + /* Then the attributes. */ + while (xptr < (this_die + aDieInfo->length)) + { + unsigned short attr; + + /* Parse the attribute based on its form. This section + must handle all dwarf1 forms, but need only handle the + actual attributes that we care about. */ + + attr = bfd_get_16 (abfd, (bfd_byte *) xptr); + xptr += 2; + + switch (FORM_FROM_ATTR (attr)) + { + case FORM_DATA2: + xptr += 2; + break; + case FORM_DATA4: + case FORM_REF: + if (attr == AT_sibling) + aDieInfo->sibling = bfd_get_32 (abfd, (bfd_byte *) xptr); + else if (attr == AT_stmt_list) + { + aDieInfo->stmt_list_offset = bfd_get_32 (abfd, (bfd_byte *) xptr); + aDieInfo->has_stmt_list = 1; + } + xptr += 4; + break; + case FORM_DATA8: + xptr += 8; + break; + case FORM_ADDR: + if (attr == AT_low_pc) + aDieInfo->low_pc = bfd_get_32 (abfd, (bfd_byte *) xptr); + else if (attr == AT_high_pc) + aDieInfo->high_pc = bfd_get_32 (abfd, (bfd_byte *) xptr); + xptr += 4; + break; + case FORM_BLOCK2: + xptr += 2 + bfd_get_16 (abfd, (bfd_byte *) xptr); + break; + case FORM_BLOCK4: + xptr += 4 + bfd_get_32 (abfd, (bfd_byte *) xptr); + break; + case FORM_STRING: + if (attr == AT_name) + aDieInfo->name = xptr; + xptr += strlen (xptr) + 1; + break; + } + } + + return TRUE; +} + +/* Parse a dwarf1 line number table for 'aUnit->stmt_list_offset' + into 'aUnit->linenumber_table'. Return FALSE if an error + occurs; TRUE otherwise. */ + +static bfd_boolean +parse_line_table (stash, aUnit) + struct dwarf1_debug* stash; + struct dwarf1_unit* aUnit; +{ + char* xptr; + + /* Load the ".line" section from the bfd if we haven't already. */ + if (stash->line_section == 0) + { + asection *msec; + bfd_size_type size; + + msec = bfd_get_section_by_name (stash->abfd, ".line"); + if (! msec) + return FALSE; + + size = bfd_get_section_size_before_reloc (msec); + stash->line_section = (char *) bfd_alloc (stash->abfd, size); + + if (! stash->line_section) + return FALSE; + + if (! bfd_get_section_contents (stash->abfd, msec, stash->line_section, + (bfd_vma) 0, size)) + { + stash->line_section = 0; + return FALSE; + } + + stash->line_section_end = stash->line_section + size; + } + + xptr = stash->line_section + aUnit->stmt_list_offset; + if (xptr < stash->line_section_end) + { + unsigned long eachLine; + char *tblend; + unsigned long base; + bfd_size_type amt; + + /* First comes the length. */ + tblend = bfd_get_32 (stash->abfd, (bfd_byte *) xptr) + xptr; + xptr += 4; + + /* Then the base address for each address in the table. */ + base = bfd_get_32 (stash->abfd, (bfd_byte *) xptr); + xptr += 4; + + /* How many line entrys? + 10 = 4 (line number) + 2 (pos in line) + 4 (address in line) */ + aUnit->line_count = (tblend - xptr) / 10; + + /* Allocate an array for the entries. */ + amt = sizeof (struct linenumber) * aUnit->line_count; + aUnit->linenumber_table = ((struct linenumber *) + bfd_alloc (stash->abfd, amt)); + + for (eachLine = 0; eachLine < aUnit->line_count; eachLine++) + { + /* A line number. */ + aUnit->linenumber_table[eachLine].linenumber + = bfd_get_32 (stash->abfd, (bfd_byte *) xptr); + xptr += 4; + + /* Skip the position within the line. */ + xptr += 2; + + /* And finally the address. */ + aUnit->linenumber_table[eachLine].addr + = base + bfd_get_32 (stash->abfd, (bfd_byte *) xptr); + xptr += 4; + } + } + + return TRUE; +} + +/* Parse each function die in a compilation unit 'aUnit'. + The first child die of 'aUnit' should be in 'aUnit->first_child', + the result is placed in 'aUnit->func_list'. + Return FALSE if error; TRUE otherwise. */ + +static bfd_boolean +parse_functions_in_unit (stash, aUnit) + struct dwarf1_debug* stash; + struct dwarf1_unit* aUnit; +{ + char* eachDie; + + if (aUnit->first_child) + for (eachDie = aUnit->first_child; + eachDie < stash->debug_section_end; + ) + { + struct die_info eachDieInfo; + + if (! parse_die (stash->abfd, &eachDieInfo, eachDie, + stash->debug_section_end)) + return FALSE; + + if (eachDieInfo.tag == TAG_global_subroutine + || eachDieInfo.tag == TAG_subroutine + || eachDieInfo.tag == TAG_inlined_subroutine + || eachDieInfo.tag == TAG_entry_point) + { + struct dwarf1_func* aFunc = alloc_dwarf1_func (stash,aUnit); + + aFunc->name = eachDieInfo.name; + aFunc->low_pc = eachDieInfo.low_pc; + aFunc->high_pc = eachDieInfo.high_pc; + } + + /* Move to next sibling, if none, end loop */ + if (eachDieInfo.sibling) + eachDie = stash->debug_section + eachDieInfo.sibling; + else + break; + } + + return TRUE; +} + +/* Find the nearest line to 'addr' in 'aUnit'. + Return whether we found the line (or a function) without error. */ + +static bfd_boolean +dwarf1_unit_find_nearest_line (stash, aUnit, addr, + filename_ptr, functionname_ptr, + linenumber_ptr) + struct dwarf1_debug* stash; + struct dwarf1_unit* aUnit; + unsigned long addr; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *linenumber_ptr; +{ + int line_p = FALSE; + int func_p = FALSE; + + if (aUnit->low_pc <= addr && addr < aUnit->high_pc) + { + if (aUnit->has_stmt_list) + { + unsigned long i; + struct dwarf1_func* eachFunc; + + if (! aUnit->linenumber_table) + { + if (! parse_line_table (stash, aUnit)) + return FALSE; + } + + if (! aUnit->func_list) + { + if (! parse_functions_in_unit (stash, aUnit)) + return FALSE; + } + + for (i = 0; i < aUnit->line_count; i++) + { + if (aUnit->linenumber_table[i].addr <= addr + && addr < aUnit->linenumber_table[i+1].addr) + { + *filename_ptr = aUnit->name; + *linenumber_ptr = aUnit->linenumber_table[i].linenumber; + line_p = TRUE; + break; + } + } + + for (eachFunc = aUnit->func_list; + eachFunc; + eachFunc = eachFunc->prev) + { + if (eachFunc->low_pc <= addr + && addr < eachFunc->high_pc) + { + *functionname_ptr = eachFunc->name; + func_p = TRUE; + break; + } + } + } + } + + return line_p || func_p; +} + +/* The DWARF 1 version of find_nearest line. + Return TRUE if the line is found without error. */ + +bfd_boolean +_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, linenumber_ptr) + bfd *abfd; + asection *section; + asymbol **symbols ATTRIBUTE_UNUSED; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *linenumber_ptr; +{ + struct dwarf1_debug *stash = elf_tdata (abfd)->dwarf1_find_line_info; + + struct dwarf1_unit* eachUnit; + + /* What address are we looking for? */ + unsigned long addr = (unsigned long)(offset + section->vma); + + *filename_ptr = NULL; + *functionname_ptr = NULL; + *linenumber_ptr = 0; + + if (! stash) + { + asection *msec; + bfd_size_type size = sizeof (struct dwarf1_debug); + + stash = elf_tdata (abfd)->dwarf1_find_line_info + = (struct dwarf1_debug *) bfd_zalloc (abfd, size); + + if (! stash) + return FALSE; + + msec = bfd_get_section_by_name (abfd, ".debug"); + if (! msec) + { + /* No dwarf1 info. Note that at this point the stash + has been allocated, but contains zeros, this lets + future calls to this function fail quicker. */ + return FALSE; + } + + size = bfd_get_section_size_before_reloc (msec); + stash->debug_section = (char *) bfd_alloc (abfd, size); + + if (! stash->debug_section) + return FALSE; + + if (! bfd_get_section_contents (abfd, msec, stash->debug_section, + (bfd_vma) 0, size)) + { + stash->debug_section = 0; + return FALSE; + } + + stash->debug_section_end = stash->debug_section + size; + stash->currentDie = stash->debug_section; + stash->abfd = abfd; + } + + /* A null debug_section indicates that there was no dwarf1 info + or that an error occured while setting up the stash. */ + + if (! stash->debug_section) + return FALSE; + + /* Look at the previously parsed units to see if any contain + the addr. */ + for (eachUnit = stash->lastUnit; eachUnit; eachUnit = eachUnit->prev) + { + if (eachUnit->low_pc <= addr && addr < eachUnit->high_pc) + return dwarf1_unit_find_nearest_line (stash, eachUnit, addr, + filename_ptr, + functionname_ptr, + linenumber_ptr); + } + + while (stash->currentDie < stash->debug_section_end) + { + struct die_info aDieInfo; + + if (! parse_die (stash->abfd, &aDieInfo, stash->currentDie, + stash->debug_section_end)) + return FALSE; + + if (aDieInfo.tag == TAG_compile_unit) + { + struct dwarf1_unit* aUnit + = alloc_dwarf1_unit (stash); + + aUnit->name = aDieInfo.name; + aUnit->low_pc = aDieInfo.low_pc; + aUnit->high_pc = aDieInfo.high_pc; + aUnit->has_stmt_list = aDieInfo.has_stmt_list; + aUnit->stmt_list_offset = aDieInfo.stmt_list_offset; + + /* A die has a child if it's followed by a die that is + not it's sibling. */ + if (aDieInfo.sibling + && stash->currentDie + aDieInfo.length + < stash->debug_section_end + && stash->currentDie + aDieInfo.length + != stash->debug_section + aDieInfo.sibling) + aUnit->first_child = stash->currentDie + aDieInfo.length; + else + aUnit->first_child = 0; + + if (aUnit->low_pc <= addr && addr < aUnit->high_pc) + return dwarf1_unit_find_nearest_line (stash, aUnit, addr, + filename_ptr, + functionname_ptr, + linenumber_ptr); + } + + if (aDieInfo.sibling != 0) + stash->currentDie = stash->debug_section + aDieInfo.sibling; + else + stash->currentDie += aDieInfo.length; + } + + return FALSE; +} + +/* EOF */ diff --git a/contrib/binutils-2.14/bfd/dwarf2.c b/contrib/binutils-2.14/bfd/dwarf2.c new file mode 100644 index 0000000000..7a9e5b00e3 --- /dev/null +++ b/contrib/binutils-2.14/bfd/dwarf2.c @@ -0,0 +1,2005 @@ +/* DWARF 2 support. + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + Adapted from gdb/dwarf2read.c by Gavin Koch of Cygnus Solutions + (gavin@cygnus.com). + + From the dwarf2read.c header: + Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology, + Inc. with support from Florida State University (under contract + with the Ada Joint Program Office), and Silicon Graphics, Inc. + Initial contribution by Brent Benson, Harris Computer Systems, Inc., + based on Fred Fish's (Cygnus Support) implementation of DWARF 1 + support in dwarfread.c + + This file is part of BFD. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at + your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libiberty.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/dwarf2.h" + +/* The data in the .debug_line statement prologue looks like this. */ + +struct line_head +{ + bfd_vma total_length; + unsigned short version; + bfd_vma prologue_length; + unsigned char minimum_instruction_length; + unsigned char default_is_stmt; + int line_base; + unsigned char line_range; + unsigned char opcode_base; + unsigned char *standard_opcode_lengths; +}; + +/* Attributes have a name and a value. */ + +struct attribute +{ + enum dwarf_attribute name; + enum dwarf_form form; + union + { + char *str; + struct dwarf_block *blk; + unsigned int unsnd; + int snd; + bfd_vma addr; + } + u; +}; + +/* Get at parts of an attribute structure. */ + +#define DW_STRING(attr) ((attr)->u.str) +#define DW_UNSND(attr) ((attr)->u.unsnd) +#define DW_BLOCK(attr) ((attr)->u.blk) +#define DW_SND(attr) ((attr)->u.snd) +#define DW_ADDR(attr) ((attr)->u.addr) + +/* Blocks are a bunch of untyped bytes. */ +struct dwarf_block +{ + unsigned int size; + char *data; +}; + +struct dwarf2_debug +{ + /* A list of all previously read comp_units. */ + struct comp_unit* all_comp_units; + + /* The next unread compilation unit within the .debug_info section. + Zero indicates that the .debug_info section has not been loaded + into a buffer yet. */ + char* info_ptr; + + /* Pointer to the end of the .debug_info section memory buffer. */ + char* info_ptr_end; + + /* Pointer to the section and address of the beginning of the + section. */ + asection* sec; + char* sec_info_ptr; + + /* Pointer to the symbol table. */ + asymbol** syms; + + /* Pointer to the .debug_abbrev section loaded into memory. */ + char* dwarf_abbrev_buffer; + + /* Length of the loaded .debug_abbrev section. */ + unsigned long dwarf_abbrev_size; + + /* Buffer for decode_line_info. */ + char *dwarf_line_buffer; + + /* Length of the loaded .debug_line section. */ + unsigned long dwarf_line_size; + + /* Pointer to the .debug_str section loaded into memory. */ + char* dwarf_str_buffer; + + /* Length of the loaded .debug_str section. */ + unsigned long dwarf_str_size; +}; + +struct arange +{ + struct arange *next; + bfd_vma low; + bfd_vma high; +}; + +/* A minimal decoding of DWARF2 compilation units. We only decode + what's needed to get to the line number information. */ + +struct comp_unit +{ + /* Chain the previously read compilation units. */ + struct comp_unit* next_unit; + + /* Keep the bdf convenient (for memory allocation). */ + bfd* abfd; + + /* The lowest and higest addresses contained in this compilation + unit as specified in the compilation unit header. */ + struct arange arange; + + /* The DW_AT_name attribute (for error messages). */ + char* name; + + /* The abbrev hash table. */ + struct abbrev_info** abbrevs; + + /* Note that an error was found by comp_unit_find_nearest_line. */ + int error; + + /* The DW_AT_comp_dir attribute. */ + char* comp_dir; + + /* TRUE if there is a line number table associated with this comp. unit. */ + int stmtlist; + + /* The offset into .debug_line of the line number table. */ + unsigned long line_offset; + + /* Pointer to the first child die for the comp unit. */ + char *first_child_die_ptr; + + /* The end of the comp unit. */ + char *end_ptr; + + /* The decoded line number, NULL if not yet decoded. */ + struct line_info_table* line_table; + + /* A list of the functions found in this comp. unit. */ + struct funcinfo* function_table; + + /* Pointer to dwarf2_debug structure. */ + struct dwarf2_debug *stash; + + /* Address size for this unit - from unit header. */ + unsigned char addr_size; + + /* Offset size for this unit - from unit header. */ + unsigned char offset_size; +}; + +/* This data structure holds the information of an abbrev. */ +struct abbrev_info +{ + unsigned int number; /* Number identifying abbrev. */ + enum dwarf_tag tag; /* DWARF tag. */ + int has_children; /* Boolean. */ + unsigned int num_attrs; /* Number of attributes. */ + struct attr_abbrev *attrs; /* An array of attribute descriptions. */ + struct abbrev_info *next; /* Next in chain. */ +}; + +struct attr_abbrev +{ + enum dwarf_attribute name; + enum dwarf_form form; +}; + +#ifndef ABBREV_HASH_SIZE +#define ABBREV_HASH_SIZE 121 +#endif +#ifndef ATTR_ALLOC_CHUNK +#define ATTR_ALLOC_CHUNK 4 +#endif + +static unsigned int read_1_byte PARAMS ((bfd *, char *)); +static int read_1_signed_byte PARAMS ((bfd *, char *)); +static unsigned int read_2_bytes PARAMS ((bfd *, char *)); +static unsigned int read_4_bytes PARAMS ((bfd *, char *)); +static bfd_vma read_8_bytes PARAMS ((bfd *, char *)); +static char *read_n_bytes PARAMS ((bfd *, char *, unsigned int)); +static char *read_string PARAMS ((bfd *, char *, unsigned int *)); +static char *read_indirect_string PARAMS ((struct comp_unit *, char *, unsigned int *)); +static unsigned int read_unsigned_leb128 + PARAMS ((bfd *, char *, unsigned int *)); +static int read_signed_leb128 + PARAMS ((bfd *, char *, unsigned int *)); +static bfd_vma read_address PARAMS ((struct comp_unit *, char *)); +static struct abbrev_info *lookup_abbrev + PARAMS ((unsigned int, struct abbrev_info **)); +static struct abbrev_info **read_abbrevs + PARAMS ((bfd *, bfd_vma, struct dwarf2_debug *)); +static char *read_attribute + PARAMS ((struct attribute *, struct attr_abbrev *, + struct comp_unit *, char *)); +static char *read_attribute_value + PARAMS ((struct attribute *, unsigned, + struct comp_unit *, char *)); +static void add_line_info + PARAMS ((struct line_info_table *, bfd_vma, char *, + unsigned int, unsigned int, int)); +static char *concat_filename PARAMS ((struct line_info_table *, unsigned int)); +static void arange_add PARAMS ((struct comp_unit *, bfd_vma, bfd_vma)); +static struct line_info_table *decode_line_info + PARAMS ((struct comp_unit *, struct dwarf2_debug *)); +static bfd_boolean lookup_address_in_line_info_table + PARAMS ((struct line_info_table *, bfd_vma, struct funcinfo *, + const char **, unsigned int *)); +static bfd_boolean lookup_address_in_function_table + PARAMS ((struct funcinfo *, bfd_vma, struct funcinfo **, const char **)); +static bfd_boolean scan_unit_for_functions PARAMS ((struct comp_unit *)); +static struct comp_unit *parse_comp_unit + PARAMS ((bfd *, struct dwarf2_debug *, bfd_vma, unsigned int)); +static bfd_boolean comp_unit_contains_address + PARAMS ((struct comp_unit *, bfd_vma)); +static bfd_boolean comp_unit_find_nearest_line + PARAMS ((struct comp_unit *, bfd_vma, const char **, const char **, + unsigned int *, struct dwarf2_debug *)); +static asection *find_debug_info PARAMS ((bfd *, asection *)); + +/* 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 (abfd, buf) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; +{ + return bfd_get_8 (abfd, (bfd_byte *) buf); +} + +static int +read_1_signed_byte (abfd, buf) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; +{ + return bfd_get_signed_8 (abfd, (bfd_byte *) buf); +} + +static unsigned int +read_2_bytes (abfd, buf) + bfd *abfd; + char *buf; +{ + return bfd_get_16 (abfd, (bfd_byte *) buf); +} + +#if 0 /* This is not used. */ + +static int +read_2_signed_bytes (abfd, buf) + bfd *abfd; + char *buf; +{ + return bfd_get_signed_16 (abfd, (bfd_byte *) buf); +} + +#endif + +static unsigned int +read_4_bytes (abfd, buf) + bfd *abfd; + char *buf; +{ + return bfd_get_32 (abfd, (bfd_byte *) buf); +} + +#if 0 /* This is not used. */ + +static int +read_4_signed_bytes (abfd, buf) + bfd *abfd; + char *buf; +{ + return bfd_get_signed_32 (abfd, (bfd_byte *) buf); +} + +#endif + +static bfd_vma +read_8_bytes (abfd, buf) + bfd *abfd; + char *buf; +{ + return bfd_get_64 (abfd, (bfd_byte *) buf); +} + +static char * +read_n_bytes (abfd, buf, size) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; + unsigned int size ATTRIBUTE_UNUSED; +{ + /* If the size of a host char is 8 bits, we can return a pointer + to the buffer, otherwise we have to copy the data to a buffer + allocated on the temporary obstack. */ + return buf; +} + +static char * +read_string (abfd, buf, bytes_read_ptr) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; + unsigned int *bytes_read_ptr; +{ + /* Return a pointer to the embedded string. */ + if (*buf == '\0') + { + *bytes_read_ptr = 1; + return NULL; + } + + *bytes_read_ptr = strlen (buf) + 1; + return buf; +} + +static char * +read_indirect_string (unit, buf, bytes_read_ptr) + struct comp_unit* unit; + char *buf; + unsigned int *bytes_read_ptr; +{ + bfd_vma offset; + struct dwarf2_debug *stash = unit->stash; + + if (unit->offset_size == 4) + offset = read_4_bytes (unit->abfd, buf); + else + offset = read_8_bytes (unit->abfd, buf); + *bytes_read_ptr = unit->offset_size; + + if (! stash->dwarf_str_buffer) + { + asection *msec; + bfd *abfd = unit->abfd; + + msec = bfd_get_section_by_name (abfd, ".debug_str"); + if (! msec) + { + (*_bfd_error_handler) + (_("Dwarf Error: Can't find .debug_str section.")); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + + stash->dwarf_str_size = msec->_raw_size; + stash->dwarf_str_buffer = (char*) bfd_alloc (abfd, msec->_raw_size); + if (! stash->dwarf_abbrev_buffer) + return NULL; + + if (! bfd_get_section_contents (abfd, msec, stash->dwarf_str_buffer, + (bfd_vma) 0, msec->_raw_size)) + return NULL; + } + + if (offset >= stash->dwarf_str_size) + { + (*_bfd_error_handler) (_("Dwarf Error: DW_FORM_strp offset (%lu) greater than or equal to .debug_str size (%lu)."), + (unsigned long) offset, stash->dwarf_str_size); + bfd_set_error (bfd_error_bad_value); + return NULL; + } + + buf = stash->dwarf_str_buffer + offset; + if (*buf == '\0') + return NULL; + return buf; +} + +static unsigned int +read_unsigned_leb128 (abfd, buf, bytes_read_ptr) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; + unsigned int *bytes_read_ptr; +{ + unsigned int result; + unsigned int num_read; + int shift; + unsigned char byte; + + result = 0; + shift = 0; + num_read = 0; + + do + { + byte = bfd_get_8 (abfd, (bfd_byte *) buf); + buf ++; + num_read ++; + result |= ((byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + + * bytes_read_ptr = num_read; + + return result; +} + +static int +read_signed_leb128 (abfd, buf, bytes_read_ptr) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; + unsigned int * bytes_read_ptr; +{ + int result; + int shift; + int num_read; + unsigned char byte; + + result = 0; + shift = 0; + num_read = 0; + + do + { + byte = bfd_get_8 (abfd, (bfd_byte *) buf); + buf ++; + num_read ++; + result |= ((byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + + if ((shift < 32) && (byte & 0x40)) + result |= -(1 << shift); + + * bytes_read_ptr = num_read; + + return result; +} + +/* END VERBATIM */ + +static bfd_vma +read_address (unit, buf) + struct comp_unit* unit; + char *buf; +{ + switch (unit->addr_size) + { + case 8: + return bfd_get_64 (unit->abfd, (bfd_byte *) buf); + case 4: + return bfd_get_32 (unit->abfd, (bfd_byte *) buf); + case 2: + return bfd_get_16 (unit->abfd, (bfd_byte *) buf); + default: + abort (); + } +} + +/* Lookup an abbrev_info structure in the abbrev hash table. */ + +static struct abbrev_info * +lookup_abbrev (number,abbrevs) + unsigned int number; + struct abbrev_info **abbrevs; +{ + unsigned int hash_number; + struct abbrev_info *abbrev; + + hash_number = number % ABBREV_HASH_SIZE; + abbrev = abbrevs[hash_number]; + + while (abbrev) + { + if (abbrev->number == number) + return abbrev; + else + abbrev = abbrev->next; + } + + return NULL; +} + +/* In DWARF version 2, the description of the debugging information is + stored in a separate .debug_abbrev section. Before we read any + dies from a section we read in all abbreviations and install them + in a hash table. */ + +static struct abbrev_info** +read_abbrevs (abfd, offset, stash) + bfd * abfd; + bfd_vma offset; + struct dwarf2_debug *stash; +{ + struct abbrev_info **abbrevs; + char *abbrev_ptr; + struct abbrev_info *cur_abbrev; + unsigned int abbrev_number, bytes_read, abbrev_name; + unsigned int abbrev_form, hash_number; + bfd_size_type amt; + + if (! stash->dwarf_abbrev_buffer) + { + asection *msec; + + msec = bfd_get_section_by_name (abfd, ".debug_abbrev"); + if (! msec) + { + (*_bfd_error_handler) (_("Dwarf Error: Can't find .debug_abbrev section.")); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + stash->dwarf_abbrev_size = msec->_raw_size; + stash->dwarf_abbrev_buffer + = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, + stash->syms); + if (! stash->dwarf_abbrev_buffer) + return 0; + } + + if (offset >= stash->dwarf_abbrev_size) + { + (*_bfd_error_handler) (_("Dwarf Error: Abbrev offset (%lu) greater than or equal to .debug_abbrev size (%lu)."), + (unsigned long) offset, stash->dwarf_abbrev_size); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + amt = sizeof (struct abbrev_info*) * ABBREV_HASH_SIZE; + abbrevs = (struct abbrev_info**) bfd_zalloc (abfd, amt); + + abbrev_ptr = stash->dwarf_abbrev_buffer + offset; + abbrev_number = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_ptr += bytes_read; + + /* Loop until we reach an abbrev number of 0. */ + while (abbrev_number) + { + amt = sizeof (struct abbrev_info); + cur_abbrev = (struct abbrev_info *) bfd_zalloc (abfd, amt); + + /* Read in abbrev header. */ + cur_abbrev->number = abbrev_number; + cur_abbrev->tag = (enum dwarf_tag) + read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_ptr += bytes_read; + cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr); + abbrev_ptr += 1; + + /* Now read in declarations. */ + abbrev_name = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_ptr += bytes_read; + abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_ptr += bytes_read; + + while (abbrev_name) + { + if ((cur_abbrev->num_attrs % ATTR_ALLOC_CHUNK) == 0) + { + amt = cur_abbrev->num_attrs + ATTR_ALLOC_CHUNK; + amt *= sizeof (struct attr_abbrev); + cur_abbrev->attrs = ((struct attr_abbrev *) + bfd_realloc (cur_abbrev->attrs, amt)); + if (! cur_abbrev->attrs) + return 0; + } + + cur_abbrev->attrs[cur_abbrev->num_attrs].name + = (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_ptr += bytes_read; + abbrev_form = read_unsigned_leb128 (abfd, abbrev_ptr, &bytes_read); + abbrev_ptr += bytes_read; + } + + hash_number = abbrev_number % ABBREV_HASH_SIZE; + cur_abbrev->next = abbrevs[hash_number]; + abbrevs[hash_number] = cur_abbrev; + + /* Get next abbreviation. + Under Irix6 the abbreviations for a compilation unit are not + always properly terminated with an abbrev number of 0. + Exit loop if we encounter an abbreviation which we have + already read (which means we are about to read the abbreviations + for the next compile unit) or if the end of the abbreviation + table is reached. */ + 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_ptr += bytes_read; + if (lookup_abbrev (abbrev_number,abbrevs) != NULL) + break; + } + + return abbrevs; +} + +/* Read an attribute value described by an attribute form. */ + +static char * +read_attribute_value (attr, form, unit, info_ptr) + struct attribute *attr; + unsigned form; + struct comp_unit *unit; + char *info_ptr; +{ + bfd *abfd = unit->abfd; + unsigned int bytes_read; + struct dwarf_block *blk; + bfd_size_type amt; + + attr->form = (enum dwarf_form) form; + + switch (form) + { + case DW_FORM_addr: + /* FIXME: DWARF3 draft says DW_FORM_ref_addr is offset_size. */ + case DW_FORM_ref_addr: + DW_ADDR (attr) = read_address (unit, info_ptr); + info_ptr += unit->addr_size; + break; + case DW_FORM_block2: + amt = sizeof (struct dwarf_block); + blk = (struct dwarf_block *) bfd_alloc (abfd, amt); + blk->size = read_2_bytes (abfd, info_ptr); + info_ptr += 2; + blk->data = read_n_bytes (abfd, info_ptr, blk->size); + info_ptr += blk->size; + DW_BLOCK (attr) = blk; + break; + case DW_FORM_block4: + amt = sizeof (struct dwarf_block); + blk = (struct dwarf_block *) bfd_alloc (abfd, amt); + blk->size = read_4_bytes (abfd, info_ptr); + info_ptr += 4; + blk->data = read_n_bytes (abfd, info_ptr, blk->size); + info_ptr += blk->size; + DW_BLOCK (attr) = blk; + break; + case DW_FORM_data2: + DW_UNSND (attr) = read_2_bytes (abfd, info_ptr); + info_ptr += 2; + break; + case DW_FORM_data4: + DW_UNSND (attr) = read_4_bytes (abfd, info_ptr); + info_ptr += 4; + break; + case DW_FORM_data8: + DW_UNSND (attr) = read_8_bytes (abfd, info_ptr); + info_ptr += 8; + break; + case DW_FORM_string: + DW_STRING (attr) = read_string (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_strp: + DW_STRING (attr) = read_indirect_string (unit, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_block: + amt = sizeof (struct dwarf_block); + blk = (struct dwarf_block *) bfd_alloc (abfd, amt); + blk->size = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + blk->data = read_n_bytes (abfd, info_ptr, blk->size); + info_ptr += blk->size; + DW_BLOCK (attr) = blk; + break; + case DW_FORM_block1: + amt = sizeof (struct dwarf_block); + blk = (struct dwarf_block *) bfd_alloc (abfd, amt); + blk->size = read_1_byte (abfd, info_ptr); + info_ptr += 1; + blk->data = read_n_bytes (abfd, info_ptr, blk->size); + info_ptr += blk->size; + DW_BLOCK (attr) = blk; + break; + case DW_FORM_data1: + DW_UNSND (attr) = read_1_byte (abfd, info_ptr); + info_ptr += 1; + break; + case DW_FORM_flag: + DW_UNSND (attr) = read_1_byte (abfd, info_ptr); + info_ptr += 1; + break; + case DW_FORM_sdata: + DW_SND (attr) = read_signed_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_udata: + DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_ref1: + DW_UNSND (attr) = read_1_byte (abfd, info_ptr); + info_ptr += 1; + break; + case DW_FORM_ref2: + DW_UNSND (attr) = read_2_bytes (abfd, info_ptr); + info_ptr += 2; + break; + case DW_FORM_ref4: + DW_UNSND (attr) = read_4_bytes (abfd, info_ptr); + info_ptr += 4; + break; + case DW_FORM_ref8: + DW_UNSND (attr) = read_8_bytes (abfd, info_ptr); + info_ptr += 8; + break; + case DW_FORM_ref_udata: + DW_UNSND (attr) = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + break; + case DW_FORM_indirect: + form = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + info_ptr = read_attribute_value (attr, form, unit, info_ptr); + break; + default: + (*_bfd_error_handler) (_("Dwarf Error: Invalid or unhandled FORM value: %u."), + form); + bfd_set_error (bfd_error_bad_value); + } + return info_ptr; +} + +/* Read an attribute described by an abbreviated attribute. */ + +static char * +read_attribute (attr, abbrev, unit, info_ptr) + struct attribute *attr; + struct attr_abbrev *abbrev; + struct comp_unit *unit; + char *info_ptr; +{ + attr->name = abbrev->name; + info_ptr = read_attribute_value (attr, abbrev->form, unit, info_ptr); + return info_ptr; +} + +/* Source line information table routines. */ + +#define FILE_ALLOC_CHUNK 5 +#define DIR_ALLOC_CHUNK 5 + +struct line_info +{ + struct line_info* prev_line; + bfd_vma address; + char* filename; + unsigned int line; + unsigned int column; + int end_sequence; /* End of (sequential) code sequence. */ +}; + +struct fileinfo +{ + char *name; + unsigned int dir; + unsigned int time; + unsigned int size; +}; + +struct line_info_table +{ + bfd* abfd; + unsigned int num_files; + unsigned int num_dirs; + char* comp_dir; + char** dirs; + struct fileinfo* files; + struct line_info* last_line; /* largest VMA */ + struct line_info* lcl_head; /* local head; used in 'add_line_info' */ +}; + +struct funcinfo +{ + struct funcinfo *prev_func; + char* name; + bfd_vma low; + bfd_vma high; +}; + +/* Adds a new entry to the line_info list in the line_info_table, ensuring + that the list is sorted. Note that the line_info list is sorted from + highest to lowest VMA (with possible duplicates); that is, + line_info->prev_line always accesses an equal or smaller VMA. */ + +static void +add_line_info (table, address, filename, line, column, end_sequence) + struct line_info_table* table; + bfd_vma address; + char* filename; + unsigned int line; + unsigned int column; + int end_sequence; +{ + bfd_size_type amt = sizeof (struct line_info); + struct line_info* info = (struct line_info*) bfd_alloc (table->abfd, amt); + + /* Find the correct location for 'info'. Normally we will receive + new line_info data 1) in order and 2) with increasing VMAs. + However some compilers break the rules (cf. decode_line_info) and + so we include some heuristics for quickly finding the correct + location for 'info'. In particular, these heuristics optimize for + the common case in which the VMA sequence that we receive is a + list of locally sorted VMAs such as + p...z a...j (where a < j < p < z) + + Note: table->lcl_head is used to head an *actual* or *possible* + sequence within the list (such as a...j) that is not directly + headed by table->last_line + + Note: we may receive duplicate entries from 'decode_line_info'. */ + + while (1) + if (!table->last_line + || address >= table->last_line->address) + { + /* Normal case: add 'info' to the beginning of the list */ + info->prev_line = table->last_line; + table->last_line = info; + + /* lcl_head: initialize to head a *possible* sequence at the end. */ + if (!table->lcl_head) + table->lcl_head = info; + break; + } + else if (!table->lcl_head->prev_line + && table->lcl_head->address > address) + { + /* Abnormal but easy: lcl_head is 1) at the *end* of the line + list and 2) the head of 'info'. */ + info->prev_line = NULL; + table->lcl_head->prev_line = info; + break; + } + else if (table->lcl_head->prev_line + && table->lcl_head->address > address + && address >= table->lcl_head->prev_line->address) + { + /* Abnormal but easy: lcl_head is 1) in the *middle* of the line + list and 2) the head of 'info'. */ + info->prev_line = table->lcl_head->prev_line; + table->lcl_head->prev_line = info; + break; + } + else + { + /* Abnormal and hard: Neither 'last_line' nor 'lcl_head' are valid + heads for 'info'. Reset 'lcl_head' and repeat. */ + struct line_info* li2 = table->last_line; /* always non-NULL */ + struct line_info* li1 = li2->prev_line; + + while (li1) + { + if (li2->address > address && address >= li1->address) + break; + + li2 = li1; /* always non-NULL */ + li1 = li1->prev_line; + } + table->lcl_head = li2; + } + + /* Set member data of 'info'. */ + info->address = address; + info->line = line; + info->column = column; + info->end_sequence = end_sequence; + + amt = strlen (filename); + if (amt) + { + info->filename = bfd_alloc (table->abfd, amt + 1); + if (info->filename) + strcpy (info->filename, filename); + } + else + info->filename = NULL; +} + +/* Extract a fully qualified filename from a line info table. + The returned string has been malloc'ed and it is the caller's + responsibility to free it. */ + +static char * +concat_filename (table, file) + struct line_info_table* table; + unsigned int file; +{ + char* filename; + + if (file - 1 >= table->num_files) + { + (*_bfd_error_handler) + (_("Dwarf Error: mangled line number section (bad file number).")); + return strdup (""); + } + + filename = table->files[file - 1].name; + + if (! IS_ABSOLUTE_PATH (filename)) + { + char* dirname = (table->files[file - 1].dir + ? table->dirs[table->files[file - 1].dir - 1] + : table->comp_dir); + + /* Not all tools set DW_AT_comp_dir, so dirname may be unknown. + The best we can do is return the filename part. */ + if (dirname != NULL) + { + unsigned int len = strlen (dirname) + strlen (filename) + 2; + char * name; + + name = bfd_malloc (len); + if (name) + sprintf (name, "%s/%s", dirname, filename); + return name; + } + } + + return strdup (filename); +} + +static void +arange_add (unit, low_pc, high_pc) + struct comp_unit *unit; + bfd_vma low_pc; + bfd_vma high_pc; +{ + struct arange *arange; + + /* First see if we can cheaply extend an existing range. */ + arange = &unit->arange; + + do + { + if (low_pc == arange->high) + { + arange->high = high_pc; + return; + } + if (high_pc == arange->low) + { + arange->low = low_pc; + return; + } + arange = arange->next; + } + while (arange); + + if (unit->arange.high == 0) + { + /* This is the first address range: store it in unit->arange. */ + unit->arange.next = 0; + unit->arange.low = low_pc; + unit->arange.high = high_pc; + return; + } + + /* Need to allocate a new arange and insert it into the arange list. */ + arange = (struct arange *) + bfd_zalloc (unit->abfd, (bfd_size_type) sizeof (*arange)); + arange->low = low_pc; + arange->high = high_pc; + + arange->next = unit->arange.next; + unit->arange.next = arange; +} + +/* Decode the line number information for UNIT. */ + +static struct line_info_table* +decode_line_info (unit, stash) + struct comp_unit *unit; + struct dwarf2_debug *stash; +{ + bfd *abfd = unit->abfd; + struct line_info_table* table; + char *line_ptr; + char *line_end; + struct line_head lh; + unsigned int i, bytes_read, offset_size; + char *cur_file, *cur_dir; + unsigned char op_code, extended_op, adj_opcode; + bfd_size_type amt; + + if (! stash->dwarf_line_buffer) + { + asection *msec; + + msec = bfd_get_section_by_name (abfd, ".debug_line"); + if (! msec) + { + (*_bfd_error_handler) (_("Dwarf Error: Can't find .debug_line section.")); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + stash->dwarf_line_size = msec->_raw_size; + stash->dwarf_line_buffer + = bfd_simple_get_relocated_section_contents (abfd, msec, NULL, + stash->syms); + if (! stash->dwarf_line_buffer) + return 0; + } + + /* It is possible to get a bad value for the line_offset. Validate + it here so that we won't get a segfault below. */ + if (unit->line_offset >= stash->dwarf_line_size) + { + (*_bfd_error_handler) (_("Dwarf Error: Line offset (%lu) greater than or equal to .debug_line size (%lu)."), + unit->line_offset, stash->dwarf_line_size); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + amt = sizeof (struct line_info_table); + table = (struct line_info_table*) bfd_alloc (abfd, amt); + table->abfd = abfd; + table->comp_dir = unit->comp_dir; + + table->num_files = 0; + table->files = NULL; + + table->num_dirs = 0; + table->dirs = NULL; + + table->files = NULL; + table->last_line = NULL; + table->lcl_head = NULL; + + line_ptr = stash->dwarf_line_buffer + unit->line_offset; + + /* Read in the prologue. */ + lh.total_length = read_4_bytes (abfd, line_ptr); + line_ptr += 4; + offset_size = 4; + if (lh.total_length == 0xffffffff) + { + lh.total_length = read_8_bytes (abfd, line_ptr); + 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); + line_ptr += 4; + offset_size = 8; + } + line_end = line_ptr + lh.total_length; + lh.version = read_2_bytes (abfd, line_ptr); + line_ptr += 2; + if (offset_size == 4) + lh.prologue_length = read_4_bytes (abfd, line_ptr); + else + lh.prologue_length = read_8_bytes (abfd, line_ptr); + line_ptr += offset_size; + lh.minimum_instruction_length = read_1_byte (abfd, line_ptr); + line_ptr += 1; + lh.default_is_stmt = read_1_byte (abfd, line_ptr); + line_ptr += 1; + lh.line_base = read_1_signed_byte (abfd, line_ptr); + line_ptr += 1; + lh.line_range = read_1_byte (abfd, line_ptr); + line_ptr += 1; + lh.opcode_base = read_1_byte (abfd, line_ptr); + line_ptr += 1; + amt = lh.opcode_base * sizeof (unsigned char); + lh.standard_opcode_lengths = (unsigned char *) bfd_alloc (abfd, amt); + + lh.standard_opcode_lengths[0] = 1; + + for (i = 1; i < lh.opcode_base; ++i) + { + lh.standard_opcode_lengths[i] = read_1_byte (abfd, line_ptr); + line_ptr += 1; + } + + /* Read directory table. */ + while ((cur_dir = read_string (abfd, line_ptr, &bytes_read)) != NULL) + { + line_ptr += bytes_read; + + if ((table->num_dirs % DIR_ALLOC_CHUNK) == 0) + { + amt = table->num_dirs + DIR_ALLOC_CHUNK; + amt *= sizeof (char *); + table->dirs = (char **) bfd_realloc (table->dirs, amt); + if (! table->dirs) + return 0; + } + + table->dirs[table->num_dirs++] = cur_dir; + } + + line_ptr += bytes_read; + + /* Read file name table. */ + while ((cur_file = read_string (abfd, line_ptr, &bytes_read)) != NULL) + { + line_ptr += bytes_read; + + if ((table->num_files % FILE_ALLOC_CHUNK) == 0) + { + amt = table->num_files + FILE_ALLOC_CHUNK; + amt *= sizeof (struct fileinfo); + table->files = (struct fileinfo *) bfd_realloc (table->files, amt); + if (! table->files) + return 0; + } + + table->files[table->num_files].name = cur_file; + table->files[table->num_files].dir = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + table->files[table->num_files].time = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + table->files[table->num_files].size = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + table->num_files++; + } + + line_ptr += bytes_read; + + /* Read the statement sequences until there's nothing left. */ + while (line_ptr < line_end) + { + /* State machine registers. */ + bfd_vma address = 0; + char * filename = concat_filename (table, 1); + unsigned int line = 1; + unsigned int column = 0; + int is_stmt = lh.default_is_stmt; + int basic_block = 0; + int end_sequence = 0; + /* eraxxon@alumni.rice.edu: Against the DWARF2 specs, some + compilers generate address sequences that are wildly out of + order using DW_LNE_set_address (e.g. Intel C++ 6.0 compiler + for ia64-Linux). Thus, to determine the low and high + address, we must compare on every DW_LNS_copy, etc. */ + bfd_vma low_pc = 0; + bfd_vma high_pc = 0; + + /* Decode the table. */ + while (! end_sequence) + { + op_code = read_1_byte (abfd, line_ptr); + line_ptr += 1; + + if (op_code >= lh.opcode_base) + { + /* Special operand. */ + adj_opcode = op_code - lh.opcode_base; + address += (adj_opcode / lh.line_range) + * lh.minimum_instruction_length; + line += lh.line_base + (adj_opcode % lh.line_range); + /* Append row to matrix using current values. */ + add_line_info (table, address, filename, line, column, 0); + basic_block = 1; + if (low_pc == 0 || address < low_pc) + low_pc = address; + if (address > high_pc) + high_pc = address; + } + else switch (op_code) + { + case DW_LNS_extended_op: + /* Ignore length. */ + line_ptr += 1; + extended_op = read_1_byte (abfd, line_ptr); + line_ptr += 1; + + switch (extended_op) + { + case DW_LNE_end_sequence: + end_sequence = 1; + add_line_info (table, address, filename, line, column, + end_sequence); + if (low_pc == 0 || address < low_pc) + low_pc = address; + if (address > high_pc) + high_pc = address; + arange_add (unit, low_pc, high_pc); + break; + case DW_LNE_set_address: + address = read_address (unit, line_ptr); + line_ptr += unit->addr_size; + break; + case DW_LNE_define_file: + cur_file = read_string (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + if ((table->num_files % FILE_ALLOC_CHUNK) == 0) + { + amt = table->num_files + FILE_ALLOC_CHUNK; + amt *= sizeof (struct fileinfo); + table->files = + (struct fileinfo *) bfd_realloc (table->files, amt); + if (! table->files) + return 0; + } + table->files[table->num_files].name = cur_file; + table->files[table->num_files].dir = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + table->files[table->num_files].time = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + table->files[table->num_files].size = + read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + table->num_files++; + break; + default: + (*_bfd_error_handler) (_("Dwarf Error: mangled line number section.")); + bfd_set_error (bfd_error_bad_value); + return 0; + } + break; + case DW_LNS_copy: + add_line_info (table, address, filename, line, column, 0); + basic_block = 0; + if (low_pc == 0 || address < low_pc) + low_pc = address; + if (address > high_pc) + high_pc = address; + break; + case DW_LNS_advance_pc: + address += lh.minimum_instruction_length + * read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + break; + case DW_LNS_advance_line: + line += read_signed_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + break; + case DW_LNS_set_file: + { + unsigned int file; + + /* The file and directory tables are 0 + based, the references are 1 based. */ + file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + if (filename) + free (filename); + filename = concat_filename (table, file); + break; + } + case DW_LNS_set_column: + column = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + line_ptr += bytes_read; + break; + case DW_LNS_negate_stmt: + is_stmt = (!is_stmt); + break; + case DW_LNS_set_basic_block: + basic_block = 1; + break; + case DW_LNS_const_add_pc: + address += lh.minimum_instruction_length + * ((255 - lh.opcode_base) / lh.line_range); + break; + case DW_LNS_fixed_advance_pc: + address += read_2_bytes (abfd, line_ptr); + line_ptr += 2; + break; + default: + { + int i; + + /* 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); + line_ptr += bytes_read; + } + } + } + } + + if (filename) + free (filename); + } + + return table; +} + +/* 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. */ + +static bfd_boolean +lookup_address_in_line_info_table (table, addr, function, filename_ptr, + linenumber_ptr) + struct line_info_table* table; + bfd_vma addr; + struct funcinfo *function; + const char **filename_ptr; + unsigned int *linenumber_ptr; +{ + /* Note: table->last_line should be a descendingly sorted list. */ + struct line_info* next_line = table->last_line; + struct line_info* each_line = NULL; + *filename_ptr = NULL; + + if (!next_line) + return FALSE; + + each_line = next_line->prev_line; + + /* Check for large addresses */ + if (addr > next_line->address) + each_line = NULL; /* ensure we skip over the normal case */ + + /* Normal case: search the list; save */ + while (each_line && next_line) + { + /* If we have an address match, save this info. This allows us + to return as good as results as possible for strange debugging + info. */ + bfd_boolean addr_match = FALSE; + if (each_line->address <= addr && addr <= next_line->address) + { + addr_match = TRUE; + + /* If this line appears to span functions, and addr is in the + later function, return the first line of that function instead + of the last line of the earlier one. This check is for GCC + 2.95, which emits the first line number for a function late. */ + if (function != NULL + && each_line->address < function->low + && next_line->address > function->low) + { + *filename_ptr = next_line->filename; + *linenumber_ptr = next_line->line; + } + else + { + *filename_ptr = each_line->filename; + *linenumber_ptr = each_line->line; + } + } + + if (addr_match && !each_line->end_sequence) + return TRUE; /* we have definitely found what we want */ + + next_line = each_line; + each_line = each_line->prev_line; + } + + /* At this point each_line is NULL but next_line is not. If we found + a candidate end-of-sequence point in the loop above, we can return + that (compatibility with a bug in the Intel compiler); otherwise, + assuming that we found the containing function for this address in + this compilation unit, return the first line we have a number for + (compatibility with GCC 2.95). */ + if (*filename_ptr == NULL && function != NULL) + { + *filename_ptr = next_line->filename; + *linenumber_ptr = next_line->line; + return TRUE; + } + + return FALSE; +} + +/* Function table functions. */ + +/* If ADDR is within TABLE, set FUNCTIONNAME_PTR, and return TRUE. */ + +static bfd_boolean +lookup_address_in_function_table (table, addr, function_ptr, + functionname_ptr) + struct funcinfo* table; + bfd_vma addr; + struct funcinfo** function_ptr; + const char **functionname_ptr; +{ + struct funcinfo* each_func; + + for (each_func = table; + each_func; + each_func = each_func->prev_func) + { + if (addr >= each_func->low && addr < each_func->high) + { + *functionname_ptr = each_func->name; + *function_ptr = each_func; + return TRUE; + } + } + + return FALSE; +} + +/* DWARF2 Compilation unit functions. */ + +/* Scan over each die in a comp. unit looking for functions to add + to the function table. */ + +static bfd_boolean +scan_unit_for_functions (unit) + struct comp_unit *unit; +{ + bfd *abfd = unit->abfd; + char *info_ptr = unit->first_child_die_ptr; + int nesting_level = 1; + + while (nesting_level) + { + unsigned int abbrev_number, bytes_read, i; + struct abbrev_info *abbrev; + struct attribute attr; + struct funcinfo *func; + char* name = 0; + + abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + + if (! abbrev_number) + { + nesting_level--; + continue; + } + + abbrev = lookup_abbrev (abbrev_number,unit->abbrevs); + if (! abbrev) + { + (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."), + abbrev_number); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + if (abbrev->tag == DW_TAG_subprogram) + { + bfd_size_type amt = sizeof (struct funcinfo); + func = (struct funcinfo *) bfd_zalloc (abfd, amt); + func->prev_func = unit->function_table; + unit->function_table = func; + } + else + func = NULL; + + for (i = 0; i < abbrev->num_attrs; ++i) + { + info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); + + if (func) + { + switch (attr.name) + { + case DW_AT_name: + + name = DW_STRING (&attr); + + /* Prefer DW_AT_MIPS_linkage_name over DW_AT_name. */ + if (func->name == NULL) + func->name = DW_STRING (&attr); + break; + + case DW_AT_MIPS_linkage_name: + func->name = DW_STRING (&attr); + break; + + case DW_AT_low_pc: + func->low = DW_ADDR (&attr); + break; + + case DW_AT_high_pc: + func->high = DW_ADDR (&attr); + break; + + default: + break; + } + } + else + { + switch (attr.name) + { + case DW_AT_name: + name = DW_STRING (&attr); + break; + + default: + break; + } + } + } + + if (abbrev->has_children) + nesting_level++; + } + + return TRUE; +} + +/* Parse a DWARF2 compilation unit starting at INFO_PTR. This + includes the compilation unit header that proceeds the DIE's, but + does not include the length field that preceeds each compilation + unit header. END_PTR points one past the end of this comp unit. + OFFSET_SIZE is the size of DWARF2 offsets (either 4 or 8 bytes). + + This routine does not read the whole compilation unit; only enough + to get to the line number information for the compilation unit. */ + +static struct comp_unit * +parse_comp_unit (abfd, stash, unit_length, offset_size) + bfd* abfd; + struct dwarf2_debug *stash; + bfd_vma unit_length; + unsigned int offset_size; +{ + struct comp_unit* unit; + unsigned int version; + bfd_vma abbrev_offset = 0; + unsigned int addr_size; + struct abbrev_info** abbrevs; + unsigned int abbrev_number, bytes_read, i; + struct abbrev_info *abbrev; + struct attribute attr; + char *info_ptr = stash->info_ptr; + char *end_ptr = info_ptr + unit_length; + bfd_size_type amt; + + version = read_2_bytes (abfd, info_ptr); + info_ptr += 2; + BFD_ASSERT (offset_size == 4 || offset_size == 8); + if (offset_size == 4) + abbrev_offset = read_4_bytes (abfd, info_ptr); + else + abbrev_offset = read_8_bytes (abfd, info_ptr); + info_ptr += offset_size; + addr_size = read_1_byte (abfd, info_ptr); + info_ptr += 1; + + if (version != 2) + { + (*_bfd_error_handler) (_("Dwarf Error: found dwarf version '%u', this reader only handles version 2 information."), version); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + if (addr_size > sizeof (bfd_vma)) + { + (*_bfd_error_handler) (_("Dwarf Error: found address size '%u', this reader can not handle sizes greater than '%u'."), + addr_size, + (unsigned int) sizeof (bfd_vma)); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + if (addr_size != 2 && addr_size != 4 && addr_size != 8) + { + (*_bfd_error_handler) ("Dwarf Error: found address size '%u', this reader can only handle address sizes '2', '4' and '8'.", addr_size); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + /* Read the abbrevs for this compilation unit into a table. */ + abbrevs = read_abbrevs (abfd, abbrev_offset, stash); + if (! abbrevs) + return 0; + + abbrev_number = read_unsigned_leb128 (abfd, info_ptr, &bytes_read); + info_ptr += bytes_read; + if (! abbrev_number) + { + (*_bfd_error_handler) (_("Dwarf Error: Bad abbrev number: %u."), + abbrev_number); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + abbrev = lookup_abbrev (abbrev_number, abbrevs); + if (! abbrev) + { + (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."), + abbrev_number); + bfd_set_error (bfd_error_bad_value); + return 0; + } + + amt = sizeof (struct comp_unit); + unit = (struct comp_unit*) bfd_zalloc (abfd, amt); + unit->abfd = abfd; + unit->addr_size = addr_size; + unit->offset_size = offset_size; + unit->abbrevs = abbrevs; + unit->end_ptr = end_ptr; + unit->stash = stash; + + for (i = 0; i < abbrev->num_attrs; ++i) + { + info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr); + + /* Store the data if it is of an attribute we want to keep in a + partial symbol table. */ + switch (attr.name) + { + case DW_AT_stmt_list: + unit->stmtlist = 1; + unit->line_offset = DW_UNSND (&attr); + break; + + case DW_AT_name: + unit->name = DW_STRING (&attr); + break; + + case DW_AT_low_pc: + unit->arange.low = DW_ADDR (&attr); + break; + + case DW_AT_high_pc: + unit->arange.high = DW_ADDR (&attr); + break; + + case DW_AT_comp_dir: + { + char* comp_dir = DW_STRING (&attr); + if (comp_dir) + { + /* Irix 6.2 native cc prepends .: to the compilation + directory, get rid of it. */ + char *cp = (char*) strchr (comp_dir, ':'); + + if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/') + comp_dir = cp + 1; + } + unit->comp_dir = comp_dir; + break; + } + + default: + break; + } + } + + unit->first_child_die_ptr = info_ptr; + return unit; +} + +/* Return TRUE if UNIT contains the address given by ADDR. */ + +static bfd_boolean +comp_unit_contains_address (unit, addr) + struct comp_unit* unit; + bfd_vma addr; +{ + struct arange *arange; + + if (unit->error) + return FALSE; + + arange = &unit->arange; + do + { + if (addr >= arange->low && addr < arange->high) + return TRUE; + arange = arange->next; + } + while (arange); + + return FALSE; +} + +/* 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 + to be filled in. + + Return TRUE if UNIT contains ADDR, and no errors were encountered; + FALSE otherwise. */ + +static bfd_boolean +comp_unit_find_nearest_line (unit, addr, filename_ptr, functionname_ptr, + linenumber_ptr, stash) + struct comp_unit* unit; + bfd_vma addr; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *linenumber_ptr; + struct dwarf2_debug *stash; +{ + bfd_boolean line_p; + bfd_boolean func_p; + struct funcinfo *function; + + if (unit->error) + return FALSE; + + if (! unit->line_table) + { + if (! unit->stmtlist) + { + unit->error = 1; + return FALSE; + } + + unit->line_table = decode_line_info (unit, stash); + + if (! unit->line_table) + { + unit->error = 1; + return FALSE; + } + + if (unit->first_child_die_ptr < unit->end_ptr + && ! scan_unit_for_functions (unit)) + { + unit->error = 1; + return FALSE; + } + } + + function = NULL; + func_p = lookup_address_in_function_table (unit->function_table, addr, + &function, functionname_ptr); + line_p = lookup_address_in_line_info_table (unit->line_table, addr, + function, filename_ptr, + linenumber_ptr); + return line_p || func_p; +} + +/* Locate a section in a BFD containing debugging info. The search starts + from the section after AFTER_SEC, or from the first section in the BFD if + AFTER_SEC is NULL. The search works by examining the names of the + sections. There are two permissiable names. The first is .debug_info. + This is the standard DWARF2 name. The second is a prefix .gnu.linkonce.wi. + This is a variation on the .debug_info section which has a checksum + describing the contents appended onto the name. This allows the linker to + identify and discard duplicate debugging sections for different + compilation units. */ +#define DWARF2_DEBUG_INFO ".debug_info" +#define GNU_LINKONCE_INFO ".gnu.linkonce.wi." + +static asection * +find_debug_info (abfd, after_sec) + bfd * abfd; + asection * after_sec; +{ + asection * msec; + + if (after_sec) + msec = after_sec->next; + else + msec = abfd->sections; + + while (msec) + { + if (strcmp (msec->name, DWARF2_DEBUG_INFO) == 0) + return msec; + + if (strncmp (msec->name, GNU_LINKONCE_INFO, strlen (GNU_LINKONCE_INFO)) == 0) + return msec; + + msec = msec->next; + } + + return NULL; +} + +/* The DWARF2 version of find_nearest line. Return TRUE if the line + is found without error. ADDR_SIZE is the number of bytes in the + initial .debug_info length field and in the abbreviation offset. + You may use zero to indicate that the default value should be + used. */ + +bfd_boolean +_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, + linenumber_ptr, addr_size, pinfo) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *linenumber_ptr; + unsigned int addr_size; + PTR *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, + lookup the address, and return the line number info. If no, go + on to the next compilation unit. + + We keep a list of all the previously read compilation units, and + a pointer to the next un-read compilation unit. Check the + previously read units before reading more. */ + struct dwarf2_debug *stash = (struct dwarf2_debug *) *pinfo; + + /* What address are we looking for? */ + bfd_vma addr = offset + section->vma; + + struct comp_unit* each; + + *filename_ptr = NULL; + *functionname_ptr = NULL; + *linenumber_ptr = 0; + + /* The DWARF2 spec says that the initial length field, and the + offset of the abbreviation table, should both be 4-byte values. + However, some compilers do things differently. */ + if (addr_size == 0) + addr_size = 4; + BFD_ASSERT (addr_size == 4 || addr_size == 8); + + if (! stash) + { + bfd_size_type total_size; + asection *msec; + bfd_size_type amt = sizeof (struct dwarf2_debug); + + stash = (struct dwarf2_debug*) bfd_zalloc (abfd, amt); + if (! stash) + return FALSE; + + *pinfo = (PTR) stash; + + msec = find_debug_info (abfd, NULL); + if (! msec) + /* No dwarf2 info. Note that at this point the stash + has been allocated, but contains zeros, this lets + future calls to this function fail quicker. */ + return FALSE; + + /* There can be more than one DWARF2 info section in a BFD these days. + Read them all in and produce one large stash. We do this in two + passes - in the first pass we just accumulate the section sizes. + In the second pass we read in the section's contents. The allows + us to avoid reallocing the data as we add sections to the stash. */ + for (total_size = 0; msec; msec = find_debug_info (abfd, msec)) + total_size += msec->_raw_size; + + stash->info_ptr = (char *) bfd_alloc (abfd, total_size); + if (stash->info_ptr == NULL) + return FALSE; + + stash->info_ptr_end = stash->info_ptr; + + for (msec = find_debug_info (abfd, NULL); + msec; + msec = find_debug_info (abfd, msec)) + { + bfd_size_type size; + bfd_size_type start; + + size = msec->_raw_size; + if (size == 0) + continue; + + start = stash->info_ptr_end - stash->info_ptr; + + if ((bfd_simple_get_relocated_section_contents + (abfd, msec, stash->info_ptr + start, symbols)) == NULL) + continue; + + stash->info_ptr_end = stash->info_ptr + start + size; + } + + BFD_ASSERT (stash->info_ptr_end == stash->info_ptr + total_size); + + stash->sec = find_debug_info (abfd, NULL); + stash->sec_info_ptr = stash->info_ptr; + stash->syms = symbols; + } + + /* A null info_ptr indicates that there is no dwarf2 info + (or that an error occured while setting up the stash). */ + if (! stash->info_ptr) + return FALSE; + + /* Check the previously read comp. units first. */ + for (each = stash->all_comp_units; each; each = each->next_unit) + if (comp_unit_contains_address (each, addr)) + return comp_unit_find_nearest_line (each, addr, filename_ptr, + functionname_ptr, linenumber_ptr, + stash); + + /* Read each remaining comp. units checking each as they are read. */ + while (stash->info_ptr < stash->info_ptr_end) + { + bfd_vma length; + bfd_boolean found; + unsigned int offset_size = addr_size; + + length = read_4_bytes (abfd, stash->info_ptr); + /* 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 (abfd, stash->info_ptr + 4); + stash->info_ptr += 12; + } + /* A zero length is the IRIX way of indicating 64-bit offsets, + mostly because the 64-bit length will generally fit in 32 + bits, and the endianness helps. */ + else if (length == 0) + { + offset_size = 8; + length = read_4_bytes (abfd, stash->info_ptr + 4); + stash->info_ptr += 8; + } + /* In the absence of the hints above, we assume addr_size-sized + offsets, for backward-compatibility with pre-DWARF3 64-bit + platforms. */ + else if (addr_size == 8) + { + length = read_8_bytes (abfd, stash->info_ptr); + stash->info_ptr += 8; + } + else + stash->info_ptr += 4; + + if (length > 0) + { + each = parse_comp_unit (abfd, stash, length, offset_size); + stash->info_ptr += length; + + if ((bfd_vma) (stash->info_ptr - stash->sec_info_ptr) + == stash->sec->_raw_size) + { + stash->sec = find_debug_info (abfd, stash->sec); + stash->sec_info_ptr = stash->info_ptr; + } + + if (each) + { + each->next_unit = stash->all_comp_units; + stash->all_comp_units = each; + + /* DW_AT_low_pc and DW_AT_high_pc are optional for + compilation units. If we don't have them (i.e., + unit->high == 0), we need to consult the line info + table to see if a compilation unit contains the given + address. */ + if (each->arange.high > 0) + { + if (comp_unit_contains_address (each, addr)) + return comp_unit_find_nearest_line (each, addr, + filename_ptr, + functionname_ptr, + linenumber_ptr, + stash); + } + else + { + found = comp_unit_find_nearest_line (each, addr, + filename_ptr, + functionname_ptr, + linenumber_ptr, + stash); + if (found) + return TRUE; + } + } + } + } + + return FALSE; +} diff --git a/contrib/binutils-2.14/bfd/elf-bfd.h b/contrib/binutils-2.14/bfd/elf-bfd.h new file mode 100644 index 0000000000..f15353ce2d --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf-bfd.h @@ -0,0 +1,1664 @@ +/* BFD back-end data structures for ELF files. + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _LIBELF_H_ +#define _LIBELF_H_ 1 + +#include "elf/common.h" +#include "elf/internal.h" +#include "elf/external.h" +#include "bfdlink.h" + +/* 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. */ +#define NUM_SHDR_ENTRIES(shdr) ((shdr)->sh_size / (shdr)->sh_entsize) + +/* If size isn't specified as 64 or 32, NAME macro should fail. */ +/* Do not "beautify" the CONCAT* macro args. Traditional C will not + remove whitespace added here, and thus will fail to concatenate + the tokens. */ +#ifndef NAME +#if ARCH_SIZE==64 +#define NAME(x,y) CONCAT4 (x,64,_,y) +#endif +#if ARCH_SIZE==32 +#define NAME(x,y) CONCAT4 (x,32,_,y) +#endif +#endif + +#ifndef NAME +#define NAME(x,y) CONCAT4 (x,NOSIZE,_,y) +#endif + +#define ElfNAME(X) NAME(Elf,X) +#define elfNAME(X) NAME(elf,X) + +/* Information held for an ELF symbol. The first field is the + corresponding asymbol. Every symbol is an ELF file is actually a + pointer to this structure, although it is often handled as a + pointer to an asymbol. */ + +typedef struct +{ + /* The BFD symbol. */ + asymbol symbol; + /* ELF symbol information. */ + Elf_Internal_Sym internal_elf_sym; + /* Backend specific information. */ + union + { + unsigned int hppa_arg_reloc; + PTR mips_extr; + PTR any; + } + tc_data; + + /* Version information. This is from an Elf_Internal_Versym + structure in a SHT_GNU_versym section. It is zero if there is no + version information. */ + unsigned short version; + +} elf_symbol_type; + +struct elf_strtab_hash; +struct got_entry; +struct plt_entry; + +/* ELF linker hash table entries. */ + +struct elf_link_hash_entry +{ + struct bfd_link_hash_entry root; + + /* Symbol index in output file. This is initialized to -1. It is + set to -2 if the symbol is used by a reloc. */ + long indx; + + /* Symbol index as a dynamic symbol. Initialized to -1, and remains + -1 if this is not a dynamic symbol. */ + /* ??? Note that this is consistently used as a synonym for tests + against whether we can perform various simplifying transformations + to the code. (E.g. changing a pc-relative jump to a PLT entry + into a pc-relative jump to the target function.) That test, which + is often relatively complex, and someplaces wrong or incomplete, + should really be replaced by a predicate in elflink.c. + + End result: this field -1 does not indicate that the symbol is + not in the dynamic symbol table, but rather that the symbol is + not visible outside this DSO. */ + long dynindx; + + /* String table index in .dynstr if this is a dynamic symbol. */ + unsigned long dynstr_index; + + /* Hash value of the name computed using the ELF hash function. */ + unsigned long elf_hash_value; + + /* If this is a weak defined symbol from a dynamic object, this + field points to a defined symbol with the same value, if there is + one. Otherwise it is NULL. */ + struct elf_link_hash_entry *weakdef; + + /* If this symbol is used in the linker created sections, the processor + specific backend uses this field to map the field into the offset + from the beginning of the section. */ + struct elf_linker_section_pointers *linker_section_pointer; + + /* Version information. */ + union + { + /* This field is used for a symbol which is not defined in a + regular object. It points to the version information read in + from the dynamic object. */ + Elf_Internal_Verdef *verdef; + /* This field is used for a symbol which is defined in a regular + object. It is set up in size_dynamic_sections. It points to + the version information we should write out for this symbol. */ + struct bfd_elf_version_tree *vertree; + } verinfo; + + /* Virtual table entry use information. This array is nominally of size + size/sizeof(target_void_pointer), though we have to be able to assume + and track a size while the symbol is still undefined. It is indexed + via offset/sizeof(target_void_pointer). */ + size_t vtable_entries_size; + bfd_boolean *vtable_entries_used; + + /* Virtual table derivation info. */ + struct elf_link_hash_entry *vtable_parent; + + /* If this symbol requires an entry in the global offset table, the + processor specific backend uses this field to track usage and + final offset. Two schemes are supported: The first assumes that + a symbol may only have one GOT entry, and uses REFCOUNT until + size_dynamic_sections, at which point the contents of the .got is + fixed. Afterward, if OFFSET is -1, then the symbol does not + require a global offset table entry. The second scheme allows + multiple GOT entries per symbol, managed via a linked list + pointed to by GLIST. */ + union gotplt_union + { + bfd_signed_vma refcount; + bfd_vma offset; + struct got_entry *glist; + struct plt_entry *plist; + } got; + + /* Same, but tracks a procedure linkage table entry. */ + union gotplt_union plt; + + /* Symbol size. */ + bfd_size_type size; + + /* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */ + char type; + + /* Symbol st_other value, symbol visibility. */ + unsigned char other; + + /* Some flags; legal values follow. */ + unsigned short elf_link_hash_flags; + /* Symbol is referenced by a non-shared object. */ +#define ELF_LINK_HASH_REF_REGULAR 01 + /* Symbol is defined by a non-shared object. */ +#define ELF_LINK_HASH_DEF_REGULAR 02 + /* Symbol is referenced by a shared object. */ +#define ELF_LINK_HASH_REF_DYNAMIC 04 + /* Symbol is defined by a shared object. */ +#define ELF_LINK_HASH_DEF_DYNAMIC 010 + /* Symbol has a non-weak reference from a non-shared object. */ +#define ELF_LINK_HASH_REF_REGULAR_NONWEAK 020 + /* Dynamic symbol has been adjustd. */ +#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 040 + /* Symbol needs a copy reloc. */ +#define ELF_LINK_HASH_NEEDS_COPY 0100 + /* Symbol needs a procedure linkage table entry. */ +#define ELF_LINK_HASH_NEEDS_PLT 0200 + /* Symbol appears in a non-ELF input file. */ +#define ELF_LINK_NON_ELF 0400 + /* Symbol should be marked as hidden in the version information. */ +#define ELF_LINK_HIDDEN 01000 + /* Symbol was forced to local scope due to a version script file. */ +#define ELF_LINK_FORCED_LOCAL 02000 + /* Symbol was marked during garbage collection. */ +#define ELF_LINK_HASH_MARK 04000 + /* Symbol is referenced by a non-GOT/non-PLT relocation. This is + not currently set by all the backends. */ +#define ELF_LINK_NON_GOT_REF 010000 + /* Symbol has a definition in a shared object. */ +#define ELF_LINK_DYNAMIC_DEF 020000 + /* Symbol is weak in all shared objects. */ +#define ELF_LINK_DYNAMIC_WEAK 040000 +}; + +/* Records local symbols to be emitted in the dynamic symbol table. */ + +struct elf_link_local_dynamic_entry +{ + struct elf_link_local_dynamic_entry *next; + + /* The input bfd this symbol came from. */ + bfd *input_bfd; + + /* The index of the local symbol being copied. */ + long input_indx; + + /* The index in the outgoing dynamic symbol table. */ + long dynindx; + + /* A copy of the input symbol. */ + Elf_Internal_Sym isym; +}; + +struct elf_link_loaded_list +{ + struct elf_link_loaded_list *next; + bfd *abfd; +}; + +/* Structures used by the eh_frame optimization code. */ +struct cie_header +{ + unsigned int length; + unsigned int id; +}; + +struct cie +{ + struct cie_header hdr; + unsigned char version; + unsigned char augmentation[20]; + unsigned int code_align; + int data_align; + unsigned int ra_column; + unsigned int augmentation_size; + struct elf_link_hash_entry *personality; + unsigned char per_encoding; + unsigned char lsda_encoding; + unsigned char fde_encoding; + unsigned char initial_insn_length; + unsigned char make_relative; + unsigned char make_lsda_relative; + unsigned char initial_instructions[50]; +}; + +struct eh_cie_fde +{ + unsigned int offset; + unsigned int size; + asection *sec; + unsigned int new_offset; + unsigned char fde_encoding; + unsigned char lsda_encoding; + unsigned char lsda_offset; + unsigned char cie : 1; + unsigned char removed : 1; + unsigned char make_relative : 1; + unsigned char make_lsda_relative : 1; + unsigned char per_encoding_relative : 1; +}; + +struct eh_frame_sec_info +{ + unsigned int count; + unsigned int alloced; + struct eh_cie_fde entry[1]; +}; + +struct eh_frame_array_ent +{ + bfd_vma initial_loc; + bfd_vma fde; +}; + +struct eh_frame_hdr_info +{ + struct cie last_cie; + asection *last_cie_sec; + asection *hdr_sec; + unsigned int last_cie_offset; + unsigned int fde_count, array_count; + struct eh_frame_array_ent *array; + /* 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; +}; + +/* Cached start, size and alignment of PT_TLS segment. */ +struct elf_link_tls_segment +{ + bfd_vma start; + bfd_size_type size; + unsigned int align; +}; + +/* ELF linker hash table. */ + +struct elf_link_hash_table +{ + struct bfd_link_hash_table root; + + /* Whether we have created the special dynamic sections required + when linking against or generating a shared object. */ + bfd_boolean dynamic_sections_created; + + /* The BFD used to hold special sections created by the linker. + This will be the first BFD found which requires these sections to + be created. */ + bfd *dynobj; + + /* The value to use when initialising got.refcount/offset and + plt.refcount/offset in an elf_link_hash_entry. Set to zero when + the values are refcounts. Set to init_offset in + size_dynamic_sections when the values may be offsets. */ + union gotplt_union init_refcount; + + /* The value to use for got.refcount/offset and plt.refcount/offset + when the values may be offsets. Normally (bfd_vma) -1. */ + union gotplt_union init_offset; + + /* The number of symbols found in the link which must be put into + the .dynsym section. */ + bfd_size_type dynsymcount; + + /* The string table of dynamic symbols, which becomes the .dynstr + section. */ + struct elf_strtab_hash *dynstr; + + /* 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; + + /* A linked list of DT_NEEDED names found in dynamic objects + included in the link. */ + struct bfd_link_needed_list *needed; + + /* The _GLOBAL_OFFSET_TABLE_ symbol. */ + struct elf_link_hash_entry *hgot; + + /* A pointer to information used to link stabs in sections. */ + PTR stab_info; + + /* A pointer to information used to merge SEC_MERGE sections. */ + PTR merge_info; + + /* Used by eh_frame code when editing .eh_frame. */ + struct eh_frame_hdr_info eh_info; + + /* A linked list of local symbols to be added to .dynsym. */ + struct elf_link_local_dynamic_entry *dynlocal; + + /* A linked list of DT_RPATH/DT_RUNPATH names found in dynamic + objects included in the link. */ + struct bfd_link_needed_list *runpath; + + /* Cached start, size and alignment of PT_TLS segment. */ + struct elf_link_tls_segment *tls_segment; + + /* A linked list of BFD's loaded in the link. */ + struct elf_link_loaded_list *loaded; +}; + +/* Look up an entry in an ELF linker hash table. */ + +#define elf_link_hash_lookup(table, string, create, copy, follow) \ + ((struct elf_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +/* Traverse an ELF linker hash table. */ + +#define elf_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (bfd_boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the ELF linker hash table from a link_info structure. */ + +#define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash)) + +/* Returns TRUE if the hash table is a struct elf_link_hash_table. */ +#define is_elf_hash_table(p) \ + ((p)->hash->type == bfd_link_elf_hash_table) + +/* Used by bfd_section_from_r_symndx to cache a small number of local + symbol to section mappings. */ +#define LOCAL_SYM_CACHE_SIZE 32 +struct sym_sec_cache +{ + bfd *abfd; + unsigned long indx[LOCAL_SYM_CACHE_SIZE]; + asection *sec[LOCAL_SYM_CACHE_SIZE]; +}; + +/* Constant information held for an ELF backend. */ + +struct elf_size_info { + unsigned char sizeof_ehdr, sizeof_phdr, sizeof_shdr; + unsigned char sizeof_rel, sizeof_rela, sizeof_sym, sizeof_dyn, sizeof_note; + + /* The size of entries in the .hash section. */ + unsigned char sizeof_hash_entry; + + /* The number of internal relocations to allocate per external + relocation entry. */ + unsigned char int_rels_per_ext_rel; + /* We use some fixed size arrays. This should be large enough to + handle all back-ends. */ +#define MAX_INT_RELS_PER_EXT_REL 3 + + unsigned char arch_size, file_align; + unsigned char elfclass, ev_current; + int (*write_out_phdrs) + PARAMS ((bfd *, const Elf_Internal_Phdr *, unsigned int)); + bfd_boolean (*write_shdrs_and_ehdr) + PARAMS ((bfd *)); + void (*write_relocs) + PARAMS ((bfd *, asection *, PTR)); + void (*swap_symbol_in) + PARAMS ((bfd *, const PTR, const PTR, Elf_Internal_Sym *)); + void (*swap_symbol_out) + PARAMS ((bfd *, const Elf_Internal_Sym *, PTR, PTR)); + bfd_boolean (*slurp_reloc_table) + PARAMS ((bfd *, asection *, asymbol **, bfd_boolean)); + long (*slurp_symbol_table) + PARAMS ((bfd *, asymbol **, bfd_boolean)); + void (*swap_dyn_in) + PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); + void (*swap_dyn_out) + PARAMS ((bfd *, const Elf_Internal_Dyn *, PTR)); + + /* This function is called to swap in a REL relocation. If an + external relocation corresponds to more than one internal + relocation, then all relocations are swapped in at once. */ + void (*swap_reloc_in) + PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); + + /* This function is called to swap out a REL relocation. */ + void (*swap_reloc_out) + PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); + + /* This function is called to swap in a RELA relocation. If an + external relocation corresponds to more than one internal + relocation, then all relocations are swapped in at once. */ + void (*swap_reloca_in) + PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); + + /* This function is called to swap out a RELA relocation. */ + void (*swap_reloca_out) + PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); +}; + +#define elf_symbol_from(ABFD,S) \ + (((S)->the_bfd->xvec->flavour == bfd_target_elf_flavour \ + && (S)->the_bfd->tdata.elf_obj_data != 0) \ + ? (elf_symbol_type *) (S) \ + : 0) + +enum elf_reloc_type_class { + reloc_class_normal, + reloc_class_relative, + reloc_class_plt, + reloc_class_copy +}; + +struct elf_reloc_cookie +{ + Elf_Internal_Rela *rels, *rel, *relend; + Elf_Internal_Sym *locsyms; + bfd *abfd; + size_t locsymcount; + size_t extsymoff; + struct elf_link_hash_entry **sym_hashes; + bfd_boolean bad_symtab; +}; + +/* The level of IRIX compatibility we're striving for. */ + +typedef enum { + ict_none, + ict_irix5, + ict_irix6 +} irix_compat_t; + +struct elf_backend_data +{ + /* The architecture for this backend. */ + enum bfd_architecture arch; + + /* The ELF machine code (EM_xxxx) for this backend. */ + int elf_machine_code; + + /* The maximum page size for this backend. */ + bfd_vma maxpagesize; + + /* A function to translate an ELF RELA relocation to a BFD arelent + structure. */ + void (*elf_info_to_howto) + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); + + /* A function to translate an ELF REL relocation to a BFD arelent + structure. */ + void (*elf_info_to_howto_rel) + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); + + /* A function to determine whether a symbol is global when + partitioning the symbol table into local and global symbols. + This should be NULL for most targets, in which case the correct + thing will be done. MIPS ELF, at least on the Irix 5, has + special requirements. */ + bfd_boolean (*elf_backend_sym_is_global) + PARAMS ((bfd *, asymbol *)); + + /* The remaining functions are hooks which are called only if they + are not NULL. */ + + /* A function to permit a backend specific check on whether a + particular BFD format is relevant for an object file, and to + permit the backend to set any global information it wishes. When + this is called elf_elfheader is set, but anything else should be + used with caution. If this returns FALSE, the check_format + routine will return a bfd_error_wrong_format error. */ + bfd_boolean (*elf_backend_object_p) + PARAMS ((bfd *)); + + /* A function to do additional symbol processing when reading the + ELF symbol table. This is where any processor-specific special + section indices are handled. */ + void (*elf_backend_symbol_processing) + PARAMS ((bfd *, asymbol *)); + + /* A function to do additional symbol processing after reading the + entire ELF symbol table. */ + bfd_boolean (*elf_backend_symbol_table_processing) + PARAMS ((bfd *, elf_symbol_type *, unsigned int)); + + /* A function to set the type of the info field. Processor-specific + types should be handled here. */ + int (*elf_backend_get_symbol_type) + PARAMS (( Elf_Internal_Sym *, int)); + + /* A function to do additional processing on the ELF section header + just before writing it out. This is used to set the flags and + type fields for some sections, or to actually write out data for + unusual sections. */ + bfd_boolean (*elf_backend_section_processing) + PARAMS ((bfd *, Elf_Internal_Shdr *)); + + /* A function to handle unusual section types when creating BFD + sections from ELF sections. */ + bfd_boolean (*elf_backend_section_from_shdr) + PARAMS ((bfd *, Elf_Internal_Shdr *, const char *)); + + /* A function to convert machine dependent section header flags to + BFD internal section header flags. */ + bfd_boolean (*elf_backend_section_flags) + PARAMS ((flagword *, Elf_Internal_Shdr *)); + + /* A function to handle unusual program segment types when creating BFD + sections from ELF program segments. */ + bfd_boolean (*elf_backend_section_from_phdr) + PARAMS ((bfd *, Elf_Internal_Phdr *, int)); + + /* A function to set up the ELF section header for a BFD section in + preparation for writing it out. This is where the flags and type + fields are set for unusual sections. */ + bfd_boolean (*elf_backend_fake_sections) + PARAMS ((bfd *, Elf_Internal_Shdr *, asection *)); + + /* A function to get the ELF section index for a BFD section. If + this returns TRUE, the section was found. If it is a normal ELF + section, *RETVAL should be left unchanged. If it is not a normal + ELF section *RETVAL should be set to the SHN_xxxx index. */ + bfd_boolean (*elf_backend_section_from_bfd_section) + PARAMS ((bfd *, asection *, int *retval)); + + /* If this field is not NULL, it is called by the add_symbols phase + of a link just before adding a symbol to the global linker hash + table. It may modify any of the fields as it wishes. If *NAME + is set to NULL, the symbol will be skipped rather than being + added to the hash table. This function is responsible for + handling all processor dependent symbol bindings and section + indices, and must set at least *FLAGS and *SEC for each processor + dependent case; failure to do so will cause a link error. */ + bfd_boolean (*elf_add_symbol_hook) + PARAMS ((bfd *abfd, struct bfd_link_info *info, + const Elf_Internal_Sym *, const char **name, + flagword *flags, asection **sec, bfd_vma *value)); + + /* If this field is not NULL, it is called by the elf_link_output_sym + phase of a link for each symbol which will appear in the object file. */ + bfd_boolean (*elf_backend_link_output_symbol_hook) + PARAMS ((bfd *, struct bfd_link_info *info, const char *, + Elf_Internal_Sym *, asection *)); + + /* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend + linker the first time it encounters a dynamic object in the link. + This function must create any sections required for dynamic + linking. The ABFD argument is a dynamic object. The .interp, + .dynamic, .dynsym, .dynstr, and .hash functions have already been + created, and this function may modify the section flags if + desired. This function will normally create the .got and .plt + sections, but different backends have different requirements. */ + bfd_boolean (*elf_backend_create_dynamic_sections) + PARAMS ((bfd *abfd, struct bfd_link_info *info)); + + /* The CHECK_RELOCS function is called by the add_symbols phase of + the ELF backend linker. It is called once for each section with + relocs of an object file, just after the symbols for the object + file have been added to the global linker hash table. The + function must look through the relocs and do any special handling + required. This generally means allocating space in the global + offset table, and perhaps allocating space for a reloc. The + relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. */ + bfd_boolean (*check_relocs) + PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o, + const Elf_Internal_Rela *relocs)); + + /* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend + linker for every symbol which is defined by a dynamic object and + referenced by a regular object. This is called after all the + input files have been seen, but before the SIZE_DYNAMIC_SECTIONS + function has been called. The hash table entry should be + bfd_link_hash_defined ore bfd_link_hash_defweak, and it should be + defined in a section from a dynamic object. Dynamic object + sections are not included in the final link, and this function is + responsible for changing the value to something which the rest of + the link can deal with. This will normally involve adding an + entry to the .plt or .got or some such section, and setting the + symbol to point to that. */ + bfd_boolean (*elf_backend_adjust_dynamic_symbol) + PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h)); + + /* The ALWAYS_SIZE_SECTIONS function is called by the backend linker + after all the linker input files have been seen but before the + section sizes have been set. This is called after + ADJUST_DYNAMIC_SYMBOL, but before SIZE_DYNAMIC_SECTIONS. */ + bfd_boolean (*elf_backend_always_size_sections) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); + + /* The SIZE_DYNAMIC_SECTIONS function is called by the ELF backend + linker after all the linker input files have been seen but before + the sections sizes have been set. This is called after + ADJUST_DYNAMIC_SYMBOL has been called on all appropriate symbols. + It is only called when linking against a dynamic object. It must + set the sizes of the dynamic sections, and may fill in their + contents as well. The generic ELF linker can handle the .dynsym, + .dynstr and .hash sections. This function must handle the + .interp section and any sections created by the + CREATE_DYNAMIC_SECTIONS entry point. */ + bfd_boolean (*elf_backend_size_dynamic_sections) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); + + /* The RELOCATE_SECTION function is called by the 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 + relocateable 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 relocateable 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. */ + bfd_boolean (*elf_backend_relocate_section) + PARAMS ((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)); + + /* The FINISH_DYNAMIC_SYMBOL function is called by the ELF backend + linker just before it writes a symbol out to the .dynsym section. + The processor backend may make any required adjustment to the + symbol. It may also take the opportunity to set contents of the + dynamic sections. Note that FINISH_DYNAMIC_SYMBOL is called on + all .dynsym symbols, while ADJUST_DYNAMIC_SYMBOL is only called + on those symbols which are defined by a dynamic object. */ + bfd_boolean (*elf_backend_finish_dynamic_symbol) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info, + struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)); + + /* The FINISH_DYNAMIC_SECTIONS function is called by the ELF backend + linker just before it writes all the dynamic sections out to the + output file. The FINISH_DYNAMIC_SYMBOL will have been called on + all dynamic symbols. */ + bfd_boolean (*elf_backend_finish_dynamic_sections) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); + + /* A function to do any beginning processing needed for the ELF file + before building the ELF headers and computing file positions. */ + void (*elf_backend_begin_write_processing) + PARAMS ((bfd *, struct bfd_link_info *)); + + /* A function to do any final processing needed for the ELF file + before writing it out. The LINKER argument is TRUE if this BFD + was created by the ELF backend linker. */ + void (*elf_backend_final_write_processing) + PARAMS ((bfd *, bfd_boolean linker)); + + /* This function is called by get_program_header_size. It should + return the number of additional program segments which this BFD + will need. It should return -1 on error. */ + int (*elf_backend_additional_program_headers) + PARAMS ((bfd *)); + + /* This function is called to modify an existing segment map in a + backend specific fashion. */ + bfd_boolean (*elf_backend_modify_segment_map) + PARAMS ((bfd *)); + + /* This function is called during section gc to discover the section a + particular relocation refers to. */ + asection * (*gc_mark_hook) + PARAMS ((asection *sec, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *h, Elf_Internal_Sym *)); + + /* This function, if defined, is called during the sweep phase of gc + in order that a backend might update any data structures it might + be maintaining. */ + bfd_boolean (*gc_sweep_hook) + PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o, + const Elf_Internal_Rela *relocs)); + + /* This function, if defined, is called after the ELF headers have + been created. This allows for things like the OS and ABI versions + to be changed. */ + void (*elf_backend_post_process_headers) + PARAMS ((bfd *, struct bfd_link_info *)); + + /* This function, if defined, prints a symbol to file and returns the + name of the symbol to be printed. It should return NULL to fall + back to default symbol printing. */ + const char *(*elf_backend_print_symbol_all) + PARAMS ((bfd *, PTR, asymbol *)); + + /* This function, if defined, is called after all local symbols and + global symbols converted to locals are emited into the symtab + section. It allows the backend to emit special global symbols + not handled in the hash table. */ + bfd_boolean (*elf_backend_output_arch_syms) + PARAMS ((bfd *, struct bfd_link_info *, PTR, + bfd_boolean (*) (PTR, const char *, Elf_Internal_Sym *, asection *))); + + /* Copy any information related to dynamic linking from a pre-existing + symbol to a newly created symbol. Also called to copy flags and + other back-end info to a weakdef, in which case the symbol is not + newly created and plt/got refcounts and dynamic indices should not + be copied. */ + void (*elf_backend_copy_indirect_symbol) + PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *, + struct elf_link_hash_entry *)); + + /* Modify any information related to dynamic linking such that the + symbol is not exported. */ + void (*elf_backend_hide_symbol) + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean)); + + /* Emit relocations. Overrides default routine for emitting relocs, + except during a relocatable link, or if all relocs are being emitted. */ + bfd_boolean (*elf_backend_emit_relocs) + PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *)); + + /* Count relocations. Not called for relocatable links + or if all relocs are being preserved in the output. */ + unsigned int (*elf_backend_count_relocs) + PARAMS ((asection *, Elf_Internal_Rela *)); + + /* This function, if defined, is called when an NT_PRSTATUS note is found + in a core file. */ + bfd_boolean (*elf_backend_grok_prstatus) + PARAMS ((bfd *, Elf_Internal_Note *)); + + /* This function, if defined, is called when an NT_PSINFO or NT_PRPSINFO + note is found in a core file. */ + bfd_boolean (*elf_backend_grok_psinfo) + PARAMS ((bfd *, Elf_Internal_Note *)); + + /* Functions to print VMAs. Special code to handle 64 bit ELF files. */ + void (* elf_backend_sprintf_vma) + PARAMS ((bfd *, char *, bfd_vma)); + void (* elf_backend_fprintf_vma) + PARAMS ((bfd *, PTR, bfd_vma)); + + /* This function returns class of a reloc type. */ + enum elf_reloc_type_class (*elf_backend_reloc_type_class) + PARAMS ((const Elf_Internal_Rela *)); + + /* This function, if defined, removes information about discarded functions + from other sections which mention them. */ + bfd_boolean (*elf_backend_discard_info) + PARAMS ((bfd *, struct elf_reloc_cookie *, struct bfd_link_info *)); + + /* This function, if defined, signals that the function above has removed + the discarded relocations for this section. */ + bfd_boolean (*elf_backend_ignore_discarded_relocs) + PARAMS ((asection *)); + + /* This function, if defined, may write out the given section. + Returns TRUE if it did so and FALSE if the caller should. */ + bfd_boolean (*elf_backend_write_section) + PARAMS ((bfd *, asection *, bfd_byte *)); + + /* The level of IRIX compatibility we're striving for. + MIPS ELF specific function. */ + irix_compat_t (*elf_backend_mips_irix_compat) + PARAMS ((bfd *)); + + reloc_howto_type *(*elf_backend_mips_rtype_to_howto) + PARAMS ((unsigned int, bfd_boolean)); + + /* The swapping table to use when dealing with ECOFF information. + Used for the MIPS ELF .mdebug section. */ + const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap; + + /* Alternate EM_xxxx machine codes for this backend. */ + int elf_machine_alt1; + int elf_machine_alt2; + + const struct elf_size_info *s; + + /* offset of the _GLOBAL_OFFSET_TABLE_ symbol from the start of the + .got section */ + bfd_vma got_symbol_offset; + + /* The size in bytes of the headers for the GOT and PLT. This includes + the so-called reserved entries on some systems. */ + bfd_vma got_header_size; + bfd_vma plt_header_size; + + /* This is TRUE if the linker should act like collect and gather + global constructors and destructors by name. This is TRUE for + MIPS ELF because the Irix 5 tools can not handle the .init + section. */ + unsigned collect : 1; + + /* This is TRUE if the linker should ignore changes to the type of a + symbol. This is TRUE for MIPS ELF because some Irix 5 objects + record undefined functions as STT_OBJECT although the definitions + are STT_FUNC. */ + unsigned type_change_ok : 1; + + /* Whether the backend may use REL relocations. (Some backends use + both REL and RELA relocations, and this flag is set for those + backends.) */ + unsigned may_use_rel_p : 1; + + /* Whether the backend may use RELA relocations. (Some backends use + both REL and RELA relocations, and this flag is set for those + backends.) */ + unsigned may_use_rela_p : 1; + + /* Whether the default relocation type is RELA. If a backend with + this flag set wants REL relocations for a particular section, + it must note that explicitly. Similarly, if this flag is clear, + and the backend wants RELA relocations for a particular + section. */ + unsigned default_use_rela_p : 1; + + /* Set if RELA relocations for a relocatable link can be handled by + generic code. Backends that set this flag need do nothing in the + backend relocate_section routine for relocatable linking. */ + unsigned rela_normal : 1; + + /* TRUE if addresses "naturally" sign extend. This is used when + swapping in from Elf32 when BFD64. */ + unsigned sign_extend_vma : 1; + + unsigned want_got_plt : 1; + unsigned plt_readonly : 1; + unsigned want_plt_sym : 1; + unsigned plt_not_loaded : 1; + unsigned plt_alignment : 4; + unsigned can_gc_sections : 1; + unsigned can_refcount : 1; + unsigned want_got_sym : 1; + unsigned want_dynbss : 1; + /* Targets which do not support physical addressing often require + that the p_paddr field in the section header to be set to zero. + This field indicates whether this behavior is required. */ + unsigned want_p_paddr_set_to_zero : 1; +}; + +/* Information stored for each BFD section in an ELF file. This + structure is allocated by elf_new_section_hook. */ + +struct bfd_elf_section_data +{ + /* The ELF header for this section. */ + Elf_Internal_Shdr this_hdr; + + /* The ELF header for the reloc section associated with this + section, if any. */ + Elf_Internal_Shdr rel_hdr; + + /* If there is a second reloc section associated with this section, + as can happen on Irix 6, this field points to the header. */ + Elf_Internal_Shdr *rel_hdr2; + + /* The number of relocations currently assigned to REL_HDR. */ + unsigned int rel_count; + + /* The number of relocations currently assigned to REL_HDR2. */ + unsigned int rel_count2; + + /* The ELF section number of this section. Only used for an output + file. */ + int this_idx; + + /* The ELF section number of the reloc section indicated by + REL_HDR if any. Only used for an output file. */ + int rel_idx; + + /* The ELF section number of the reloc section indicated by + REL_HDR2 if any. Only used for an output file. */ + int rel_idx2; + + /* Used by the backend linker when generating a shared library to + record the dynamic symbol index for a section symbol + corresponding to this section. A value of 0 means that there is + no dynamic symbol for this section. */ + int dynindx; + + /* Used by the backend linker to store the symbol hash table entries + associated with relocs against global symbols. */ + struct elf_link_hash_entry **rel_hashes; + + /* A pointer to the swapped relocs. If the section uses REL relocs, + rather than RELA, all the r_addend fields will be zero. This + pointer may be NULL. It is used by the backend linker. */ + Elf_Internal_Rela *relocs; + + /* A pointer to a linked list tracking dynamic relocs copied for + local symbols. */ + PTR local_dynrel; + + /* A pointer to the bfd section used for dynamic relocs. */ + asection *sreloc; + + union { + /* Group name, if this section is a member of a group. */ + const char *name; + + /* Group signature sym, if this is the SHT_GROUP section. */ + struct symbol_cache_entry *id; + } group; + + /* A linked list of sections in the group. Circular when used by + the linker. */ + asection *next_in_group; + + /* A pointer used for various section optimizations. */ + PTR sec_info; +}; + +#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd) +#define elf_group_name(sec) (elf_section_data(sec)->group.name) +#define elf_group_id(sec) (elf_section_data(sec)->group.id) +#define elf_next_in_group(sec) (elf_section_data(sec)->next_in_group) + +/* Return TRUE if section has been discarded. */ +#define elf_discarded_section(sec) \ + (!bfd_is_abs_section (sec) \ + && bfd_is_abs_section ((sec)->output_section) \ + && sec->sec_info_type != ELF_INFO_TYPE_MERGE \ + && sec->sec_info_type != ELF_INFO_TYPE_JUST_SYMS) + +#define get_elf_backend_data(abfd) \ + ((struct elf_backend_data *) (abfd)->xvec->backend_data) + +/* Enumeration to specify the special section. */ +typedef enum elf_linker_section_enum +{ + LINKER_SECTION_UNKNOWN, /* not used */ + LINKER_SECTION_GOT, /* .got section for global offset pointers */ + LINKER_SECTION_PLT, /* .plt section for generated procedure stubs */ + LINKER_SECTION_SDATA, /* .sdata/.sbss section for PowerPC */ + LINKER_SECTION_SDATA2, /* .sdata2/.sbss2 section for PowerPC */ + LINKER_SECTION_MAX /* # of linker sections */ +} elf_linker_section_enum_t; + +/* Sections created by the linker. */ + +typedef struct elf_linker_section +{ + char *name; /* name of the section */ + char *rel_name; /* name of the associated .rel{,a}. section */ + char *bss_name; /* name of a related .bss section */ + char *sym_name; /* name of symbol to reference this section */ + asection *section; /* pointer to the section */ + asection *bss_section; /* pointer to the bss section associated with this */ + asection *rel_section; /* pointer to the relocations needed for this section */ + struct elf_link_hash_entry *sym_hash; /* pointer to the created symbol hash value */ + bfd_vma initial_size; /* initial size before any linker generated allocations */ + bfd_vma sym_offset; /* offset of symbol from beginning of section */ + bfd_vma hole_size; /* size of reserved address hole in allocation */ + bfd_vma hole_offset; /* current offset for the hole */ + bfd_vma max_hole_offset; /* maximum offset for the hole */ + elf_linker_section_enum_t which; /* which section this is */ + bfd_boolean hole_written_p; /* whether the hole has been initialized */ + unsigned int alignment; /* alignment for the section */ + flagword flags; /* flags to use to create the section */ +} elf_linker_section_t; + +/* Linked list of allocated pointer entries. This hangs off of the symbol lists, and + provides allows us to return different pointers, based on different addend's. */ + +typedef struct elf_linker_section_pointers +{ + struct elf_linker_section_pointers *next; /* next allocated pointer for this symbol */ + bfd_vma offset; /* offset of pointer from beginning of section */ + bfd_vma addend; /* addend used */ + elf_linker_section_enum_t which; /* which linker section this is */ + bfd_boolean written_address_p; /* whether address was written yet */ +} elf_linker_section_pointers_t; + +/* Some private data is stashed away for future use using the tdata pointer + in the bfd structure. */ + +struct elf_obj_tdata +{ + Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */ + Elf_Internal_Shdr **elf_sect_ptr; + Elf_Internal_Phdr *phdr; + struct elf_segment_map *segment_map; + struct elf_strtab_hash *strtab_ptr; + int num_locals; + int num_globals; + unsigned int num_elf_sections; /* elf_sect_ptr size */ + int num_section_syms; + asymbol **section_syms; /* STT_SECTION symbols for each section */ + Elf_Internal_Shdr symtab_hdr; + Elf_Internal_Shdr shstrtab_hdr; + Elf_Internal_Shdr strtab_hdr; + Elf_Internal_Shdr dynsymtab_hdr; + Elf_Internal_Shdr dynstrtab_hdr; + Elf_Internal_Shdr dynversym_hdr; + Elf_Internal_Shdr dynverref_hdr; + Elf_Internal_Shdr dynverdef_hdr; + Elf_Internal_Shdr symtab_shndx_hdr; + unsigned int symtab_section, shstrtab_section; + unsigned int strtab_section, dynsymtab_section; + unsigned int symtab_shndx_section; + unsigned int dynversym_section, dynverdef_section, dynverref_section; + file_ptr next_file_pos; +#if 0 + /* we don't need these inside bfd anymore, and I think + these weren't used outside bfd. */ + void *prstatus; /* The raw /proc prstatus structure */ + void *prpsinfo; /* The raw /proc prpsinfo structure */ +#endif + bfd_vma gp; /* The gp value */ + unsigned int gp_size; /* The gp size */ + + Elf_Internal_Shdr **group_sect_ptr; + int num_group; + + /* Information grabbed from an elf core file. */ + int core_signal; + int core_pid; + int core_lwpid; + char* core_program; + char* core_command; + + /* This is set to TRUE if the object was created by the backend + linker. */ + bfd_boolean linker; + + /* A mapping from external symbols to entries in the linker hash + table, used when linking. This is indexed by the symbol index + minus the sh_info field of the symbol table header. */ + struct elf_link_hash_entry **sym_hashes; + + /* Track usage and final offsets of GOT entries for local symbols. + This array is indexed by symbol index. Elements are used + identically to "got" in struct elf_link_hash_entry. */ + union + { + bfd_signed_vma *refcounts; + bfd_vma *offsets; + struct got_entry **ents; + } local_got; + + /* A mapping from local symbols to offsets into the various linker + sections added. This is index by the symbol index. */ + elf_linker_section_pointers_t **linker_section_pointers; + + /* The linker ELF emulation code needs to let the backend ELF linker + know what filename should be used for a dynamic object if the + dynamic object is found using a search. The emulation code then + sometimes needs to know what name was actually used. Until the + file has been added to the linker symbol table, this field holds + the name the linker wants. After it has been added, it holds the + name actually used, which will be the DT_SONAME entry if there is + one. */ + const char *dt_name; + + /* When a reference in a regular object is resolved by a shared + object is loaded into via the DT_NEEDED entries by the linker + ELF emulation code, we need to add the shared object to the + DT_NEEDED list of the resulting binary to indicate the dependency + as if the -l option is passed to the linker. This field holds the + name of the loaded shared object. */ + const char *dt_soname; + + /* Irix 5 often screws up the symbol table, sorting local symbols + after global symbols. This flag is set if the symbol table in + this BFD appears to be screwed up. If it is, we ignore the + sh_info field in the symbol table header, and always read all the + symbols. */ + bfd_boolean bad_symtab; + + /* Records the result of `get_program_header_size'. */ + bfd_size_type program_header_size; + + /* Used by find_nearest_line entry point. */ + PTR line_info; + + /* Used by MIPS ELF find_nearest_line entry point. The structure + could be included directly in this one, but there's no point to + wasting the memory just for the infrequently called + find_nearest_line. */ + struct mips_elf_find_line *find_line_info; + + /* A place to stash dwarf1 info for this bfd. */ + struct dwarf1_debug *dwarf1_find_line_info; + + /* A place to stash dwarf2 info for this bfd. */ + PTR dwarf2_find_line_info; + + /* An array of stub sections indexed by symbol number, used by the + MIPS ELF linker. FIXME: We should figure out some way to only + include this field for a MIPS ELF target. */ + asection **local_stubs; + + /* Used to determine if PT_GNU_EH_FRAME segment header should be + created. */ + asection *eh_frame_hdr; + + /* Used to determine if the e_flags field has been initialized */ + bfd_boolean flags_init; + + /* Number of symbol version definitions we are about to emit. */ + unsigned int cverdefs; + + /* Number of symbol version references we are about to emit. */ + unsigned int cverrefs; + + /* Symbol version definitions in external objects. */ + Elf_Internal_Verdef *verdef; + + /* Symbol version references to external objects. */ + Elf_Internal_Verneed *verref; + + /* Linker sections that we are interested in. */ + struct elf_linker_section *linker_section[ (int)LINKER_SECTION_MAX ]; + + /* The Irix 5 support uses two virtual sections, which represent + text/data symbols defined in dynamic objects. */ + asymbol *elf_data_symbol; + asymbol *elf_text_symbol; + asection *elf_data_section; + asection *elf_text_section; +}; + +#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) +#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header) +#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr) +#define elf_numsections(bfd) (elf_tdata(bfd) -> num_elf_sections) +#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr) +#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section) +#define elf_symtab_shndx(bfd) (elf_tdata(bfd) -> symtab_shndx_section) +#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section) +#define elf_dynversym(bfd) (elf_tdata(bfd) -> dynversym_section) +#define elf_dynverdef(bfd) (elf_tdata(bfd) -> dynverdef_section) +#define elf_dynverref(bfd) (elf_tdata(bfd) -> dynverref_section) +#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals) +#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals) +#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms) +#define elf_num_section_syms(bfd) (elf_tdata(bfd) -> num_section_syms) +#define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo) +#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus) +#define elf_gp(bfd) (elf_tdata(bfd) -> gp) +#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) +#define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes) +#define elf_local_got_refcounts(bfd) (elf_tdata(bfd) -> local_got.refcounts) +#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets) +#define elf_local_got_ents(bfd) (elf_tdata(bfd) -> local_got.ents) +#define elf_local_ptr_offsets(bfd) (elf_tdata(bfd) -> linker_section_pointers) +#define elf_dt_name(bfd) (elf_tdata(bfd) -> dt_name) +#define elf_dt_soname(bfd) (elf_tdata(bfd) -> dt_soname) +#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) +#define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init) +#define elf_linker_section(bfd,n) (elf_tdata(bfd) -> linker_section[(int)n]) + +extern void _bfd_elf_swap_verdef_in + PARAMS ((bfd *, const Elf_External_Verdef *, Elf_Internal_Verdef *)); +extern void _bfd_elf_swap_verdef_out + PARAMS ((bfd *, const Elf_Internal_Verdef *, Elf_External_Verdef *)); +extern void _bfd_elf_swap_verdaux_in + PARAMS ((bfd *, const Elf_External_Verdaux *, Elf_Internal_Verdaux *)); +extern void _bfd_elf_swap_verdaux_out + PARAMS ((bfd *, const Elf_Internal_Verdaux *, Elf_External_Verdaux *)); +extern void _bfd_elf_swap_verneed_in + PARAMS ((bfd *, const Elf_External_Verneed *, Elf_Internal_Verneed *)); +extern void _bfd_elf_swap_verneed_out + PARAMS ((bfd *, const Elf_Internal_Verneed *, Elf_External_Verneed *)); +extern void _bfd_elf_swap_vernaux_in + PARAMS ((bfd *, const Elf_External_Vernaux *, Elf_Internal_Vernaux *)); +extern void _bfd_elf_swap_vernaux_out + PARAMS ((bfd *, const Elf_Internal_Vernaux *, Elf_External_Vernaux *)); +extern void _bfd_elf_swap_versym_in + PARAMS ((bfd *, const Elf_External_Versym *, Elf_Internal_Versym *)); +extern void _bfd_elf_swap_versym_out + PARAMS ((bfd *, const Elf_Internal_Versym *, Elf_External_Versym *)); + +extern int _bfd_elf_section_from_bfd_section + PARAMS ((bfd *, asection *)); +extern char *bfd_elf_string_from_elf_section + PARAMS ((bfd *, unsigned, unsigned)); +extern char *bfd_elf_get_str_section + PARAMS ((bfd *, unsigned)); +extern Elf_Internal_Sym *bfd_elf_get_elf_syms + PARAMS ((bfd *, Elf_Internal_Shdr *, size_t, size_t, + Elf_Internal_Sym *, PTR, Elf_External_Sym_Shndx *)); +extern const char *bfd_elf_local_sym_name + PARAMS ((bfd *, Elf_Internal_Sym *)); + +extern bfd_boolean _bfd_elf_copy_private_bfd_data + PARAMS ((bfd *, bfd *)); +extern bfd_boolean _bfd_elf_print_private_bfd_data + PARAMS ((bfd *, PTR)); +extern void bfd_elf_print_symbol + PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type)); + +#define elf_string_from_elf_strtab(abfd, strindex) \ + bfd_elf_string_from_elf_section(abfd, elf_elfheader(abfd)->e_shstrndx, \ + strindex) + +#define bfd_elf32_print_symbol bfd_elf_print_symbol +#define bfd_elf64_print_symbol bfd_elf_print_symbol + +extern void _bfd_elf_sprintf_vma + PARAMS ((bfd *, char *, bfd_vma)); +extern void _bfd_elf_fprintf_vma + PARAMS ((bfd *, PTR, bfd_vma)); + +extern enum elf_reloc_type_class _bfd_elf_reloc_type_class + PARAMS ((const Elf_Internal_Rela *)); +extern bfd_vma _bfd_elf_rela_local_sym + PARAMS ((bfd *, Elf_Internal_Sym *, asection *, Elf_Internal_Rela *)); +extern bfd_vma _bfd_elf_rel_local_sym + PARAMS ((bfd *, Elf_Internal_Sym *, asection **, bfd_vma)); +extern bfd_vma _bfd_elf_section_offset + PARAMS ((bfd *, struct bfd_link_info *, asection *, bfd_vma)); + +extern unsigned long bfd_elf_hash + PARAMS ((const char *)); + +extern bfd_reloc_status_type bfd_elf_generic_reloc + PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **)); +extern bfd_boolean bfd_elf_mkobject + PARAMS ((bfd *)); +extern bfd_boolean bfd_elf_mkcorefile + PARAMS ((bfd *)); +extern Elf_Internal_Shdr *bfd_elf_find_section + PARAMS ((bfd *, char *)); +extern bfd_boolean _bfd_elf_make_section_from_shdr + PARAMS ((bfd *, Elf_Internal_Shdr *, const char *)); +extern bfd_boolean _bfd_elf_make_section_from_phdr + PARAMS ((bfd *, Elf_Internal_Phdr *, int, const char *)); +extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create + PARAMS ((bfd *)); +extern void _bfd_elf_link_hash_copy_indirect + PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *, + struct elf_link_hash_entry *)); +extern void _bfd_elf_link_hash_hide_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean)); +extern bfd_boolean _bfd_elf_link_hash_table_init + PARAMS ((struct elf_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); +extern bfd_boolean _bfd_elf_slurp_version_tables + PARAMS ((bfd *)); +extern bfd_boolean _bfd_elf_merge_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_elf_discard_group + PARAMS ((bfd *, struct sec *)); +extern void bfd_elf_set_group_contents + PARAMS ((bfd *, asection *, PTR)); +extern void _bfd_elf_link_just_syms + PARAMS ((asection *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf_copy_private_symbol_data + PARAMS ((bfd *, asymbol *, bfd *, asymbol *)); +extern bfd_boolean _bfd_elf_copy_private_section_data + PARAMS ((bfd *, asection *, bfd *, asection *)); +extern bfd_boolean _bfd_elf_write_object_contents + PARAMS ((bfd *)); +extern bfd_boolean _bfd_elf_write_corefile_contents + PARAMS ((bfd *)); +extern bfd_boolean _bfd_elf_set_section_contents + PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); +extern long _bfd_elf_get_symtab_upper_bound + PARAMS ((bfd *)); +extern long _bfd_elf_get_symtab + PARAMS ((bfd *, asymbol **)); +extern long _bfd_elf_get_dynamic_symtab_upper_bound + PARAMS ((bfd *)); +extern long _bfd_elf_canonicalize_dynamic_symtab + PARAMS ((bfd *, asymbol **)); +extern long _bfd_elf_get_reloc_upper_bound + PARAMS ((bfd *, sec_ptr)); +extern long _bfd_elf_canonicalize_reloc + PARAMS ((bfd *, sec_ptr, arelent **, asymbol **)); +extern long _bfd_elf_get_dynamic_reloc_upper_bound + PARAMS ((bfd *)); +extern long _bfd_elf_canonicalize_dynamic_reloc + PARAMS ((bfd *, arelent **, asymbol **)); +extern asymbol *_bfd_elf_make_empty_symbol + PARAMS ((bfd *)); +extern void _bfd_elf_get_symbol_info + PARAMS ((bfd *, asymbol *, symbol_info *)); +extern bfd_boolean _bfd_elf_is_local_label_name + PARAMS ((bfd *, const char *)); +extern alent *_bfd_elf_get_lineno + PARAMS ((bfd *, asymbol *)); +extern bfd_boolean _bfd_elf_set_arch_mach + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); +extern bfd_boolean _bfd_elf_find_nearest_line + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *)); +#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 + PARAMS ((bfd *, bfd_boolean)); +extern bfd_boolean _bfd_elf_new_section_hook + PARAMS ((bfd *, asection *)); +extern bfd_boolean _bfd_elf_init_reloc_shdr + PARAMS ((bfd *, Elf_Internal_Shdr *, asection *, bfd_boolean)); + +/* If the target doesn't have reloc handling written yet: */ +extern void _bfd_elf_no_info_to_howto + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); + +extern bfd_boolean bfd_section_from_shdr + PARAMS ((bfd *, unsigned int shindex)); +extern bfd_boolean bfd_section_from_phdr + PARAMS ((bfd *, Elf_Internal_Phdr *, int)); + +extern int _bfd_elf_symbol_from_bfd_symbol + PARAMS ((bfd *, asymbol **)); + +extern asection *bfd_section_from_r_symndx + PARAMS ((bfd *, struct sym_sec_cache *, asection *, unsigned long)); +extern asection *bfd_section_from_elf_index + PARAMS ((bfd *, unsigned int)); +extern bfd_boolean _bfd_elf_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern struct bfd_strtab_hash *_bfd_elf_stringtab_init + PARAMS ((void)); + +extern struct elf_strtab_hash * _bfd_elf_strtab_init + PARAMS ((void)); +extern void _bfd_elf_strtab_free + PARAMS ((struct elf_strtab_hash *)); +extern bfd_size_type _bfd_elf_strtab_add + PARAMS ((struct elf_strtab_hash *, const char *, bfd_boolean)); +extern void _bfd_elf_strtab_addref + PARAMS ((struct elf_strtab_hash *, bfd_size_type)); +extern void _bfd_elf_strtab_delref + PARAMS ((struct elf_strtab_hash *, bfd_size_type)); +extern void _bfd_elf_strtab_clear_all_refs + PARAMS ((struct elf_strtab_hash *)); +extern bfd_size_type _bfd_elf_strtab_size + PARAMS ((struct elf_strtab_hash *)); +extern bfd_size_type _bfd_elf_strtab_offset + PARAMS ((struct elf_strtab_hash *, bfd_size_type)); +extern bfd_boolean _bfd_elf_strtab_emit + PARAMS ((bfd *, struct elf_strtab_hash *)); +extern void _bfd_elf_strtab_finalize + PARAMS ((struct elf_strtab_hash *)); + +extern bfd_boolean _bfd_elf_discard_section_eh_frame + PARAMS ((bfd *, struct bfd_link_info *, asection *, + bfd_boolean (*) (bfd_vma, PTR), struct elf_reloc_cookie *)); +extern bfd_boolean _bfd_elf_discard_section_eh_frame_hdr + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_vma _bfd_elf_eh_frame_section_offset + PARAMS ((bfd *, asection *, bfd_vma)); +extern bfd_boolean _bfd_elf_write_section_eh_frame + PARAMS ((bfd *, struct bfd_link_info *, asection *, bfd_byte *)); +extern bfd_boolean _bfd_elf_write_section_eh_frame_hdr + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf_maybe_strip_eh_frame_hdr + PARAMS ((struct bfd_link_info *)); + +extern bfd_boolean _bfd_elf_link_record_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +extern long _bfd_elf_link_lookup_local_dynindx + PARAMS ((struct bfd_link_info *, bfd *, long)); +extern bfd_boolean _bfd_elf_compute_section_file_positions + PARAMS ((bfd *, struct bfd_link_info *)); +extern void _bfd_elf_assign_file_positions_for_relocs + PARAMS ((bfd *)); +extern file_ptr _bfd_elf_assign_file_position_for_section + PARAMS ((Elf_Internal_Shdr *, file_ptr, bfd_boolean)); + +extern bfd_boolean _bfd_elf_validate_reloc + PARAMS ((bfd *, arelent *)); + +extern bfd_boolean _bfd_elf_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf_create_got_section + PARAMS ((bfd *, struct bfd_link_info *)); +extern unsigned long _bfd_elf_link_renumber_dynsyms + PARAMS ((bfd *, struct bfd_link_info *)); + +extern bfd_boolean _bfd_elfcore_make_pseudosection + PARAMS ((bfd *, char *, size_t, ufile_ptr)); +extern char *_bfd_elfcore_strndup + PARAMS ((bfd *, char *, size_t)); + +extern elf_linker_section_t *_bfd_elf_create_linker_section + PARAMS ((bfd *, struct bfd_link_info *, enum elf_linker_section_enum, + elf_linker_section_t *)); + +extern elf_linker_section_pointers_t *_bfd_elf_find_pointer_linker_section + PARAMS ((elf_linker_section_pointers_t *, bfd_vma, + elf_linker_section_enum_t)); + +extern bfd_boolean bfd_elf32_create_pointer_linker_section + PARAMS ((bfd *, struct bfd_link_info *, elf_linker_section_t *, + struct elf_link_hash_entry *, const Elf_Internal_Rela *)); + +extern bfd_vma bfd_elf32_finish_pointer_linker_section + PARAMS ((bfd *, bfd *, struct bfd_link_info *, elf_linker_section_t *, + struct elf_link_hash_entry *, bfd_vma, + const Elf_Internal_Rela *, int)); + +extern bfd_boolean bfd_elf64_create_pointer_linker_section + PARAMS ((bfd *, struct bfd_link_info *, elf_linker_section_t *, + struct elf_link_hash_entry *, const Elf_Internal_Rela *)); + +extern bfd_vma bfd_elf64_finish_pointer_linker_section + PARAMS ((bfd *, bfd *, struct bfd_link_info *, elf_linker_section_t *, + struct elf_link_hash_entry *, bfd_vma, + const Elf_Internal_Rela *, int)); + +extern bfd_boolean _bfd_elf_make_linker_section_rela + PARAMS ((bfd *, elf_linker_section_t *, int)); + +extern const bfd_target *bfd_elf32_object_p + PARAMS ((bfd *)); +extern const bfd_target *bfd_elf32_core_file_p + PARAMS ((bfd *)); +extern char *bfd_elf32_core_file_failing_command + PARAMS ((bfd *)); +extern int bfd_elf32_core_file_failing_signal + PARAMS ((bfd *)); +extern bfd_boolean bfd_elf32_core_file_matches_executable_p + PARAMS ((bfd *, bfd *)); + +extern bfd_boolean bfd_elf32_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_elf32_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern void bfd_elf32_swap_symbol_in + PARAMS ((bfd *, const PTR, const PTR, Elf_Internal_Sym *)); +extern void bfd_elf32_swap_symbol_out + PARAMS ((bfd *, const Elf_Internal_Sym *, PTR, PTR)); +extern void bfd_elf32_swap_reloc_in + PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); +extern void bfd_elf32_swap_reloc_out + PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); +extern void bfd_elf32_swap_reloca_in + PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); +extern void bfd_elf32_swap_reloca_out + PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); +extern void bfd_elf32_swap_phdr_in + PARAMS ((bfd *, const Elf32_External_Phdr *, Elf_Internal_Phdr *)); +extern void bfd_elf32_swap_phdr_out + PARAMS ((bfd *, const Elf_Internal_Phdr *, Elf32_External_Phdr *)); +extern void bfd_elf32_swap_dyn_in + PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); +extern void bfd_elf32_swap_dyn_out + PARAMS ((bfd *, const Elf_Internal_Dyn *, PTR)); +extern long bfd_elf32_slurp_symbol_table + PARAMS ((bfd *, asymbol **, bfd_boolean)); +extern bfd_boolean bfd_elf32_write_shdrs_and_ehdr + PARAMS ((bfd *)); +extern int bfd_elf32_write_out_phdrs + PARAMS ((bfd *, const Elf_Internal_Phdr *, unsigned int)); +extern void bfd_elf32_write_relocs + PARAMS ((bfd *, asection *, PTR)); +extern bfd_boolean bfd_elf32_slurp_reloc_table + PARAMS ((bfd *, asection *, asymbol **, bfd_boolean)); +extern bfd_boolean bfd_elf32_add_dynamic_entry + PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma)); +extern bfd_boolean bfd_elf32_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern Elf_Internal_Rela *_bfd_elf32_link_read_relocs + PARAMS ((bfd *, asection *, PTR, Elf_Internal_Rela *, bfd_boolean)); + +extern const bfd_target *bfd_elf64_object_p + PARAMS ((bfd *)); +extern const bfd_target *bfd_elf64_core_file_p + PARAMS ((bfd *)); +extern char *bfd_elf64_core_file_failing_command + PARAMS ((bfd *)); +extern int bfd_elf64_core_file_failing_signal + PARAMS ((bfd *)); +extern bfd_boolean bfd_elf64_core_file_matches_executable_p + PARAMS ((bfd *, bfd *)); +extern bfd_boolean bfd_elf64_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean bfd_elf64_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern void bfd_elf64_swap_symbol_in + PARAMS ((bfd *, const PTR, const PTR, Elf_Internal_Sym *)); +extern void bfd_elf64_swap_symbol_out + PARAMS ((bfd *, const Elf_Internal_Sym *, PTR, PTR)); +extern void bfd_elf64_swap_reloc_in + PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); +extern void bfd_elf64_swap_reloc_out + PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); +extern void bfd_elf64_swap_reloca_in + PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); +extern void bfd_elf64_swap_reloca_out + PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); +extern void bfd_elf64_swap_phdr_in + PARAMS ((bfd *, const Elf64_External_Phdr *, Elf_Internal_Phdr *)); +extern void bfd_elf64_swap_phdr_out + PARAMS ((bfd *, const Elf_Internal_Phdr *, Elf64_External_Phdr *)); +extern void bfd_elf64_swap_dyn_in + PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); +extern void bfd_elf64_swap_dyn_out + PARAMS ((bfd *, const Elf_Internal_Dyn *, PTR)); +extern long bfd_elf64_slurp_symbol_table + PARAMS ((bfd *, asymbol **, bfd_boolean)); +extern bfd_boolean bfd_elf64_write_shdrs_and_ehdr + PARAMS ((bfd *)); +extern int bfd_elf64_write_out_phdrs + PARAMS ((bfd *, const Elf_Internal_Phdr *, unsigned int)); +extern void bfd_elf64_write_relocs + PARAMS ((bfd *, asection *, PTR)); +extern bfd_boolean bfd_elf64_slurp_reloc_table + PARAMS ((bfd *, asection *, asymbol **, bfd_boolean)); +extern bfd_boolean bfd_elf64_add_dynamic_entry + PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma)); +extern bfd_boolean bfd_elf64_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern Elf_Internal_Rela *_bfd_elf64_link_read_relocs + PARAMS ((bfd *, asection *, PTR, Elf_Internal_Rela *, bfd_boolean)); + +#define bfd_elf32_link_record_dynamic_symbol \ + _bfd_elf_link_record_dynamic_symbol +#define bfd_elf64_link_record_dynamic_symbol \ + _bfd_elf_link_record_dynamic_symbol + +extern int elf_link_record_local_dynamic_symbol + PARAMS ((struct bfd_link_info *, bfd *, long)); +#define _bfd_elf32_link_record_local_dynamic_symbol \ + elf_link_record_local_dynamic_symbol +#define _bfd_elf64_link_record_local_dynamic_symbol \ + elf_link_record_local_dynamic_symbol + +extern bfd_boolean _bfd_elf_close_and_cleanup + PARAMS ((bfd *)); +extern bfd_reloc_status_type _bfd_elf_rel_vtable_reloc_fn + PARAMS ((bfd *, arelent *, struct symbol_cache_entry *, PTR, + asection *, bfd *, char **)); + +extern bfd_boolean _bfd_elf32_gc_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf32_gc_common_finalize_got_offsets + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf32_gc_common_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf32_gc_record_vtinherit + PARAMS ((bfd *, asection *, struct elf_link_hash_entry *, bfd_vma)); +extern bfd_boolean _bfd_elf32_gc_record_vtentry + PARAMS ((bfd *, asection *, struct elf_link_hash_entry *, bfd_vma)); + +extern bfd_boolean _bfd_elf64_gc_sections + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf64_gc_common_finalize_got_offsets + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf64_gc_common_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_elf64_gc_record_vtinherit + PARAMS ((bfd *, asection *, struct elf_link_hash_entry *, bfd_vma)); +extern bfd_boolean _bfd_elf64_gc_record_vtentry + PARAMS ((bfd *, asection *, struct elf_link_hash_entry *, bfd_vma)); + +extern bfd_boolean _bfd_elf32_reloc_symbol_deleted_p + PARAMS ((bfd_vma, PTR)); +extern bfd_boolean _bfd_elf64_reloc_symbol_deleted_p + PARAMS ((bfd_vma, PTR)); + +/* Exported interface for writing elf corefile notes. */ +extern char *elfcore_write_note + PARAMS ((bfd *, char *, int *, const char *, int, const PTR, int)); +extern char *elfcore_write_prpsinfo + PARAMS ((bfd *, char *, int *, const char *, const char *)); +extern char *elfcore_write_prstatus + PARAMS ((bfd *, char *, int *, long, int, const PTR)); +extern char * elfcore_write_pstatus + PARAMS ((bfd *, char *, int *, long, int, const PTR)); +extern char *elfcore_write_prfpreg + PARAMS ((bfd *, char *, int *, const PTR, int)); +extern char *elfcore_write_prxfpreg + PARAMS ((bfd *, char *, int *, const PTR, int)); +extern char *elfcore_write_lwpstatus + PARAMS ((bfd *, char *, int *, long, int, const PTR)); + +/* SH ELF specific routine. */ + +extern bfd_boolean _sh_elf_set_mach_from_flags + PARAMS ((bfd *)); + +#endif /* _LIBELF_H_ */ diff --git a/contrib/binutils-2.14/bfd/elf-eh-frame.c b/contrib/binutils-2.14/bfd/elf-eh-frame.c new file mode 100644 index 0000000000..7d0b52bc40 --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf-eh-frame.c @@ -0,0 +1,1189 @@ +/* .eh_frame section optimization. + Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + Written by Jakub Jelinek . + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "elf/dwarf2.h" + +#define EH_FRAME_HDR_SIZE 8 + +static bfd_vma read_unsigned_leb128 + PARAMS ((bfd *, char *, unsigned int *)); +static bfd_signed_vma read_signed_leb128 + PARAMS ((bfd *, char *, unsigned int *)); +static int get_DW_EH_PE_width + PARAMS ((int, int)); +static bfd_vma read_value + PARAMS ((bfd *, bfd_byte *, int, int)); +static void write_value + PARAMS ((bfd *, bfd_byte *, bfd_vma, int)); +static int cie_compare + PARAMS ((struct cie *, struct cie *)); +static int vma_compare + PARAMS ((const PTR, const PTR)); + +/* Helper function for reading uleb128 encoded data. */ + +static bfd_vma +read_unsigned_leb128 (abfd, buf, bytes_read_ptr) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; + unsigned int *bytes_read_ptr; +{ + bfd_vma result; + unsigned int num_read; + int shift; + unsigned char byte; + + result = 0; + shift = 0; + num_read = 0; + do + { + byte = bfd_get_8 (abfd, (bfd_byte *) buf); + buf ++; + num_read ++; + result |= (((bfd_vma) byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + * bytes_read_ptr = num_read; + return result; +} + +/* Helper function for reading sleb128 encoded data. */ + +static bfd_signed_vma +read_signed_leb128 (abfd, buf, bytes_read_ptr) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; + unsigned int * bytes_read_ptr; +{ + bfd_vma result; + int shift; + int num_read; + unsigned char byte; + + result = 0; + shift = 0; + num_read = 0; + do + { + byte = bfd_get_8 (abfd, (bfd_byte *) buf); + buf ++; + num_read ++; + result |= (((bfd_vma) byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + if (byte & 0x40) + result |= (((bfd_vma) -1) << (shift - 7)) << 7; + * bytes_read_ptr = num_read; + return result; +} + +#define read_uleb128(VAR, BUF) \ +do \ + { \ + (VAR) = read_unsigned_leb128 (abfd, buf, &leb128_tmp); \ + (BUF) += leb128_tmp; \ + } \ +while (0) + +#define read_sleb128(VAR, BUF) \ +do \ + { \ + (VAR) = read_signed_leb128 (abfd, buf, &leb128_tmp); \ + (BUF) += leb128_tmp; \ + } \ +while (0) + +/* Return 0 if either encoding is variable width, or not yet known to bfd. */ + +static +int get_DW_EH_PE_width (encoding, ptr_size) + int encoding, ptr_size; +{ + /* DW_EH_PE_ values of 0x60 and 0x70 weren't defined at the time .eh_frame + was added to bfd. */ + if ((encoding & 0x60) == 0x60) + return 0; + + switch (encoding & 7) + { + case DW_EH_PE_udata2: return 2; + case DW_EH_PE_udata4: return 4; + case DW_EH_PE_udata8: return 8; + case DW_EH_PE_absptr: return ptr_size; + default: + break; + } + + return 0; +} + +#define get_DW_EH_PE_signed(encoding) (((encoding) & DW_EH_PE_signed) != 0) + +/* Read a width sized value from memory. */ + +static bfd_vma +read_value (abfd, buf, width, is_signed) + bfd *abfd; + bfd_byte *buf; + int width; + int is_signed; +{ + bfd_vma value; + + switch (width) + { + case 2: + if (is_signed) + value = bfd_get_signed_16 (abfd, buf); + else + value = bfd_get_16 (abfd, buf); + break; + case 4: + if (is_signed) + value = bfd_get_signed_32 (abfd, buf); + else + value = bfd_get_32 (abfd, buf); + break; + case 8: + if (is_signed) + value = bfd_get_signed_64 (abfd, buf); + else + value = bfd_get_64 (abfd, buf); + break; + default: + BFD_FAIL (); + return 0; + } + + return value; +} + +/* Store a width sized value to memory. */ + +static void +write_value (abfd, buf, value, width) + bfd *abfd; + bfd_byte *buf; + bfd_vma value; + int width; +{ + switch (width) + { + case 2: bfd_put_16 (abfd, value, buf); break; + case 4: bfd_put_32 (abfd, value, buf); break; + case 8: bfd_put_64 (abfd, value, buf); break; + default: BFD_FAIL (); + } +} + +/* Return zero if C1 and C2 CIEs can be merged. */ + +static +int cie_compare (c1, c2) + struct cie *c1, *c2; +{ + if (c1->hdr.length == c2->hdr.length + && c1->version == c2->version + && strcmp (c1->augmentation, c2->augmentation) == 0 + && strcmp (c1->augmentation, "eh") != 0 + && c1->code_align == c2->code_align + && c1->data_align == c2->data_align + && c1->ra_column == c2->ra_column + && c1->augmentation_size == c2->augmentation_size + && c1->personality == c2->personality + && 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) + && memcmp (c1->initial_instructions, + c2->initial_instructions, + c1->initial_insn_length) == 0) + return 0; + + return 1; +} + +/* This function is called for each input file before the .eh_frame + section is relocated. It discards duplicate CIEs and FDEs for discarded + functions. The function returns TRUE iff any entries have been + deleted. */ + +bfd_boolean +_bfd_elf_discard_section_eh_frame (abfd, info, sec, + reloc_symbol_deleted_p, cookie) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + bfd_boolean (*reloc_symbol_deleted_p) PARAMS ((bfd_vma, PTR)); + struct elf_reloc_cookie *cookie; +{ + bfd_byte *ehbuf = NULL, *buf; + bfd_byte *last_cie, *last_fde; + struct cie_header hdr; + struct cie cie; + struct elf_link_hash_table *htab; + struct eh_frame_hdr_info *hdr_info; + struct eh_frame_sec_info *sec_info = NULL; + unsigned int leb128_tmp; + unsigned int cie_usage_count, last_cie_ndx, i, offset; + unsigned int make_relative, make_lsda_relative; + bfd_size_type new_size; + unsigned int ptr_size; + + if (sec->_raw_size == 0) + { + /* This file does not contain .eh_frame information. */ + return FALSE; + } + + if ((sec->output_section != NULL + && 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 FALSE; + } + + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + + /* Read the frame unwind information from abfd. */ + + ehbuf = (bfd_byte *) bfd_malloc (sec->_raw_size); + if (ehbuf == NULL) + goto free_no_table; + + if (! bfd_get_section_contents (abfd, sec, ehbuf, (bfd_vma) 0, + sec->_raw_size)) + goto free_no_table; + + if (sec->_raw_size >= 4 + && bfd_get_32 (abfd, ehbuf) == 0 + && cookie->rel == cookie->relend) + { + /* Empty .eh_frame section. */ + free (ehbuf); + return FALSE; + } + + /* If .eh_frame section size doesn't fit into int, we cannot handle + it (it would need to use 64-bit .eh_frame format anyway). */ + if (sec->_raw_size != (unsigned int) sec->_raw_size) + goto free_no_table; + + ptr_size = (elf_elfheader (abfd)->e_ident[EI_CLASS] + == ELFCLASS64) ? 8 : 4; + buf = ehbuf; + last_cie = NULL; + last_cie_ndx = 0; + memset (&cie, 0, sizeof (cie)); + cie_usage_count = 0; + new_size = sec->_raw_size; + make_relative = hdr_info->last_cie.make_relative; + make_lsda_relative = hdr_info->last_cie.make_lsda_relative; + sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + + 99 * sizeof (struct eh_cie_fde)); + if (sec_info == NULL) + goto free_no_table; + sec_info->alloced = 100; + +#define ENSURE_NO_RELOCS(buf) \ + if (cookie->rel < cookie->relend \ + && (cookie->rel->r_offset \ + < (bfd_size_type) ((buf) - ehbuf)) \ + && cookie->rel->r_info != 0) \ + goto free_no_table + +#define SKIP_RELOCS(buf) \ + while (cookie->rel < cookie->relend \ + && (cookie->rel->r_offset \ + < (bfd_size_type) ((buf) - ehbuf))) \ + cookie->rel++ + +#define GET_RELOC(buf) \ + ((cookie->rel < cookie->relend \ + && (cookie->rel->r_offset \ + == (bfd_size_type) ((buf) - ehbuf))) \ + ? cookie->rel : NULL) + + for (;;) + { + unsigned char *aug; + + if (sec_info->count == sec_info->alloced) + { + sec_info = bfd_realloc (sec_info, + sizeof (struct eh_frame_sec_info) + + (sec_info->alloced + 99) + * sizeof (struct eh_cie_fde)); + if (sec_info == NULL) + goto free_no_table; + + memset (&sec_info->entry[sec_info->alloced], 0, + 100 * sizeof (struct eh_cie_fde)); + sec_info->alloced += 100; + } + + last_fde = buf; + /* If we are at the end of the section, we still need to decide + on whether to output or discard last encountered CIE (if any). */ + if ((bfd_size_type) (buf - ehbuf) == sec->_raw_size) + hdr.id = (unsigned int) -1; + else + { + if ((bfd_size_type) (buf + 4 - ehbuf) > sec->_raw_size) + /* No space for CIE/FDE header length. */ + goto free_no_table; + + hdr.length = bfd_get_32 (abfd, buf); + if (hdr.length == 0xffffffff) + /* 64-bit .eh_frame is not supported. */ + goto free_no_table; + buf += 4; + if ((bfd_size_type) (buf - ehbuf) + hdr.length > sec->_raw_size) + /* CIE/FDE not contained fully in this .eh_frame input section. */ + goto free_no_table; + + sec_info->entry[sec_info->count].offset = last_fde - ehbuf; + sec_info->entry[sec_info->count].size = 4 + hdr.length; + + if (hdr.length == 0) + { + /* CIE with length 0 must be only the last in the section. */ + if ((bfd_size_type) (buf - ehbuf) < sec->_raw_size) + goto free_no_table; + ENSURE_NO_RELOCS (buf); + sec_info->count++; + /* Now just finish last encountered CIE processing and break + the loop. */ + hdr.id = (unsigned int) -1; + } + else + { + hdr.id = bfd_get_32 (abfd, buf); + buf += 4; + if (hdr.id == (unsigned int) -1) + goto free_no_table; + } + } + + if (hdr.id == 0 || hdr.id == (unsigned int) -1) + { + unsigned int initial_insn_length; + + /* CIE */ + if (last_cie != NULL) + { + /* Now check if this CIE is identical to the last CIE, + in which case we can remove it provided we adjust + all FDEs. Also, it can be removed if we have removed + all FDEs using it. */ + if ((!info->relocateable + && cie_compare (&cie, &hdr_info->last_cie) == 0) + || cie_usage_count == 0) + { + new_size -= cie.hdr.length + 4; + sec_info->entry[last_cie_ndx].removed = 1; + sec_info->entry[last_cie_ndx].sec = hdr_info->last_cie_sec; + sec_info->entry[last_cie_ndx].new_offset + = hdr_info->last_cie_offset; + } + else + { + hdr_info->last_cie = cie; + hdr_info->last_cie_sec = sec; + hdr_info->last_cie_offset = last_cie - ehbuf; + sec_info->entry[last_cie_ndx].make_relative + = cie.make_relative; + sec_info->entry[last_cie_ndx].make_lsda_relative + = cie.make_lsda_relative; + sec_info->entry[last_cie_ndx].per_encoding_relative + = (cie.per_encoding & 0x70) == DW_EH_PE_pcrel; + } + } + + if (hdr.id == (unsigned int) -1) + break; + + last_cie_ndx = sec_info->count; + sec_info->entry[sec_info->count].cie = 1; + + cie_usage_count = 0; + memset (&cie, 0, sizeof (cie)); + cie.hdr = hdr; + cie.version = *buf++; + + /* Cannot handle unknown versions. */ + if (cie.version != 1) + goto free_no_table; + if (strlen (buf) > sizeof (cie.augmentation) - 1) + goto free_no_table; + + strcpy (cie.augmentation, buf); + buf = strchr (buf, '\0') + 1; + ENSURE_NO_RELOCS (buf); + if (buf[0] == 'e' && buf[1] == 'h') + { + /* GCC < 3.0 .eh_frame CIE */ + /* We cannot merge "eh" CIEs because __EXCEPTION_TABLE__ + is private to each CIE, so we don't need it for anything. + Just skip it. */ + buf += ptr_size; + SKIP_RELOCS (buf); + } + read_uleb128 (cie.code_align, buf); + read_sleb128 (cie.data_align, buf); + /* Note - in DWARF2 the return address column is an unsigned byte. + In DWARF3 it is a ULEB128. We are following DWARF3. For most + ports this will not matter as the value will be less than 128. + For the others (eg FRV, SH, MMIX, IA64) they need a fixed GCC + which conforms to the DWARF3 standard. */ + read_uleb128 (cie.ra_column, buf); + ENSURE_NO_RELOCS (buf); + cie.lsda_encoding = DW_EH_PE_omit; + cie.fde_encoding = DW_EH_PE_omit; + cie.per_encoding = DW_EH_PE_omit; + aug = cie.augmentation; + if (aug[0] != 'e' || aug[1] != 'h') + { + if (*aug == 'z') + { + aug++; + read_uleb128 (cie.augmentation_size, buf); + ENSURE_NO_RELOCS (buf); + } + + while (*aug != '\0') + switch (*aug++) + { + case 'L': + cie.lsda_encoding = *buf++; + ENSURE_NO_RELOCS (buf); + if (get_DW_EH_PE_width (cie.lsda_encoding, ptr_size) == 0) + goto free_no_table; + break; + case 'R': + cie.fde_encoding = *buf++; + ENSURE_NO_RELOCS (buf); + if (get_DW_EH_PE_width (cie.fde_encoding, ptr_size) == 0) + goto free_no_table; + break; + case 'P': + { + int per_width; + + cie.per_encoding = *buf++; + per_width = get_DW_EH_PE_width (cie.per_encoding, + ptr_size); + if (per_width == 0) + goto free_no_table; + if ((cie.per_encoding & 0xf0) == DW_EH_PE_aligned) + buf = (ehbuf + + ((buf - ehbuf + per_width - 1) + & ~((bfd_size_type) per_width - 1))); + ENSURE_NO_RELOCS (buf); + /* Ensure we have a reloc here, against + a global symbol. */ + if (GET_RELOC (buf) != NULL) + { + unsigned long r_symndx; + +#ifdef BFD64 + if (ptr_size == 8) + r_symndx = ELF64_R_SYM (cookie->rel->r_info); + else +#endif + r_symndx = ELF32_R_SYM (cookie->rel->r_info); + if (r_symndx >= cookie->locsymcount) + { + struct elf_link_hash_entry *h; + + r_symndx -= cookie->extsymoff; + h = cookie->sym_hashes[r_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; + + cie.personality = h; + } + cookie->rel++; + } + buf += per_width; + } + break; + default: + /* Unrecognized augmentation. Better bail out. */ + goto free_no_table; + } + } + + /* For shared libraries, try to get rid of as many RELATIVE relocs + as possible. */ + if (info->shared + && (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) + cie.make_relative = 1; + + if (info->shared + && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr) + cie.make_lsda_relative = 1; + + /* If FDE encoding was not specified, it defaults to + DW_EH_absptr. */ + if (cie.fde_encoding == DW_EH_PE_omit) + cie.fde_encoding = DW_EH_PE_absptr; + + initial_insn_length = cie.hdr.length - (buf - last_fde - 4); + if (initial_insn_length <= 50) + { + cie.initial_insn_length = initial_insn_length; + memcpy (cie.initial_instructions, buf, initial_insn_length); + } + buf += initial_insn_length; + ENSURE_NO_RELOCS (buf); + last_cie = last_fde; + } + else + { + /* Ensure this FDE uses the last CIE encountered. */ + if (last_cie == NULL + || hdr.id != (unsigned int) (buf - 4 - last_cie)) + goto free_no_table; + + ENSURE_NO_RELOCS (buf); + if (GET_RELOC (buf) == NULL) + /* This should not happen. */ + goto free_no_table; + if ((*reloc_symbol_deleted_p) (buf - ehbuf, cookie)) + { + /* This is a FDE against a discarded section. It should + be deleted. */ + new_size -= hdr.length + 4; + sec_info->entry[sec_info->count].removed = 1; + } + else + { + if (info->shared + && (((cie.fde_encoding & 0xf0) == DW_EH_PE_absptr + && cie.make_relative == 0) + || (cie.fde_encoding & 0xf0) == DW_EH_PE_aligned)) + { + /* If a shared library uses absolute pointers + 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; + } + cie_usage_count++; + hdr_info->fde_count++; + } + if (cie.lsda_encoding != DW_EH_PE_omit) + { + unsigned int dummy; + + aug = buf; + buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size); + if (cie.augmentation[0] == 'z') + read_uleb128 (dummy, buf); + /* If some new augmentation data is added before LSDA + in FDE augmentation area, this need to be adjusted. */ + sec_info->entry[sec_info->count].lsda_offset = (buf - aug); + } + buf = last_fde + 4 + hdr.length; + SKIP_RELOCS (buf); + } + + sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding; + sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding; + sec_info->count++; + } + + elf_section_data (sec)->sec_info = sec_info; + sec->sec_info_type = ELF_INFO_TYPE_EH_FRAME; + + /* Ok, now we can assign new offsets. */ + offset = 0; + last_cie_ndx = 0; + for (i = 0; i < sec_info->count; i++) + { + if (! sec_info->entry[i].removed) + { + sec_info->entry[i].new_offset = offset; + offset += sec_info->entry[i].size; + if (sec_info->entry[i].cie) + { + last_cie_ndx = i; + make_relative = sec_info->entry[i].make_relative; + make_lsda_relative = sec_info->entry[i].make_lsda_relative; + } + else + { + sec_info->entry[i].make_relative = make_relative; + sec_info->entry[i].make_lsda_relative = make_lsda_relative; + sec_info->entry[i].per_encoding_relative = 0; + } + } + else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec) + { + /* Need to adjust new_offset too. */ + BFD_ASSERT (sec_info->entry[last_cie_ndx].offset + == sec_info->entry[i].new_offset); + sec_info->entry[i].new_offset + = sec_info->entry[last_cie_ndx].new_offset; + } + } + if (hdr_info->last_cie_sec == sec) + { + BFD_ASSERT (sec_info->entry[last_cie_ndx].offset + == hdr_info->last_cie_offset); + hdr_info->last_cie_offset = sec_info->entry[last_cie_ndx].new_offset; + } + + /* FIXME: Currently it is not possible to shrink sections to zero size at + this point, so build a fake minimal CIE. */ + if (new_size == 0) + new_size = 16; + + /* Shrink the sec as needed. */ + sec->_cooked_size = new_size; + if (sec->_cooked_size == 0) + sec->flags |= SEC_EXCLUDE; + + free (ehbuf); + return new_size != sec->_raw_size; + +free_no_table: + if (ehbuf) + free (ehbuf); + if (sec_info) + free (sec_info); + hdr_info->table = FALSE; + hdr_info->last_cie.hdr.length = 0; + return FALSE; +} + +/* This function is called for .eh_frame_hdr section after + _bfd_elf_discard_section_eh_frame has been called on all .eh_frame + input sections. It finalizes the size of .eh_frame_hdr section. */ + +bfd_boolean +_bfd_elf_discard_section_eh_frame_hdr (abfd, info) + 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 (sec == NULL) + return FALSE; + + sec->_cooked_size = EH_FRAME_HDR_SIZE; + if (hdr_info->table) + sec->_cooked_size += 4 + hdr_info->fde_count * 8; + + /* Request program headers to be recalculated. */ + elf_tdata (abfd)->program_header_size = 0; + elf_tdata (abfd)->eh_frame_hdr = sec; + return TRUE; +} + +/* This function is called from size_dynamic_sections. + It needs to decide whether .eh_frame_hdr should be output or not, + because later on it is too late for calling _bfd_strip_section_from_output, + since dynamic symbol table has been sized. */ + +bfd_boolean +_bfd_elf_maybe_strip_eh_frame_hdr (info) + struct bfd_link_info *info; +{ + asection *o; + bfd *abfd; + struct elf_link_hash_table *htab; + struct eh_frame_hdr_info *hdr_info; + + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + if (hdr_info->hdr_sec == NULL) + return TRUE; + + if (bfd_is_abs_section (hdr_info->hdr_sec->output_section)) + { + hdr_info->hdr_sec = NULL; + return TRUE; + } + + abfd = NULL; + if (info->eh_frame_hdr) + for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) + { + /* Count only sections which have at least a single CIE or FDE. + There cannot be any CIE or FDE <= 8 bytes. */ + o = bfd_get_section_by_name (abfd, ".eh_frame"); + if (o && o->_raw_size > 8 && !bfd_is_abs_section (o->output_section)) + break; + } + + if (abfd == NULL) + { + _bfd_strip_section_from_output (info, hdr_info->hdr_sec); + hdr_info->hdr_sec = NULL; + return TRUE; + } + + hdr_info->table = TRUE; + return TRUE; +} + +/* Adjust an address in the .eh_frame section. Given OFFSET within + SEC, this returns the new offset in the adjusted .eh_frame section, + or -1 if the address refers to a CIE/FDE which has been removed + or to offset with dynamic relocation which is no longer needed. */ + +bfd_vma +_bfd_elf_eh_frame_section_offset (output_bfd, sec, offset) + bfd *output_bfd ATTRIBUTE_UNUSED; + asection *sec; + bfd_vma offset; +{ + struct eh_frame_sec_info *sec_info; + unsigned int lo, hi, mid; + + if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) + return offset; + sec_info = (struct eh_frame_sec_info *) + elf_section_data (sec)->sec_info; + + if (offset >= sec->_raw_size) + return offset - (sec->_cooked_size - sec->_raw_size); + + lo = 0; + hi = sec_info->count; + mid = 0; + while (lo < hi) + { + mid = (lo + hi) / 2; + if (offset < sec_info->entry[mid].offset) + hi = mid; + else if (offset + >= sec_info->entry[mid].offset + sec_info->entry[mid].size) + lo = mid + 1; + else + break; + } + + BFD_ASSERT (lo < hi); + + /* FDE or CIE was removed. */ + if (sec_info->entry[mid].removed) + return (bfd_vma) -1; + + /* If converting to DW_EH_PE_pcrel, there will be no need for run-time + relocation against FDE's initial_location field. */ + if (sec_info->entry[mid].make_relative + && ! sec_info->entry[mid].cie + && offset == sec_info->entry[mid].offset + 8) + return (bfd_vma) -2; + + /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need + for run-time relocation against LSDA field. */ + if (sec_info->entry[mid].make_lsda_relative + && ! sec_info->entry[mid].cie + && (offset == (sec_info->entry[mid].offset + 8 + + sec_info->entry[mid].lsda_offset))) + return (bfd_vma) -2; + + return (offset + sec_info->entry[mid].new_offset + - sec_info->entry[mid].offset); +} + +/* Write out .eh_frame section. This is called with the relocated + contents. */ + +bfd_boolean +_bfd_elf_write_section_eh_frame (abfd, info, sec, contents) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + bfd_byte *contents; +{ + struct eh_frame_sec_info *sec_info; + struct elf_link_hash_table *htab; + struct eh_frame_hdr_info *hdr_info; + unsigned int i; + bfd_byte *p, *buf; + unsigned int leb128_tmp; + unsigned int cie_offset = 0; + unsigned int ptr_size; + + ptr_size = (elf_elfheader (sec->owner)->e_ident[EI_CLASS] + == ELFCLASS64) ? 8 : 4; + + if (sec->sec_info_type != ELF_INFO_TYPE_EH_FRAME) + return bfd_set_section_contents (abfd, sec->output_section, + contents, + (file_ptr) sec->output_offset, + sec->_raw_size); + sec_info = (struct eh_frame_sec_info *) + elf_section_data (sec)->sec_info; + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + if (hdr_info->table && hdr_info->array == NULL) + hdr_info->array + = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); + if (hdr_info->array == NULL) + hdr_info = NULL; + + p = contents; + for (i = 0; i < sec_info->count; ++i) + { + if (sec_info->entry[i].removed) + { + if (sec_info->entry[i].cie) + { + /* If CIE is removed due to no remaining FDEs referencing it + and there were no CIEs kept before it, sec_info->entry[i].sec + will be zero. */ + if (sec_info->entry[i].sec == NULL) + cie_offset = 0; + else + { + cie_offset = sec_info->entry[i].new_offset; + cie_offset += (sec_info->entry[i].sec->output_section->vma + + sec_info->entry[i].sec->output_offset + - sec->output_section->vma + - sec->output_offset); + } + } + continue; + } + + if (sec_info->entry[i].cie) + { + /* CIE */ + cie_offset = sec_info->entry[i].new_offset; + if (sec_info->entry[i].make_relative + || sec_info->entry[i].make_lsda_relative + || sec_info->entry[i].per_encoding_relative) + { + unsigned char *aug; + unsigned int action; + unsigned int dummy, per_width, per_encoding; + + /* Need to find 'R' or 'L' augmentation's argument and modify + DW_EH_PE_* value. */ + action = (sec_info->entry[i].make_relative ? 1 : 0) + | (sec_info->entry[i].make_lsda_relative ? 2 : 0) + | (sec_info->entry[i].per_encoding_relative ? 4 : 0); + buf = contents + sec_info->entry[i].offset; + /* Skip length, id and version. */ + buf += 9; + aug = buf; + buf = strchr (buf, '\0') + 1; + read_uleb128 (dummy, buf); + read_sleb128 (dummy, buf); + read_uleb128 (dummy, buf); + if (*aug == 'z') + { + read_uleb128 (dummy, buf); + aug++; + } + + while (action) + switch (*aug++) + { + case 'L': + if (action & 2) + { + BFD_ASSERT (*buf == sec_info->entry[i].lsda_encoding); + *buf |= DW_EH_PE_pcrel; + action &= ~2; + } + buf++; + break; + case 'P': + per_encoding = *buf++; + per_width = get_DW_EH_PE_width (per_encoding, + ptr_size); + BFD_ASSERT (per_width != 0); + BFD_ASSERT (((per_encoding & 0x70) == DW_EH_PE_pcrel) + == sec_info->entry[i].per_encoding_relative); + if ((per_encoding & 0xf0) == DW_EH_PE_aligned) + buf = (contents + + ((buf - contents + per_width - 1) + & ~((bfd_size_type) per_width - 1))); + if (action & 4) + { + bfd_vma value; + + value = read_value (abfd, buf, per_width, + get_DW_EH_PE_signed + (per_encoding)); + value += (sec_info->entry[i].offset + - sec_info->entry[i].new_offset); + write_value (abfd, buf, value, per_width); + action &= ~4; + } + buf += per_width; + break; + case 'R': + if (action & 1) + { + BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding); + *buf |= DW_EH_PE_pcrel; + action &= ~1; + } + buf++; + break; + default: + BFD_FAIL (); + } + } + } + else if (sec_info->entry[i].size > 4) + { + /* FDE */ + bfd_vma value = 0, address; + unsigned int width; + + buf = contents + sec_info->entry[i].offset; + /* Skip length. */ + buf += 4; + bfd_put_32 (abfd, + sec_info->entry[i].new_offset + 4 - cie_offset, buf); + buf += 4; + width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding, + ptr_size); + address = value = read_value (abfd, buf, width, + get_DW_EH_PE_signed + (sec_info->entry[i].fde_encoding)); + if (value) + { + switch (sec_info->entry[i].fde_encoding & 0xf0) + { + case DW_EH_PE_indirect: + case DW_EH_PE_textrel: + BFD_ASSERT (hdr_info == NULL); + break; + case DW_EH_PE_datarel: + { + asection *got = bfd_get_section_by_name (abfd, ".got"); + + BFD_ASSERT (got != NULL); + address += got->vma; + } + break; + case DW_EH_PE_pcrel: + value += (sec_info->entry[i].offset + - sec_info->entry[i].new_offset); + address += (sec->output_section->vma + sec->output_offset + + sec_info->entry[i].offset + 8); + break; + } + if (sec_info->entry[i].make_relative) + value -= (sec->output_section->vma + sec->output_offset + + sec_info->entry[i].new_offset + 8); + write_value (abfd, buf, value, width); + } + + if (hdr_info) + { + hdr_info->array[hdr_info->array_count].initial_loc = address; + hdr_info->array[hdr_info->array_count++].fde + = (sec->output_section->vma + sec->output_offset + + sec_info->entry[i].new_offset); + } + + if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel + || sec_info->entry[i].make_lsda_relative) + { + buf += sec_info->entry[i].lsda_offset; + width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding, + ptr_size); + value = read_value (abfd, buf, width, + get_DW_EH_PE_signed + (sec_info->entry[i].lsda_encoding)); + if (value) + { + if ((sec_info->entry[i].lsda_encoding & 0xf0) + == DW_EH_PE_pcrel) + value += (sec_info->entry[i].offset + - sec_info->entry[i].new_offset); + else if (sec_info->entry[i].make_lsda_relative) + value -= (sec->output_section->vma + sec->output_offset + + sec_info->entry[i].new_offset + 8 + + sec_info->entry[i].lsda_offset); + write_value (abfd, buf, value, width); + } + } + } + else + /* Terminating FDE must be at the end of .eh_frame section only. */ + BFD_ASSERT (i == sec_info->count - 1); + + BFD_ASSERT (p == contents + sec_info->entry[i].new_offset); + memmove (p, contents + sec_info->entry[i].offset, + sec_info->entry[i].size); + p += sec_info->entry[i].size; + } + + /* FIXME: Once _bfd_elf_discard_section_eh_frame will be able to + shrink sections to zero size, this won't be needed any more. */ + if (p == contents && sec->_cooked_size == 16) + { + bfd_put_32 (abfd, 12, p); /* Fake CIE length */ + bfd_put_32 (abfd, 0, p + 4); /* Fake CIE id */ + p[8] = 1; /* Fake CIE version */ + memset (p + 9, 0, 7); /* Fake CIE augmentation, 3xleb128 + and 3xDW_CFA_nop as pad */ + p += 16; + } + + BFD_ASSERT ((bfd_size_type) (p - contents) == sec->_cooked_size); + + return bfd_set_section_contents (abfd, sec->output_section, + contents, (file_ptr) sec->output_offset, + sec->_cooked_size); +} + +/* Helper function used to sort .eh_frame_hdr search table by increasing + VMA of FDE initial location. */ + +static int +vma_compare (a, b) + const PTR a; + const PTR b; +{ + struct eh_frame_array_ent *p = (struct eh_frame_array_ent *) a; + struct eh_frame_array_ent *q = (struct eh_frame_array_ent *) b; + if (p->initial_loc > q->initial_loc) + return 1; + if (p->initial_loc < q->initial_loc) + 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: + ubyte version (currently 1) + ubyte eh_frame_ptr_enc (DW_EH_PE_* encoding of pointer to start of + .eh_frame section) + ubyte fde_count_enc (DW_EH_PE_* encoding of total FDE count + number (or DW_EH_PE_omit if there is no + binary search table computed)) + ubyte table_enc (DW_EH_PE_* encoding of binary search table, + or DW_EH_PE_omit if not present. + DW_EH_PE_datarel is using address of + .eh_frame_hdr section start as base) + [encoded] eh_frame_ptr (pointer to start of .eh_frame section) + optionally followed by: + [encoded] fde_count (total number of FDEs in .eh_frame section) + fde_count x [encoded] initial_loc, fde + (array of encoded pairs containing + FDE initial_location field and FDE address, + sorted by increasing initial_loc). */ + +bfd_boolean +_bfd_elf_write_section_eh_frame_hdr (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + struct elf_link_hash_table *htab; + struct eh_frame_hdr_info *hdr_info; + asection *sec; + bfd_byte *contents; + asection *eh_frame_sec; + bfd_size_type size; + bfd_boolean retval; + + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + sec = hdr_info->hdr_sec; + if (sec == NULL) + return TRUE; + + 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_malloc (size); + if (contents == NULL) + 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); + contents[0] = 1; /* Version. */ + contents[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; /* .eh_frame offset. */ + if (hdr_info->array && hdr_info->array_count == hdr_info->fde_count) + { + contents[2] = DW_EH_PE_udata4; /* FDE count encoding. */ + contents[3] = DW_EH_PE_datarel | DW_EH_PE_sdata4; /* Search table enc. */ + } + else + { + contents[2] = DW_EH_PE_omit; + contents[3] = DW_EH_PE_omit; + } + bfd_put_32 (abfd, eh_frame_sec->vma - sec->output_section->vma - 4, + contents + 4); + if (contents[2] != DW_EH_PE_omit) + { + unsigned int i; + + 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); + } + } + + retval = bfd_set_section_contents (abfd, sec->output_section, + contents, (file_ptr) sec->output_offset, + sec->_cooked_size); + free (contents); + return retval; +} diff --git a/contrib/binutils-2.14/bfd/elf-strtab.c b/contrib/binutils-2.14/bfd/elf-strtab.c new file mode 100644 index 0000000000..3bd5531a81 --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf-strtab.c @@ -0,0 +1,450 @@ +/* ELF strtab with GC and suffix merging support. + Copyright 2001, 2002 Free Software Foundation, Inc. + Written by Jakub Jelinek . + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "hashtab.h" +#include "libiberty.h" + +/* An entry in the strtab hash table. */ + +struct elf_strtab_hash_entry +{ + struct bfd_hash_entry root; + /* Length of this entry. */ + unsigned int len; + unsigned int refcount; + union { + /* Index within the merged section. */ + bfd_size_type index; + /* Entry this is a suffix of (if len is 0). */ + struct elf_strtab_hash_entry *suffix; + struct elf_strtab_hash_entry *next; + } u; +}; + +/* The strtab hash table. */ + +struct elf_strtab_hash +{ + struct bfd_hash_table table; + /* Next available index. */ + bfd_size_type size; + /* Number of array entries alloced. */ + bfd_size_type alloced; + /* Final strtab size. */ + bfd_size_type sec_size; + /* Array of pointers to strtab entries. */ + struct elf_strtab_hash_entry **array; +}; + +static struct bfd_hash_entry *elf_strtab_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static int cmplengthentry PARAMS ((const PTR, const PTR)); +static int last4_eq PARAMS ((const PTR, const PTR)); + +/* Routine to create an entry in a section merge hashtab. */ + +static struct bfd_hash_entry * +elf_strtab_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct elf_strtab_hash_entry *ret = (struct elf_strtab_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct elf_strtab_hash_entry *) NULL) + ret = ((struct elf_strtab_hash_entry *) + bfd_hash_allocate (table, sizeof (struct elf_strtab_hash_entry))); + if (ret == (struct elf_strtab_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct elf_strtab_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->u.index = -1; + ret->refcount = 0; + ret->len = 0; + } + + return (struct bfd_hash_entry *)ret; +} + +/* Create a new hash table. */ + +struct elf_strtab_hash * +_bfd_elf_strtab_init () +{ + struct elf_strtab_hash *table; + bfd_size_type amt = sizeof (struct elf_strtab_hash); + + table = (struct elf_strtab_hash *) bfd_malloc (amt); + if (table == NULL) + return NULL; + + if (! bfd_hash_table_init (&table->table, elf_strtab_hash_newfunc)) + { + free (table); + return NULL; + } + + table->sec_size = 0; + table->size = 1; + table->alloced = 64; + amt = sizeof (struct elf_strtab_hasn_entry *); + table->array = (struct elf_strtab_hash_entry **) + bfd_malloc (table->alloced * amt); + if (table->array == NULL) + { + free (table); + return NULL; + } + + table->array[0] = NULL; + + return table; +} + +/* Free a strtab. */ + +void +_bfd_elf_strtab_free (tab) + struct elf_strtab_hash *tab; +{ + bfd_hash_table_free (&tab->table); + free (tab->array); + free (tab); +} + +/* Get the index of an entity in a hash table, adding it if it is not + already present. */ + +bfd_size_type +_bfd_elf_strtab_add (tab, str, copy) + struct elf_strtab_hash *tab; + const char *str; + bfd_boolean copy; +{ + register struct elf_strtab_hash_entry *entry; + + /* We handle this specially, since we don't want to do refcounting + on it. */ + if (*str == '\0') + return 0; + + BFD_ASSERT (tab->sec_size == 0); + entry = (struct elf_strtab_hash_entry *) + bfd_hash_lookup (&tab->table, str, TRUE, copy); + + if (entry == NULL) + return (bfd_size_type) -1; + + entry->refcount++; + if (entry->len == 0) + { + entry->len = strlen (str) + 1; + if (tab->size == tab->alloced) + { + bfd_size_type amt = sizeof (struct elf_strtab_hash_entry *); + tab->alloced *= 2; + tab->array = (struct elf_strtab_hash_entry **) + bfd_realloc (tab->array, tab->alloced * amt); + if (tab->array == NULL) + return (bfd_size_type) -1; + } + + entry->u.index = tab->size++; + tab->array[entry->u.index] = entry; + } + return entry->u.index; +} + +void +_bfd_elf_strtab_addref (tab, idx) + struct elf_strtab_hash *tab; + bfd_size_type idx; +{ + if (idx == 0 || idx == (bfd_size_type) -1) + return; + BFD_ASSERT (tab->sec_size == 0); + BFD_ASSERT (idx < tab->size); + ++tab->array[idx]->refcount; +} + +void +_bfd_elf_strtab_delref (tab, idx) + struct elf_strtab_hash *tab; + bfd_size_type idx; +{ + if (idx == 0 || idx == (bfd_size_type) -1) + return; + BFD_ASSERT (tab->sec_size == 0); + BFD_ASSERT (idx < tab->size); + BFD_ASSERT (tab->array[idx]->refcount > 0); + --tab->array[idx]->refcount; +} + +void +_bfd_elf_strtab_clear_all_refs (tab) + struct elf_strtab_hash *tab; +{ + bfd_size_type idx; + + for (idx = 1; idx < tab->size; ++idx) + tab->array[idx]->refcount = 0; +} + +bfd_size_type +_bfd_elf_strtab_size (tab) + struct elf_strtab_hash *tab; +{ + return tab->sec_size ? tab->sec_size : tab->size; +} + +bfd_size_type +_bfd_elf_strtab_offset (tab, idx) + struct elf_strtab_hash *tab; + bfd_size_type idx; +{ + struct elf_strtab_hash_entry *entry; + + if (idx == 0) + return 0; + BFD_ASSERT (idx < tab->size); + BFD_ASSERT (tab->sec_size); + entry = tab->array[idx]; + BFD_ASSERT (entry->refcount > 0); + entry->refcount--; + return tab->array[idx]->u.index; +} + +bfd_boolean +_bfd_elf_strtab_emit (abfd, tab) + register bfd *abfd; + struct elf_strtab_hash *tab; +{ + bfd_size_type off = 1, i; + + if (bfd_bwrite ("", 1, abfd) != 1) + return FALSE; + + for (i = 1; i < tab->size; ++i) + { + register const char *str; + register size_t len; + + str = tab->array[i]->root.string; + len = tab->array[i]->len; + BFD_ASSERT (tab->array[i]->refcount == 0); + if (len == 0) + continue; + + if (bfd_bwrite ((PTR) str, (bfd_size_type) len, abfd) != len) + return FALSE; + + off += len; + } + + BFD_ASSERT (off == tab->sec_size); + return TRUE; +} + +/* Compare two elf_strtab_hash_entry structures. This is called via qsort. */ + +static int +cmplengthentry (a, b) + const PTR a; + const PTR b; +{ + struct elf_strtab_hash_entry * A = *(struct elf_strtab_hash_entry **) a; + struct elf_strtab_hash_entry * B = *(struct elf_strtab_hash_entry **) b; + + if (A->len < B->len) + return 1; + else if (A->len > B->len) + return -1; + + return memcmp (A->root.string, B->root.string, A->len); +} + +static int +last4_eq (a, b) + const PTR a; + const PTR b; +{ + struct elf_strtab_hash_entry * A = (struct elf_strtab_hash_entry *) a; + struct elf_strtab_hash_entry * B = (struct elf_strtab_hash_entry *) b; + + if (memcmp (A->root.string + A->len - 5, B->root.string + B->len - 5, 4) + != 0) + /* This was a hashtable collision. */ + return 0; + + if (A->len <= B->len) + /* B cannot be a suffix of A unless A is equal to B, which is guaranteed + not to be equal by the hash table. */ + return 0; + + return memcmp (A->root.string + (A->len - B->len), + B->root.string, B->len - 5) == 0; +} + +/* This function assigns final string table offsets for used strings, + merging strings matching suffixes of longer strings if possible. */ + +void +_bfd_elf_strtab_finalize (tab) + struct elf_strtab_hash *tab; +{ + struct elf_strtab_hash_entry **array, **a, **end, *e; + htab_t last4tab = NULL; + bfd_size_type size, amt; + struct elf_strtab_hash_entry *last[256], **last_ptr[256]; + + /* GCC 2.91.66 (egcs-1.1.2) on i386 miscompiles this function when i is + a 64-bit bfd_size_type: a 64-bit target or --enable-64-bit-bfd. + Besides, indexing with a long long wouldn't give anything but extra + cycles. */ + size_t i; + + /* Now sort the strings by length, longest first. */ + array = NULL; + amt = tab->size * sizeof (struct elf_strtab_hash_entry *); + array = (struct elf_strtab_hash_entry **) bfd_malloc (amt); + if (array == NULL) + goto alloc_failure; + + memset (last, 0, sizeof (last)); + for (i = 0; i < 256; ++i) + last_ptr[i] = &last[i]; + for (i = 1, a = array; i < tab->size; ++i) + if (tab->array[i]->refcount) + *a++ = tab->array[i]; + else + tab->array[i]->len = 0; + + size = a - array; + + qsort (array, size, sizeof (struct elf_strtab_hash_entry *), cmplengthentry); + + last4tab = htab_create_alloc (size * 4, NULL, last4_eq, NULL, calloc, free); + if (last4tab == NULL) + goto alloc_failure; + + /* Now insert the strings into hash tables (strings with last 4 characters + and strings with last character equal), look for longer strings which + we're suffix of. */ + for (a = array, end = array + size; a < end; a++) + { + register hashval_t hash; + unsigned int c; + unsigned int j; + const unsigned char *s; + PTR *p; + + e = *a; + if (e->len > 4) + { + s = e->root.string + e->len - 1; + hash = 0; + for (j = 0; j < 4; j++) + { + c = *--s; + hash += c + (c << 17); + hash ^= hash >> 2; + } + p = htab_find_slot_with_hash (last4tab, e, hash, INSERT); + if (p == NULL) + goto alloc_failure; + if (*p) + { + struct elf_strtab_hash_entry *ent; + + ent = (struct elf_strtab_hash_entry *) *p; + e->u.suffix = ent; + e->len = 0; + continue; + } + else + *p = (PTR) e; + } + else + { + struct elf_strtab_hash_entry *tem; + + c = e->root.string[e->len - 2] & 0xff; + + for (tem = last[c]; tem; tem = tem->u.next) + if (tem->len > e->len + && memcmp (tem->root.string + (tem->len - e->len), + e->root.string, e->len - 1) == 0) + break; + if (tem) + { + e->u.suffix = tem; + e->len = 0; + continue; + } + } + + c = e->root.string[e->len - 2] & 0xff; + /* Put longest strings first. */ + *last_ptr[c] = e; + last_ptr[c] = &e->u.next; + e->u.next = NULL; + } + +alloc_failure: + if (array) + free (array); + if (last4tab) + htab_delete (last4tab); + + /* Now assign positions to the strings we want to keep. */ + size = 1; + for (i = 1; i < tab->size; ++i) + { + e = tab->array[i]; + if (e->refcount && e->len) + { + e->u.index = size; + size += e->len; + } + } + + tab->sec_size = size; + + /* And now adjust the rest. */ + for (i = 1; i < tab->size; ++i) + { + e = tab->array[i]; + if (e->refcount && ! e->len) + e->u.index = e->u.suffix->u.index + + (e->u.suffix->len - strlen (e->root.string) - 1); + } +} diff --git a/contrib/binutils-2.14/bfd/elf.c b/contrib/binutils-2.14/bfd/elf.c new file mode 100644 index 0000000000..7e1bacd286 --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf.c @@ -0,0 +1,7537 @@ +/* ELF executable support for BFD. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* SECTION + + ELF backends + + BFD support for ELF formats is being worked on. + Currently, the best supported back ends are for sparc and i386 + (running svr4 or Solaris 2). + + Documentation of the internals of the support code still needs + to be written. The code is changing quickly enough that we + haven't bothered yet. */ + +/* For sparc64-cross-sparc32. */ +#define _SYSCALL32 +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#define ARCH_SIZE 0 +#include "elf-bfd.h" +#include "libiberty.h" + +static INLINE struct elf_segment_map *make_mapping + PARAMS ((bfd *, asection **, unsigned int, unsigned int, bfd_boolean)); +static bfd_boolean map_sections_to_segments + PARAMS ((bfd *)); +static int elf_sort_sections + PARAMS ((const PTR, const PTR)); +static bfd_boolean assign_file_positions_for_segments + PARAMS ((bfd *)); +static bfd_boolean assign_file_positions_except_relocs + PARAMS ((bfd *)); +static bfd_boolean prep_headers + PARAMS ((bfd *)); +static bfd_boolean swap_out_syms + PARAMS ((bfd *, struct bfd_strtab_hash **, int)); +static bfd_boolean copy_private_bfd_data + PARAMS ((bfd *, bfd *)); +static char *elf_read + PARAMS ((bfd *, file_ptr, bfd_size_type)); +static const char *group_signature + PARAMS ((bfd *, Elf_Internal_Shdr *)); +static bfd_boolean setup_group + PARAMS ((bfd *, Elf_Internal_Shdr *, asection *)); +static void merge_sections_remove_hook + PARAMS ((bfd *, asection *)); +static void elf_fake_sections + PARAMS ((bfd *, asection *, PTR)); +static bfd_boolean assign_section_numbers + PARAMS ((bfd *)); +static INLINE int sym_is_global + PARAMS ((bfd *, asymbol *)); +static bfd_boolean elf_map_symbols + PARAMS ((bfd *)); +static bfd_size_type get_program_header_size + PARAMS ((bfd *)); +static bfd_boolean elfcore_read_notes + PARAMS ((bfd *, file_ptr, bfd_size_type)); +static bfd_boolean elf_find_function + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **)); +static int elfcore_make_pid + PARAMS ((bfd *)); +static bfd_boolean elfcore_maybe_make_sect + PARAMS ((bfd *, char *, asection *)); +static bfd_boolean elfcore_make_note_pseudosection + PARAMS ((bfd *, char *, Elf_Internal_Note *)); +static bfd_boolean elfcore_grok_prfpreg + PARAMS ((bfd *, Elf_Internal_Note *)); +static bfd_boolean elfcore_grok_prxfpreg + PARAMS ((bfd *, Elf_Internal_Note *)); +static bfd_boolean elfcore_grok_note + PARAMS ((bfd *, Elf_Internal_Note *)); +static bfd_boolean elfcore_netbsd_get_lwpid + PARAMS ((Elf_Internal_Note *, int *)); +static bfd_boolean elfcore_grok_netbsd_procinfo + PARAMS ((bfd *, Elf_Internal_Note *)); +static bfd_boolean elfcore_grok_netbsd_note + PARAMS ((bfd *, Elf_Internal_Note *)); +static bfd_boolean elfcore_grok_nto_gregs + PARAMS ((bfd *, Elf_Internal_Note *, pid_t)); +static bfd_boolean elfcore_grok_nto_status + PARAMS ((bfd *, Elf_Internal_Note *, pid_t *)); +static bfd_boolean elfcore_grok_nto_note + PARAMS ((bfd *, Elf_Internal_Note *)); + +/* Swap version information in and out. The version information is + currently size independent. If that ever changes, this code will + need to move into elfcode.h. */ + +/* Swap in a Verdef structure. */ + +void +_bfd_elf_swap_verdef_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Verdef *src; + Elf_Internal_Verdef *dst; +{ + dst->vd_version = H_GET_16 (abfd, src->vd_version); + dst->vd_flags = H_GET_16 (abfd, src->vd_flags); + dst->vd_ndx = H_GET_16 (abfd, src->vd_ndx); + dst->vd_cnt = H_GET_16 (abfd, src->vd_cnt); + dst->vd_hash = H_GET_32 (abfd, src->vd_hash); + dst->vd_aux = H_GET_32 (abfd, src->vd_aux); + dst->vd_next = H_GET_32 (abfd, src->vd_next); +} + +/* Swap out a Verdef structure. */ + +void +_bfd_elf_swap_verdef_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Verdef *src; + Elf_External_Verdef *dst; +{ + H_PUT_16 (abfd, src->vd_version, dst->vd_version); + H_PUT_16 (abfd, src->vd_flags, dst->vd_flags); + H_PUT_16 (abfd, src->vd_ndx, dst->vd_ndx); + H_PUT_16 (abfd, src->vd_cnt, dst->vd_cnt); + H_PUT_32 (abfd, src->vd_hash, dst->vd_hash); + H_PUT_32 (abfd, src->vd_aux, dst->vd_aux); + H_PUT_32 (abfd, src->vd_next, dst->vd_next); +} + +/* Swap in a Verdaux structure. */ + +void +_bfd_elf_swap_verdaux_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Verdaux *src; + Elf_Internal_Verdaux *dst; +{ + dst->vda_name = H_GET_32 (abfd, src->vda_name); + dst->vda_next = H_GET_32 (abfd, src->vda_next); +} + +/* Swap out a Verdaux structure. */ + +void +_bfd_elf_swap_verdaux_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Verdaux *src; + Elf_External_Verdaux *dst; +{ + H_PUT_32 (abfd, src->vda_name, dst->vda_name); + H_PUT_32 (abfd, src->vda_next, dst->vda_next); +} + +/* Swap in a Verneed structure. */ + +void +_bfd_elf_swap_verneed_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Verneed *src; + Elf_Internal_Verneed *dst; +{ + dst->vn_version = H_GET_16 (abfd, src->vn_version); + dst->vn_cnt = H_GET_16 (abfd, src->vn_cnt); + dst->vn_file = H_GET_32 (abfd, src->vn_file); + dst->vn_aux = H_GET_32 (abfd, src->vn_aux); + dst->vn_next = H_GET_32 (abfd, src->vn_next); +} + +/* Swap out a Verneed structure. */ + +void +_bfd_elf_swap_verneed_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Verneed *src; + Elf_External_Verneed *dst; +{ + H_PUT_16 (abfd, src->vn_version, dst->vn_version); + H_PUT_16 (abfd, src->vn_cnt, dst->vn_cnt); + H_PUT_32 (abfd, src->vn_file, dst->vn_file); + H_PUT_32 (abfd, src->vn_aux, dst->vn_aux); + H_PUT_32 (abfd, src->vn_next, dst->vn_next); +} + +/* Swap in a Vernaux structure. */ + +void +_bfd_elf_swap_vernaux_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Vernaux *src; + Elf_Internal_Vernaux *dst; +{ + dst->vna_hash = H_GET_32 (abfd, src->vna_hash); + dst->vna_flags = H_GET_16 (abfd, src->vna_flags); + dst->vna_other = H_GET_16 (abfd, src->vna_other); + dst->vna_name = H_GET_32 (abfd, src->vna_name); + dst->vna_next = H_GET_32 (abfd, src->vna_next); +} + +/* Swap out a Vernaux structure. */ + +void +_bfd_elf_swap_vernaux_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Vernaux *src; + Elf_External_Vernaux *dst; +{ + H_PUT_32 (abfd, src->vna_hash, dst->vna_hash); + H_PUT_16 (abfd, src->vna_flags, dst->vna_flags); + H_PUT_16 (abfd, src->vna_other, dst->vna_other); + H_PUT_32 (abfd, src->vna_name, dst->vna_name); + H_PUT_32 (abfd, src->vna_next, dst->vna_next); +} + +/* Swap in a Versym structure. */ + +void +_bfd_elf_swap_versym_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Versym *src; + Elf_Internal_Versym *dst; +{ + dst->vs_vers = H_GET_16 (abfd, src->vs_vers); +} + +/* Swap out a Versym structure. */ + +void +_bfd_elf_swap_versym_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Versym *src; + Elf_External_Versym *dst; +{ + H_PUT_16 (abfd, src->vs_vers, dst->vs_vers); +} + +/* Standard ELF hash function. Do not change this function; you will + cause invalid hash tables to be generated. */ + +unsigned long +bfd_elf_hash (namearg) + const char *namearg; +{ + const unsigned char *name = (const unsigned char *) namearg; + unsigned long h = 0; + unsigned long g; + int ch; + + while ((ch = *name++) != '\0') + { + h = (h << 4) + ch; + if ((g = (h & 0xf0000000)) != 0) + { + h ^= g >> 24; + /* The ELF ABI says `h &= ~g', but this is equivalent in + this case and on some machines one insn instead of two. */ + h ^= g; + } + } + return h & 0xffffffff; +} + +/* Read a specified number of bytes at a specified offset in an ELF + file, into a newly allocated buffer, and return a pointer to the + buffer. */ + +static char * +elf_read (abfd, offset, size) + bfd *abfd; + file_ptr offset; + bfd_size_type size; +{ + char *buf; + + if ((buf = bfd_alloc (abfd, size)) == NULL) + return NULL; + if (bfd_seek (abfd, offset, SEEK_SET) != 0) + return NULL; + if (bfd_bread ((PTR) buf, size, abfd) != size) + { + if (bfd_get_error () != bfd_error_system_call) + bfd_set_error (bfd_error_file_truncated); + return NULL; + } + return buf; +} + +bfd_boolean +bfd_elf_mkobject (abfd) + bfd *abfd; +{ + /* This just does initialization. */ + /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ + bfd_size_type amt = sizeof (struct elf_obj_tdata); + elf_tdata (abfd) = (struct elf_obj_tdata *) bfd_zalloc (abfd, amt); + if (elf_tdata (abfd) == 0) + return FALSE; + /* Since everything is done at close time, do we need any + initialization? */ + + return TRUE; +} + +bfd_boolean +bfd_elf_mkcorefile (abfd) + bfd *abfd; +{ + /* I think this can be done just like an object file. */ + return bfd_elf_mkobject (abfd); +} + +char * +bfd_elf_get_str_section (abfd, shindex) + bfd *abfd; + unsigned int shindex; +{ + Elf_Internal_Shdr **i_shdrp; + char *shstrtab = NULL; + file_ptr offset; + bfd_size_type shstrtabsize; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp == 0 || i_shdrp[shindex] == 0) + return 0; + + shstrtab = (char *) i_shdrp[shindex]->contents; + if (shstrtab == NULL) + { + /* No cached one, attempt to read, and cache what we read. */ + offset = i_shdrp[shindex]->sh_offset; + shstrtabsize = i_shdrp[shindex]->sh_size; + shstrtab = elf_read (abfd, offset, shstrtabsize); + i_shdrp[shindex]->contents = (PTR) shstrtab; + } + return shstrtab; +} + +char * +bfd_elf_string_from_elf_section (abfd, shindex, strindex) + bfd *abfd; + unsigned int shindex; + unsigned int strindex; +{ + Elf_Internal_Shdr *hdr; + + if (strindex == 0) + return ""; + + hdr = elf_elfsections (abfd)[shindex]; + + if (hdr->contents == NULL + && bfd_elf_get_str_section (abfd, shindex) == NULL) + return NULL; + + if (strindex >= hdr->sh_size) + { + (*_bfd_error_handler) + (_("%s: invalid string offset %u >= %lu for section `%s'"), + bfd_archive_filename (abfd), strindex, (unsigned long) hdr->sh_size, + ((shindex == elf_elfheader(abfd)->e_shstrndx + && strindex == hdr->sh_name) + ? ".shstrtab" + : elf_string_from_elf_strtab (abfd, hdr->sh_name))); + return ""; + } + + return ((char *) hdr->contents) + strindex; +} + +/* Read and convert symbols to internal format. + SYMCOUNT specifies the number of symbols to read, starting from + symbol SYMOFFSET. If any of INTSYM_BUF, EXTSYM_BUF or EXTSHNDX_BUF + are non-NULL, they are used to store the internal symbols, external + symbols, and symbol section index extensions, respectively. */ + +Elf_Internal_Sym * +bfd_elf_get_elf_syms (ibfd, symtab_hdr, symcount, symoffset, + intsym_buf, extsym_buf, extshndx_buf) + bfd *ibfd; + Elf_Internal_Shdr *symtab_hdr; + size_t symcount; + size_t symoffset; + Elf_Internal_Sym *intsym_buf; + PTR extsym_buf; + Elf_External_Sym_Shndx *extshndx_buf; +{ + Elf_Internal_Shdr *shndx_hdr; + PTR alloc_ext; + const bfd_byte *esym; + Elf_External_Sym_Shndx *alloc_extshndx; + Elf_External_Sym_Shndx *shndx; + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + struct elf_backend_data *bed; + size_t extsym_size; + bfd_size_type amt; + file_ptr pos; + + if (symcount == 0) + return intsym_buf; + + /* Normal syms might have section extension entries. */ + shndx_hdr = NULL; + if (symtab_hdr == &elf_tdata (ibfd)->symtab_hdr) + shndx_hdr = &elf_tdata (ibfd)->symtab_shndx_hdr; + + /* Read the symbols. */ + alloc_ext = NULL; + alloc_extshndx = NULL; + bed = get_elf_backend_data (ibfd); + extsym_size = bed->s->sizeof_sym; + amt = symcount * extsym_size; + pos = symtab_hdr->sh_offset + symoffset * extsym_size; + if (extsym_buf == NULL) + { + alloc_ext = bfd_malloc (amt); + extsym_buf = alloc_ext; + } + if (extsym_buf == NULL + || bfd_seek (ibfd, pos, SEEK_SET) != 0 + || bfd_bread (extsym_buf, amt, ibfd) != amt) + { + intsym_buf = NULL; + goto out; + } + + if (shndx_hdr == NULL || shndx_hdr->sh_size == 0) + extshndx_buf = NULL; + else + { + amt = symcount * sizeof (Elf_External_Sym_Shndx); + pos = shndx_hdr->sh_offset + symoffset * sizeof (Elf_External_Sym_Shndx); + if (extshndx_buf == NULL) + { + alloc_extshndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); + extshndx_buf = alloc_extshndx; + } + if (extshndx_buf == NULL + || bfd_seek (ibfd, pos, SEEK_SET) != 0 + || bfd_bread (extshndx_buf, amt, ibfd) != amt) + { + intsym_buf = NULL; + goto out; + } + } + + if (intsym_buf == NULL) + { + bfd_size_type amt = symcount * sizeof (Elf_Internal_Sym); + intsym_buf = (Elf_Internal_Sym *) bfd_malloc (amt); + if (intsym_buf == NULL) + goto out; + } + + /* Convert the symbols to internal form. */ + isymend = intsym_buf + symcount; + for (esym = extsym_buf, isym = intsym_buf, shndx = extshndx_buf; + isym < isymend; + esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL) + (*bed->s->swap_symbol_in) (ibfd, esym, (const PTR) shndx, isym); + + out: + if (alloc_ext != NULL) + free (alloc_ext); + if (alloc_extshndx != NULL) + free (alloc_extshndx); + + return intsym_buf; +} + +/* Look up a symbol name. */ +const char * +bfd_elf_local_sym_name (abfd, isym) + bfd *abfd; + Elf_Internal_Sym *isym; +{ + unsigned int iname = isym->st_name; + unsigned int shindex = elf_tdata (abfd)->symtab_hdr.sh_link; + if (iname == 0 && ELF_ST_TYPE (isym->st_info) == STT_SECTION) + { + iname = elf_elfsections (abfd)[isym->st_shndx]->sh_name; + shindex = elf_elfheader (abfd)->e_shstrndx; + } + + return bfd_elf_string_from_elf_section (abfd, shindex, iname); +} + +/* Elf_Internal_Shdr->contents is an array of these for SHT_GROUP + sections. The first element is the flags, the rest are section + pointers. */ + +typedef union elf_internal_group { + Elf_Internal_Shdr *shdr; + unsigned int flags; +} Elf_Internal_Group; + +/* Return the name of the group signature symbol. Why isn't the + signature just a string? */ + +static const char * +group_signature (abfd, ghdr) + bfd *abfd; + Elf_Internal_Shdr *ghdr; +{ + Elf_Internal_Shdr *hdr; + unsigned char esym[sizeof (Elf64_External_Sym)]; + Elf_External_Sym_Shndx eshndx; + Elf_Internal_Sym isym; + + /* First we need to ensure the symbol table is available. */ + if (! bfd_section_from_shdr (abfd, ghdr->sh_link)) + return NULL; + + /* Go read the symbol. */ + hdr = &elf_tdata (abfd)->symtab_hdr; + if (bfd_elf_get_elf_syms (abfd, hdr, 1, ghdr->sh_info, + &isym, esym, &eshndx) == NULL) + return NULL; + + return bfd_elf_local_sym_name (abfd, &isym); +} + +/* Set next_in_group list pointer, and group name for NEWSECT. */ + +static bfd_boolean +setup_group (abfd, hdr, newsect) + bfd *abfd; + Elf_Internal_Shdr *hdr; + asection *newsect; +{ + unsigned int num_group = elf_tdata (abfd)->num_group; + + /* If num_group is zero, read in all SHT_GROUP sections. The count + is set to -1 if there are no SHT_GROUP sections. */ + if (num_group == 0) + { + unsigned int i, shnum; + + /* First count the number of groups. If we have a SHT_GROUP + section with just a flag word (ie. sh_size is 4), ignore it. */ + shnum = elf_numsections (abfd); + num_group = 0; + for (i = 0; i < shnum; i++) + { + Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; + if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8) + num_group += 1; + } + + if (num_group == 0) + num_group = (unsigned) -1; + elf_tdata (abfd)->num_group = num_group; + + if (num_group > 0) + { + /* We keep a list of elf section headers for group sections, + so we can find them quickly. */ + bfd_size_type amt = num_group * sizeof (Elf_Internal_Shdr *); + elf_tdata (abfd)->group_sect_ptr = bfd_alloc (abfd, amt); + if (elf_tdata (abfd)->group_sect_ptr == NULL) + return FALSE; + + num_group = 0; + for (i = 0; i < shnum; i++) + { + Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; + if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8) + { + unsigned char *src; + Elf_Internal_Group *dest; + + /* Add to list of sections. */ + elf_tdata (abfd)->group_sect_ptr[num_group] = shdr; + num_group += 1; + + /* Read the raw contents. */ + BFD_ASSERT (sizeof (*dest) >= 4); + amt = shdr->sh_size * sizeof (*dest) / 4; + shdr->contents = bfd_alloc (abfd, amt); + if (shdr->contents == NULL + || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 + || (bfd_bread (shdr->contents, shdr->sh_size, abfd) + != shdr->sh_size)) + return FALSE; + + /* Translate raw contents, a flag word followed by an + array of elf section indices all in target byte order, + to the flag word followed by an array of elf section + pointers. */ + src = shdr->contents + shdr->sh_size; + dest = (Elf_Internal_Group *) (shdr->contents + amt); + while (1) + { + unsigned int idx; + + src -= 4; + --dest; + idx = H_GET_32 (abfd, src); + if (src == shdr->contents) + { + dest->flags = idx; + if (shdr->bfd_section != NULL && (idx & GRP_COMDAT)) + shdr->bfd_section->flags + |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + break; + } + if (idx >= shnum) + { + ((*_bfd_error_handler) + (_("%s: invalid SHT_GROUP entry"), + bfd_archive_filename (abfd))); + idx = 0; + } + dest->shdr = elf_elfsections (abfd)[idx]; + } + } + } + } + } + + if (num_group != (unsigned) -1) + { + unsigned int i; + + for (i = 0; i < num_group; i++) + { + Elf_Internal_Shdr *shdr = elf_tdata (abfd)->group_sect_ptr[i]; + Elf_Internal_Group *idx = (Elf_Internal_Group *) shdr->contents; + unsigned int n_elt = shdr->sh_size / 4; + + /* Look through this group's sections to see if current + section is a member. */ + while (--n_elt != 0) + if ((++idx)->shdr == hdr) + { + asection *s = NULL; + + /* We are a member of this group. Go looking through + other members to see if any others are linked via + next_in_group. */ + idx = (Elf_Internal_Group *) shdr->contents; + n_elt = shdr->sh_size / 4; + while (--n_elt != 0) + if ((s = (++idx)->shdr->bfd_section) != NULL + && elf_next_in_group (s) != NULL) + break; + if (n_elt != 0) + { + /* Snarf the group name from other member, and + insert current section in circular list. */ + elf_group_name (newsect) = elf_group_name (s); + elf_next_in_group (newsect) = elf_next_in_group (s); + elf_next_in_group (s) = newsect; + } + else + { + const char *gname; + + gname = group_signature (abfd, shdr); + if (gname == NULL) + return FALSE; + elf_group_name (newsect) = gname; + + /* Start a circular list with one element. */ + elf_next_in_group (newsect) = newsect; + } + + /* If the group section has been created, point to the + new member. */ + if (shdr->bfd_section != NULL) + elf_next_in_group (shdr->bfd_section) = newsect; + + i = num_group - 1; + break; + } + } + } + + if (elf_group_name (newsect) == NULL) + { + (*_bfd_error_handler) (_("%s: no group info for section %s"), + bfd_archive_filename (abfd), newsect->name); + } + return TRUE; +} + +bfd_boolean +bfd_elf_discard_group (abfd, group) + bfd *abfd ATTRIBUTE_UNUSED; + asection *group; +{ + asection *first = elf_next_in_group (group); + asection *s = first; + + while (s != NULL) + { + s->output_section = bfd_abs_section_ptr; + s = elf_next_in_group (s); + /* These lists are circular. */ + if (s == first) + break; + } + return TRUE; +} + +/* Make a BFD section from an ELF section. We store a pointer to the + BFD section in the bfd_section field of the header. */ + +bfd_boolean +_bfd_elf_make_section_from_shdr (abfd, hdr, name) + bfd *abfd; + Elf_Internal_Shdr *hdr; + const char *name; +{ + asection *newsect; + flagword flags; + struct elf_backend_data *bed; + + if (hdr->bfd_section != NULL) + { + BFD_ASSERT (strcmp (name, + bfd_get_section_name (abfd, hdr->bfd_section)) == 0); + return TRUE; + } + + newsect = bfd_make_section_anyway (abfd, name); + if (newsect == NULL) + return FALSE; + + newsect->filepos = hdr->sh_offset; + + if (! bfd_set_section_vma (abfd, newsect, hdr->sh_addr) + || ! bfd_set_section_size (abfd, newsect, hdr->sh_size) + || ! bfd_set_section_alignment (abfd, newsect, + bfd_log2 ((bfd_vma) hdr->sh_addralign))) + return FALSE; + + flags = SEC_NO_FLAGS; + if (hdr->sh_type != SHT_NOBITS) + flags |= SEC_HAS_CONTENTS; + if (hdr->sh_type == SHT_GROUP) + flags |= SEC_GROUP | SEC_EXCLUDE; + if ((hdr->sh_flags & SHF_ALLOC) != 0) + { + flags |= SEC_ALLOC; + if (hdr->sh_type != SHT_NOBITS) + flags |= SEC_LOAD; + } + if ((hdr->sh_flags & SHF_WRITE) == 0) + flags |= SEC_READONLY; + if ((hdr->sh_flags & SHF_EXECINSTR) != 0) + flags |= SEC_CODE; + else if ((flags & SEC_LOAD) != 0) + flags |= SEC_DATA; + if ((hdr->sh_flags & SHF_MERGE) != 0) + { + flags |= SEC_MERGE; + newsect->entsize = hdr->sh_entsize; + if ((hdr->sh_flags & SHF_STRINGS) != 0) + flags |= SEC_STRINGS; + } + if (hdr->sh_flags & SHF_GROUP) + if (!setup_group (abfd, hdr, newsect)) + return FALSE; + if ((hdr->sh_flags & SHF_TLS) != 0) + flags |= SEC_THREAD_LOCAL; + + /* The debugging sections appear to be recognized only by name, not + any sort of flag. */ + { + static const char *debug_sec_names [] = + { + ".debug", + ".gnu.linkonce.wi.", + ".line", + ".stab" + }; + int i; + + for (i = ARRAY_SIZE (debug_sec_names); i--;) + if (strncmp (name, debug_sec_names[i], strlen (debug_sec_names[i])) == 0) + break; + + if (i >= 0) + flags |= SEC_DEBUGGING; + } + + /* As a GNU extension, if the name begins with .gnu.linkonce, we + only link a single copy of the section. This is used to support + g++. g++ will emit each template expansion in its own section. + The symbols will be defined as weak, so that multiple definitions + are permitted. The GNU linker extension is to actually discard + all but one of the sections. */ + if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0 + && elf_next_in_group (newsect) == NULL) + flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_section_flags) + if (! bed->elf_backend_section_flags (&flags, hdr)) + return FALSE; + + if (! bfd_set_section_flags (abfd, newsect, flags)) + return FALSE; + + if ((flags & SEC_ALLOC) != 0) + { + Elf_Internal_Phdr *phdr; + unsigned int i; + + /* Look through the phdrs to see if we need to adjust the lma. + If all the p_paddr fields are zero, we ignore them, since + some ELF linkers produce such output. */ + phdr = elf_tdata (abfd)->phdr; + for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) + { + if (phdr->p_paddr != 0) + break; + } + if (i < elf_elfheader (abfd)->e_phnum) + { + phdr = elf_tdata (abfd)->phdr; + for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) + { + /* This section is part of this segment if its file + offset plus size lies within the segment's memory + span and, if the section is loaded, the extent of the + loaded data lies within the extent of the segment. + + Note - we used to check the p_paddr field as well, and + refuse to set the LMA if it was 0. This is wrong + though, as a perfectly valid initialised segment can + have a p_paddr of zero. Some architectures, eg ARM, + place special significance on the address 0 and + executables need to be able to have a segment which + covers this address. */ + if (phdr->p_type == PT_LOAD + && (bfd_vma) hdr->sh_offset >= phdr->p_offset + && (hdr->sh_offset + hdr->sh_size + <= phdr->p_offset + phdr->p_memsz) + && ((flags & SEC_LOAD) == 0 + || (hdr->sh_offset + hdr->sh_size + <= phdr->p_offset + phdr->p_filesz))) + { + if ((flags & SEC_LOAD) == 0) + newsect->lma = (phdr->p_paddr + + hdr->sh_addr - phdr->p_vaddr); + else + /* We used to use the same adjustment for SEC_LOAD + sections, but that doesn't work if the segment + is packed with code from multiple VMAs. + Instead we calculate the section LMA based on + the segment LMA. It is assumed that the + segment will contain sections with contiguous + LMAs, even if the VMAs are not. */ + newsect->lma = (phdr->p_paddr + + hdr->sh_offset - phdr->p_offset); + + /* With contiguous segments, we can't tell from file + offsets whether a section with zero size should + be placed at the end of one segment or the + beginning of the next. Decide based on vaddr. */ + if (hdr->sh_addr >= phdr->p_vaddr + && (hdr->sh_addr + hdr->sh_size + <= phdr->p_vaddr + phdr->p_memsz)) + break; + } + } + } + } + + hdr->bfd_section = newsect; + elf_section_data (newsect)->this_hdr = *hdr; + + return TRUE; +} + +/* +INTERNAL_FUNCTION + bfd_elf_find_section + +SYNOPSIS + struct elf_internal_shdr *bfd_elf_find_section (bfd *abfd, char *name); + +DESCRIPTION + Helper functions for GDB to locate the string tables. + Since BFD hides string tables from callers, GDB needs to use an + internal hook to find them. Sun's .stabstr, in particular, + isn't even pointed to by the .stab section, so ordinary + mechanisms wouldn't work to find it, even if we had some. +*/ + +struct elf_internal_shdr * +bfd_elf_find_section (abfd, name) + bfd *abfd; + char *name; +{ + Elf_Internal_Shdr **i_shdrp; + char *shstrtab; + unsigned int max; + unsigned int i; + + i_shdrp = elf_elfsections (abfd); + if (i_shdrp != NULL) + { + shstrtab = bfd_elf_get_str_section (abfd, + elf_elfheader (abfd)->e_shstrndx); + if (shstrtab != NULL) + { + max = elf_numsections (abfd); + for (i = 1; i < max; i++) + if (!strcmp (&shstrtab[i_shdrp[i]->sh_name], name)) + return i_shdrp[i]; + } + } + return 0; +} + +const char *const bfd_elf_section_type_names[] = { + "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB", + "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", + "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM", +}; + +/* ELF relocs are against symbols. If we are producing relocateable + output, and the reloc is against an external symbol, and nothing + has given us any additional addend, the resulting reloc will also + be against the same symbol. In such a case, we don't want to + change anything about the way the reloc is handled, since it will + all be done at final link time. Rather than put special case code + into bfd_perform_relocation, all the reloc types use this howto + function. It just short circuits the reloc if producing + relocateable output against an external symbol. */ + +bfd_reloc_status_type +bfd_elf_generic_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd, + error_message) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *reloc_entry; + asymbol *symbol; + PTR data ATTRIBUTE_UNUSED; + asection *input_section; + bfd *output_bfd; + char **error_message ATTRIBUTE_UNUSED; +{ + 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; + } + + return bfd_reloc_continue; +} + +/* Make sure sec_info_type is cleared if sec_info is cleared too. */ + +static void +merge_sections_remove_hook (abfd, sec) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; +{ + BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE); + sec->sec_info_type = ELF_INFO_TYPE_NONE; +} + +/* Finish SHF_MERGE section merging. */ + +bfd_boolean +_bfd_elf_merge_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (!is_elf_hash_table (info)) + return FALSE; + if (elf_hash_table (info)->merge_info) + _bfd_merge_sections (abfd, elf_hash_table (info)->merge_info, + merge_sections_remove_hook); + return TRUE; +} + +void +_bfd_elf_link_just_syms (sec, info) + asection *sec; + struct bfd_link_info *info; +{ + sec->output_section = bfd_abs_section_ptr; + sec->output_offset = sec->vma; + if (!is_elf_hash_table (info)) + return; + + sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS; +} + +/* Copy the program header and other data from one object module to + another. */ + +bfd_boolean +_bfd_elf_copy_private_bfd_data (ibfd, obfd) + 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_gp (obfd) = elf_gp (ibfd); + elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; + elf_flags_init (obfd) = TRUE; + return TRUE; +} + +/* Print out the program headers. */ + +bfd_boolean +_bfd_elf_print_private_bfd_data (abfd, farg) + bfd *abfd; + PTR farg; +{ + FILE *f = (FILE *) farg; + Elf_Internal_Phdr *p; + asection *s; + bfd_byte *dynbuf = NULL; + + p = elf_tdata (abfd)->phdr; + if (p != NULL) + { + unsigned int i, c; + + fprintf (f, _("\nProgram Header:\n")); + c = elf_elfheader (abfd)->e_phnum; + for (i = 0; i < c; i++, p++) + { + const char *pt; + char buf[20]; + + switch (p->p_type) + { + case PT_NULL: pt = "NULL"; break; + case PT_LOAD: pt = "LOAD"; break; + case PT_DYNAMIC: pt = "DYNAMIC"; break; + case PT_INTERP: pt = "INTERP"; break; + case PT_NOTE: pt = "NOTE"; break; + case PT_SHLIB: pt = "SHLIB"; break; + case PT_PHDR: pt = "PHDR"; break; + case PT_TLS: pt = "TLS"; break; + case PT_GNU_EH_FRAME: pt = "EH_FRAME"; break; + default: sprintf (buf, "0x%lx", p->p_type); pt = buf; break; + } + fprintf (f, "%8s off 0x", pt); + bfd_fprintf_vma (abfd, f, p->p_offset); + fprintf (f, " vaddr 0x"); + bfd_fprintf_vma (abfd, f, p->p_vaddr); + fprintf (f, " paddr 0x"); + bfd_fprintf_vma (abfd, f, p->p_paddr); + fprintf (f, " align 2**%u\n", bfd_log2 (p->p_align)); + fprintf (f, " filesz 0x"); + bfd_fprintf_vma (abfd, f, p->p_filesz); + fprintf (f, " memsz 0x"); + bfd_fprintf_vma (abfd, f, p->p_memsz); + fprintf (f, " flags %c%c%c", + (p->p_flags & PF_R) != 0 ? 'r' : '-', + (p->p_flags & PF_W) != 0 ? 'w' : '-', + (p->p_flags & PF_X) != 0 ? 'x' : '-'); + if ((p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)) != 0) + fprintf (f, " %lx", p->p_flags &~ (unsigned) (PF_R | PF_W | PF_X)); + fprintf (f, "\n"); + } + } + + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + { + int elfsec; + unsigned long shlink; + bfd_byte *extdyn, *extdynend; + size_t extdynsize; + void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); + + fprintf (f, _("\nDynamic Section:\n")); + + dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size); + if (dynbuf == NULL) + goto error_return; + if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, (file_ptr) 0, + s->_raw_size)) + goto error_return; + + elfsec = _bfd_elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_return; + shlink = elf_elfsections (abfd)[elfsec]->sh_link; + + extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; + swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; + + extdyn = dynbuf; + extdynend = extdyn + s->_raw_size; + for (; extdyn < extdynend; extdyn += extdynsize) + { + Elf_Internal_Dyn dyn; + const char *name; + char ab[20]; + bfd_boolean stringp; + + (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn); + + if (dyn.d_tag == DT_NULL) + break; + + stringp = FALSE; + switch (dyn.d_tag) + { + default: + sprintf (ab, "0x%lx", (unsigned long) dyn.d_tag); + name = ab; + break; + + case DT_NEEDED: name = "NEEDED"; stringp = TRUE; break; + case DT_PLTRELSZ: name = "PLTRELSZ"; break; + case DT_PLTGOT: name = "PLTGOT"; break; + case DT_HASH: name = "HASH"; break; + case DT_STRTAB: name = "STRTAB"; break; + case DT_SYMTAB: name = "SYMTAB"; break; + case DT_RELA: name = "RELA"; break; + case DT_RELASZ: name = "RELASZ"; break; + case DT_RELAENT: name = "RELAENT"; break; + case DT_STRSZ: name = "STRSZ"; break; + case DT_SYMENT: name = "SYMENT"; break; + case DT_INIT: name = "INIT"; break; + case DT_FINI: name = "FINI"; break; + case DT_SONAME: name = "SONAME"; stringp = TRUE; break; + case DT_RPATH: name = "RPATH"; stringp = TRUE; break; + case DT_SYMBOLIC: name = "SYMBOLIC"; break; + case DT_REL: name = "REL"; break; + case DT_RELSZ: name = "RELSZ"; break; + case DT_RELENT: name = "RELENT"; break; + case DT_PLTREL: name = "PLTREL"; break; + case DT_DEBUG: name = "DEBUG"; break; + case DT_TEXTREL: name = "TEXTREL"; break; + case DT_JMPREL: name = "JMPREL"; break; + case DT_BIND_NOW: name = "BIND_NOW"; break; + case DT_INIT_ARRAY: name = "INIT_ARRAY"; break; + case DT_FINI_ARRAY: name = "FINI_ARRAY"; break; + case DT_INIT_ARRAYSZ: name = "INIT_ARRAYSZ"; break; + case DT_FINI_ARRAYSZ: name = "FINI_ARRAYSZ"; break; + case DT_RUNPATH: name = "RUNPATH"; stringp = TRUE; break; + case DT_FLAGS: name = "FLAGS"; break; + case DT_PREINIT_ARRAY: name = "PREINIT_ARRAY"; break; + case DT_PREINIT_ARRAYSZ: name = "PREINIT_ARRAYSZ"; break; + case DT_CHECKSUM: name = "CHECKSUM"; break; + case DT_PLTPADSZ: name = "PLTPADSZ"; break; + case DT_MOVEENT: name = "MOVEENT"; break; + case DT_MOVESZ: name = "MOVESZ"; break; + case DT_FEATURE: name = "FEATURE"; break; + case DT_POSFLAG_1: name = "POSFLAG_1"; break; + case DT_SYMINSZ: name = "SYMINSZ"; break; + case DT_SYMINENT: name = "SYMINENT"; break; + case DT_CONFIG: name = "CONFIG"; stringp = TRUE; break; + case DT_DEPAUDIT: name = "DEPAUDIT"; stringp = TRUE; break; + case DT_AUDIT: name = "AUDIT"; stringp = TRUE; break; + case DT_PLTPAD: name = "PLTPAD"; break; + case DT_MOVETAB: name = "MOVETAB"; break; + case DT_SYMINFO: name = "SYMINFO"; break; + case DT_RELACOUNT: name = "RELACOUNT"; break; + case DT_RELCOUNT: name = "RELCOUNT"; break; + case DT_FLAGS_1: name = "FLAGS_1"; break; + case DT_VERSYM: name = "VERSYM"; break; + case DT_VERDEF: name = "VERDEF"; break; + case DT_VERDEFNUM: name = "VERDEFNUM"; break; + case DT_VERNEED: name = "VERNEED"; break; + case DT_VERNEEDNUM: name = "VERNEEDNUM"; break; + case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break; + case DT_USED: name = "USED"; break; + case DT_FILTER: name = "FILTER"; stringp = TRUE; break; + } + + fprintf (f, " %-11s ", name); + if (! stringp) + fprintf (f, "0x%lx", (unsigned long) dyn.d_un.d_val); + else + { + const char *string; + unsigned int tagv = dyn.d_un.d_val; + + string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (string == NULL) + goto error_return; + fprintf (f, "%s", string); + } + fprintf (f, "\n"); + } + + free (dynbuf); + dynbuf = NULL; + } + + if ((elf_dynverdef (abfd) != 0 && elf_tdata (abfd)->verdef == NULL) + || (elf_dynverref (abfd) != 0 && elf_tdata (abfd)->verref == NULL)) + { + if (! _bfd_elf_slurp_version_tables (abfd)) + return FALSE; + } + + if (elf_dynverdef (abfd) != 0) + { + Elf_Internal_Verdef *t; + + fprintf (f, _("\nVersion definitions:\n")); + for (t = elf_tdata (abfd)->verdef; t != NULL; t = t->vd_nextdef) + { + fprintf (f, "%d 0x%2.2x 0x%8.8lx %s\n", t->vd_ndx, + t->vd_flags, t->vd_hash, t->vd_nodename); + if (t->vd_auxptr->vda_nextptr != NULL) + { + Elf_Internal_Verdaux *a; + + fprintf (f, "\t"); + for (a = t->vd_auxptr->vda_nextptr; + a != NULL; + a = a->vda_nextptr) + fprintf (f, "%s ", a->vda_nodename); + fprintf (f, "\n"); + } + } + } + + if (elf_dynverref (abfd) != 0) + { + Elf_Internal_Verneed *t; + + fprintf (f, _("\nVersion References:\n")); + for (t = elf_tdata (abfd)->verref; t != NULL; t = t->vn_nextref) + { + Elf_Internal_Vernaux *a; + + fprintf (f, _(" required from %s:\n"), t->vn_filename); + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + fprintf (f, " 0x%8.8lx 0x%2.2x %2.2d %s\n", a->vna_hash, + a->vna_flags, a->vna_other, a->vna_nodename); + } + } + + return TRUE; + + error_return: + if (dynbuf != NULL) + free (dynbuf); + return FALSE; +} + +/* Display ELF-specific fields of a symbol. */ + +void +bfd_elf_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) filep; + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + fprintf (file, "elf "); + bfd_fprintf_vma (abfd, file, symbol->value); + fprintf (file, " %lx", (long) symbol->flags); + break; + case bfd_print_symbol_all: + { + const char *section_name; + const char *name = NULL; + struct elf_backend_data *bed; + unsigned char st_other; + bfd_vma val; + + section_name = symbol->section ? symbol->section->name : "(*none*)"; + + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_print_symbol_all) + name = (*bed->elf_backend_print_symbol_all) (abfd, filep, symbol); + + if (name == NULL) + { + name = symbol->name; + bfd_print_symbol_vandf (abfd, (PTR) file, symbol); + } + + fprintf (file, " %s\t", section_name); + /* Print the "other" value for a symbol. For common symbols, + we've already printed the size; now print the alignment. + For other symbols, we have no specified alignment, and + we've printed the address; now print the size. */ + if (bfd_is_com_section (symbol->section)) + val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_value; + else + val = ((elf_symbol_type *) symbol)->internal_elf_sym.st_size; + bfd_fprintf_vma (abfd, file, val); + + /* If we have version information, print it. */ + if (elf_tdata (abfd)->dynversym_section != 0 + && (elf_tdata (abfd)->dynverdef_section != 0 + || elf_tdata (abfd)->dynverref_section != 0)) + { + 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) + fprintf (file, " %-11s", version_string); + else + { + int i; + + fprintf (file, " (%s)", version_string); + for (i = 10 - strlen (version_string); i > 0; --i) + putc (' ', file); + } + } + + /* If the st_other field is not zero, print it. */ + st_other = ((elf_symbol_type *) symbol)->internal_elf_sym.st_other; + + switch (st_other) + { + case 0: break; + case STV_INTERNAL: fprintf (file, " .internal"); break; + case STV_HIDDEN: fprintf (file, " .hidden"); break; + case STV_PROTECTED: fprintf (file, " .protected"); break; + default: + /* Some other non-defined flags are also present, so print + everything hex. */ + fprintf (file, " 0x%02x", (unsigned int) st_other); + } + + fprintf (file, " %s", name); + } + break; + } +} + +/* Create an entry in an ELF linker hash table. */ + +struct bfd_hash_entry * +_bfd_elf_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = _bfd_link_hash_newfunc (entry, table, string); + if (entry != NULL) + { + struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry; + struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table; + + /* Set local fields. */ + ret->indx = -1; + ret->dynindx = -1; + ret->dynstr_index = 0; + ret->elf_hash_value = 0; + ret->weakdef = NULL; + ret->linker_section_pointer = NULL; + ret->verinfo.verdef = NULL; + ret->vtable_entries_size = 0; + ret->vtable_entries_used = NULL; + ret->vtable_parent = NULL; + ret->got = htab->init_refcount; + ret->plt = htab->init_refcount; + ret->size = 0; + ret->type = STT_NOTYPE; + ret->other = 0; + /* Assume that we have been called by a non-ELF symbol reader. + This flag is then reset by the code which reads an ELF input + file. This ensures that a symbol created by a non-ELF symbol + reader will have the flag set correctly. */ + ret->elf_link_hash_flags = ELF_LINK_NON_ELF; + } + + return entry; +} + +/* Copy data from an indirect symbol to its direct symbol, hiding the + old indirect symbol. Also used for copying flags to a weakdef. */ + +void +_bfd_elf_link_hash_copy_indirect (bed, dir, ind) + struct elf_backend_data *bed; + struct elf_link_hash_entry *dir, *ind; +{ + bfd_signed_vma tmp; + bfd_signed_vma lowest_valid = bed->can_refcount; + + /* Copy down any references that we may have already seen to the + symbol which just became indirect. */ + + dir->elf_link_hash_flags |= + (ind->elf_link_hash_flags + & (ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK + | ELF_LINK_NON_GOT_REF)); + + if (ind->root.type != bfd_link_hash_indirect) + return; + + /* Copy over the global and procedure linkage table refcount entries. + These may have been already set up by a check_relocs routine. */ + tmp = dir->got.refcount; + if (tmp < lowest_valid) + { + dir->got.refcount = ind->got.refcount; + ind->got.refcount = tmp; + } + else + BFD_ASSERT (ind->got.refcount < lowest_valid); + + tmp = dir->plt.refcount; + if (tmp < lowest_valid) + { + dir->plt.refcount = ind->plt.refcount; + ind->plt.refcount = tmp; + } + else + BFD_ASSERT (ind->plt.refcount < lowest_valid); + + if (dir->dynindx == -1) + { + dir->dynindx = ind->dynindx; + dir->dynstr_index = ind->dynstr_index; + ind->dynindx = -1; + ind->dynstr_index = 0; + } + else + BFD_ASSERT (ind->dynindx == -1); +} + +void +_bfd_elf_link_hash_hide_symbol (info, h, force_local) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + bfd_boolean force_local; +{ + h->plt = elf_hash_table (info)->init_offset; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + if (force_local) + { + h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL; + if (h->dynindx != -1) + { + h->dynindx = -1; + _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, + h->dynstr_index); + } + } +} + +/* Initialize an ELF linker hash table. */ + +bfd_boolean +_bfd_elf_link_hash_table_init (table, abfd, newfunc) + struct elf_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); +{ + bfd_boolean ret; + + table->dynamic_sections_created = FALSE; + table->dynobj = NULL; + /* Make sure can_refcount is extended to the width and signedness of + init_refcount before we subtract one from it. */ + table->init_refcount.refcount = get_elf_backend_data (abfd)->can_refcount; + table->init_refcount.refcount -= 1; + table->init_offset.offset = -(bfd_vma) 1; + /* The first dynamic symbol is a dummy. */ + table->dynsymcount = 1; + table->dynstr = NULL; + table->bucketcount = 0; + table->needed = NULL; + table->hgot = NULL; + table->stab_info = NULL; + table->merge_info = NULL; + memset (&table->eh_info, 0, sizeof (table->eh_info)); + table->dynlocal = NULL; + table->runpath = NULL; + table->tls_segment = NULL; + table->loaded = NULL; + + ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc); + table->root.type = bfd_link_elf_hash_table; + + return ret; +} + +/* Create an ELF linker hash table. */ + +struct bfd_link_hash_table * +_bfd_elf_link_hash_table_create (abfd) + bfd *abfd; +{ + struct elf_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf_link_hash_table); + + ret = (struct elf_link_hash_table *) bfd_malloc (amt); + if (ret == (struct elf_link_hash_table *) NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc)) + { + free (ret); + return NULL; + } + + return &ret->root; +} + +/* This is a hook for the ELF emulation code in the generic linker to + tell the backend linker what file name to use for the DT_NEEDED + entry for a dynamic object. The generic linker passes name as an + empty string to indicate that no DT_NEEDED entry should be made. */ + +void +bfd_elf_set_dt_needed_name (abfd, name) + bfd *abfd; + const char *name; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + elf_dt_name (abfd) = name; +} + +void +bfd_elf_set_dt_needed_soname (abfd, name) + bfd *abfd; + const char *name; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + elf_dt_soname (abfd) = name; +} + +/* Get the list of DT_NEEDED entries for a link. This is a hook for + the linker ELF emulation code. */ + +struct bfd_link_needed_list * +bfd_elf_get_needed_list (abfd, info) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; +{ + if (! is_elf_hash_table (info)) + return NULL; + return elf_hash_table (info)->needed; +} + +/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a + hook for the linker ELF emulation code. */ + +struct bfd_link_needed_list * +bfd_elf_get_runpath_list (abfd, info) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; +{ + if (! is_elf_hash_table (info)) + return NULL; + return elf_hash_table (info)->runpath; +} + +/* Get the name actually used for a dynamic object for a link. This + is the SONAME entry if there is one. Otherwise, it is the string + passed to bfd_elf_set_dt_needed_name, or it is the filename. */ + +const char * +bfd_elf_get_dt_soname (abfd) + bfd *abfd; +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + return elf_dt_name (abfd); + return NULL; +} + +/* Get the list of DT_NEEDED entries from a BFD. This is a hook for + the ELF linker emulation code. */ + +bfd_boolean +bfd_elf_get_bfd_needed_list (abfd, pneeded) + bfd *abfd; + struct bfd_link_needed_list **pneeded; +{ + asection *s; + bfd_byte *dynbuf = NULL; + int elfsec; + unsigned long shlink; + bfd_byte *extdyn, *extdynend; + size_t extdynsize; + void (*swap_dyn_in) PARAMS ((bfd *, const PTR, Elf_Internal_Dyn *)); + + *pneeded = NULL; + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour + || bfd_get_format (abfd) != bfd_object) + return TRUE; + + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s == NULL || s->_raw_size == 0) + return TRUE; + + dynbuf = (bfd_byte *) bfd_malloc (s->_raw_size); + if (dynbuf == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, (file_ptr) 0, + s->_raw_size)) + goto error_return; + + elfsec = _bfd_elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_return; + + shlink = elf_elfsections (abfd)[elfsec]->sh_link; + + extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; + swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; + + extdyn = dynbuf; + extdynend = extdyn + s->_raw_size; + for (; extdyn < extdynend; extdyn += extdynsize) + { + Elf_Internal_Dyn dyn; + + (*swap_dyn_in) (abfd, (PTR) extdyn, &dyn); + + if (dyn.d_tag == DT_NULL) + break; + + if (dyn.d_tag == DT_NEEDED) + { + const char *string; + struct bfd_link_needed_list *l; + unsigned int tagv = dyn.d_un.d_val; + bfd_size_type amt; + + string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (string == NULL) + goto error_return; + + amt = sizeof *l; + l = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); + if (l == NULL) + goto error_return; + + l->by = abfd; + l->name = string; + l->next = *pneeded; + *pneeded = l; + } + } + + free (dynbuf); + + return TRUE; + + error_return: + if (dynbuf != NULL) + free (dynbuf); + return FALSE; +} + +/* Allocate an ELF string table--force the first byte to be zero. */ + +struct bfd_strtab_hash * +_bfd_elf_stringtab_init () +{ + 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 */ + +/* Create a new bfd section from an ELF section header. */ + +bfd_boolean +bfd_section_from_shdr (abfd, shindex) + bfd *abfd; + unsigned int shindex; +{ + Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[shindex]; + Elf_Internal_Ehdr *ehdr = elf_elfheader (abfd); + struct elf_backend_data *bed = get_elf_backend_data (abfd); + const char *name; + + name = elf_string_from_elf_strtab (abfd, hdr->sh_name); + + switch (hdr->sh_type) + { + case SHT_NULL: + /* Inactive section. Throw it away. */ + return TRUE; + + 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. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + case SHT_DYNAMIC: /* Dynamic linking information. */ + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return FALSE; + if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_STRTAB) + { + Elf_Internal_Shdr *dynsymhdr; + + /* The shared libraries distributed with hpux11 have a bogus + sh_link field for the ".dynamic" section. Find the + string table for the ".dynsym" section instead. */ + if (elf_dynsymtab (abfd) != 0) + { + dynsymhdr = elf_elfsections (abfd)[elf_dynsymtab (abfd)]; + hdr->sh_link = dynsymhdr->sh_link; + } + else + { + unsigned int i, num_sec; + + num_sec = elf_numsections (abfd); + for (i = 1; i < num_sec; i++) + { + dynsymhdr = elf_elfsections (abfd)[i]; + if (dynsymhdr->sh_type == SHT_DYNSYM) + { + hdr->sh_link = dynsymhdr->sh_link; + break; + } + } + } + } + break; + + case SHT_SYMTAB: /* A symbol table */ + if (elf_onesymtab (abfd) == shindex) + return TRUE; + + BFD_ASSERT (hdr->sh_entsize == bed->s->sizeof_sym); + BFD_ASSERT (elf_onesymtab (abfd) == 0); + elf_onesymtab (abfd) = shindex; + elf_tdata (abfd)->symtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->symtab_hdr; + abfd->flags |= HAS_SYMS; + + /* Sometimes a shared object will map in the symbol table. If + SHF_ALLOC is set, and this is a shared object, then we also + treat this section as a BFD section. We can not base the + decision purely on SHF_ALLOC, because that flag is sometimes + set in a relocateable object file, which would confuse the + linker. */ + if ((hdr->sh_flags & SHF_ALLOC) != 0 + && (abfd->flags & DYNAMIC) != 0 + && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return FALSE; + + return TRUE; + + case SHT_DYNSYM: /* A dynamic symbol table */ + if (elf_dynsymtab (abfd) == shindex) + return TRUE; + + BFD_ASSERT (hdr->sh_entsize == bed->s->sizeof_sym); + BFD_ASSERT (elf_dynsymtab (abfd) == 0); + elf_dynsymtab (abfd) = shindex; + elf_tdata (abfd)->dynsymtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr; + abfd->flags |= HAS_SYMS; + + /* 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); + + case SHT_SYMTAB_SHNDX: /* Symbol section indices when >64k sections */ + if (elf_symtab_shndx (abfd) == shindex) + return TRUE; + + /* Get the associated symbol table. */ + if (! bfd_section_from_shdr (abfd, hdr->sh_link) + || hdr->sh_link != elf_onesymtab (abfd)) + return FALSE; + + elf_symtab_shndx (abfd) = shindex; + elf_tdata (abfd)->symtab_shndx_hdr = *hdr; + elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_shndx_hdr; + return TRUE; + + case SHT_STRTAB: /* A string table */ + if (hdr->bfd_section != NULL) + return TRUE; + if (ehdr->e_shstrndx == shindex) + { + elf_tdata (abfd)->shstrtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->shstrtab_hdr; + return TRUE; + } + { + unsigned int i, num_sec; + + num_sec = elf_numsections (abfd); + for (i = 1; i < num_sec; i++) + { + Elf_Internal_Shdr *hdr2 = elf_elfsections (abfd)[i]; + if (hdr2->sh_link == shindex) + { + if (! bfd_section_from_shdr (abfd, i)) + return FALSE; + if (elf_onesymtab (abfd) == i) + { + elf_tdata (abfd)->strtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = + &elf_tdata (abfd)->strtab_hdr; + return TRUE; + } + if (elf_dynsymtab (abfd) == i) + { + elf_tdata (abfd)->dynstrtab_hdr = *hdr; + elf_elfsections (abfd)[shindex] = hdr = + &elf_tdata (abfd)->dynstrtab_hdr; + /* We also treat this as a regular section, so + that objcopy can handle it. */ + break; + } +#if 0 /* Not handling other string tables specially right now. */ + hdr2 = elf_elfsections (abfd)[i]; /* in case it moved */ + /* We have a strtab for some random other section. */ + newsect = (asection *) hdr2->bfd_section; + if (!newsect) + break; + hdr->bfd_section = newsect; + hdr2 = &elf_section_data (newsect)->str_hdr; + *hdr2 = *hdr; + elf_elfsections (abfd)[shindex] = hdr2; +#endif + } + } + } + + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + case SHT_REL: + case SHT_RELA: + /* *These* do a lot of work -- but build no sections! */ + { + asection *target_sect; + Elf_Internal_Shdr *hdr2; + unsigned int num_sec = elf_numsections (abfd); + + /* Check for a bogus link to avoid crashing. */ + if ((hdr->sh_link >= SHN_LORESERVE && hdr->sh_link <= SHN_HIRESERVE) + || hdr->sh_link >= num_sec) + { + ((*_bfd_error_handler) + (_("%s: invalid link %lu for reloc section %s (index %u)"), + bfd_archive_filename (abfd), hdr->sh_link, name, shindex)); + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + } + + /* For some incomprehensible reason Oracle distributes + libraries for Solaris in which some of the objects have + bogus sh_link fields. It would be nice if we could just + reject them, but, unfortunately, some people need to use + them. We scan through the section headers; if we find only + one suitable symbol table, we clobber the sh_link to point + to it. I hope this doesn't break anything. */ + if (elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_SYMTAB + && elf_elfsections (abfd)[hdr->sh_link]->sh_type != SHT_DYNSYM) + { + unsigned int scan; + int found; + + found = 0; + for (scan = 1; scan < num_sec; scan++) + { + if (elf_elfsections (abfd)[scan]->sh_type == SHT_SYMTAB + || elf_elfsections (abfd)[scan]->sh_type == SHT_DYNSYM) + { + if (found != 0) + { + found = 0; + break; + } + found = scan; + } + } + if (found != 0) + hdr->sh_link = found; + } + + /* Get the symbol table. */ + if (elf_elfsections (abfd)[hdr->sh_link]->sh_type == SHT_SYMTAB + && ! bfd_section_from_shdr (abfd, hdr->sh_link)) + return FALSE; + + /* If this reloc section does not use the main symbol table we + don't treat it as a reloc section. BFD can't adequately + represent such a section, so at least for now, we don't + try. We just present it as a normal section. We also + can't use it as a reloc section if it points to the null + section. */ + if (hdr->sh_link != elf_onesymtab (abfd) || hdr->sh_info == SHN_UNDEF) + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + + if (! bfd_section_from_shdr (abfd, hdr->sh_info)) + return FALSE; + target_sect = bfd_section_from_elf_index (abfd, hdr->sh_info); + if (target_sect == NULL) + return FALSE; + + if ((target_sect->flags & SEC_RELOC) == 0 + || target_sect->reloc_count == 0) + hdr2 = &elf_section_data (target_sect)->rel_hdr; + else + { + bfd_size_type amt; + BFD_ASSERT (elf_section_data (target_sect)->rel_hdr2 == NULL); + amt = sizeof (*hdr2); + hdr2 = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); + elf_section_data (target_sect)->rel_hdr2 = hdr2; + } + *hdr2 = *hdr; + elf_elfsections (abfd)[shindex] = hdr2; + target_sect->reloc_count += NUM_SHDR_ENTRIES (hdr); + target_sect->flags |= SEC_RELOC; + target_sect->relocation = NULL; + target_sect->rel_filepos = hdr->sh_offset; + /* In the section to which the relocations apply, mark whether + its relocations are of the REL or RELA variety. */ + if (hdr->sh_size != 0) + target_sect->use_rela_p = hdr->sh_type == SHT_RELA; + abfd->flags |= HAS_RELOC; + return TRUE; + } + break; + + case SHT_GNU_verdef: + elf_dynverdef (abfd) = shindex; + elf_tdata (abfd)->dynverdef_hdr = *hdr; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + break; + + case SHT_GNU_versym: + elf_dynversym (abfd) = shindex; + elf_tdata (abfd)->dynversym_hdr = *hdr; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + break; + + case SHT_GNU_verneed: + elf_dynverref (abfd) = shindex; + elf_tdata (abfd)->dynverref_hdr = *hdr; + return _bfd_elf_make_section_from_shdr (abfd, hdr, name); + break; + + case SHT_SHLIB: + return TRUE; + + case SHT_GROUP: + /* We need a BFD section for objcopy and relocatable linking, + and it's handy to have the signature available as the section + name. */ + name = group_signature (abfd, hdr); + if (name == NULL) + return FALSE; + if (!_bfd_elf_make_section_from_shdr (abfd, hdr, name)) + return FALSE; + if (hdr->contents != NULL) + { + Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents; + unsigned int n_elt = hdr->sh_size / 4; + asection *s; + + if (idx->flags & GRP_COMDAT) + hdr->bfd_section->flags + |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + + while (--n_elt != 0) + if ((s = (++idx)->shdr->bfd_section) != NULL + && elf_next_in_group (s) != NULL) + { + elf_next_in_group (hdr->bfd_section) = s; + break; + } + } + break; + + default: + /* Check for any processor-specific section types. */ + { + if (bed->elf_backend_section_from_shdr) + (*bed->elf_backend_section_from_shdr) (abfd, hdr, name); + } + break; + } + + return TRUE; +} + +/* Return the section for the local symbol specified by ABFD, R_SYMNDX. + Return SEC for sections that have no elf section, and NULL on error. */ + +asection * +bfd_section_from_r_symndx (abfd, cache, sec, r_symndx) + bfd *abfd; + struct sym_sec_cache *cache; + asection *sec; + unsigned long r_symndx; +{ + Elf_Internal_Shdr *symtab_hdr; + unsigned char esym[sizeof (Elf64_External_Sym)]; + Elf_External_Sym_Shndx eshndx; + Elf_Internal_Sym isym; + unsigned int ent = r_symndx % LOCAL_SYM_CACHE_SIZE; + + if (cache->abfd == abfd && cache->indx[ent] == r_symndx) + return cache->sec[ent]; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + if (bfd_elf_get_elf_syms (abfd, symtab_hdr, 1, r_symndx, + &isym, esym, &eshndx) == NULL) + return NULL; + + if (cache->abfd != abfd) + { + memset (cache->indx, -1, sizeof (cache->indx)); + cache->abfd = abfd; + } + cache->indx[ent] = r_symndx; + cache->sec[ent] = sec; + if (isym.st_shndx < SHN_LORESERVE || isym.st_shndx > SHN_HIRESERVE) + { + asection *s; + s = bfd_section_from_elf_index (abfd, isym.st_shndx); + if (s != NULL) + cache->sec[ent] = s; + } + return cache->sec[ent]; +} + +/* Given an ELF section number, retrieve the corresponding BFD + section. */ + +asection * +bfd_section_from_elf_index (abfd, index) + bfd *abfd; + unsigned int index; +{ + if (index >= elf_numsections (abfd)) + return NULL; + return elf_elfsections (abfd)[index]->bfd_section; +} + +bfd_boolean +_bfd_elf_new_section_hook (abfd, sec) + bfd *abfd; + asection *sec; +{ + struct bfd_elf_section_data *sdata; + + sdata = (struct bfd_elf_section_data *) sec->used_by_bfd; + if (sdata == NULL) + { + bfd_size_type amt = sizeof (*sdata); + sdata = (struct bfd_elf_section_data *) bfd_zalloc (abfd, amt); + if (sdata == NULL) + return FALSE; + sec->used_by_bfd = (PTR) sdata; + } + + /* Indicate whether or not this section should use RELA relocations. */ + sec->use_rela_p = get_elf_backend_data (abfd)->default_use_rela_p; + + return TRUE; +} + +/* Create a new bfd section from an ELF program header. + + Since program segments have no names, we generate a synthetic name + of the form segment, where NUM is generally the index in the + program header table. For segments that are split (see below) we + generate the names segmenta and segmentb. + + Note that some program segments may have a file size that is different than + (less than) the memory size. All this means is that at execution the + system must allocate the amount of memory specified by the memory size, + but only initialize it with the first "file size" bytes read from the + file. This would occur for example, with program segments consisting + of combined data+bss. + + To handle the above situation, this routine generates TWO bfd sections + for the single program segment. The first has the length specified by + the file size of the segment, and the second has the length specified + by the difference between the two sizes. In effect, the segment is split + into it's initialized and uninitialized parts. + + */ + +bfd_boolean +_bfd_elf_make_section_from_phdr (abfd, hdr, index, typename) + bfd *abfd; + Elf_Internal_Phdr *hdr; + int index; + const char *typename; +{ + asection *newsect; + char *name; + char namebuf[64]; + size_t len; + int split; + + split = ((hdr->p_memsz > 0) + && (hdr->p_filesz > 0) + && (hdr->p_memsz > hdr->p_filesz)); + sprintf (namebuf, "%s%d%s", typename, index, split ? "a" : ""); + len = strlen (namebuf) + 1; + name = bfd_alloc (abfd, (bfd_size_type) len); + if (!name) + return FALSE; + memcpy (name, namebuf, len); + newsect = bfd_make_section (abfd, name); + if (newsect == NULL) + return FALSE; + newsect->vma = hdr->p_vaddr; + newsect->lma = hdr->p_paddr; + newsect->_raw_size = hdr->p_filesz; + newsect->filepos = hdr->p_offset; + newsect->flags |= SEC_HAS_CONTENTS; + if (hdr->p_type == PT_LOAD) + { + newsect->flags |= SEC_ALLOC; + newsect->flags |= SEC_LOAD; + if (hdr->p_flags & PF_X) + { + /* FIXME: all we known is that it has execute PERMISSION, + may be data. */ + newsect->flags |= SEC_CODE; + } + } + if (!(hdr->p_flags & PF_W)) + { + newsect->flags |= SEC_READONLY; + } + + if (split) + { + sprintf (namebuf, "%s%db", typename, index); + len = strlen (namebuf) + 1; + name = bfd_alloc (abfd, (bfd_size_type) len); + if (!name) + return FALSE; + memcpy (name, namebuf, len); + newsect = bfd_make_section (abfd, name); + if (newsect == NULL) + return FALSE; + newsect->vma = hdr->p_vaddr + hdr->p_filesz; + newsect->lma = hdr->p_paddr + hdr->p_filesz; + newsect->_raw_size = hdr->p_memsz - hdr->p_filesz; + if (hdr->p_type == PT_LOAD) + { + newsect->flags |= SEC_ALLOC; + if (hdr->p_flags & PF_X) + newsect->flags |= SEC_CODE; + } + if (!(hdr->p_flags & PF_W)) + newsect->flags |= SEC_READONLY; + } + + return TRUE; +} + +bfd_boolean +bfd_section_from_phdr (abfd, hdr, index) + bfd *abfd; + Elf_Internal_Phdr *hdr; + int index; +{ + struct elf_backend_data *bed; + + switch (hdr->p_type) + { + case PT_NULL: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "null"); + + case PT_LOAD: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "load"); + + case PT_DYNAMIC: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "dynamic"); + + case PT_INTERP: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "interp"); + + case PT_NOTE: + if (! _bfd_elf_make_section_from_phdr (abfd, hdr, index, "note")) + return FALSE; + if (! elfcore_read_notes (abfd, (file_ptr) hdr->p_offset, hdr->p_filesz)) + return FALSE; + return TRUE; + + case PT_SHLIB: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "shlib"); + + case PT_PHDR: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "phdr"); + + case PT_GNU_EH_FRAME: + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, + "eh_frame_hdr"); + + default: + /* Check for any processor-specific program segment types. + If no handler for them, default to making "segment" sections. */ + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_section_from_phdr) + return (*bed->elf_backend_section_from_phdr) (abfd, hdr, index); + else + return _bfd_elf_make_section_from_phdr (abfd, hdr, index, "segment"); + } +} + +/* Initialize REL_HDR, the section-header for new section, containing + relocations against ASECT. If USE_RELA_P is TRUE, we use RELA + relocations; otherwise, we use REL relocations. */ + +bfd_boolean +_bfd_elf_init_reloc_shdr (abfd, rel_hdr, asect, use_rela_p) + bfd *abfd; + Elf_Internal_Shdr *rel_hdr; + asection *asect; + bfd_boolean use_rela_p; +{ + char *name; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_size_type amt = sizeof ".rela" + strlen (asect->name); + + name = 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) + return FALSE; + rel_hdr->sh_type = use_rela_p ? SHT_RELA : SHT_REL; + rel_hdr->sh_entsize = (use_rela_p + ? bed->s->sizeof_rela + : bed->s->sizeof_rel); + rel_hdr->sh_addralign = bed->s->file_align; + rel_hdr->sh_flags = 0; + rel_hdr->sh_addr = 0; + rel_hdr->sh_size = 0; + rel_hdr->sh_offset = 0; + + return TRUE; +} + +/* Set up an ELF internal section header for a section. */ + +static void +elf_fake_sections (abfd, asect, failedptrarg) + bfd *abfd; + asection *asect; + PTR failedptrarg; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_boolean *failedptr = (bfd_boolean *) failedptrarg; + Elf_Internal_Shdr *this_hdr; + + if (*failedptr) + { + /* We already failed; just get out of the bfd_map_over_sections + loop. */ + return; + } + + this_hdr = &elf_section_data (asect)->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) + { + *failedptr = TRUE; + return; + } + + this_hdr->sh_flags = 0; + + if ((asect->flags & SEC_ALLOC) != 0 + || asect->user_set_vma) + this_hdr->sh_addr = asect->vma; + else + this_hdr->sh_addr = 0; + + this_hdr->sh_offset = 0; + this_hdr->sh_size = asect->_raw_size; + this_hdr->sh_link = 0; + this_hdr->sh_addralign = 1 << asect->alignment_power; + /* The sh_entsize and sh_info fields may have been set already by + copy_private_section_data. */ + + this_hdr->bfd_section = asect; + this_hdr->contents = NULL; + + /* FIXME: This should not be based on section names. */ + if (strcmp (asect->name, ".dynstr") == 0) + this_hdr->sh_type = SHT_STRTAB; + else if (strcmp (asect->name, ".hash") == 0) + { + this_hdr->sh_type = SHT_HASH; + this_hdr->sh_entsize = bed->s->sizeof_hash_entry; + } + else if (strcmp (asect->name, ".dynsym") == 0) + { + this_hdr->sh_type = SHT_DYNSYM; + this_hdr->sh_entsize = bed->s->sizeof_sym; + } + else if (strcmp (asect->name, ".dynamic") == 0) + { + this_hdr->sh_type = SHT_DYNAMIC; + this_hdr->sh_entsize = bed->s->sizeof_dyn; + } + else if (strncmp (asect->name, ".rela", 5) == 0 + && get_elf_backend_data (abfd)->may_use_rela_p) + { + this_hdr->sh_type = SHT_RELA; + this_hdr->sh_entsize = bed->s->sizeof_rela; + } + else if (strncmp (asect->name, ".rel", 4) == 0 + && get_elf_backend_data (abfd)->may_use_rel_p) + { + this_hdr->sh_type = SHT_REL; + this_hdr->sh_entsize = bed->s->sizeof_rel; + } + else if (strcmp (asect->name, ".init_array") == 0) + this_hdr->sh_type = SHT_INIT_ARRAY; + else if (strcmp (asect->name, ".fini_array") == 0) + this_hdr->sh_type = SHT_FINI_ARRAY; + else if (strcmp (asect->name, ".preinit_array") == 0) + this_hdr->sh_type = SHT_PREINIT_ARRAY; + else if (strncmp (asect->name, ".note", 5) == 0) + this_hdr->sh_type = SHT_NOTE; + else if (strncmp (asect->name, ".stab", 5) == 0 + && strcmp (asect->name + strlen (asect->name) - 3, "str") == 0) + this_hdr->sh_type = SHT_STRTAB; + else if (strcmp (asect->name, ".gnu.version") == 0) + { + this_hdr->sh_type = SHT_GNU_versym; + this_hdr->sh_entsize = sizeof (Elf_External_Versym); + } + else if (strcmp (asect->name, ".gnu.version_d") == 0) + { + this_hdr->sh_type = SHT_GNU_verdef; + this_hdr->sh_entsize = 0; + /* objcopy or strip will copy over sh_info, but may not set + cverdefs. The linker will set cverdefs, but sh_info will be + zero. */ + if (this_hdr->sh_info == 0) + this_hdr->sh_info = elf_tdata (abfd)->cverdefs; + else + BFD_ASSERT (elf_tdata (abfd)->cverdefs == 0 + || this_hdr->sh_info == elf_tdata (abfd)->cverdefs); + } + else if (strcmp (asect->name, ".gnu.version_r") == 0) + { + this_hdr->sh_type = SHT_GNU_verneed; + this_hdr->sh_entsize = 0; + /* objcopy or strip will copy over sh_info, but may not set + cverrefs. The linker will set cverrefs, but sh_info will be + zero. */ + if (this_hdr->sh_info == 0) + this_hdr->sh_info = elf_tdata (abfd)->cverrefs; + else + BFD_ASSERT (elf_tdata (abfd)->cverrefs == 0 + || this_hdr->sh_info == elf_tdata (abfd)->cverrefs); + } + else if ((asect->flags & SEC_GROUP) != 0) + { + this_hdr->sh_type = SHT_GROUP; + this_hdr->sh_entsize = 4; + } + else if ((asect->flags & SEC_ALLOC) != 0 + && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + || (asect->flags & SEC_NEVER_LOAD) != 0)) + this_hdr->sh_type = SHT_NOBITS; + else + this_hdr->sh_type = SHT_PROGBITS; + + if ((asect->flags & SEC_ALLOC) != 0) + this_hdr->sh_flags |= SHF_ALLOC; + if ((asect->flags & SEC_READONLY) == 0) + this_hdr->sh_flags |= SHF_WRITE; + if ((asect->flags & SEC_CODE) != 0) + this_hdr->sh_flags |= SHF_EXECINSTR; + if ((asect->flags & SEC_MERGE) != 0) + { + this_hdr->sh_flags |= SHF_MERGE; + this_hdr->sh_entsize = asect->entsize; + if ((asect->flags & SEC_STRINGS) != 0) + this_hdr->sh_flags |= SHF_STRINGS; + } + if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL) + this_hdr->sh_flags |= SHF_GROUP; + if ((asect->flags & SEC_THREAD_LOCAL) != 0) + { + this_hdr->sh_flags |= SHF_TLS; + if (asect->_raw_size == 0 && (asect->flags & SEC_HAS_CONTENTS) == 0) + { + struct bfd_link_order *o; + + this_hdr->sh_size = 0; + for (o = asect->link_order_head; o != NULL; o = o->next) + if (this_hdr->sh_size < o->offset + o->size) + this_hdr->sh_size = o->offset + o->size; + if (this_hdr->sh_size) + this_hdr->sh_type = SHT_NOBITS; + } + } + + /* Check for processor-specific section types. */ + if (bed->elf_backend_fake_sections + && !(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect)) + *failedptr = TRUE; + + /* If the section has relocs, set up a section header for the + SHT_REL[A] section. If two relocation sections are required for + this section, it is up to the processor-specific back-end to + create the other. */ + if ((asect->flags & SEC_RELOC) != 0 + && !_bfd_elf_init_reloc_shdr (abfd, + &elf_section_data (asect)->rel_hdr, + asect, + asect->use_rela_p)) + *failedptr = TRUE; +} + +/* Fill in the contents of a SHT_GROUP section. */ + +void +bfd_elf_set_group_contents (abfd, sec, failedptrarg) + bfd *abfd; + asection *sec; + PTR failedptrarg; +{ + bfd_boolean *failedptr = (bfd_boolean *) failedptrarg; + unsigned long symindx; + asection *elt, *first; + unsigned char *loc; + struct bfd_link_order *l; + bfd_boolean gas; + + if (elf_section_data (sec)->this_hdr.sh_type != SHT_GROUP + || *failedptr) + return; + + symindx = 0; + if (elf_group_id (sec) != NULL) + symindx = elf_group_id (sec)->udata.i; + + if (symindx == 0) + { + /* If called from the assembler, swap_out_syms will have set up + elf_section_syms; If called for "ld -r", use target_index. */ + if (elf_section_syms (abfd) != NULL) + symindx = elf_section_syms (abfd)[sec->index]->udata.i; + else + symindx = sec->target_index; + } + elf_section_data (sec)->this_hdr.sh_info = symindx; + + /* The contents won't be allocated for "ld -r" or objcopy. */ + gas = TRUE; + if (sec->contents == NULL) + { + gas = FALSE; + sec->contents = bfd_alloc (abfd, sec->_raw_size); + + /* Arrange for the section to be written out. */ + elf_section_data (sec)->this_hdr.contents = sec->contents; + if (sec->contents == NULL) + { + *failedptr = TRUE; + return; + } + } + + loc = sec->contents + sec->_raw_size; + + /* Get the pointer to the first section in the group that gas + squirreled away here. objcopy arranges for this to be set to the + start of the input section group. */ + first = elt = elf_next_in_group (sec); + + /* First element is a flag word. Rest of section is elf section + indices for all the sections of the group. Write them backwards + just to keep the group in the same order as given in .section + directives, not that it matters. */ + while (elt != NULL) + { + asection *s; + unsigned int idx; + + loc -= 4; + s = elt; + if (!gas) + s = s->output_section; + idx = 0; + if (s != NULL) + idx = elf_section_data (s)->this_idx; + H_PUT_32 (abfd, idx, loc); + elt = elf_next_in_group (elt); + if (elt == first) + break; + } + + /* If this is a relocatable link, then the above did nothing because + SEC is the output section. Look through the input sections + instead. */ + for (l = sec->link_order_head; l != NULL; l = l->next) + if (l->type == bfd_indirect_link_order + && (elt = elf_next_in_group (l->u.indirect.section)) != NULL) + do + { + loc -= 4; + H_PUT_32 (abfd, + elf_section_data (elt->output_section)->this_idx, loc); + elt = elf_next_in_group (elt); + /* During a relocatable link, the lists are circular. */ + } + while (elt != elf_next_in_group (l->u.indirect.section)); + + /* With ld -r, merging SHT_GROUP sections results in wasted space + due to allowing for the flag word on each input. We may well + duplicate entries too. */ + while ((loc -= 4) > sec->contents) + H_PUT_32 (abfd, 0, loc); + + if (loc != sec->contents) + abort (); + + H_PUT_32 (abfd, sec->flags & SEC_LINK_ONCE ? GRP_COMDAT : 0, loc); +} + +/* 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. */ + +static bfd_boolean +assign_section_numbers (abfd) + bfd *abfd; +{ + struct elf_obj_tdata *t = elf_tdata (abfd); + asection *sec; + unsigned int section_number, secn; + Elf_Internal_Shdr **i_shdrp; + bfd_size_type amt; + + section_number = 1; + + _bfd_elf_strtab_clear_all_refs (elf_shstrtab (abfd)); + + for (sec = abfd->sections; sec; sec = sec->next) + { + struct bfd_elf_section_data *d = elf_section_data (sec); + + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + d->this_idx = section_number++; + _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->this_hdr.sh_name); + if ((sec->flags & SEC_RELOC) == 0) + d->rel_idx = 0; + else + { + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + d->rel_idx = section_number++; + _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr.sh_name); + } + + if (d->rel_hdr2) + { + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + d->rel_idx2 = section_number++; + _bfd_elf_strtab_addref (elf_shstrtab (abfd), d->rel_hdr2->sh_name); + } + else + d->rel_idx2 = 0; + } + + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + t->shstrtab_section = section_number++; + _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->shstrtab_hdr.sh_name); + elf_elfheader (abfd)->e_shstrndx = t->shstrtab_section; + + if (bfd_get_symcount (abfd) > 0) + { + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + t->symtab_section = section_number++; + _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->symtab_hdr.sh_name); + if (section_number > SHN_LORESERVE - 2) + { + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + t->symtab_shndx_section = section_number++; + t->symtab_shndx_hdr.sh_name + = (unsigned int) _bfd_elf_strtab_add (elf_shstrtab (abfd), + ".symtab_shndx", FALSE); + if (t->symtab_shndx_hdr.sh_name == (unsigned int) -1) + return FALSE; + } + if (section_number == SHN_LORESERVE) + section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; + t->strtab_section = section_number++; + _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name); + } + + _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; + if (section_number > SHN_LORESERVE) + elf_elfheader (abfd)->e_shnum -= SHN_HIRESERVE + 1 - SHN_LORESERVE; + + /* Set up the list of section header pointers, in agreement with the + indices. */ + amt = section_number * sizeof (Elf_Internal_Shdr *); + i_shdrp = (Elf_Internal_Shdr **) bfd_zalloc (abfd, amt); + if (i_shdrp == NULL) + return FALSE; + + amt = sizeof (Elf_Internal_Shdr); + i_shdrp[0] = (Elf_Internal_Shdr *) bfd_zalloc (abfd, amt); + if (i_shdrp[0] == NULL) + { + bfd_release (abfd, i_shdrp); + return FALSE; + } + + elf_elfsections (abfd) = i_shdrp; + + i_shdrp[t->shstrtab_section] = &t->shstrtab_hdr; + if (bfd_get_symcount (abfd) > 0) + { + i_shdrp[t->symtab_section] = &t->symtab_hdr; + if (elf_numsections (abfd) > SHN_LORESERVE) + { + i_shdrp[t->symtab_shndx_section] = &t->symtab_shndx_hdr; + t->symtab_shndx_hdr.sh_link = t->symtab_section; + } + i_shdrp[t->strtab_section] = &t->strtab_hdr; + t->symtab_hdr.sh_link = t->strtab_section; + } + for (sec = abfd->sections; sec; sec = sec->next) + { + struct bfd_elf_section_data *d = elf_section_data (sec); + asection *s; + const char *name; + + i_shdrp[d->this_idx] = &d->this_hdr; + if (d->rel_idx != 0) + i_shdrp[d->rel_idx] = &d->rel_hdr; + if (d->rel_idx2 != 0) + i_shdrp[d->rel_idx2] = d->rel_hdr2; + + /* Fill in the sh_link and sh_info fields while we're at it. */ + + /* sh_link of a reloc section is the section index of the symbol + table. sh_info is the section index of the section to which + the relocation entries apply. */ + if (d->rel_idx != 0) + { + d->rel_hdr.sh_link = t->symtab_section; + d->rel_hdr.sh_info = d->this_idx; + } + if (d->rel_idx2 != 0) + { + d->rel_hdr2->sh_link = t->symtab_section; + d->rel_hdr2->sh_info = d->this_idx; + } + + switch (d->this_hdr.sh_type) + { + case SHT_REL: + case SHT_RELA: + /* A reloc section which we are treating as a normal BFD + section. sh_link is the section index of the symbol + table. sh_info is the section index of the section to + which the relocation entries apply. We assume that an + allocated reloc section uses the dynamic symbol table. + FIXME: How can we be sure? */ + s = bfd_get_section_by_name (abfd, ".dynsym"); + 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); + if (s != NULL) + d->this_hdr.sh_info = elf_section_data (s)->this_idx; + break; + + case SHT_STRTAB: + /* We assume that a section named .stab*str is a stabs + string section. We look for a section with the same name + but without the trailing ``str'', and set its sh_link + field to point to this section. */ + if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0 + && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0) + { + size_t len; + char *alc; + + len = strlen (sec->name); + alc = (char *) bfd_malloc ((bfd_size_type) (len - 2)); + if (alc == NULL) + return FALSE; + memcpy (alc, sec->name, len - 3); + alc[len - 3] = '\0'; + s = bfd_get_section_by_name (abfd, alc); + free (alc); + if (s != NULL) + { + elf_section_data (s)->this_hdr.sh_link = d->this_idx; + + /* This is a .stab section. */ + if (elf_section_data (s)->this_hdr.sh_entsize == 0) + elf_section_data (s)->this_hdr.sh_entsize + = 4 + 2 * bfd_get_arch_size (abfd) / 8; + } + } + break; + + case SHT_DYNAMIC: + case SHT_DYNSYM: + case SHT_GNU_verneed: + case SHT_GNU_verdef: + /* sh_link is the section header index of the string table + used for the dynamic entries, or the symbol table, or the + version strings. */ + s = bfd_get_section_by_name (abfd, ".dynstr"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + break; + + case SHT_HASH: + case SHT_GNU_versym: + /* sh_link is the section header index of the symbol table + this hash table or version table is for. */ + s = bfd_get_section_by_name (abfd, ".dynsym"); + if (s != NULL) + d->this_hdr.sh_link = elf_section_data (s)->this_idx; + break; + + case SHT_GROUP: + d->this_hdr.sh_link = t->symtab_section; + } + } + + 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); + return TRUE; +} + +/* Map symbol from it's internal number to the external number, moving + all local symbols to be at the head of the list. */ + +static INLINE int +sym_is_global (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + /* If the backend has a special mapping, use it. */ + if (get_elf_backend_data (abfd)->elf_backend_sym_is_global) + return ((*get_elf_backend_data (abfd)->elf_backend_sym_is_global) + (abfd, sym)); + + return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym))); +} + +static bfd_boolean +elf_map_symbols (abfd) + bfd *abfd; +{ + unsigned int symcount = bfd_get_symcount (abfd); + asymbol **syms = bfd_get_outsymbols (abfd); + asymbol **sect_syms; + unsigned int num_locals = 0; + unsigned int num_globals = 0; + unsigned int num_locals2 = 0; + unsigned int num_globals2 = 0; + int max_index = 0; + unsigned int idx; + asection *asect; + asymbol **new_syms; + bfd_size_type amt; + +#ifdef DEBUG + fprintf (stderr, "elf_map_symbols\n"); + fflush (stderr); +#endif + + for (asect = abfd->sections; asect; asect = asect->next) + { + if (max_index < asect->index) + max_index = asect->index; + } + + max_index++; + amt = max_index * sizeof (asymbol *); + sect_syms = (asymbol **) bfd_zalloc (abfd, amt); + if (sect_syms == NULL) + return FALSE; + elf_section_syms (abfd) = sect_syms; + elf_num_section_syms (abfd) = max_index; + + /* Init sect_syms entries for any section symbols we have already + decided to output. */ + for (idx = 0; idx < symcount; idx++) + { + asymbol *sym = syms[idx]; + + if ((sym->flags & BSF_SECTION_SYM) != 0 + && sym->value == 0) + { + asection *sec; + + sec = sym->section; + + if (sec->owner != NULL) + { + if (sec->owner != abfd) + { + if (sec->output_offset != 0) + continue; + + sec = sec->output_section; + + /* Empty sections in the input files may have had a + section symbol created for them. (See the comment + near the end of _bfd_generic_link_output_symbols in + linker.c). If the linker script discards such + sections then we will reach this point. Since we know + that we cannot avoid this case, we detect it and skip + the abort and the assignment to the sect_syms array. + To reproduce this particular case try running the + linker testsuite test ld-scripts/weak.exp for an ELF + port that uses the generic linker. */ + if (sec->owner == NULL) + continue; + + BFD_ASSERT (sec->owner == abfd); + } + sect_syms[sec->index] = syms[idx]; + } + } + } + + /* Classify all of the symbols. */ + for (idx = 0; idx < symcount; idx++) + { + if (!sym_is_global (abfd, syms[idx])) + num_locals++; + else + num_globals++; + } + + /* We will be adding a section symbol for each BFD section. Most normal + sections will already have a section symbol in outsymbols, but + eg. SHT_GROUP sections will not, and we need the section symbol mapped + at least in that case. */ + for (asect = abfd->sections; asect; asect = asect->next) + { + if (sect_syms[asect->index] == NULL) + { + if (!sym_is_global (abfd, asect->symbol)) + num_locals++; + else + num_globals++; + } + } + + /* Now sort the symbols so the local symbols are first. */ + amt = (num_locals + num_globals) * sizeof (asymbol *); + new_syms = (asymbol **) bfd_alloc (abfd, amt); + + if (new_syms == NULL) + return FALSE; + + for (idx = 0; idx < symcount; idx++) + { + asymbol *sym = syms[idx]; + unsigned int i; + + if (!sym_is_global (abfd, sym)) + i = num_locals2++; + else + i = num_locals + num_globals2++; + new_syms[i] = sym; + sym->udata.i = i + 1; + } + for (asect = abfd->sections; asect; asect = asect->next) + { + if (sect_syms[asect->index] == NULL) + { + asymbol *sym = asect->symbol; + unsigned int i; + + sect_syms[asect->index] = sym; + if (!sym_is_global (abfd, sym)) + i = num_locals2++; + else + i = num_locals + num_globals2++; + new_syms[i] = sym; + sym->udata.i = i + 1; + } + } + + bfd_set_symtab (abfd, new_syms, num_locals + num_globals); + + elf_num_locals (abfd) = num_locals; + elf_num_globals (abfd) = num_globals; + return TRUE; +} + +/* Align to the maximum file alignment that could be required for any + ELF data structure. */ + +static INLINE file_ptr align_file_position + PARAMS ((file_ptr, int)); +static INLINE file_ptr +align_file_position (off, align) + file_ptr off; + int align; +{ + return (off + align - 1) & ~(align - 1); +} + +/* Assign a file position to a section, optionally aligning to the + required section alignment. */ + +INLINE file_ptr +_bfd_elf_assign_file_position_for_section (i_shdrp, offset, align) + Elf_Internal_Shdr *i_shdrp; + file_ptr offset; + bfd_boolean align; +{ + if (align) + { + unsigned int al; + + al = i_shdrp->sh_addralign; + if (al > 1) + offset = BFD_ALIGN (offset, al); + } + i_shdrp->sh_offset = offset; + if (i_shdrp->bfd_section != NULL) + i_shdrp->bfd_section->filepos = offset; + if (i_shdrp->sh_type != SHT_NOBITS) + offset += i_shdrp->sh_size; + return offset; +} + +/* Compute the file positions we are going to put the sections at, and + otherwise prepare to begin writing out the ELF file. If LINK_INFO + is not NULL, this is being called by the ELF backend linker. */ + +bfd_boolean +_bfd_elf_compute_section_file_positions (abfd, link_info) + bfd *abfd; + struct bfd_link_info *link_info; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_boolean failed; + struct bfd_strtab_hash *strtab; + Elf_Internal_Shdr *shstrtab_hdr; + + if (abfd->output_has_begun) + return TRUE; + + /* Do any elf backend specific processing first. */ + if (bed->elf_backend_begin_write_processing) + (*bed->elf_backend_begin_write_processing) (abfd, link_info); + + if (! prep_headers (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); + + failed = FALSE; + bfd_map_over_sections (abfd, elf_fake_sections, &failed); + if (failed) + return FALSE; + + if (!assign_section_numbers (abfd)) + return FALSE; + + /* The backend linker builds symbol table information itself. */ + if (link_info == NULL && bfd_get_symcount (abfd) > 0) + { + /* Non-zero if doing a relocatable link. */ + int relocatable_p = ! (abfd->flags & (EXEC_P | DYNAMIC)); + + if (! swap_out_syms (abfd, &strtab, relocatable_p)) + return FALSE; + } + + if (link_info == NULL) + { + bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed); + if (failed) + return FALSE; + } + + shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr; + /* sh_name was set in prep_headers. */ + 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)); + 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. */ + shstrtab_hdr->sh_addralign = 1; + + if (!assign_file_positions_except_relocs (abfd)) + return FALSE; + + if (link_info == NULL && bfd_get_symcount (abfd) > 0) + { + file_ptr off; + Elf_Internal_Shdr *hdr; + + off = elf_tdata (abfd)->next_file_pos; + + hdr = &elf_tdata (abfd)->symtab_hdr; + off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + + hdr = &elf_tdata (abfd)->symtab_shndx_hdr; + if (hdr->sh_size != 0) + off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + + hdr = &elf_tdata (abfd)->strtab_hdr; + off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + + elf_tdata (abfd)->next_file_pos = off; + + /* 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)) + return FALSE; + _bfd_stringtab_free (strtab); + } + + abfd->output_has_begun = TRUE; + + return TRUE; +} + +/* Create a mapping from a set of sections to a program segment. */ + +static INLINE struct elf_segment_map * +make_mapping (abfd, sections, from, to, phdr) + bfd *abfd; + asection **sections; + unsigned int from; + unsigned int to; + bfd_boolean phdr; +{ + struct elf_segment_map *m; + unsigned int i; + asection **hdrpp; + bfd_size_type amt; + + amt = sizeof (struct elf_segment_map); + amt += (to - from - 1) * sizeof (asection *); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (m == NULL) + return NULL; + m->next = NULL; + m->p_type = PT_LOAD; + for (i = from, hdrpp = sections + from; i < to; i++, hdrpp++) + m->sections[i - from] = *hdrpp; + m->count = to - from; + + if (from == 0 && phdr) + { + /* Include the headers in the first PT_LOAD segment. */ + m->includes_filehdr = 1; + m->includes_phdrs = 1; + } + + return m; +} + +/* Set up a mapping from BFD sections to program segments. */ + +static bfd_boolean +map_sections_to_segments (abfd) + bfd *abfd; +{ + asection **sections = NULL; + asection *s; + unsigned int i; + unsigned int count; + struct elf_segment_map *mfirst; + struct elf_segment_map **pm; + struct elf_segment_map *m; + asection *last_hdr; + unsigned int phdr_index; + bfd_vma maxpagesize; + asection **hdrpp; + bfd_boolean phdr_in_segment = TRUE; + bfd_boolean writable; + int tls_count = 0; + asection *first_tls = NULL; + asection *dynsec, *eh_frame_hdr; + bfd_size_type amt; + + if (elf_tdata (abfd)->segment_map != NULL) + return TRUE; + + if (bfd_count_sections (abfd) == 0) + return TRUE; + + /* Select the allocated sections, and sort them. */ + + amt = bfd_count_sections (abfd) * sizeof (asection *); + sections = (asection **) bfd_malloc (amt); + if (sections == NULL) + goto error_return; + + i = 0; + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_ALLOC) != 0) + { + sections[i] = s; + ++i; + } + } + BFD_ASSERT (i <= bfd_count_sections (abfd)); + count = i; + + qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); + + /* Build the mapping. */ + + mfirst = NULL; + pm = &mfirst; + + /* If we have a .interp section, then create a PT_PHDR segment for + the program headers and a PT_INTERP segment for the .interp + section. */ + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_PHDR; + /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */ + m->p_flags = PF_R | PF_X; + m->p_flags_valid = 1; + m->includes_phdrs = 1; + + *pm = m; + pm = &m->next; + + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_INTERP; + m->count = 1; + m->sections[0] = s; + + *pm = m; + pm = &m->next; + } + + /* Look through the sections. We put sections in the same program + segment when the start of the second section can be placed within + a few bytes of the end of the first section. */ + last_hdr = NULL; + phdr_index = 0; + maxpagesize = get_elf_backend_data (abfd)->maxpagesize; + writable = FALSE; + dynsec = bfd_get_section_by_name (abfd, ".dynamic"); + if (dynsec != NULL + && (dynsec->flags & SEC_LOAD) == 0) + dynsec = NULL; + + /* Deal with -Ttext or something similar such that the first section + is not adjacent to the program headers. This is an + approximation, since at this point we don't know exactly how many + program headers we will need. */ + if (count > 0) + { + bfd_size_type phdr_size; + + phdr_size = elf_tdata (abfd)->program_header_size; + if (phdr_size == 0) + phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr; + if ((abfd->flags & D_PAGED) == 0 + || sections[0]->lma < phdr_size + || sections[0]->lma % maxpagesize < phdr_size % maxpagesize) + phdr_in_segment = FALSE; + } + + for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) + { + asection *hdr; + bfd_boolean new_segment; + + hdr = *hdrpp; + + /* See if this section and the last one will fit in the same + segment. */ + + if (last_hdr == NULL) + { + /* If we don't have a segment yet, then we don't need a new + one (we build the last one after this loop). */ + new_segment = FALSE; + } + else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma) + { + /* If this section has a different relation between the + virtual address and the load address, then we need a new + segment. */ + new_segment = TRUE; + } + else if (BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize) + < BFD_ALIGN (hdr->lma, maxpagesize)) + { + /* If putting this section in this segment would force us to + skip a page in the segment, then we need a new segment. */ + new_segment = TRUE; + } + else if ((last_hdr->flags & SEC_LOAD) == 0 + && (hdr->flags & SEC_LOAD) != 0) + { + /* We don't want to put a loadable section after a + nonloadable section in the same segment. */ + new_segment = TRUE; + } + else if ((abfd->flags & D_PAGED) == 0) + { + /* If the file is not demand paged, which means that we + don't require the sections to be correctly aligned in the + file, then there is no other reason for a new segment. */ + new_segment = FALSE; + } + else if (! writable + && (hdr->flags & SEC_READONLY) == 0 + && (((last_hdr->lma + last_hdr->_raw_size - 1) + & ~(maxpagesize - 1)) + != (hdr->lma & ~(maxpagesize - 1)))) + { + /* We don't want to put a writable section in a read only + segment, unless they are on the same page in memory + anyhow. We already know that the last section does not + bring us past the current section on the page, so the + only case in which the new section is not on the same + page as the previous section is when the previous section + ends precisely on a page boundary. */ + new_segment = TRUE; + } + else + { + /* Otherwise, we can use the same segment. */ + new_segment = FALSE; + } + + if (! new_segment) + { + if ((hdr->flags & SEC_READONLY) == 0) + writable = TRUE; + last_hdr = hdr; + continue; + } + + /* We need a new program segment. We must create a new program + header holding all the sections from phdr_index until hdr. */ + + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; + + if ((hdr->flags & SEC_READONLY) == 0) + writable = TRUE; + else + writable = FALSE; + + last_hdr = hdr; + phdr_index = i; + phdr_in_segment = FALSE; + } + + /* Create a final PT_LOAD program segment. */ + if (last_hdr != NULL) + { + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; + } + + /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ + if (dynsec != NULL) + { + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_DYNAMIC; + m->count = 1; + m->sections[0] = dynsec; + + *pm = m; + pm = &m->next; + } + + /* For each loadable .note section, add a PT_NOTE segment. We don't + use bfd_get_section_by_name, because if we link together + nonloadable .note sections and loadable .note sections, we will + generate two .note sections in the output file. FIXME: Using + names for section types is bogus anyhow. */ + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LOAD) != 0 + && strncmp (s->name, ".note", 5) == 0) + { + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_NOTE; + m->count = 1; + m->sections[0] = s; + + *pm = m; + pm = &m->next; + } + if (s->flags & SEC_THREAD_LOCAL) + { + if (! tls_count) + first_tls = s; + tls_count++; + } + } + + /* If there are any SHF_TLS output sections, add PT_TLS segment. */ + if (tls_count > 0) + { + int i; + + amt = sizeof (struct elf_segment_map); + amt += (tls_count - 1) * sizeof (asection *); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_TLS; + m->count = tls_count; + /* Mandated PF_R. */ + m->p_flags = PF_R; + m->p_flags_valid = 1; + for (i = 0; i < tls_count; ++i) + { + BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL); + m->sections[i] = first_tls; + first_tls = first_tls->next; + } + + *pm = m; + pm = &m->next; + } + + /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME + segment. */ + eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr; + if (eh_frame_hdr != NULL + && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0) + { + amt = sizeof (struct elf_segment_map); + m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_EH_FRAME; + m->count = 1; + m->sections[0] = eh_frame_hdr->output_section; + + *pm = m; + pm = &m->next; + } + + free (sections); + sections = NULL; + + elf_tdata (abfd)->segment_map = mfirst; + return TRUE; + + error_return: + if (sections != NULL) + free (sections); + return FALSE; +} + +/* Sort sections by address. */ + +static int +elf_sort_sections (arg1, arg2) + const PTR arg1; + const PTR arg2; +{ + const asection *sec1 = *(const asection **) arg1; + const asection *sec2 = *(const asection **) arg2; + bfd_size_type size1, size2; + + /* Sort by LMA first, since this is the address used to + place the section into a segment. */ + if (sec1->lma < sec2->lma) + return -1; + else if (sec1->lma > sec2->lma) + return 1; + + /* Then sort by VMA. Normally the LMA and the VMA will be + the same, and this will do nothing. */ + if (sec1->vma < sec2->vma) + return -1; + else if (sec1->vma > sec2->vma) + return 1; + + /* Put !SEC_LOAD sections after SEC_LOAD ones. */ + +#define TOEND(x) (((x)->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0) + + if (TOEND (sec1)) + { + if (TOEND (sec2)) + { + /* If the indicies are the same, do not return 0 + here, but continue to try the next comparison. */ + if (sec1->target_index - sec2->target_index != 0) + return sec1->target_index - sec2->target_index; + } + else + return 1; + } + else if (TOEND (sec2)) + return -1; + +#undef TOEND + + /* Sort by size, to put zero sized sections + before others at the same address. */ + + size1 = (sec1->flags & SEC_LOAD) ? sec1->_raw_size : 0; + size2 = (sec2->flags & SEC_LOAD) ? sec2->_raw_size : 0; + + if (size1 < size2) + return -1; + if (size1 > size2) + return 1; + + return sec1->target_index - sec2->target_index; +} + +/* Assign file positions to the sections based on the mapping from + sections to segments. This function also sets up some fields in + the file header, and writes out the program headers. */ + +static bfd_boolean +assign_file_positions_for_segments (abfd) + bfd *abfd; +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + unsigned int count; + struct elf_segment_map *m; + unsigned int alloc; + Elf_Internal_Phdr *phdrs; + file_ptr off, voff; + bfd_vma filehdr_vaddr, filehdr_paddr; + bfd_vma phdrs_vaddr, phdrs_paddr; + Elf_Internal_Phdr *p; + bfd_size_type amt; + + if (elf_tdata (abfd)->segment_map == NULL) + { + if (! map_sections_to_segments (abfd)) + return FALSE; + } + else + { + /* The placement algorithm assumes that non allocated sections are + not in PT_LOAD segments. We ensure this here by removing such + sections from the segment map. */ + for (m = elf_tdata (abfd)->segment_map; + m != NULL; + m = m->next) + { + unsigned int new_count; + unsigned int i; + + if (m->p_type != PT_LOAD) + continue; + + new_count = 0; + for (i = 0; i < m->count; i ++) + { + if ((m->sections[i]->flags & SEC_ALLOC) != 0) + { + if (i != new_count) + m->sections[new_count] = m->sections[i]; + + new_count ++; + } + } + + if (new_count != m->count) + m->count = new_count; + } + } + + if (bed->elf_backend_modify_segment_map) + { + if (! (*bed->elf_backend_modify_segment_map) (abfd)) + return FALSE; + } + + count = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++count; + + elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr; + elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr; + elf_elfheader (abfd)->e_phnum = count; + + if (count == 0) + return TRUE; + + /* If we already counted the number of program segments, make sure + that we allocated enough space. This happens when SIZEOF_HEADERS + is used in a linker script. */ + alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr; + if (alloc != 0 && count > alloc) + { + ((*_bfd_error_handler) + (_("%s: Not enough room for program headers (allocated %u, need %u)"), + bfd_get_filename (abfd), alloc, count)); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + if (alloc == 0) + alloc = count; + + amt = alloc * sizeof (Elf_Internal_Phdr); + phdrs = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt); + if (phdrs == NULL) + return FALSE; + + off = bed->s->sizeof_ehdr; + off += alloc * bed->s->sizeof_phdr; + + filehdr_vaddr = 0; + filehdr_paddr = 0; + phdrs_vaddr = 0; + phdrs_paddr = 0; + + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + unsigned int i; + asection **secpp; + + /* If elf_segment_map is not from map_sections_to_segments, the + sections may not be correctly ordered. NOTE: sorting should + not be done to the PT_NOTE section of a corefile, which may + contain several pseudo-sections artificially created by bfd. + Sorting these pseudo-sections breaks things badly. */ + if (m->count > 1 + && !(elf_elfheader (abfd)->e_type == ET_CORE + && m->p_type == PT_NOTE)) + qsort (m->sections, (size_t) m->count, sizeof (asection *), + elf_sort_sections); + + p->p_type = m->p_type; + p->p_flags = m->p_flags; + + if (p->p_type == PT_LOAD + && m->count > 0 + && (m->sections[0]->flags & SEC_ALLOC) != 0) + { + if ((abfd->flags & D_PAGED) != 0) + off += (m->sections[0]->vma - off) % bed->maxpagesize; + else + { + bfd_size_type align; + + align = 0; + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) + { + bfd_size_type secalign; + + secalign = bfd_get_section_alignment (abfd, *secpp); + if (secalign > align) + align = secalign; + } + + off += (m->sections[0]->vma - off) % (1 << align); + } + } + + if (m->count == 0) + p->p_vaddr = 0; + else + p->p_vaddr = m->sections[0]->vma; + + if (m->p_paddr_valid) + p->p_paddr = m->p_paddr; + else if (m->count == 0) + p->p_paddr = 0; + else + p->p_paddr = m->sections[0]->lma; + + if (p->p_type == PT_LOAD + && (abfd->flags & D_PAGED) != 0) + p->p_align = bed->maxpagesize; + else if (m->count == 0) + p->p_align = bed->s->file_align; + else + p->p_align = 0; + + p->p_offset = 0; + p->p_filesz = 0; + p->p_memsz = 0; + + if (m->includes_filehdr) + { + if (! m->p_flags_valid) + p->p_flags |= PF_R; + p->p_offset = 0; + p->p_filesz = bed->s->sizeof_ehdr; + p->p_memsz = bed->s->sizeof_ehdr; + if (m->count > 0) + { + BFD_ASSERT (p->p_type == PT_LOAD); + + if (p->p_vaddr < (bfd_vma) off) + { + (*_bfd_error_handler) + (_("%s: Not enough room for program headers, try linking with -N"), + bfd_get_filename (abfd)); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + p->p_vaddr -= off; + if (! m->p_paddr_valid) + p->p_paddr -= off; + } + if (p->p_type == PT_LOAD) + { + filehdr_vaddr = p->p_vaddr; + filehdr_paddr = p->p_paddr; + } + } + + if (m->includes_phdrs) + { + if (! m->p_flags_valid) + p->p_flags |= PF_R; + + if (m->includes_filehdr) + { + if (p->p_type == PT_LOAD) + { + phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr; + phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr; + } + } + else + { + p->p_offset = bed->s->sizeof_ehdr; + + if (m->count > 0) + { + BFD_ASSERT (p->p_type == PT_LOAD); + p->p_vaddr -= off - p->p_offset; + if (! m->p_paddr_valid) + p->p_paddr -= off - p->p_offset; + } + + if (p->p_type == PT_LOAD) + { + phdrs_vaddr = p->p_vaddr; + phdrs_paddr = p->p_paddr; + } + else + phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; + } + + p->p_filesz += alloc * bed->s->sizeof_phdr; + p->p_memsz += alloc * bed->s->sizeof_phdr; + } + + if (p->p_type == PT_LOAD + || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)) + { + if (! m->includes_filehdr && ! m->includes_phdrs) + p->p_offset = off; + else + { + file_ptr adjust; + + adjust = off - (p->p_offset + p->p_filesz); + p->p_filesz += adjust; + p->p_memsz += adjust; + } + } + + voff = off; + + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) + { + asection *sec; + flagword flags; + bfd_size_type align; + + sec = *secpp; + flags = sec->flags; + align = 1 << bfd_get_section_alignment (abfd, sec); + + /* The section may have artificial alignment forced by a + link script. Notice this case by the gap between the + cumulative phdr lma and the section's lma. */ + if (p->p_paddr + p->p_memsz < sec->lma) + { + bfd_vma adjust = sec->lma - (p->p_paddr + p->p_memsz); + + p->p_memsz += adjust; + if (p->p_type == PT_LOAD + || (p->p_type == PT_NOTE + && bfd_get_format (abfd) == bfd_core)) + { + off += adjust; + voff += adjust; + } + if ((flags & SEC_LOAD) != 0 + || (flags & SEC_THREAD_LOCAL) != 0) + p->p_filesz += adjust; + } + + if (p->p_type == PT_LOAD) + { + bfd_signed_vma adjust; + + if ((flags & SEC_LOAD) != 0) + { + adjust = sec->lma - (p->p_paddr + p->p_memsz); + if (adjust < 0) + adjust = 0; + } + else if ((flags & SEC_ALLOC) != 0) + { + /* The section VMA must equal the file position + modulo the page size. FIXME: I'm not sure if + this adjustment is really necessary. We used to + not have the SEC_LOAD case just above, and then + this was necessary, but now I'm not sure. */ + if ((abfd->flags & D_PAGED) != 0) + adjust = (sec->vma - voff) % bed->maxpagesize; + else + adjust = (sec->vma - voff) % align; + } + else + adjust = 0; + + if (adjust != 0) + { + if (i == 0) + { + (* _bfd_error_handler) (_("\ +Error: First section in segment (%s) starts at 0x%x whereas the segment starts at 0x%x"), + bfd_section_name (abfd, sec), + sec->lma, + p->p_paddr); + return FALSE; + } + p->p_memsz += adjust; + off += adjust; + voff += adjust; + if ((flags & SEC_LOAD) != 0) + p->p_filesz += adjust; + } + + sec->filepos = off; + + /* We check SEC_HAS_CONTENTS here because if NOLOAD is + used in a linker script we may have a section with + SEC_LOAD clear but which is supposed to have + contents. */ + if ((flags & SEC_LOAD) != 0 + || (flags & SEC_HAS_CONTENTS) != 0) + off += sec->_raw_size; + + if ((flags & SEC_ALLOC) != 0 + && ((flags & SEC_LOAD) != 0 + || (flags & SEC_THREAD_LOCAL) == 0)) + voff += sec->_raw_size; + } + + if (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core) + { + /* The actual "note" segment has i == 0. + This is the one that actually contains everything. */ + if (i == 0) + { + sec->filepos = off; + p->p_filesz = sec->_raw_size; + off += sec->_raw_size; + voff = off; + } + else + { + /* Fake sections -- don't need to be written. */ + sec->filepos = 0; + sec->_raw_size = 0; + flags = sec->flags = 0; + } + p->p_memsz = 0; + p->p_align = 1; + } + else + { + if ((sec->flags & SEC_LOAD) != 0 + || (sec->flags & SEC_THREAD_LOCAL) == 0 + || p->p_type == PT_TLS) + p->p_memsz += sec->_raw_size; + + if ((flags & SEC_LOAD) != 0) + p->p_filesz += sec->_raw_size; + + if (p->p_type == PT_TLS + && sec->_raw_size == 0 + && (sec->flags & SEC_HAS_CONTENTS) == 0) + { + struct bfd_link_order *o; + bfd_vma tbss_size = 0; + + for (o = sec->link_order_head; o != NULL; o = o->next) + if (tbss_size < o->offset + o->size) + tbss_size = o->offset + o->size; + + p->p_memsz += tbss_size; + } + + if (align > p->p_align + && (p->p_type != PT_LOAD || (abfd->flags & D_PAGED) == 0)) + p->p_align = align; + } + + if (! m->p_flags_valid) + { + p->p_flags |= PF_R; + if ((flags & SEC_CODE) != 0) + p->p_flags |= PF_X; + if ((flags & SEC_READONLY) == 0) + p->p_flags |= PF_W; + } + } + } + + /* Now that we have set the section file positions, we can set up + the file positions for the non PT_LOAD segments. */ + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + if (p->p_type != PT_LOAD && m->count > 0) + { + BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs); + p->p_offset = m->sections[0]->filepos; + } + if (m->count == 0) + { + if (m->includes_filehdr) + { + p->p_vaddr = filehdr_vaddr; + if (! m->p_paddr_valid) + p->p_paddr = filehdr_paddr; + } + else if (m->includes_phdrs) + { + p->p_vaddr = phdrs_vaddr; + if (! m->p_paddr_valid) + p->p_paddr = phdrs_paddr; + } + } + } + + /* Clear out any program headers we allocated but did not use. */ + for (; count < alloc; count++, p++) + { + memset (p, 0, sizeof *p); + p->p_type = PT_NULL; + } + + elf_tdata (abfd)->phdr = phdrs; + + elf_tdata (abfd)->next_file_pos = off; + + /* Write out the program headers. */ + if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 + || bed->s->write_out_phdrs (abfd, phdrs, alloc) != 0) + return FALSE; + + return TRUE; +} + +/* Get the size of the program header. + + If this is called by the linker before any of the section VMA's are set, it + can't calculate the correct value for a strange memory layout. This only + happens when SIZEOF_HEADERS is used in a linker script. In this case, + SORTED_HDRS is NULL and we assume the normal scenario of one text and one + data segment (exclusive of .interp and .dynamic). + + ??? User written scripts must either not use SIZEOF_HEADERS, or assume there + will be two segments. */ + +static bfd_size_type +get_program_header_size (abfd) + bfd *abfd; +{ + size_t segs; + asection *s; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* We can't return a different result each time we're called. */ + if (elf_tdata (abfd)->program_header_size != 0) + return elf_tdata (abfd)->program_header_size; + + if (elf_tdata (abfd)->segment_map != NULL) + { + struct elf_segment_map *m; + + segs = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++segs; + elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; + return elf_tdata (abfd)->program_header_size; + } + + /* Assume we will need exactly two PT_LOAD segments: one for text + and one for data. */ + segs = 2; + + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + /* If we have a loadable interpreter section, we need a + PT_INTERP segment. In this case, assume we also need a + PT_PHDR segment, although that may not be true for all + targets. */ + segs += 2; + } + + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) + { + /* We need a PT_DYNAMIC segment. */ + ++segs; + } + + if (elf_tdata (abfd)->eh_frame_hdr) + { + /* We need a PT_GNU_EH_FRAME segment. */ + ++segs; + } + + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LOAD) != 0 + && strncmp (s->name, ".note", 5) == 0) + { + /* We need a PT_NOTE segment. */ + ++segs; + } + } + + for (s = abfd->sections; s != NULL; s = s->next) + { + if (s->flags & SEC_THREAD_LOCAL) + { + /* We need a PT_TLS segment. */ + ++segs; + break; + } + } + + /* Let the backend count up any program headers it might need. */ + if (bed->elf_backend_additional_program_headers) + { + int a; + + a = (*bed->elf_backend_additional_program_headers) (abfd); + if (a == -1) + abort (); + segs += a; + } + + elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; + return elf_tdata (abfd)->program_header_size; +} + +/* Work out the file positions of all the sections. This is called by + _bfd_elf_compute_section_file_positions. All the section sizes and + VMAs must be known before this is called. + + We do not consider reloc sections at this point, unless they form + part of the loadable image. Reloc sections are assigned file + positions in assign_file_positions_for_relocs, which is called by + write_object_contents and final_link. + + We also don't set the positions of the .symtab and .strtab here. */ + +static bfd_boolean +assign_file_positions_except_relocs (abfd) + bfd *abfd; +{ + struct elf_obj_tdata * const tdata = elf_tdata (abfd); + Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd); + Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); + unsigned int num_sec = elf_numsections (abfd); + file_ptr off; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 + && bfd_get_format (abfd) != bfd_core) + { + Elf_Internal_Shdr **hdrpp; + unsigned int i; + + /* Start after the ELF header. */ + off = i_ehdrp->e_ehsize; + + /* We are not creating an executable, which means that we are + not creating a program header, and that the actual order of + the sections in the file is unimportant. */ + for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) + { + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if (hdr->sh_type == SHT_REL + || hdr->sh_type == SHT_RELA + || i == tdata->symtab_section + || i == tdata->symtab_shndx_section + || i == tdata->strtab_section) + { + hdr->sh_offset = -1; + } + else + off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + + if (i == SHN_LORESERVE - 1) + { + i += SHN_HIRESERVE + 1 - SHN_LORESERVE; + hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE; + } + } + } + else + { + unsigned int i; + Elf_Internal_Shdr **hdrpp; + + /* Assign file positions for the loaded sections based on the + assignment of sections to segments. */ + if (! assign_file_positions_for_segments (abfd)) + return FALSE; + + /* Assign file positions for the other sections. */ + + off = elf_tdata (abfd)->next_file_pos; + for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) + { + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if (hdr->bfd_section != NULL + && hdr->bfd_section->filepos != 0) + hdr->sh_offset = hdr->bfd_section->filepos; + else if ((hdr->sh_flags & SHF_ALLOC) != 0) + { + ((*_bfd_error_handler) + (_("%s: warning: allocated section `%s' not in segment"), + bfd_get_filename (abfd), + (hdr->bfd_section == NULL + ? "*unknown*" + : hdr->bfd_section->name))); + if ((abfd->flags & D_PAGED) != 0) + off += (hdr->sh_addr - off) % bed->maxpagesize; + else + off += (hdr->sh_addr - off) % hdr->sh_addralign; + off = _bfd_elf_assign_file_position_for_section (hdr, off, + FALSE); + } + else if (hdr->sh_type == SHT_REL + || hdr->sh_type == SHT_RELA + || hdr == i_shdrpp[tdata->symtab_section] + || hdr == i_shdrpp[tdata->symtab_shndx_section] + || hdr == i_shdrpp[tdata->strtab_section]) + hdr->sh_offset = -1; + else + off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + + if (i == SHN_LORESERVE - 1) + { + i += SHN_HIRESERVE + 1 - SHN_LORESERVE; + hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE; + } + } + } + + /* Place the section headers. */ + off = align_file_position (off, bed->s->file_align); + i_ehdrp->e_shoff = off; + off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; + + elf_tdata (abfd)->next_file_pos = off; + + return TRUE; +} + +static bfd_boolean +prep_headers (abfd) + bfd *abfd; +{ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_Internal_Phdr *i_phdrp = 0; /* Program header table, internal form */ + Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ + struct elf_strtab_hash *shstrtab; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + i_ehdrp = elf_elfheader (abfd); + i_shdrp = elf_elfsections (abfd); + + shstrtab = _bfd_elf_strtab_init (); + if (shstrtab == NULL) + return FALSE; + + elf_shstrtab (abfd) = shstrtab; + + i_ehdrp->e_ident[EI_MAG0] = ELFMAG0; + i_ehdrp->e_ident[EI_MAG1] = ELFMAG1; + i_ehdrp->e_ident[EI_MAG2] = ELFMAG2; + i_ehdrp->e_ident[EI_MAG3] = ELFMAG3; + + i_ehdrp->e_ident[EI_CLASS] = bed->s->elfclass; + i_ehdrp->e_ident[EI_DATA] = + bfd_big_endian (abfd) ? ELFDATA2MSB : ELFDATA2LSB; + i_ehdrp->e_ident[EI_VERSION] = bed->s->ev_current; + + if ((abfd->flags & DYNAMIC) != 0) + i_ehdrp->e_type = ET_DYN; + else if ((abfd->flags & EXEC_P) != 0) + i_ehdrp->e_type = ET_EXEC; + else if (bfd_get_format (abfd) == bfd_core) + i_ehdrp->e_type = ET_CORE; + else + i_ehdrp->e_type = ET_REL; + + switch (bfd_get_arch (abfd)) + { + case bfd_arch_unknown: + i_ehdrp->e_machine = EM_NONE; + break; + + /* There used to be a long list of cases here, each one setting + e_machine to the same EM_* macro #defined as ELF_MACHINE_CODE + in the corresponding bfd definition. To avoid duplication, + the switch was removed. Machines that need special handling + can generally do it in elf_backend_final_write_processing(), + unless they need the information earlier than the final write. + Such need can generally be supplied by replacing the tests for + e_machine with the conditions used to determine it. */ + default: + if (get_elf_backend_data (abfd) != NULL) + i_ehdrp->e_machine = get_elf_backend_data (abfd)->elf_machine_code; + else + i_ehdrp->e_machine = EM_NONE; + } + + i_ehdrp->e_version = bed->s->ev_current; + i_ehdrp->e_ehsize = bed->s->sizeof_ehdr; + + /* No program header, for now. */ + i_ehdrp->e_phoff = 0; + i_ehdrp->e_phentsize = 0; + i_ehdrp->e_phnum = 0; + + /* Each bfd section is section header entry. */ + i_ehdrp->e_entry = bfd_get_start_address (abfd); + i_ehdrp->e_shentsize = bed->s->sizeof_shdr; + + /* If we're building an executable, we'll need a program header table. */ + if (abfd->flags & EXEC_P) + { + /* It all happens later. */ +#if 0 + i_ehdrp->e_phentsize = sizeof (Elf_External_Phdr); + + /* elf_build_phdrs() returns a (NULL-terminated) array of + Elf_Internal_Phdrs. */ + i_phdrp = elf_build_phdrs (abfd, i_ehdrp, i_shdrp, &i_ehdrp->e_phnum); + i_ehdrp->e_phoff = outbase; + outbase += i_ehdrp->e_phentsize * i_ehdrp->e_phnum; +#endif + } + else + { + i_ehdrp->e_phentsize = 0; + i_phdrp = 0; + i_ehdrp->e_phoff = 0; + } + + elf_tdata (abfd)->symtab_hdr.sh_name = + (unsigned int) _bfd_elf_strtab_add (shstrtab, ".symtab", FALSE); + elf_tdata (abfd)->strtab_hdr.sh_name = + (unsigned int) _bfd_elf_strtab_add (shstrtab, ".strtab", FALSE); + 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)->shstrtab_hdr.sh_name == (unsigned int) -1) + return FALSE; + + return TRUE; +} + +/* Assign file positions for all the reloc sections which are not part + of the loadable file image. */ + +void +_bfd_elf_assign_file_positions_for_relocs (abfd) + bfd *abfd; +{ + file_ptr off; + unsigned int i, num_sec; + Elf_Internal_Shdr **shdrpp; + + off = elf_tdata (abfd)->next_file_pos; + + num_sec = elf_numsections (abfd); + for (i = 1, shdrpp = elf_elfsections (abfd) + 1; i < num_sec; i++, 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); + } + + elf_tdata (abfd)->next_file_pos = off; +} + +bfd_boolean +_bfd_elf_write_object_contents (abfd) + bfd *abfd; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + Elf_Internal_Ehdr *i_ehdrp; + Elf_Internal_Shdr **i_shdrp; + bfd_boolean failed; + unsigned int count, num_sec; + + if (! abfd->output_has_begun + && ! _bfd_elf_compute_section_file_positions + (abfd, (struct bfd_link_info *) NULL)) + return FALSE; + + i_shdrp = elf_elfsections (abfd); + i_ehdrp = elf_elfheader (abfd); + + failed = FALSE; + bfd_map_over_sections (abfd, bed->s->write_relocs, &failed); + if (failed) + return FALSE; + + _bfd_elf_assign_file_positions_for_relocs (abfd); + + /* After writing the headers, we need to write the sections too... */ + num_sec = elf_numsections (abfd); + for (count = 1; count < num_sec; count++) + { + if (bed->elf_backend_section_processing) + (*bed->elf_backend_section_processing) (abfd, i_shdrp[count]); + if (i_shdrp[count]->contents) + { + bfd_size_type amt = i_shdrp[count]->sh_size; + + if (bfd_seek (abfd, i_shdrp[count]->sh_offset, SEEK_SET) != 0 + || bfd_bwrite (i_shdrp[count]->contents, amt, abfd) != amt) + return FALSE; + } + if (count == SHN_LORESERVE - 1) + count += SHN_HIRESERVE + 1 - SHN_LORESERVE; + } + + /* Write out the section header names. */ + if (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0 + || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd))) + return FALSE; + + if (bed->elf_backend_final_write_processing) + (*bed->elf_backend_final_write_processing) (abfd, + elf_tdata (abfd)->linker); + + return bed->s->write_shdrs_and_ehdr (abfd); +} + +bfd_boolean +_bfd_elf_write_corefile_contents (abfd) + bfd *abfd; +{ + /* Hopefully this can be done just like an object file. */ + return _bfd_elf_write_object_contents (abfd); +} + +/* Given a section, search the header to find them. */ + +int +_bfd_elf_section_from_bfd_section (abfd, asect) + bfd *abfd; + struct sec *asect; +{ + struct elf_backend_data *bed; + int index; + + if (elf_section_data (asect) != NULL + && elf_section_data (asect)->this_idx != 0) + return elf_section_data (asect)->this_idx; + + if (bfd_is_abs_section (asect)) + index = SHN_ABS; + else if (bfd_is_com_section (asect)) + index = SHN_COMMON; + else if (bfd_is_und_section (asect)) + index = SHN_UNDEF; + else + { + Elf_Internal_Shdr **i_shdrp = elf_elfsections (abfd); + int maxindex = elf_numsections (abfd); + + for (index = 1; index < maxindex; index++) + { + Elf_Internal_Shdr *hdr = i_shdrp[index]; + + if (hdr != NULL && hdr->bfd_section == asect) + return index; + } + index = -1; + } + + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_section_from_bfd_section) + { + int retval = index; + + if ((*bed->elf_backend_section_from_bfd_section) (abfd, asect, &retval)) + return retval; + } + + if (index == -1) + bfd_set_error (bfd_error_nonrepresentable_section); + + return index; +} + +/* Given a BFD symbol, return the index in the ELF symbol table, or -1 + on error. */ + +int +_bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) + bfd *abfd; + asymbol **asym_ptr_ptr; +{ + asymbol *asym_ptr = *asym_ptr_ptr; + int idx; + flagword flags = asym_ptr->flags; + + /* When gas creates relocations against local labels, it creates its + own symbol for the section, but does put the symbol into the + symbol chain, so udata is 0. When the linker is generating + relocatable output, this section symbol may be for one of the + input sections rather than the output section. */ + if (asym_ptr->udata.i == 0 + && (flags & BSF_SECTION_SYM) + && asym_ptr->section) + { + int indx; + + if (asym_ptr->section->output_section != NULL) + indx = asym_ptr->section->output_section->index; + else + indx = asym_ptr->section->index; + if (indx < elf_num_section_syms (abfd) + && elf_section_syms (abfd)[indx] != NULL) + asym_ptr->udata.i = elf_section_syms (abfd)[indx]->udata.i; + } + + idx = asym_ptr->udata.i; + + if (idx == 0) + { + /* This case can occur when using --strip-symbol on a symbol + which is used in a relocation entry. */ + (*_bfd_error_handler) + (_("%s: symbol `%s' required but not present"), + bfd_archive_filename (abfd), bfd_asymbol_name (asym_ptr)); + bfd_set_error (bfd_error_no_symbols); + return -1; + } + +#if DEBUG & 4 + { + fprintf (stderr, + "elf_symbol_from_bfd_symbol 0x%.8lx, name = %s, sym num = %d, flags = 0x%.8lx%s\n", + (long) asym_ptr, asym_ptr->name, idx, flags, + elf_symbol_flags (flags)); + fflush (stderr); + } +#endif + + return idx; +} + +/* Copy private BFD data. This copies any program header information. */ + +static bfd_boolean +copy_private_bfd_data (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + Elf_Internal_Ehdr *iehdr; + struct elf_segment_map *map; + struct elf_segment_map *map_first; + struct elf_segment_map **pointer_to_map; + Elf_Internal_Phdr *segment; + asection *section; + unsigned int i; + unsigned int num_segments; + bfd_boolean phdr_included = FALSE; + bfd_vma maxpagesize; + struct elf_segment_map *phdr_adjust_seg = NULL; + unsigned int phdr_adjust_num = 0; + struct elf_backend_data *bed; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + if (elf_tdata (ibfd)->phdr == NULL) + return TRUE; + + bed = get_elf_backend_data (ibfd); + iehdr = elf_elfheader (ibfd); + + map_first = NULL; + pointer_to_map = &map_first; + + num_segments = elf_elfheader (ibfd)->e_phnum; + maxpagesize = get_elf_backend_data (obfd)->maxpagesize; + + /* Returns the end address of the segment + 1. */ +#define SEGMENT_END(segment, start) \ + (start + (segment->p_memsz > segment->p_filesz \ + ? segment->p_memsz : segment->p_filesz)) + +#define SECTION_SIZE(section, segment) \ + (((section->flags & (SEC_HAS_CONTENTS | SEC_THREAD_LOCAL)) \ + != SEC_THREAD_LOCAL || segment->p_type == PT_TLS) \ + ? section->_raw_size : 0) + + /* Returns TRUE if the given section is contained within + the given segment. VMA addresses are compared. */ +#define IS_CONTAINED_BY_VMA(section, segment) \ + (section->vma >= segment->p_vaddr \ + && (section->vma + SECTION_SIZE (section, segment) \ + <= (SEGMENT_END (segment, segment->p_vaddr)))) + + /* Returns TRUE if the given section is contained within + the given segment. LMA addresses are compared. */ +#define IS_CONTAINED_BY_LMA(section, segment, base) \ + (section->lma >= base \ + && (section->lma + SECTION_SIZE (section, segment) \ + <= SEGMENT_END (segment, base))) + + /* Special case: corefile "NOTE" section containing regs, prpsinfo etc. */ +#define IS_COREFILE_NOTE(p, s) \ + (p->p_type == PT_NOTE \ + && bfd_get_format (ibfd) == bfd_core \ + && s->vma == 0 && s->lma == 0 \ + && (bfd_vma) s->filepos >= p->p_offset \ + && ((bfd_vma) s->filepos + s->_raw_size \ + <= p->p_offset + p->p_filesz)) + + /* The complicated case when p_vaddr is 0 is to handle the Solaris + linker, which generates a PT_INTERP section with p_vaddr and + p_memsz set to 0. */ +#define IS_SOLARIS_PT_INTERP(p, s) \ + (p->p_vaddr == 0 \ + && p->p_paddr == 0 \ + && p->p_memsz == 0 \ + && p->p_filesz > 0 \ + && (s->flags & SEC_HAS_CONTENTS) != 0 \ + && s->_raw_size > 0 \ + && (bfd_vma) s->filepos >= p->p_offset \ + && ((bfd_vma) s->filepos + s->_raw_size \ + <= p->p_offset + p->p_filesz)) + + /* Decide if the given section should be included in the given segment. + A section will be included if: + 1. It is within the address space of the segment -- we use the LMA + if that is set for the segment and the VMA otherwise, + 2. It is an allocated segment, + 3. There is an output section associated with it, + 4. The section has not already been allocated to a previous segment. + 5. PT_TLS segment includes only SHF_TLS sections. + 6. SHF_TLS sections are only in PT_TLS or PT_LOAD segments. */ +#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed) \ + ((((segment->p_paddr \ + ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr) \ + : IS_CONTAINED_BY_VMA (section, segment)) \ + && (section->flags & SEC_ALLOC) != 0) \ + || IS_COREFILE_NOTE (segment, section)) \ + && section->output_section != NULL \ + && (segment->p_type != PT_TLS \ + || (section->flags & SEC_THREAD_LOCAL)) \ + && (segment->p_type == PT_LOAD \ + || segment->p_type == PT_TLS \ + || (section->flags & SEC_THREAD_LOCAL) == 0) \ + && ! section->segment_mark) + + /* Returns TRUE iff seg1 starts after the end of seg2. */ +#define SEGMENT_AFTER_SEGMENT(seg1, seg2, field) \ + (seg1->field >= SEGMENT_END (seg2, seg2->field)) + + /* Returns TRUE iff seg1 and seg2 overlap. Segments overlap iff both + their VMA address ranges and their LMA address ranges overlap. + It is possible to have overlapping VMA ranges without overlapping LMA + ranges. RedBoot images for example can have both .data and .bss mapped + to the same VMA range, but with the .data section mapped to a different + LMA. */ +#define SEGMENT_OVERLAPS(seg1, seg2) \ + ( !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_vaddr) \ + || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr)) \ + && !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_paddr) \ + || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr))) + + /* Initialise the segment mark field. */ + for (section = ibfd->sections; section != NULL; section = section->next) + section->segment_mark = FALSE; + + /* Scan through the segments specified in the program header + of the input BFD. For this first scan we look for overlaps + in the loadable segments. These can be created by weird + parameters to objcopy. Also, fix some solaris weirdness. */ + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i++, segment++) + { + unsigned int j; + Elf_Internal_Phdr *segment2; + + if (segment->p_type == PT_INTERP) + for (section = ibfd->sections; section; section = section->next) + if (IS_SOLARIS_PT_INTERP (segment, section)) + { + /* Mininal change so that the normal section to segment + assigment code will work. */ + segment->p_vaddr = section->vma; + break; + } + + if (segment->p_type != PT_LOAD) + continue; + + /* Determine if this segment overlaps any previous segments. */ + for (j = 0, segment2 = elf_tdata (ibfd)->phdr; j < i; j++, segment2 ++) + { + bfd_signed_vma extra_length; + + if (segment2->p_type != PT_LOAD + || ! SEGMENT_OVERLAPS (segment, segment2)) + continue; + + /* Merge the two segments together. */ + if (segment2->p_vaddr < segment->p_vaddr) + { + /* Extend SEGMENT2 to include SEGMENT and then delete + SEGMENT. */ + extra_length = + SEGMENT_END (segment, segment->p_vaddr) + - SEGMENT_END (segment2, segment2->p_vaddr); + + if (extra_length > 0) + { + segment2->p_memsz += extra_length; + segment2->p_filesz += extra_length; + } + + segment->p_type = PT_NULL; + + /* Since we have deleted P we must restart the outer loop. */ + i = 0; + segment = elf_tdata (ibfd)->phdr; + break; + } + else + { + /* Extend SEGMENT to include SEGMENT2 and then delete + SEGMENT2. */ + extra_length = + SEGMENT_END (segment2, segment2->p_vaddr) + - SEGMENT_END (segment, segment->p_vaddr); + + if (extra_length > 0) + { + segment->p_memsz += extra_length; + segment->p_filesz += extra_length; + } + + segment2->p_type = PT_NULL; + } + } + } + + /* The second scan attempts to assign sections to segments. */ + for (i = 0, segment = elf_tdata (ibfd)->phdr; + i < num_segments; + i ++, segment ++) + { + unsigned int section_count; + asection ** sections; + asection * output_section; + unsigned int isec; + bfd_vma matching_lma; + bfd_vma suggested_lma; + unsigned int j; + bfd_size_type amt; + + if (segment->p_type == PT_NULL) + continue; + + /* Compute how many sections might be placed into this segment. */ + for (section = ibfd->sections, section_count = 0; + section != NULL; + section = section->next) + if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed)) + ++section_count; + + /* Allocate a segment map big enough to contain + all of the sections we have selected. */ + amt = sizeof (struct elf_segment_map); + amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); + map = (struct elf_segment_map *) bfd_alloc (obfd, amt); + if (map == NULL) + return FALSE; + + /* Initialise the fields of the segment map. Default to + using the physical address of the segment in the input BFD. */ + map->next = NULL; + map->p_type = segment->p_type; + map->p_flags = segment->p_flags; + map->p_flags_valid = 1; + map->p_paddr = segment->p_paddr; + map->p_paddr_valid = 1; + + /* Determine if this segment contains the ELF file header + and if it contains the program headers themselves. */ + map->includes_filehdr = (segment->p_offset == 0 + && segment->p_filesz >= iehdr->e_ehsize); + + map->includes_phdrs = 0; + + if (! phdr_included || segment->p_type != PT_LOAD) + { + map->includes_phdrs = + (segment->p_offset <= (bfd_vma) iehdr->e_phoff + && (segment->p_offset + segment->p_filesz + >= ((bfd_vma) iehdr->e_phoff + + iehdr->e_phnum * iehdr->e_phentsize))); + + if (segment->p_type == PT_LOAD && map->includes_phdrs) + phdr_included = TRUE; + } + + if (section_count == 0) + { + /* Special segments, such as the PT_PHDR segment, may contain + no sections, but ordinary, loadable segments should contain + something. They are allowed by the ELF spec however, so only + a warning is produced. */ + if (segment->p_type == PT_LOAD) + (*_bfd_error_handler) + (_("%s: warning: Empty loadable segment detected, is this intentional ?\n"), + bfd_archive_filename (ibfd)); + + map->count = 0; + *pointer_to_map = map; + pointer_to_map = &map->next; + + continue; + } + + /* Now scan the sections in the input BFD again and attempt + to add their corresponding output sections to the segment map. + The problem here is how to handle an output section which has + been moved (ie had its LMA changed). There are four possibilities: + + 1. None of the sections have been moved. + In this case we can continue to use the segment LMA from the + input BFD. + + 2. All of the sections have been moved by the same amount. + In this case we can change the segment's LMA to match the LMA + of the first section. + + 3. Some of the sections have been moved, others have not. + In this case those sections which have not been moved can be + placed in the current segment which will have to have its size, + and possibly its LMA changed, and a new segment or segments will + have to be created to contain the other sections. + + 4. The sections have been moved, but not by the same amount. + In this case we can change the segment's LMA to match the LMA + of the first section and we will have to create a new segment + or segments to contain the other sections. + + In order to save time, we allocate an array to hold the section + pointers that we are interested in. As these sections get assigned + to a segment, they are removed from this array. */ + + /* Gcc 2.96 miscompiles this code on mips. Don't do casting here + to work around this long long bug. */ + amt = section_count * sizeof (asection *); + sections = (asection **) bfd_malloc (amt); + if (sections == NULL) + return FALSE; + + /* Step One: Scan for segment vs section LMA conflicts. + Also add the sections to the section array allocated above. + Also add the sections to the current segment. In the common + case, where the sections have not been moved, this means that + we have completely filled the segment, and there is nothing + more to do. */ + isec = 0; + matching_lma = 0; + suggested_lma = 0; + + for (j = 0, section = ibfd->sections; + section != NULL; + section = section->next) + { + if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed)) + { + output_section = section->output_section; + + sections[j ++] = section; + + /* The Solaris native linker always sets p_paddr to 0. + We try to catch that case here, and set it to the + correct value. Note - some backends require that + p_paddr be left as zero. */ + if (segment->p_paddr == 0 + && segment->p_vaddr != 0 + && (! bed->want_p_paddr_set_to_zero) + && isec == 0 + && output_section->lma != 0 + && (output_section->vma == (segment->p_vaddr + + (map->includes_filehdr + ? iehdr->e_ehsize + : 0) + + (map->includes_phdrs + ? (iehdr->e_phnum + * iehdr->e_phentsize) + : 0)))) + map->p_paddr = segment->p_vaddr; + + /* Match up the physical address of the segment with the + LMA address of the output section. */ + if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) + || IS_COREFILE_NOTE (segment, section) + || (bed->want_p_paddr_set_to_zero && + IS_CONTAINED_BY_VMA (output_section, segment)) + ) + { + if (matching_lma == 0) + matching_lma = output_section->lma; + + /* We assume that if the section fits within the segment + then it does not overlap any other section within that + segment. */ + map->sections[isec ++] = output_section; + } + else if (suggested_lma == 0) + suggested_lma = output_section->lma; + } + } + + BFD_ASSERT (j == section_count); + + /* Step Two: Adjust the physical address of the current segment, + if necessary. */ + if (isec == section_count) + { + /* All of the sections fitted within the segment as currently + specified. This is the default case. Add the segment to + the list of built segments and carry on to process the next + program header in the input BFD. */ + map->count = section_count; + *pointer_to_map = map; + pointer_to_map = &map->next; + + free (sections); + continue; + } + else + { + if (matching_lma != 0) + { + /* At least one section fits inside the current segment. + Keep it, but modify its physical address to match the + LMA of the first section that fitted. */ + map->p_paddr = matching_lma; + } + else + { + /* None of the sections fitted inside the current segment. + Change the current segment's physical address to match + the LMA of the first section. */ + map->p_paddr = suggested_lma; + } + + /* Offset the segment physical address from the lma + to allow for space taken up by elf headers. */ + if (map->includes_filehdr) + map->p_paddr -= iehdr->e_ehsize; + + if (map->includes_phdrs) + { + map->p_paddr -= iehdr->e_phnum * iehdr->e_phentsize; + + /* iehdr->e_phnum is just an estimate of the number + of program headers that we will need. Make a note + here of the number we used and the segment we chose + to hold these headers, so that we can adjust the + offset when we know the correct value. */ + phdr_adjust_num = iehdr->e_phnum; + phdr_adjust_seg = map; + } + } + + /* Step Three: Loop over the sections again, this time assigning + those that fit to the current segment and removing them from the + sections array; but making sure not to leave large gaps. Once all + possible sections have been assigned to the current segment it is + added to the list of built segments and if sections still remain + to be assigned, a new segment is constructed before repeating + the loop. */ + isec = 0; + do + { + map->count = 0; + suggested_lma = 0; + + /* Fill the current segment with sections that fit. */ + for (j = 0; j < section_count; j++) + { + section = sections[j]; + + if (section == NULL) + continue; + + output_section = section->output_section; + + BFD_ASSERT (output_section != NULL); + + if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) + || IS_COREFILE_NOTE (segment, section)) + { + if (map->count == 0) + { + /* If the first section in a segment does not start at + the beginning of the segment, then something is + wrong. */ + if (output_section->lma != + (map->p_paddr + + (map->includes_filehdr ? iehdr->e_ehsize : 0) + + (map->includes_phdrs + ? iehdr->e_phnum * iehdr->e_phentsize + : 0))) + abort (); + } + else + { + asection * prev_sec; + + prev_sec = map->sections[map->count - 1]; + + /* If the gap between the end of the previous section + and the start of this section is more than + maxpagesize then we need to start a new segment. */ + if ((BFD_ALIGN (prev_sec->lma + prev_sec->_raw_size, + maxpagesize) + < BFD_ALIGN (output_section->lma, maxpagesize)) + || ((prev_sec->lma + prev_sec->_raw_size) + > output_section->lma)) + { + if (suggested_lma == 0) + suggested_lma = output_section->lma; + + continue; + } + } + + map->sections[map->count++] = output_section; + ++isec; + sections[j] = NULL; + section->segment_mark = TRUE; + } + else if (suggested_lma == 0) + suggested_lma = output_section->lma; + } + + BFD_ASSERT (map->count > 0); + + /* Add the current segment to the list of built segments. */ + *pointer_to_map = map; + pointer_to_map = &map->next; + + if (isec < section_count) + { + /* We still have not allocated all of the sections to + segments. Create a new segment here, initialise it + and carry on looping. */ + amt = sizeof (struct elf_segment_map); + amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); + map = (struct elf_segment_map *) bfd_alloc (obfd, amt); + if (map == NULL) + { + free (sections); + return FALSE; + } + + /* Initialise the fields of the segment map. Set the physical + physical address to the LMA of the first section that has + not yet been assigned. */ + map->next = NULL; + map->p_type = segment->p_type; + map->p_flags = segment->p_flags; + map->p_flags_valid = 1; + map->p_paddr = suggested_lma; + map->p_paddr_valid = 1; + map->includes_filehdr = 0; + map->includes_phdrs = 0; + } + } + while (isec < section_count); + + free (sections); + } + + /* The Solaris linker creates program headers in which all the + p_paddr fields are zero. When we try to objcopy or strip such a + file, we get confused. Check for this case, and if we find it + reset the p_paddr_valid fields. */ + for (map = map_first; map != NULL; map = map->next) + if (map->p_paddr != 0) + break; + if (map == NULL) + for (map = map_first; map != NULL; map = map->next) + map->p_paddr_valid = 0; + + elf_tdata (obfd)->segment_map = map_first; + + /* If we had to estimate the number of program headers that were + going to be needed, then check our estimate now and adjust + the offset if necessary. */ + if (phdr_adjust_seg != NULL) + { + unsigned int count; + + for (count = 0, map = map_first; map != NULL; map = map->next) + count++; + + if (count > phdr_adjust_num) + phdr_adjust_seg->p_paddr + -= (count - phdr_adjust_num) * iehdr->e_phentsize; + } + +#if 0 + /* Final Step: Sort the segments into ascending order of physical + address. */ + if (map_first != NULL) + { + struct elf_segment_map *prev; + + prev = map_first; + for (map = map_first->next; map != NULL; prev = map, map = map->next) + { + /* Yes I know - its a bubble sort.... */ + if (map->next != NULL && (map->next->p_paddr < map->p_paddr)) + { + /* Swap map and map->next. */ + prev->next = map->next; + map->next = map->next->next; + prev->next->next = map; + + /* Restart loop. */ + map = map_first; + } + } + } +#endif + +#undef SEGMENT_END +#undef SECTION_SIZE +#undef IS_CONTAINED_BY_VMA +#undef IS_CONTAINED_BY_LMA +#undef IS_COREFILE_NOTE +#undef IS_SOLARIS_PT_INTERP +#undef INCLUDE_SECTION_IN_SEGMENT +#undef SEGMENT_AFTER_SEGMENT +#undef SEGMENT_OVERLAPS + return TRUE; +} + +/* Copy private section information. This copies over the entsize + field, and sometimes the info field. */ + +bfd_boolean +_bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec) + bfd *ibfd; + asection *isec; + bfd *obfd; + asection *osec; +{ + Elf_Internal_Shdr *ihdr, *ohdr; + + if (ibfd->xvec->flavour != bfd_target_elf_flavour + || obfd->xvec->flavour != bfd_target_elf_flavour) + return TRUE; + + if (elf_tdata (obfd)->segment_map == NULL && elf_tdata (ibfd)->phdr != NULL) + { + asection *s; + + /* Only set up the segments if there are no more SEC_ALLOC + sections. FIXME: This won't do the right thing if objcopy is + used to remove the last SEC_ALLOC section, since objcopy + won't call this routine in that case. */ + for (s = isec->next; s != NULL; s = s->next) + if ((s->flags & SEC_ALLOC) != 0) + break; + if (s == NULL) + { + if (! copy_private_bfd_data (ibfd, obfd)) + return FALSE; + } + } + + ihdr = &elf_section_data (isec)->this_hdr; + ohdr = &elf_section_data (osec)->this_hdr; + + ohdr->sh_entsize = ihdr->sh_entsize; + + if (ihdr->sh_type == SHT_SYMTAB + || ihdr->sh_type == SHT_DYNSYM + || ihdr->sh_type == SHT_GNU_verneed + || ihdr->sh_type == SHT_GNU_verdef) + ohdr->sh_info = ihdr->sh_info; + + /* Set things up for objcopy. The output SHT_GROUP section will + have its elf_next_in_group pointing back to the input group + members. */ + elf_next_in_group (osec) = elf_next_in_group (isec); + elf_group_name (osec) = elf_group_name (isec); + + osec->use_rela_p = isec->use_rela_p; + + return TRUE; +} + +/* Copy private symbol information. If this symbol is in a section + which we did not map into a BFD section, try to map the section + index correctly. We use special macro definitions for the mapped + section indices; these definitions are interpreted by the + swap_out_syms function. */ + +#define MAP_ONESYMTAB (SHN_HIOS + 1) +#define MAP_DYNSYMTAB (SHN_HIOS + 2) +#define MAP_STRTAB (SHN_HIOS + 3) +#define MAP_SHSTRTAB (SHN_HIOS + 4) +#define MAP_SYM_SHNDX (SHN_HIOS + 5) + +bfd_boolean +_bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg) + bfd *ibfd; + asymbol *isymarg; + bfd *obfd; + asymbol *osymarg; +{ + elf_symbol_type *isym, *osym; + + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + return TRUE; + + isym = elf_symbol_from (ibfd, isymarg); + osym = elf_symbol_from (obfd, osymarg); + + if (isym != NULL + && osym != NULL + && bfd_is_abs_section (isym->symbol.section)) + { + unsigned int shndx; + + shndx = isym->internal_elf_sym.st_shndx; + if (shndx == elf_onesymtab (ibfd)) + shndx = MAP_ONESYMTAB; + else if (shndx == elf_dynsymtab (ibfd)) + shndx = MAP_DYNSYMTAB; + else if (shndx == elf_tdata (ibfd)->strtab_section) + shndx = MAP_STRTAB; + else if (shndx == elf_tdata (ibfd)->shstrtab_section) + shndx = MAP_SHSTRTAB; + else if (shndx == elf_tdata (ibfd)->symtab_shndx_section) + shndx = MAP_SYM_SHNDX; + osym->internal_elf_sym.st_shndx = shndx; + } + + return TRUE; +} + +/* Swap out the symbols. */ + +static bfd_boolean +swap_out_syms (abfd, sttp, relocatable_p) + bfd *abfd; + struct bfd_strtab_hash **sttp; + int relocatable_p; +{ + struct elf_backend_data *bed; + int symcount; + asymbol **syms; + struct bfd_strtab_hash *stt; + Elf_Internal_Shdr *symtab_hdr; + Elf_Internal_Shdr *symtab_shndx_hdr; + Elf_Internal_Shdr *symstrtab_hdr; + char *outbound_syms; + char *outbound_shndx; + int idx; + bfd_size_type amt; + + if (!elf_map_symbols (abfd)) + return FALSE; + + /* Dump out the symtabs. */ + stt = _bfd_elf_stringtab_init (); + if (stt == NULL) + return FALSE; + + bed = get_elf_backend_data (abfd); + symcount = bfd_get_symcount (abfd); + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr->sh_type = SHT_SYMTAB; + symtab_hdr->sh_entsize = bed->s->sizeof_sym; + symtab_hdr->sh_size = symtab_hdr->sh_entsize * (symcount + 1); + symtab_hdr->sh_info = elf_num_locals (abfd) + 1; + symtab_hdr->sh_addralign = bed->s->file_align; + + symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; + symstrtab_hdr->sh_type = SHT_STRTAB; + + amt = (bfd_size_type) (1 + symcount) * bed->s->sizeof_sym; + outbound_syms = bfd_alloc (abfd, amt); + if (outbound_syms == NULL) + { + _bfd_stringtab_free (stt); + return FALSE; + } + symtab_hdr->contents = (PTR) outbound_syms; + + outbound_shndx = NULL; + symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; + if (symtab_shndx_hdr->sh_name != 0) + { + amt = (bfd_size_type) (1 + symcount) * sizeof (Elf_External_Sym_Shndx); + outbound_shndx = bfd_zalloc (abfd, amt); + if (outbound_shndx == NULL) + { + _bfd_stringtab_free (stt); + return FALSE; + } + + symtab_shndx_hdr->contents = outbound_shndx; + symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX; + symtab_shndx_hdr->sh_size = amt; + symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx); + symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx); + } + + /* Now generate the data (for "contents"). */ + { + /* Fill in zeroth symbol and swap it out. */ + Elf_Internal_Sym sym; + sym.st_name = 0; + sym.st_value = 0; + sym.st_size = 0; + sym.st_info = 0; + sym.st_other = 0; + sym.st_shndx = SHN_UNDEF; + bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx); + outbound_syms += bed->s->sizeof_sym; + if (outbound_shndx != NULL) + outbound_shndx += sizeof (Elf_External_Sym_Shndx); + } + + syms = bfd_get_outsymbols (abfd); + for (idx = 0; idx < symcount; idx++) + { + Elf_Internal_Sym sym; + bfd_vma value = syms[idx]->value; + elf_symbol_type *type_ptr; + flagword flags = syms[idx]->flags; + int type; + + if ((flags & (BSF_SECTION_SYM | BSF_GLOBAL)) == BSF_SECTION_SYM) + { + /* Local section symbols have no name. */ + sym.st_name = 0; + } + else + { + sym.st_name = (unsigned long) _bfd_stringtab_add (stt, + syms[idx]->name, + TRUE, FALSE); + if (sym.st_name == (unsigned long) -1) + { + _bfd_stringtab_free (stt); + return FALSE; + } + } + + type_ptr = elf_symbol_from (abfd, syms[idx]); + + if ((flags & BSF_SECTION_SYM) == 0 + && bfd_is_com_section (syms[idx]->section)) + { + /* ELF common symbols put the alignment into the `value' field, + and the size into the `size' field. This is backwards from + how BFD handles it, so reverse it here. */ + sym.st_size = value; + if (type_ptr == NULL + || type_ptr->internal_elf_sym.st_value == 0) + sym.st_value = value >= 16 ? 16 : (1 << bfd_log2 (value)); + else + sym.st_value = type_ptr->internal_elf_sym.st_value; + sym.st_shndx = _bfd_elf_section_from_bfd_section + (abfd, syms[idx]->section); + } + else + { + asection *sec = syms[idx]->section; + int shndx; + + if (sec->output_section) + { + value += sec->output_offset; + sec = sec->output_section; + } + + /* Don't add in the section vma for relocatable output. */ + if (! relocatable_p) + value += sec->vma; + sym.st_value = value; + sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0; + + if (bfd_is_abs_section (sec) + && type_ptr != NULL + && type_ptr->internal_elf_sym.st_shndx != 0) + { + /* This symbol is in a real ELF section which we did + not create as a BFD section. Undo the mapping done + by copy_private_symbol_data. */ + shndx = type_ptr->internal_elf_sym.st_shndx; + switch (shndx) + { + case MAP_ONESYMTAB: + shndx = elf_onesymtab (abfd); + break; + case MAP_DYNSYMTAB: + shndx = elf_dynsymtab (abfd); + break; + case MAP_STRTAB: + shndx = elf_tdata (abfd)->strtab_section; + break; + case MAP_SHSTRTAB: + shndx = elf_tdata (abfd)->shstrtab_section; + break; + case MAP_SYM_SHNDX: + shndx = elf_tdata (abfd)->symtab_shndx_section; + break; + default: + break; + } + } + else + { + shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + + if (shndx == -1) + { + asection *sec2; + + /* Writing this would be a hell of a lot easier if + we had some decent documentation on bfd, and + knew what to expect of the library, and what to + demand of applications. For example, it + appears that `objcopy' might not set the + section of a symbol to be a section that is + actually in the output file. */ + sec2 = bfd_get_section_by_name (abfd, sec->name); + if (sec2 == NULL) + { + _bfd_error_handler (_("\ +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; + } + + shndx = _bfd_elf_section_from_bfd_section (abfd, sec2); + BFD_ASSERT (shndx != -1); + } + } + + sym.st_shndx = shndx; + } + + if ((flags & BSF_THREAD_LOCAL) != 0) + type = STT_TLS; + else if ((flags & BSF_FUNCTION) != 0) + type = STT_FUNC; + else if ((flags & BSF_OBJECT) != 0) + type = STT_OBJECT; + else + type = STT_NOTYPE; + + if (syms[idx]->section->flags & SEC_THREAD_LOCAL) + type = STT_TLS; + + /* Processor-specific types. */ + if (type_ptr != NULL + && bed->elf_backend_get_symbol_type) + type = ((*bed->elf_backend_get_symbol_type) + (&type_ptr->internal_elf_sym, type)); + + if (flags & BSF_SECTION_SYM) + { + if (flags & BSF_GLOBAL) + sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); + else + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + } + else if (bfd_is_com_section (syms[idx]->section)) + sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); + else if (bfd_is_und_section (syms[idx]->section)) + sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK) + ? STB_WEAK + : STB_GLOBAL), + type); + else if (flags & BSF_FILE) + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + else + { + int bind = STB_LOCAL; + + if (flags & BSF_LOCAL) + bind = STB_LOCAL; + else if (flags & BSF_WEAK) + bind = STB_WEAK; + else if (flags & BSF_GLOBAL) + bind = STB_GLOBAL; + + sym.st_info = ELF_ST_INFO (bind, type); + } + + if (type_ptr != NULL) + sym.st_other = type_ptr->internal_elf_sym.st_other; + else + sym.st_other = 0; + + bed->s->swap_symbol_out (abfd, &sym, outbound_syms, outbound_shndx); + outbound_syms += bed->s->sizeof_sym; + if (outbound_shndx != NULL) + outbound_shndx += sizeof (Elf_External_Sym_Shndx); + } + + *sttp = stt; + symstrtab_hdr->sh_size = _bfd_stringtab_size (stt); + symstrtab_hdr->sh_type = SHT_STRTAB; + + symstrtab_hdr->sh_flags = 0; + symstrtab_hdr->sh_addr = 0; + symstrtab_hdr->sh_entsize = 0; + symstrtab_hdr->sh_link = 0; + symstrtab_hdr->sh_info = 0; + symstrtab_hdr->sh_addralign = 1; + + return TRUE; +} + +/* Return the number of bytes required to hold the symtab vector. + + Note that we base it on the count plus 1, since we will null terminate + the vector allocated based on this size. However, the ELF symbol table + always has a dummy entry as symbol #0, so it ends up even. */ + +long +_bfd_elf_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + long symcount; + long symtab_size; + Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->symtab_hdr; + + symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; + symtab_size = (symcount + 1) * (sizeof (asymbol *)); + if (symcount > 0) + symtab_size -= sizeof (asymbol *); + + return symtab_size; +} + +long +_bfd_elf_get_dynamic_symtab_upper_bound (abfd) + bfd *abfd; +{ + long symcount; + long symtab_size; + Elf_Internal_Shdr *hdr = &elf_tdata (abfd)->dynsymtab_hdr; + + if (elf_dynsymtab (abfd) == 0) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + symcount = hdr->sh_size / get_elf_backend_data (abfd)->s->sizeof_sym; + symtab_size = (symcount + 1) * (sizeof (asymbol *)); + if (symcount > 0) + symtab_size -= sizeof (asymbol *); + + return symtab_size; +} + +long +_bfd_elf_get_reloc_upper_bound (abfd, asect) + bfd *abfd ATTRIBUTE_UNUSED; + sec_ptr asect; +{ + return (asect->reloc_count + 1) * sizeof (arelent *); +} + +/* Canonicalize the relocs. */ + +long +_bfd_elf_canonicalize_reloc (abfd, section, relptr, symbols) + bfd *abfd; + sec_ptr section; + arelent **relptr; + asymbol **symbols; +{ + arelent *tblptr; + unsigned int i; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (! bed->s->slurp_reloc_table (abfd, section, symbols, FALSE)) + return -1; + + tblptr = section->relocation; + for (i = 0; i < section->reloc_count; i++) + *relptr++ = tblptr++; + + *relptr = NULL; + + return section->reloc_count; +} + +long +_bfd_elf_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + long symcount = bed->s->slurp_symbol_table (abfd, alocation, FALSE); + + if (symcount >= 0) + bfd_get_symcount (abfd) = symcount; + return symcount; +} + +long +_bfd_elf_canonicalize_dynamic_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + long symcount = bed->s->slurp_symbol_table (abfd, alocation, TRUE); + + if (symcount >= 0) + bfd_get_dynamic_symcount (abfd) = symcount; + return symcount; +} + +/* Return the size required for the dynamic reloc entries. Any + section that was actually installed in the BFD, and has type + SHT_REL or SHT_RELA, and uses the dynamic symbol table, is + considered to be a dynamic reloc section. */ + +long +_bfd_elf_get_dynamic_reloc_upper_bound (abfd) + bfd *abfd; +{ + long ret; + asection *s; + + if (elf_dynsymtab (abfd) == 0) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + ret = sizeof (arelent *); + for (s = abfd->sections; s != NULL; s = s->next) + if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) + && (elf_section_data (s)->this_hdr.sh_type == SHT_REL + || elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) + ret += ((s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize) + * sizeof (arelent *)); + + return ret; +} + +/* Canonicalize the dynamic relocation entries. Note that we return + the dynamic relocations as a single block, although they are + actually associated with particular sections; the interface, which + was designed for SunOS style shared libraries, expects that there + is only one set of dynamic relocs. Any section that was actually + installed in the BFD, and has type SHT_REL or SHT_RELA, and uses + the dynamic symbol table, is considered to be a dynamic reloc + section. */ + +long +_bfd_elf_canonicalize_dynamic_reloc (abfd, storage, syms) + bfd *abfd; + arelent **storage; + asymbol **syms; +{ + bfd_boolean (*slurp_relocs) + PARAMS ((bfd *, asection *, asymbol **, bfd_boolean)); + asection *s; + long ret; + + if (elf_dynsymtab (abfd) == 0) + { + bfd_set_error (bfd_error_invalid_operation); + return -1; + } + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + ret = 0; + for (s = abfd->sections; s != NULL; s = s->next) + { + if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) + && (elf_section_data (s)->this_hdr.sh_type == SHT_REL + || elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) + { + arelent *p; + long count, i; + + if (! (*slurp_relocs) (abfd, s, syms, TRUE)) + return -1; + count = s->_raw_size / elf_section_data (s)->this_hdr.sh_entsize; + p = s->relocation; + for (i = 0; i < count; i++) + *storage++ = p++; + ret += count; + } + } + + *storage = NULL; + + return ret; +} + +/* Read in the version information. */ + +bfd_boolean +_bfd_elf_slurp_version_tables (abfd) + bfd *abfd; +{ + bfd_byte *contents = NULL; + bfd_size_type amt; + + if (elf_dynverdef (abfd) != 0) + { + Elf_Internal_Shdr *hdr; + Elf_External_Verdef *everdef; + Elf_Internal_Verdef *iverdef; + Elf_Internal_Verdef *iverdefarr; + Elf_Internal_Verdef iverdefmem; + unsigned int i; + unsigned int maxidx; + + hdr = &elf_tdata (abfd)->dynverdef_hdr; + + contents = (bfd_byte *) bfd_malloc (hdr->sh_size); + if (contents == NULL) + goto error_return; + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || bfd_bread ((PTR) contents, hdr->sh_size, abfd) != hdr->sh_size) + goto error_return; + + /* We know the number of entries in the section but not the maximum + index. Therefore we have to run through all entries and find + the maximum. */ + everdef = (Elf_External_Verdef *) contents; + maxidx = 0; + for (i = 0; i < hdr->sh_info; ++i) + { + _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); + + if ((iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION)) > maxidx) + maxidx = iverdefmem.vd_ndx & ((unsigned) VERSYM_VERSION); + + everdef = ((Elf_External_Verdef *) + ((bfd_byte *) everdef + iverdefmem.vd_next)); + } + + amt = (bfd_size_type) maxidx * sizeof (Elf_Internal_Verdef); + elf_tdata (abfd)->verdef = (Elf_Internal_Verdef *) bfd_zalloc (abfd, amt); + if (elf_tdata (abfd)->verdef == NULL) + goto error_return; + + elf_tdata (abfd)->cverdefs = maxidx; + + everdef = (Elf_External_Verdef *) contents; + iverdefarr = elf_tdata (abfd)->verdef; + for (i = 0; i < hdr->sh_info; i++) + { + Elf_External_Verdaux *everdaux; + Elf_Internal_Verdaux *iverdaux; + unsigned int j; + + _bfd_elf_swap_verdef_in (abfd, everdef, &iverdefmem); + + iverdef = &iverdefarr[(iverdefmem.vd_ndx & VERSYM_VERSION) - 1]; + memcpy (iverdef, &iverdefmem, sizeof (Elf_Internal_Verdef)); + + iverdef->vd_bfd = abfd; + + amt = (bfd_size_type) iverdef->vd_cnt * sizeof (Elf_Internal_Verdaux); + iverdef->vd_auxptr = (Elf_Internal_Verdaux *) bfd_alloc (abfd, amt); + if (iverdef->vd_auxptr == NULL) + goto error_return; + + everdaux = ((Elf_External_Verdaux *) + ((bfd_byte *) everdef + iverdef->vd_aux)); + iverdaux = iverdef->vd_auxptr; + for (j = 0; j < iverdef->vd_cnt; j++, iverdaux++) + { + _bfd_elf_swap_verdaux_in (abfd, everdaux, iverdaux); + + iverdaux->vda_nodename = + bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + iverdaux->vda_name); + if (iverdaux->vda_nodename == NULL) + goto error_return; + + if (j + 1 < iverdef->vd_cnt) + iverdaux->vda_nextptr = iverdaux + 1; + else + iverdaux->vda_nextptr = NULL; + + everdaux = ((Elf_External_Verdaux *) + ((bfd_byte *) everdaux + iverdaux->vda_next)); + } + + iverdef->vd_nodename = iverdef->vd_auxptr->vda_nodename; + + if (i + 1 < hdr->sh_info) + iverdef->vd_nextdef = iverdef + 1; + else + iverdef->vd_nextdef = NULL; + + everdef = ((Elf_External_Verdef *) + ((bfd_byte *) everdef + iverdef->vd_next)); + } + + free (contents); + contents = NULL; + } + + if (elf_dynverref (abfd) != 0) + { + Elf_Internal_Shdr *hdr; + Elf_External_Verneed *everneed; + Elf_Internal_Verneed *iverneed; + unsigned int i; + + hdr = &elf_tdata (abfd)->dynverref_hdr; + + amt = (bfd_size_type) hdr->sh_info * sizeof (Elf_Internal_Verneed); + elf_tdata (abfd)->verref = + (Elf_Internal_Verneed *) bfd_zalloc (abfd, amt); + 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) + goto error_return; + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 + || bfd_bread ((PTR) contents, hdr->sh_size, abfd) != hdr->sh_size) + goto error_return; + + everneed = (Elf_External_Verneed *) contents; + iverneed = elf_tdata (abfd)->verref; + for (i = 0; i < hdr->sh_info; i++, iverneed++) + { + Elf_External_Vernaux *evernaux; + Elf_Internal_Vernaux *ivernaux; + unsigned int j; + + _bfd_elf_swap_verneed_in (abfd, everneed, iverneed); + + iverneed->vn_bfd = abfd; + + iverneed->vn_filename = + bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + iverneed->vn_file); + if (iverneed->vn_filename == NULL) + goto error_return; + + amt = iverneed->vn_cnt; + amt *= sizeof (Elf_Internal_Vernaux); + iverneed->vn_auxptr = (Elf_Internal_Vernaux *) bfd_alloc (abfd, amt); + + evernaux = ((Elf_External_Vernaux *) + ((bfd_byte *) everneed + iverneed->vn_aux)); + ivernaux = iverneed->vn_auxptr; + for (j = 0; j < iverneed->vn_cnt; j++, ivernaux++) + { + _bfd_elf_swap_vernaux_in (abfd, evernaux, ivernaux); + + ivernaux->vna_nodename = + bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + ivernaux->vna_name); + if (ivernaux->vna_nodename == NULL) + goto error_return; + + if (j + 1 < iverneed->vn_cnt) + ivernaux->vna_nextptr = ivernaux + 1; + else + ivernaux->vna_nextptr = NULL; + + evernaux = ((Elf_External_Vernaux *) + ((bfd_byte *) evernaux + ivernaux->vna_next)); + } + + if (i + 1 < hdr->sh_info) + iverneed->vn_nextref = iverneed + 1; + else + iverneed->vn_nextref = NULL; + + everneed = ((Elf_External_Verneed *) + ((bfd_byte *) everneed + iverneed->vn_next)); + } + + free (contents); + contents = NULL; + } + + return TRUE; + + error_return: + if (contents != NULL) + free (contents); + return FALSE; +} + +asymbol * +_bfd_elf_make_empty_symbol (abfd) + bfd *abfd; +{ + elf_symbol_type *newsym; + bfd_size_type amt = sizeof (elf_symbol_type); + + newsym = (elf_symbol_type *) bfd_zalloc (abfd, amt); + if (!newsym) + return NULL; + else + { + newsym->symbol.the_bfd = abfd; + return &newsym->symbol; + } +} + +void +_bfd_elf_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +/* Return whether a symbol name implies a local symbol. Most targets + use this function for the is_local_label_name entry point, but some + override it. */ + +bfd_boolean +_bfd_elf_is_local_label_name (abfd, name) + bfd *abfd ATTRIBUTE_UNUSED; + const char *name; +{ + /* Normal local symbols start with ``.L''. */ + if (name[0] == '.' && name[1] == 'L') + return TRUE; + + /* At least some SVR4 compilers (e.g., UnixWare 2.1 cc) generate + DWARF debugging symbols starting with ``..''. */ + if (name[0] == '.' && name[1] == '.') + return TRUE; + + /* gcc will sometimes generate symbols beginning with ``_.L_'' when + emitting DWARF debugging output. I suspect this is actually a + small bug in gcc (it calls ASM_OUTPUT_LABEL when it should call + ASM_GENERATE_INTERNAL_LABEL, and this causes the leading + underscore to be emitted on some ELF targets). For ease of use, + we treat such symbols as local. */ + if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_') + return TRUE; + + return FALSE; +} + +alent * +_bfd_elf_get_lineno (ignore_abfd, symbol) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + asymbol *symbol ATTRIBUTE_UNUSED; +{ + abort (); + return NULL; +} + +bfd_boolean +_bfd_elf_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + /* If this isn't the right architecture for this backend, and this + isn't the generic backend, fail. */ + if (arch != get_elf_backend_data (abfd)->arch + && arch != bfd_arch_unknown + && get_elf_backend_data (abfd)->arch != bfd_arch_unknown) + return FALSE; + + 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 (abfd, section, symbols, offset, + filename_ptr, functionname_ptr) + bfd *abfd ATTRIBUTE_UNUSED; + asection *section; + asymbol **symbols; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; +{ + const char *filename; + asymbol *func; + bfd_vma low_func; + asymbol **p; + + filename = NULL; + func = NULL; + low_func = 0; + + for (p = symbols; *p != NULL; p++) + { + elf_symbol_type *q; + + q = (elf_symbol_type *) *p; + + if (bfd_get_section (&q->symbol) != section) + continue; + + switch (ELF_ST_TYPE (q->internal_elf_sym.st_info)) + { + default: + break; + case STT_FILE: + filename = bfd_asymbol_name (&q->symbol); + break; + case STT_NOTYPE: + case STT_FUNC: + if (q->symbol.section == section + && q->symbol.value >= low_func + && q->symbol.value <= offset) + { + func = (asymbol *) q; + low_func = q->symbol.value; + } + break; + } + } + + if (func == NULL) + return FALSE; + + if (filename_ptr) + *filename_ptr = filename; + if (functionname_ptr) + *functionname_ptr = bfd_asymbol_name (func); + + return TRUE; +} + +/* Find the nearest line to a particular section and offset, + for error reporting. */ + +bfd_boolean +_bfd_elf_find_nearest_line (abfd, section, symbols, offset, + filename_ptr, functionname_ptr, line_ptr) + bfd *abfd; + asection *section; + asymbol **symbols; + bfd_vma offset; + const char **filename_ptr; + const char **functionname_ptr; + unsigned int *line_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, section, symbols, offset, + filename_ptr, functionname_ptr, + line_ptr, 0, + &elf_tdata (abfd)->dwarf2_find_line_info)) + { + if (!*functionname_ptr) + elf_find_function (abfd, section, symbols, offset, + *filename_ptr ? NULL : filename_ptr, + functionname_ptr); + + return TRUE; + } + + if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, + &found, filename_ptr, + functionname_ptr, line_ptr, + &elf_tdata (abfd)->line_info)) + return FALSE; + if (found && (*functionname_ptr || *line_ptr)) + return TRUE; + + if (symbols == NULL) + return FALSE; + + if (! elf_find_function (abfd, section, symbols, offset, + filename_ptr, functionname_ptr)) + return FALSE; + + *line_ptr = 0; + return TRUE; +} + +int +_bfd_elf_sizeof_headers (abfd, reloc) + bfd *abfd; + bfd_boolean reloc; +{ + int ret; + + ret = get_elf_backend_data (abfd)->s->sizeof_ehdr; + if (! reloc) + ret += get_program_header_size (abfd); + return ret; +} + +bfd_boolean +_bfd_elf_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + Elf_Internal_Shdr *hdr; + bfd_signed_vma pos; + + if (! abfd->output_has_begun + && ! (_bfd_elf_compute_section_file_positions + (abfd, (struct bfd_link_info *) NULL))) + return FALSE; + + hdr = &elf_section_data (section)->this_hdr; + pos = hdr->sh_offset + offset; + if (bfd_seek (abfd, pos, SEEK_SET) != 0 + || bfd_bwrite (location, count, abfd) != count) + return FALSE; + + return TRUE; +} + +void +_bfd_elf_no_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *cache_ptr ATTRIBUTE_UNUSED; + Elf_Internal_Rela *dst ATTRIBUTE_UNUSED; +{ + abort (); +} + +/* Try to convert a non-ELF reloc into an ELF one. */ + +bfd_boolean +_bfd_elf_validate_reloc (abfd, areloc) + bfd *abfd; + arelent *areloc; +{ + /* Check whether we really have an ELF howto. */ + + if ((*areloc->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec) + { + bfd_reloc_code_real_type code; + reloc_howto_type *howto; + + /* Alien reloc: Try to determine its type to replace it with an + equivalent ELF reloc. */ + + if (areloc->howto->pc_relative) + { + switch (areloc->howto->bitsize) + { + case 8: + code = BFD_RELOC_8_PCREL; + break; + case 12: + code = BFD_RELOC_12_PCREL; + break; + case 16: + code = BFD_RELOC_16_PCREL; + break; + case 24: + code = BFD_RELOC_24_PCREL; + break; + case 32: + code = BFD_RELOC_32_PCREL; + break; + case 64: + code = BFD_RELOC_64_PCREL; + break; + default: + goto fail; + } + + howto = bfd_reloc_type_lookup (abfd, code); + + if (areloc->howto->pcrel_offset != howto->pcrel_offset) + { + if (howto->pcrel_offset) + areloc->addend += areloc->address; + else + areloc->addend -= areloc->address; /* addend is unsigned!! */ + } + } + else + { + switch (areloc->howto->bitsize) + { + case 8: + code = BFD_RELOC_8; + break; + case 14: + code = BFD_RELOC_14; + break; + case 16: + code = BFD_RELOC_16; + break; + case 26: + code = BFD_RELOC_26; + break; + case 32: + code = BFD_RELOC_32; + break; + case 64: + code = BFD_RELOC_64; + break; + default: + goto fail; + } + + howto = bfd_reloc_type_lookup (abfd, code); + } + + if (howto) + areloc->howto = howto; + else + goto fail; + } + + return TRUE; + + fail: + (*_bfd_error_handler) + (_("%s: unsupported relocation type %s"), + bfd_archive_filename (abfd), areloc->howto->name); + bfd_set_error (bfd_error_bad_value); + return FALSE; +} + +bfd_boolean +_bfd_elf_close_and_cleanup (abfd) + bfd *abfd; +{ + if (bfd_get_format (abfd) == bfd_object) + { + if (elf_shstrtab (abfd) != NULL) + _bfd_elf_strtab_free (elf_shstrtab (abfd)); + } + + return _bfd_generic_close_and_cleanup (abfd); +} + +/* For Rel targets, we encode meaningful data for BFD_RELOC_VTABLE_ENTRY + in the relocation's offset. Thus we cannot allow any sort of sanity + range-checking to interfere. There is nothing else to do in processing + this reloc. */ + +bfd_reloc_status_type +_bfd_elf_rel_vtable_reloc_fn (abfd, re, symbol, data, is, obfd, errmsg) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *re ATTRIBUTE_UNUSED; + struct symbol_cache_entry *symbol ATTRIBUTE_UNUSED; + PTR data ATTRIBUTE_UNUSED; + asection *is ATTRIBUTE_UNUSED; + bfd *obfd ATTRIBUTE_UNUSED; + char **errmsg ATTRIBUTE_UNUSED; +{ + return bfd_reloc_ok; +} + +/* Elf core file support. Much of this only works on native + toolchains, since we rely on knowing the + machine-dependent procfs structure in order to pick + out details about the corefile. */ + +#ifdef HAVE_SYS_PROCFS_H +# include +#endif + +/* FIXME: this is kinda wrong, but it's what gdb wants. */ + +static int +elfcore_make_pid (abfd) + bfd *abfd; +{ + return ((elf_tdata (abfd)->core_lwpid << 16) + + (elf_tdata (abfd)->core_pid)); +} + +/* If there isn't a section called NAME, make one, using + data from SECT. Note, this function will generate a + reference to NAME, so you shouldn't deallocate or + overwrite it. */ + +static bfd_boolean +elfcore_maybe_make_sect (abfd, name, sect) + bfd *abfd; + char *name; + asection *sect; +{ + asection *sect2; + + if (bfd_get_section_by_name (abfd, name) != NULL) + return TRUE; + + sect2 = bfd_make_section (abfd, name); + if (sect2 == NULL) + return FALSE; + + sect2->_raw_size = sect->_raw_size; + sect2->filepos = sect->filepos; + sect2->flags = sect->flags; + sect2->alignment_power = sect->alignment_power; + return TRUE; +} + +/* Create a pseudosection containing SIZE bytes at FILEPOS. This + actually creates up to two pseudosections: + - For the single-threaded case, a section named NAME, unless + such a section already exists. + - For the multi-threaded case, a section named "NAME/PID", where + PID is elfcore_make_pid (abfd). + Both pseudosections have identical contents. */ +bfd_boolean +_bfd_elfcore_make_pseudosection (abfd, name, size, filepos) + bfd *abfd; + char *name; + size_t size; + ufile_ptr filepos; +{ + char buf[100]; + char *threaded_name; + size_t len; + asection *sect; + + /* Build the section name. */ + + sprintf (buf, "%s/%d", name, elfcore_make_pid (abfd)); + len = strlen (buf) + 1; + threaded_name = bfd_alloc (abfd, (bfd_size_type) len); + if (threaded_name == NULL) + return FALSE; + memcpy (threaded_name, buf, len); + + sect = bfd_make_section (abfd, threaded_name); + if (sect == NULL) + return FALSE; + sect->_raw_size = size; + sect->filepos = filepos; + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + return elfcore_maybe_make_sect (abfd, name, sect); +} + +/* prstatus_t exists on: + solaris 2.5+ + linux 2.[01] + glibc + unixware 4.2 +*/ + +#if defined (HAVE_PRSTATUS_T) +static bfd_boolean elfcore_grok_prstatus + PARAMS ((bfd *, Elf_Internal_Note *)); + +static bfd_boolean +elfcore_grok_prstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + size_t raw_size; + int offset; + + if (note->descsz == sizeof (prstatus_t)) + { + prstatus_t prstat; + + raw_size = sizeof (prstat.pr_reg); + offset = offsetof (prstatus_t, pr_reg); + memcpy (&prstat, note->descdata, sizeof (prstat)); + + /* Do not overwrite the core signal if it + has already been set by another thread. */ + if (elf_tdata (abfd)->core_signal == 0) + elf_tdata (abfd)->core_signal = prstat.pr_cursig; + elf_tdata (abfd)->core_pid = prstat.pr_pid; + + /* pr_who exists on: + solaris 2.5+ + unixware 4.2 + pr_who doesn't exist on: + linux 2.[01] + */ +#if defined (HAVE_PRSTATUS_T_PR_WHO) + elf_tdata (abfd)->core_lwpid = prstat.pr_who; +#endif + } +#if defined (HAVE_PRSTATUS32_T) + else if (note->descsz == sizeof (prstatus32_t)) + { + /* 64-bit host, 32-bit corefile */ + prstatus32_t prstat; + + raw_size = sizeof (prstat.pr_reg); + offset = offsetof (prstatus32_t, pr_reg); + memcpy (&prstat, note->descdata, sizeof (prstat)); + + /* Do not overwrite the core signal if it + has already been set by another thread. */ + if (elf_tdata (abfd)->core_signal == 0) + elf_tdata (abfd)->core_signal = prstat.pr_cursig; + elf_tdata (abfd)->core_pid = prstat.pr_pid; + + /* pr_who exists on: + solaris 2.5+ + unixware 4.2 + pr_who doesn't exist on: + linux 2.[01] + */ +#if defined (HAVE_PRSTATUS32_T_PR_WHO) + elf_tdata (abfd)->core_lwpid = prstat.pr_who; +#endif + } +#endif /* HAVE_PRSTATUS32_T */ + else + { + /* Fail - we don't know how to handle any other + note size (ie. data object type). */ + return TRUE; + } + + /* Make a ".reg/999" section and a ".reg" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + raw_size, note->descpos + offset); +} +#endif /* defined (HAVE_PRSTATUS_T) */ + +/* Create a pseudosection containing the exact contents of NOTE. */ +static bfd_boolean +elfcore_make_note_pseudosection (abfd, name, note) + bfd *abfd; + char *name; + Elf_Internal_Note *note; +{ + return _bfd_elfcore_make_pseudosection (abfd, name, + note->descsz, note->descpos); +} + +/* There isn't a consistent prfpregset_t across platforms, + but it doesn't matter, because we don't have to pick this + data structure apart. */ + +static bfd_boolean +elfcore_grok_prfpreg (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + return elfcore_make_note_pseudosection (abfd, ".reg2", note); +} + +/* Linux dumps the Intel SSE regs in a note named "LINUX" with a note + type of 5 (NT_PRXFPREG). Just include the whole note's contents + literally. */ + +static bfd_boolean +elfcore_grok_prxfpreg (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + return elfcore_make_note_pseudosection (abfd, ".reg-xfp", note); +} + +#if defined (HAVE_PRPSINFO_T) +typedef prpsinfo_t elfcore_psinfo_t; +#if defined (HAVE_PRPSINFO32_T) /* Sparc64 cross Sparc32 */ +typedef prpsinfo32_t elfcore_psinfo32_t; +#endif +#endif + +#if defined (HAVE_PSINFO_T) +typedef psinfo_t elfcore_psinfo_t; +#if defined (HAVE_PSINFO32_T) /* Sparc64 cross Sparc32 */ +typedef psinfo32_t elfcore_psinfo32_t; +#endif +#endif + +/* return a malloc'ed copy of a string at START which is at + most MAX bytes long, possibly without a terminating '\0'. + the copy will always have a terminating '\0'. */ + +char * +_bfd_elfcore_strndup (abfd, start, max) + bfd *abfd; + char *start; + size_t max; +{ + char *dups; + char *end = memchr (start, '\0', max); + size_t len; + + if (end == NULL) + len = max; + else + len = end - start; + + dups = bfd_alloc (abfd, (bfd_size_type) len + 1); + if (dups == NULL) + return NULL; + + memcpy (dups, start, len); + dups[len] = '\0'; + + return dups; +} + +#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) +static bfd_boolean elfcore_grok_psinfo + PARAMS ((bfd *, Elf_Internal_Note *)); + +static bfd_boolean +elfcore_grok_psinfo (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + if (note->descsz == sizeof (elfcore_psinfo_t)) + { + elfcore_psinfo_t psinfo; + + memcpy (&psinfo, note->descdata, sizeof (psinfo)); + + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, psinfo.pr_fname, + sizeof (psinfo.pr_fname)); + + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, psinfo.pr_psargs, + sizeof (psinfo.pr_psargs)); + } +#if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T) + else if (note->descsz == sizeof (elfcore_psinfo32_t)) + { + /* 64-bit host, 32-bit corefile */ + elfcore_psinfo32_t psinfo; + + memcpy (&psinfo, note->descdata, sizeof (psinfo)); + + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, psinfo.pr_fname, + sizeof (psinfo.pr_fname)); + + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, psinfo.pr_psargs, + sizeof (psinfo.pr_psargs)); + } +#endif + + else + { + /* Fail - we don't know how to handle any other + note size (ie. data object type). */ + return TRUE; + } + + /* 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; +} +#endif /* defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) */ + +#if defined (HAVE_PSTATUS_T) +static bfd_boolean elfcore_grok_pstatus + PARAMS ((bfd *, Elf_Internal_Note *)); + +static bfd_boolean +elfcore_grok_pstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + if (note->descsz == sizeof (pstatus_t) +#if defined (HAVE_PXSTATUS_T) + || note->descsz == sizeof (pxstatus_t) +#endif + ) + { + pstatus_t pstat; + + memcpy (&pstat, note->descdata, sizeof (pstat)); + + elf_tdata (abfd)->core_pid = pstat.pr_pid; + } +#if defined (HAVE_PSTATUS32_T) + else if (note->descsz == sizeof (pstatus32_t)) + { + /* 64-bit host, 32-bit corefile */ + pstatus32_t pstat; + + memcpy (&pstat, note->descdata, sizeof (pstat)); + + elf_tdata (abfd)->core_pid = pstat.pr_pid; + } +#endif + /* Could grab some more details from the "representative" + lwpstatus_t in pstat.pr_lwp, but we'll catch it all in an + NT_LWPSTATUS note, presumably. */ + + return TRUE; +} +#endif /* defined (HAVE_PSTATUS_T) */ + +#if defined (HAVE_LWPSTATUS_T) +static bfd_boolean elfcore_grok_lwpstatus + PARAMS ((bfd *, Elf_Internal_Note *)); + +static bfd_boolean +elfcore_grok_lwpstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + lwpstatus_t lwpstat; + char buf[100]; + char *name; + size_t len; + asection *sect; + + if (note->descsz != sizeof (lwpstat) +#if defined (HAVE_LWPXSTATUS_T) + && note->descsz != sizeof (lwpxstatus_t) +#endif + ) + return TRUE; + + memcpy (&lwpstat, note->descdata, sizeof (lwpstat)); + + elf_tdata (abfd)->core_lwpid = lwpstat.pr_lwpid; + elf_tdata (abfd)->core_signal = lwpstat.pr_cursig; + + /* Make a ".reg/999" section. */ + + sprintf (buf, ".reg/%d", elfcore_make_pid (abfd)); + len = strlen (buf) + 1; + name = bfd_alloc (abfd, (bfd_size_type) len); + if (name == NULL) + return FALSE; + memcpy (name, buf, len); + + sect = bfd_make_section (abfd, name); + if (sect == NULL) + return FALSE; + +#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT) + sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.gregs); + sect->filepos = note->descpos + + offsetof (lwpstatus_t, pr_context.uc_mcontext.gregs); +#endif + +#if defined (HAVE_LWPSTATUS_T_PR_REG) + sect->_raw_size = sizeof (lwpstat.pr_reg); + sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg); +#endif + + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + if (!elfcore_maybe_make_sect (abfd, ".reg", sect)) + return FALSE; + + /* Make a ".reg2/999" section */ + + sprintf (buf, ".reg2/%d", elfcore_make_pid (abfd)); + len = strlen (buf) + 1; + name = bfd_alloc (abfd, (bfd_size_type) len); + if (name == NULL) + return FALSE; + memcpy (name, buf, len); + + sect = bfd_make_section (abfd, name); + if (sect == NULL) + return FALSE; + +#if defined (HAVE_LWPSTATUS_T_PR_CONTEXT) + sect->_raw_size = sizeof (lwpstat.pr_context.uc_mcontext.fpregs); + sect->filepos = note->descpos + + offsetof (lwpstatus_t, pr_context.uc_mcontext.fpregs); +#endif + +#if defined (HAVE_LWPSTATUS_T_PR_FPREG) + sect->_raw_size = sizeof (lwpstat.pr_fpreg); + sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg); +#endif + + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + return elfcore_maybe_make_sect (abfd, ".reg2", sect); +} +#endif /* defined (HAVE_LWPSTATUS_T) */ + +#if defined (HAVE_WIN32_PSTATUS_T) +static bfd_boolean +elfcore_grok_win32pstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + char buf[30]; + char *name; + size_t len; + asection *sect; + win32_pstatus_t pstatus; + + if (note->descsz < sizeof (pstatus)) + return TRUE; + + memcpy (&pstatus, note->descdata, sizeof (pstatus)); + + switch (pstatus.data_type) + { + case NOTE_INFO_PROCESS: + /* FIXME: need to add ->core_command. */ + elf_tdata (abfd)->core_signal = pstatus.data.process_info.signal; + elf_tdata (abfd)->core_pid = pstatus.data.process_info.pid; + break; + + case NOTE_INFO_THREAD: + /* Make a ".reg/999" section. */ + sprintf (buf, ".reg/%d", pstatus.data.thread_info.tid); + + len = strlen (buf) + 1; + name = bfd_alloc (abfd, (bfd_size_type) len); + if (name == NULL) + return FALSE; + + memcpy (name, buf, len); + + sect = bfd_make_section (abfd, name); + if (sect == NULL) + return FALSE; + + sect->_raw_size = sizeof (pstatus.data.thread_info.thread_context); + sect->filepos = (note->descpos + + offsetof (struct win32_pstatus, + data.thread_info.thread_context)); + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + if (pstatus.data.thread_info.is_active_thread) + if (! elfcore_maybe_make_sect (abfd, ".reg", sect)) + return FALSE; + break; + + case NOTE_INFO_MODULE: + /* Make a ".module/xxxxxxxx" section. */ + sprintf (buf, ".module/%08x", pstatus.data.module_info.base_address); + + len = strlen (buf) + 1; + name = bfd_alloc (abfd, (bfd_size_type) len); + if (name == NULL) + return FALSE; + + memcpy (name, buf, len); + + sect = bfd_make_section (abfd, name); + + if (sect == NULL) + return FALSE; + + sect->_raw_size = note->descsz; + sect->filepos = note->descpos; + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + break; + + default: + return TRUE; + } + + return TRUE; +} +#endif /* HAVE_WIN32_PSTATUS_T */ + +static bfd_boolean +elfcore_grok_note (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + switch (note->type) + { + default: + return TRUE; + + case NT_PRSTATUS: + if (bed->elf_backend_grok_prstatus) + if ((*bed->elf_backend_grok_prstatus) (abfd, note)) + return TRUE; +#if defined (HAVE_PRSTATUS_T) + return elfcore_grok_prstatus (abfd, note); +#else + return TRUE; +#endif + +#if defined (HAVE_PSTATUS_T) + case NT_PSTATUS: + return elfcore_grok_pstatus (abfd, note); +#endif + +#if defined (HAVE_LWPSTATUS_T) + case NT_LWPSTATUS: + return elfcore_grok_lwpstatus (abfd, note); +#endif + + case NT_FPREGSET: /* FIXME: rename to NT_PRFPREG */ + return elfcore_grok_prfpreg (abfd, note); + +#if defined (HAVE_WIN32_PSTATUS_T) + case NT_WIN32PSTATUS: + return elfcore_grok_win32pstatus (abfd, note); +#endif + + case NT_PRXFPREG: /* Linux SSE extension */ + if (note->namesz == 6 + && strcmp (note->namedata, "LINUX") == 0) + return elfcore_grok_prxfpreg (abfd, note); + else + return TRUE; + + case NT_PRPSINFO: + case NT_PSINFO: + if (bed->elf_backend_grok_psinfo) + if ((*bed->elf_backend_grok_psinfo) (abfd, note)) + return TRUE; +#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) + return elfcore_grok_psinfo (abfd, note); +#else + return TRUE; +#endif + } +} + +static bfd_boolean +elfcore_netbsd_get_lwpid (note, lwpidp) + Elf_Internal_Note *note; + int *lwpidp; +{ + char *cp; + + cp = strchr (note->namedata, '@'); + if (cp != NULL) + { + *lwpidp = atoi(cp + 1); + return TRUE; + } + return FALSE; +} + +static bfd_boolean +elfcore_grok_netbsd_procinfo (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + + /* Signal number at offset 0x08. */ + elf_tdata (abfd)->core_signal + = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08); + + /* Process ID at offset 0x50. */ + elf_tdata (abfd)->core_pid + = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x50); + + /* Command name at 0x7c (max 32 bytes, including nul). */ + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 0x7c, 31); + + return TRUE; +} + +static bfd_boolean +elfcore_grok_netbsd_note (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + int lwp; + + if (elfcore_netbsd_get_lwpid (note, &lwp)) + elf_tdata (abfd)->core_lwpid = lwp; + + if (note->type == NT_NETBSDCORE_PROCINFO) + { + /* NetBSD-specific core "procinfo". Note that we expect to + find this note before any of the others, which is fine, + since the kernel writes this note out first when it + creates a core file. */ + + return elfcore_grok_netbsd_procinfo (abfd, note); + } + + /* As of Jan 2002 there are no other machine-independent notes + defined for NetBSD core files. If the note type is less + than the start of the machine-dependent note types, we don't + understand it. */ + + if (note->type < NT_NETBSDCORE_FIRSTMACH) + return TRUE; + + + switch (bfd_get_arch (abfd)) + { + /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and + PT_GETFPREGS == mach+2. */ + + case bfd_arch_alpha: + case bfd_arch_sparc: + switch (note->type) + { + case NT_NETBSDCORE_FIRSTMACH+0: + return elfcore_make_note_pseudosection (abfd, ".reg", note); + + case NT_NETBSDCORE_FIRSTMACH+2: + return elfcore_make_note_pseudosection (abfd, ".reg2", note); + + default: + return TRUE; + } + + /* On all other arch's, PT_GETREGS == mach+1 and + PT_GETFPREGS == mach+3. */ + + default: + switch (note->type) + { + case NT_NETBSDCORE_FIRSTMACH+1: + return elfcore_make_note_pseudosection (abfd, ".reg", note); + + case NT_NETBSDCORE_FIRSTMACH+3: + return elfcore_make_note_pseudosection (abfd, ".reg2", note); + + default: + return TRUE; + } + } + /* NOTREACHED */ +} + +static bfd_boolean +elfcore_grok_nto_status (abfd, note, tid) + bfd *abfd; + Elf_Internal_Note *note; + pid_t *tid; +{ + void *ddata = note->descdata; + char buf[100]; + char *name; + asection *sect; + + /* nto_procfs_status 'pid' field is at offset 0. */ + elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, (bfd_byte *) ddata); + + /* nto_procfs_status 'tid' field is at offset 4. */ + elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, (bfd_byte *) ddata + 4); + + /* nto_procfs_status 'what' field is at offset 14. */ + elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, (bfd_byte *) ddata + 14); + + /* Pass tid back. */ + *tid = elf_tdata (abfd)->core_lwpid; + + /* Make a ".qnx_core_status/%d" section. */ + sprintf (buf, ".qnx_core_status/%d", *tid); + + name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1); + if (name == NULL) + return FALSE; + strcpy (name, buf); + + sect = bfd_make_section (abfd, name); + if (sect == NULL) + return FALSE; + + sect->_raw_size = note->descsz; + sect->filepos = note->descpos; + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + return (elfcore_maybe_make_sect (abfd, ".qnx_core_status", sect)); +} + +static bfd_boolean +elfcore_grok_nto_gregs (abfd, note, tid) + bfd *abfd; + Elf_Internal_Note *note; + pid_t tid; +{ + char buf[100]; + char *name; + asection *sect; + + /* Make a ".reg/%d" section. */ + sprintf (buf, ".reg/%d", tid); + + name = bfd_alloc (abfd, (bfd_size_type) strlen (buf) + 1); + if (name == NULL) + return FALSE; + strcpy (name, buf); + + sect = bfd_make_section (abfd, name); + if (sect == NULL) + return FALSE; + + sect->_raw_size = note->descsz; + sect->filepos = note->descpos; + sect->flags = SEC_HAS_CONTENTS; + sect->alignment_power = 2; + + return elfcore_maybe_make_sect (abfd, ".reg", sect); +} + +#define BFD_QNT_CORE_INFO 7 +#define BFD_QNT_CORE_STATUS 8 +#define BFD_QNT_CORE_GREG 9 +#define BFD_QNT_CORE_FPREG 10 + +static bfd_boolean +elfcore_grok_nto_note (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + /* Every GREG section has a STATUS section before it. Store the + tid from the previous call to pass down to the next gregs + function. */ + static pid_t tid = 1; + + switch (note->type) + { + case BFD_QNT_CORE_INFO: return elfcore_make_note_pseudosection (abfd, ".qnx_core_info", note); + case BFD_QNT_CORE_STATUS: return elfcore_grok_nto_status (abfd, note, &tid); + case BFD_QNT_CORE_GREG: return elfcore_grok_nto_gregs (abfd, note, tid); + case BFD_QNT_CORE_FPREG: return elfcore_grok_prfpreg (abfd, note); + default: return TRUE; + } +} + +/* Function: elfcore_write_note + + Inputs: + buffer to hold note + name of note + type of note + data for note + size of data for note + + Return: + End of buffer containing note. */ + +char * +elfcore_write_note (abfd, buf, bufsiz, name, type, input, size) + bfd *abfd; + char *buf; + int *bufsiz; + const char *name; + int type; + const PTR input; + int size; +{ + Elf_External_Note *xnp; + size_t namesz; + size_t pad; + size_t newspace; + char *p, *dest; + + namesz = 0; + pad = 0; + if (name != NULL) + { + struct elf_backend_data *bed; + + namesz = strlen (name) + 1; + bed = get_elf_backend_data (abfd); + pad = -namesz & (bed->s->file_align - 1); + } + + newspace = sizeof (Elf_External_Note) - 1 + namesz + pad + size; + + p = realloc (buf, *bufsiz + newspace); + dest = p + *bufsiz; + *bufsiz += newspace; + xnp = (Elf_External_Note *) dest; + H_PUT_32 (abfd, namesz, xnp->namesz); + H_PUT_32 (abfd, size, xnp->descsz); + H_PUT_32 (abfd, type, xnp->type); + dest = xnp->name; + if (name != NULL) + { + memcpy (dest, name, namesz); + dest += namesz; + while (pad != 0) + { + *dest++ = '\0'; + --pad; + } + } + memcpy (dest, input, size); + return p; +} + +#if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) +char * +elfcore_write_prpsinfo (abfd, buf, bufsiz, fname, psargs) + bfd *abfd; + char *buf; + int *bufsiz; + const char *fname; + const char *psargs; +{ + int note_type; + char *note_name = "CORE"; + +#if defined (HAVE_PSINFO_T) + psinfo_t data; + note_type = NT_PSINFO; +#else + prpsinfo_t data; + note_type = NT_PRPSINFO; +#endif + + memset (&data, 0, sizeof (data)); + strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); + strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); + return elfcore_write_note (abfd, buf, bufsiz, + note_name, note_type, &data, sizeof (data)); +} +#endif /* PSINFO_T or PRPSINFO_T */ + +#if defined (HAVE_PRSTATUS_T) +char * +elfcore_write_prstatus (abfd, buf, bufsiz, pid, cursig, gregs) + bfd *abfd; + char *buf; + int *bufsiz; + long pid; + int cursig; + const PTR gregs; +{ + prstatus_t prstat; + char *note_name = "CORE"; + + memset (&prstat, 0, sizeof (prstat)); + prstat.pr_pid = pid; + prstat.pr_cursig = cursig; + memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg)); + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_PRSTATUS, &prstat, sizeof (prstat)); +} +#endif /* HAVE_PRSTATUS_T */ + +#if defined (HAVE_LWPSTATUS_T) +char * +elfcore_write_lwpstatus (abfd, buf, bufsiz, pid, cursig, gregs) + bfd *abfd; + char *buf; + int *bufsiz; + long pid; + int cursig; + const PTR gregs; +{ + lwpstatus_t lwpstat; + char *note_name = "CORE"; + + memset (&lwpstat, 0, sizeof (lwpstat)); + 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)); +#elif defined (HAVE_LWPSTATUS_T_PR_CONTEXT) +#if !defined(gregs) + memcpy (lwpstat.pr_context.uc_mcontext.gregs, + gregs, sizeof (lwpstat.pr_context.uc_mcontext.gregs)); +#else + memcpy (lwpstat.pr_context.uc_mcontext.__gregs, + gregs, sizeof (lwpstat.pr_context.uc_mcontext.__gregs)); +#endif +#endif + return elfcore_write_note (abfd, buf, bufsiz, note_name, + NT_LWPSTATUS, &lwpstat, sizeof (lwpstat)); +} +#endif /* HAVE_LWPSTATUS_T */ + +#if defined (HAVE_PSTATUS_T) +char * +elfcore_write_pstatus (abfd, buf, bufsiz, pid, cursig, gregs) + bfd *abfd; + char *buf; + int *bufsiz; + long pid; + int cursig; + const PTR gregs; +{ + pstatus_t pstat; + char *note_name = "CORE"; + + memset (&pstat, 0, sizeof (pstat)); + pstat.pr_pid = pid & 0xffff; + buf = elfcore_write_note (abfd, buf, bufsiz, note_name, + NT_PSTATUS, &pstat, sizeof (pstat)); + return buf; +} +#endif /* HAVE_PSTATUS_T */ + +char * +elfcore_write_prfpreg (abfd, buf, bufsiz, fpregs, size) + bfd *abfd; + char *buf; + int *bufsiz; + const PTR fpregs; + int size; +{ + char *note_name = "CORE"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_FPREGSET, fpregs, size); +} + +char * +elfcore_write_prxfpreg (abfd, buf, bufsiz, xfpregs, size) + bfd *abfd; + char *buf; + int *bufsiz; + const PTR xfpregs; + int size; +{ + char *note_name = "LINUX"; + return elfcore_write_note (abfd, buf, bufsiz, + note_name, NT_PRXFPREG, xfpregs, size); +} + +static bfd_boolean +elfcore_read_notes (abfd, offset, size) + bfd *abfd; + file_ptr offset; + bfd_size_type size; +{ + char *buf; + char *p; + + if (size <= 0) + return TRUE; + + if (bfd_seek (abfd, offset, SEEK_SET) != 0) + return FALSE; + + buf = bfd_malloc (size); + if (buf == NULL) + return FALSE; + + if (bfd_bread (buf, size, abfd) != size) + { + error: + free (buf); + return FALSE; + } + + p = buf; + while (p < buf + size) + { + /* FIXME: bad alignment assumption. */ + Elf_External_Note *xnp = (Elf_External_Note *) p; + Elf_Internal_Note in; + + in.type = H_GET_32 (abfd, xnp->type); + + in.namesz = H_GET_32 (abfd, xnp->namesz); + in.namedata = xnp->name; + + in.descsz = H_GET_32 (abfd, xnp->descsz); + in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4); + in.descpos = offset + (in.descdata - buf); + + if (strncmp (in.namedata, "NetBSD-CORE", 11) == 0) + { + if (! elfcore_grok_netbsd_note (abfd, &in)) + goto error; + } + else if (strncmp (in.namedata, "QNX", 3) == 0) + { + if (! elfcore_grok_nto_note (abfd, &in)) + goto error; + } + else + { + if (! elfcore_grok_note (abfd, &in)) + goto error; + } + + p = in.descdata + BFD_ALIGN (in.descsz, 4); + } + + free (buf); + return TRUE; +} + +/* Providing external access to the ELF program header table. */ + +/* Return an upper bound on the number of bytes required to store a + copy of ABFD's program header table entries. Return -1 if an error + occurs; bfd_get_error will return an appropriate code. */ + +long +bfd_get_elf_phdr_upper_bound (abfd) + bfd *abfd; +{ + if (abfd->xvec->flavour != bfd_target_elf_flavour) + { + bfd_set_error (bfd_error_wrong_format); + return -1; + } + + return elf_elfheader (abfd)->e_phnum * sizeof (Elf_Internal_Phdr); +} + +/* Copy ABFD's program header table entries to *PHDRS. The entries + will be stored as an array of Elf_Internal_Phdr structures, as + defined in include/elf/internal.h. To find out how large the + buffer needs to be, call bfd_get_elf_phdr_upper_bound. + + Return the number of program header table entries read, or -1 if an + error occurs; bfd_get_error will return an appropriate code. */ + +int +bfd_get_elf_phdrs (abfd, phdrs) + bfd *abfd; + void *phdrs; +{ + int num_phdrs; + + if (abfd->xvec->flavour != bfd_target_elf_flavour) + { + bfd_set_error (bfd_error_wrong_format); + return -1; + } + + num_phdrs = elf_elfheader (abfd)->e_phnum; + memcpy (phdrs, elf_tdata (abfd)->phdr, + num_phdrs * sizeof (Elf_Internal_Phdr)); + + return num_phdrs; +} + +void +_bfd_elf_sprintf_vma (abfd, buf, value) + bfd *abfd ATTRIBUTE_UNUSED; + char *buf; + bfd_vma value; +{ +#ifdef BFD64 + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + + i_ehdrp = elf_elfheader (abfd); + if (i_ehdrp == NULL) + sprintf_vma (buf, value); + else + { + if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64) + { +#if BFD_HOST_64BIT_LONG + sprintf (buf, "%016lx", value); +#else + sprintf (buf, "%08lx%08lx", _bfd_int64_high (value), + _bfd_int64_low (value)); +#endif + } + else + sprintf (buf, "%08lx", (unsigned long) (value & 0xffffffff)); + } +#else + sprintf_vma (buf, value); +#endif +} + +void +_bfd_elf_fprintf_vma (abfd, stream, value) + bfd *abfd ATTRIBUTE_UNUSED; + PTR stream; + bfd_vma value; +{ +#ifdef BFD64 + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + + i_ehdrp = elf_elfheader (abfd); + if (i_ehdrp == NULL) + fprintf_vma ((FILE *) stream, value); + else + { + if (i_ehdrp->e_ident[EI_CLASS] == ELFCLASS64) + { +#if BFD_HOST_64BIT_LONG + fprintf ((FILE *) stream, "%016lx", value); +#else + fprintf ((FILE *) stream, "%08lx%08lx", + _bfd_int64_high (value), _bfd_int64_low (value)); +#endif + } + else + fprintf ((FILE *) stream, "%08lx", + (unsigned long) (value & 0xffffffff)); + } +#else + fprintf_vma ((FILE *) stream, value); +#endif +} + +enum elf_reloc_type_class +_bfd_elf_reloc_type_class (rela) + const Elf_Internal_Rela *rela ATTRIBUTE_UNUSED; +{ + return reloc_class_normal; +} + +/* For RELA architectures, return the relocation value for a + relocation against a local symbol. */ + +bfd_vma +_bfd_elf_rela_local_sym (abfd, sym, sec, rel) + bfd *abfd; + Elf_Internal_Sym *sym; + asection *sec; + Elf_Internal_Rela *rel; +{ + bfd_vma relocation; + + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + if ((sec->flags & SEC_MERGE) + && ELF_ST_TYPE (sym->st_info) == STT_SECTION + && sec->sec_info_type == ELF_INFO_TYPE_MERGE) + { + asection *msec; + + msec = sec; + rel->r_addend = + _bfd_merged_section_offset (abfd, &msec, + elf_section_data (sec)->sec_info, + sym->st_value + rel->r_addend, + (bfd_vma) 0) + - relocation; + rel->r_addend += msec->output_section->vma + msec->output_offset; + } + return relocation; +} + +bfd_vma +_bfd_elf_rel_local_sym (abfd, sym, psec, addend) + bfd *abfd; + Elf_Internal_Sym *sym; + asection **psec; + bfd_vma addend; +{ + asection *sec = *psec; + + if (sec->sec_info_type != ELF_INFO_TYPE_MERGE) + return sym->st_value + addend; + + return _bfd_merged_section_offset (abfd, psec, + elf_section_data (sec)->sec_info, + sym->st_value + addend, (bfd_vma) 0); +} + +bfd_vma +_bfd_elf_section_offset (abfd, info, sec, offset) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + bfd_vma offset; +{ + struct bfd_elf_section_data *sec_data; + + sec_data = elf_section_data (sec); + switch (sec->sec_info_type) + { + case ELF_INFO_TYPE_STABS: + return _bfd_stab_section_offset (abfd, + &elf_hash_table (info)->merge_info, + sec, &sec_data->sec_info, offset); + case ELF_INFO_TYPE_EH_FRAME: + return _bfd_elf_eh_frame_section_offset (abfd, sec, offset); + default: + return offset; + } +} diff --git a/contrib/binutils-2.14/bfd/elf32-i386.c b/contrib/binutils-2.14/bfd/elf32-i386.c new file mode 100644 index 0000000000..060d66c20c --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf32-i386.c @@ -0,0 +1,3435 @@ +/* Intel 80386/80486-specific support for 32-bit ELF + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" + +static reloc_howto_type *elf_i386_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void elf_i386_info_to_howto_rel + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); +static bfd_boolean elf_i386_is_local_label_name + PARAMS ((bfd *, const char *)); +static bfd_boolean elf_i386_grok_prstatus + PARAMS ((bfd *abfd, Elf_Internal_Note *note)); +static bfd_boolean elf_i386_grok_psinfo + PARAMS ((bfd *abfd, Elf_Internal_Note *note)); +static struct bfd_hash_entry *link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static struct bfd_link_hash_table *elf_i386_link_hash_table_create + PARAMS ((bfd *)); +static bfd_boolean create_got_section + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_boolean elf_i386_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static void elf_i386_copy_indirect_symbol + PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *, + struct elf_link_hash_entry *)); +static int elf_i386_tls_transition + PARAMS ((struct bfd_link_info *, int, int)); + +static bfd_boolean elf_i386_mkobject + PARAMS ((bfd *)); +static bfd_boolean elf_i386_object_p + PARAMS ((bfd *)); +static bfd_boolean elf_i386_check_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); +static asection *elf_i386_gc_mark_hook + PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *, Elf_Internal_Sym *)); +static bfd_boolean elf_i386_gc_sweep_hook + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); +static bfd_boolean elf_i386_adjust_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static bfd_boolean allocate_dynrelocs + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean readonly_dynrelocs + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_i386_fake_sections + PARAMS ((bfd *, Elf_Internal_Shdr *, asection *)); +static bfd_boolean elf_i386_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_vma dtpoff_base + PARAMS ((struct bfd_link_info *)); +static bfd_vma tpoff + PARAMS ((struct bfd_link_info *, bfd_vma)); +static bfd_boolean elf_i386_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static bfd_boolean elf_i386_finish_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *)); +static enum elf_reloc_type_class elf_i386_reloc_type_class + PARAMS ((const Elf_Internal_Rela *)); +static bfd_boolean elf_i386_finish_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +#define USE_REL 1 /* 386 uses REL relocations instead of RELA. */ + +#include "elf/i386.h" + +static reloc_howto_type elf_howto_table[]= +{ + HOWTO(R_386_NONE, 0, 0, 0, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_NONE", + TRUE, 0x00000000, 0x00000000, FALSE), + HOWTO(R_386_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_PC32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_PC32", + TRUE, 0xffffffff, 0xffffffff, TRUE), + HOWTO(R_386_GOT32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_GOT32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_PLT32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_PLT32", + TRUE, 0xffffffff, 0xffffffff, TRUE), + HOWTO(R_386_COPY, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_COPY", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_GLOB_DAT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_GLOB_DAT", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_JUMP_SLOT, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_JUMP_SLOT", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_RELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_RELATIVE", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_GOTOFF, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_GOTOFF", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_GOTPC, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_GOTPC", + TRUE, 0xffffffff, 0xffffffff, TRUE), + + /* We have a gap in the reloc numbers here. + R_386_standard counts the number up to this point, and + R_386_ext_offset is the value to subtract from a reloc type of + R_386_16 thru R_386_PC8 to form an index into this table. */ +#define R_386_standard ((unsigned int) R_386_GOTPC + 1) +#define R_386_ext_offset ((unsigned int) R_386_TLS_TPOFF - R_386_standard) + + /* These relocs are a GNU extension. */ + HOWTO(R_386_TLS_TPOFF, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_TPOFF", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_IE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_IE", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_GOTIE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_GOTIE", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_LE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_LE", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_GD, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_GD", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_LDM, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_LDM", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_16", + TRUE, 0xffff, 0xffff, FALSE), + HOWTO(R_386_PC16, 0, 1, 16, TRUE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_PC16", + TRUE, 0xffff, 0xffff, TRUE), + HOWTO(R_386_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_8", + TRUE, 0xff, 0xff, FALSE), + HOWTO(R_386_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_386_PC8", + TRUE, 0xff, 0xff, TRUE), + +#define R_386_ext ((unsigned int) R_386_PC8 + 1 - R_386_ext_offset) +#define R_386_tls_offset ((unsigned int) R_386_TLS_LDO_32 - R_386_ext) + /* These are common with Solaris TLS implementation. */ + HOWTO(R_386_TLS_LDO_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_LDO_32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_IE_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_IE_32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_LE_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_LE_32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_DTPMOD32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_DTPMOD32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_DTPOFF32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_TPOFF32", + TRUE, 0xffffffff, 0xffffffff, FALSE), + + /* Another gap. */ +#define R_386_tls ((unsigned int) R_386_TLS_TPOFF32 + 1 - R_386_tls_offset) +#define R_386_vt_offset ((unsigned int) R_386_GNU_VTINHERIT - R_386_tls) + +/* GNU extension to record C++ vtable hierarchy. */ + HOWTO (R_386_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_386_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_386_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_386_GNU_VTENTRY", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE) /* pcrel_offset */ + +#define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset) + +}; + +#ifdef DEBUG_GEN_RELOC +#define TRACE(str) fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str) +#else +#define TRACE(str) +#endif + +static reloc_howto_type * +elf_i386_reloc_type_lookup (abfd, code) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_NONE: + TRACE ("BFD_RELOC_NONE"); + return &elf_howto_table[(unsigned int) R_386_NONE ]; + + case BFD_RELOC_32: + TRACE ("BFD_RELOC_32"); + return &elf_howto_table[(unsigned int) R_386_32 ]; + + case BFD_RELOC_CTOR: + TRACE ("BFD_RELOC_CTOR"); + return &elf_howto_table[(unsigned int) R_386_32 ]; + + case BFD_RELOC_32_PCREL: + TRACE ("BFD_RELOC_PC32"); + return &elf_howto_table[(unsigned int) R_386_PC32 ]; + + case BFD_RELOC_386_GOT32: + TRACE ("BFD_RELOC_386_GOT32"); + return &elf_howto_table[(unsigned int) R_386_GOT32 ]; + + case BFD_RELOC_386_PLT32: + TRACE ("BFD_RELOC_386_PLT32"); + return &elf_howto_table[(unsigned int) R_386_PLT32 ]; + + case BFD_RELOC_386_COPY: + TRACE ("BFD_RELOC_386_COPY"); + return &elf_howto_table[(unsigned int) R_386_COPY ]; + + case BFD_RELOC_386_GLOB_DAT: + TRACE ("BFD_RELOC_386_GLOB_DAT"); + return &elf_howto_table[(unsigned int) R_386_GLOB_DAT ]; + + case BFD_RELOC_386_JUMP_SLOT: + TRACE ("BFD_RELOC_386_JUMP_SLOT"); + return &elf_howto_table[(unsigned int) R_386_JUMP_SLOT ]; + + case BFD_RELOC_386_RELATIVE: + TRACE ("BFD_RELOC_386_RELATIVE"); + return &elf_howto_table[(unsigned int) R_386_RELATIVE ]; + + case BFD_RELOC_386_GOTOFF: + TRACE ("BFD_RELOC_386_GOTOFF"); + return &elf_howto_table[(unsigned int) R_386_GOTOFF ]; + + case BFD_RELOC_386_GOTPC: + TRACE ("BFD_RELOC_386_GOTPC"); + return &elf_howto_table[(unsigned int) R_386_GOTPC ]; + + /* These relocs are a GNU extension. */ + case BFD_RELOC_386_TLS_TPOFF: + TRACE ("BFD_RELOC_386_TLS_TPOFF"); + return &elf_howto_table[(unsigned int) R_386_TLS_TPOFF - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_IE: + TRACE ("BFD_RELOC_386_TLS_IE"); + return &elf_howto_table[(unsigned int) R_386_TLS_IE - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_GOTIE: + TRACE ("BFD_RELOC_386_TLS_GOTIE"); + return &elf_howto_table[(unsigned int) R_386_TLS_GOTIE - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_LE: + TRACE ("BFD_RELOC_386_TLS_LE"); + return &elf_howto_table[(unsigned int) R_386_TLS_LE - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_GD: + TRACE ("BFD_RELOC_386_TLS_GD"); + return &elf_howto_table[(unsigned int) R_386_TLS_GD - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_LDM: + TRACE ("BFD_RELOC_386_TLS_LDM"); + return &elf_howto_table[(unsigned int) R_386_TLS_LDM - R_386_ext_offset]; + + case BFD_RELOC_16: + TRACE ("BFD_RELOC_16"); + return &elf_howto_table[(unsigned int) R_386_16 - R_386_ext_offset]; + + case BFD_RELOC_16_PCREL: + TRACE ("BFD_RELOC_16_PCREL"); + return &elf_howto_table[(unsigned int) R_386_PC16 - R_386_ext_offset]; + + case BFD_RELOC_8: + TRACE ("BFD_RELOC_8"); + return &elf_howto_table[(unsigned int) R_386_8 - R_386_ext_offset]; + + case BFD_RELOC_8_PCREL: + TRACE ("BFD_RELOC_8_PCREL"); + return &elf_howto_table[(unsigned int) R_386_PC8 - R_386_ext_offset]; + + /* Common with Sun TLS implementation. */ + case BFD_RELOC_386_TLS_LDO_32: + TRACE ("BFD_RELOC_386_TLS_LDO_32"); + return &elf_howto_table[(unsigned int) R_386_TLS_LDO_32 - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_IE_32: + TRACE ("BFD_RELOC_386_TLS_IE_32"); + return &elf_howto_table[(unsigned int) R_386_TLS_IE_32 - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_LE_32: + TRACE ("BFD_RELOC_386_TLS_LE_32"); + return &elf_howto_table[(unsigned int) R_386_TLS_LE_32 - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_DTPMOD32: + TRACE ("BFD_RELOC_386_TLS_DTPMOD32"); + return &elf_howto_table[(unsigned int) R_386_TLS_DTPMOD32 - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_DTPOFF32: + TRACE ("BFD_RELOC_386_TLS_DTPOFF32"); + return &elf_howto_table[(unsigned int) R_386_TLS_DTPOFF32 - R_386_tls_offset]; + + case BFD_RELOC_386_TLS_TPOFF32: + TRACE ("BFD_RELOC_386_TLS_TPOFF32"); + return &elf_howto_table[(unsigned int) R_386_TLS_TPOFF32 - R_386_tls_offset]; + + case BFD_RELOC_VTABLE_INHERIT: + TRACE ("BFD_RELOC_VTABLE_INHERIT"); + return &elf_howto_table[(unsigned int) R_386_GNU_VTINHERIT + - R_386_vt_offset]; + + case BFD_RELOC_VTABLE_ENTRY: + TRACE ("BFD_RELOC_VTABLE_ENTRY"); + return &elf_howto_table[(unsigned int) R_386_GNU_VTENTRY + - R_386_vt_offset]; + + default: + break; + } + + TRACE ("Unknown"); + return 0; +} + +static void +elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *cache_ptr; + Elf_Internal_Rela *dst; +{ + unsigned int r_type = ELF32_R_TYPE (dst->r_info); + unsigned int indx; + + if ((indx = r_type) >= R_386_standard + && ((indx = r_type - R_386_ext_offset) - R_386_standard + >= R_386_ext - R_386_standard) + && ((indx = r_type - R_386_tls_offset) - R_386_ext + >= R_386_tls - R_386_ext) + && ((indx = r_type - R_386_vt_offset) - R_386_tls + >= R_386_vt - R_386_tls)) + { + (*_bfd_error_handler) (_("%s: invalid relocation type %d"), + bfd_archive_filename (abfd), (int) r_type); + indx = (unsigned int) R_386_NONE; + } + cache_ptr->howto = &elf_howto_table[indx]; +} + +/* Return whether a symbol name implies a local label. The UnixWare + 2.1 cc generates temporary symbols that start with .X, so we + recognize them here. FIXME: do other SVR4 compilers also use .X?. + If so, we should move the .X recognition into + _bfd_elf_is_local_label_name. */ + +static bfd_boolean +elf_i386_is_local_label_name (abfd, name) + bfd *abfd; + const char *name; +{ + if (name[0] == '.' && name[1] == 'X') + return TRUE; + + return _bfd_elf_is_local_label_name (abfd, name); +} + +/* Support for core dump NOTE sections. */ +static bfd_boolean +elf_i386_grok_prstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + int offset; + size_t raw_size; + + switch (note->descsz) + { + default: + return FALSE; + + case 144: /* Linux/i386 */ + /* 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; + raw_size = 68; + + break; + } + + /* Make a ".reg/999" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + raw_size, note->descpos + offset); +} + +static bfd_boolean +elf_i386_grok_psinfo (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + switch (note->descsz) + { + default: + return FALSE; + + case 124: /* Linux/i386 elf_prpsinfo */ + 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); + } + + /* 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; +} + +/* Functions for the i386 ELF linker. + + In order to gain some understanding of code in this file without + knowing all the intricate details of the linker, note the + following: + + Functions named elf_i386_* are called by external routines, other + functions are only called locally. elf_i386_* functions appear + in this file more or less in the order in which they are called + from external routines. eg. elf_i386_check_relocs is called + early in the link process, elf_i386_finish_dynamic_sections is + one of the last functions. */ + + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" + +/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid + copying dynamic variables from a shared lib into an app's dynbss + section, and instead use a dynamic relocation to point into the + shared lib. */ +#define ELIMINATE_COPY_RELOCS 1 + +/* The size in bytes of an entry in the procedure linkage table. */ + +#define PLT_ENTRY_SIZE 16 + +/* The first entry in an absolute procedure linkage table looks like + this. See the SVR4 ABI i386 supplement to see how this works. */ + +static const bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x35, /* pushl contents of address */ + 0, 0, 0, 0, /* replaced with address of .got + 4. */ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with address of .got + 8. */ + 0, 0, 0, 0 /* pad out to 16 bytes. */ +}; + +/* Subsequent entries in an absolute procedure linkage table look like + this. */ + +static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x25, /* jmp indirect */ + 0, 0, 0, 0, /* replaced with address of this symbol in .got. */ + 0x68, /* pushl immediate */ + 0, 0, 0, 0, /* replaced with offset into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0 /* replaced with offset to start of .plt. */ +}; + +/* The first entry in a PIC procedure linkage table look like this. */ + +static const bfd_byte elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ + 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ + 0, 0, 0, 0 /* pad out to 16 bytes. */ +}; + +/* Subsequent entries in a PIC procedure linkage table look like this. */ + +static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0xa3, /* jmp *offset(%ebx) */ + 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ + 0x68, /* pushl immediate */ + 0, 0, 0, 0, /* replaced with offset into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0 /* replaced with offset to start of .plt. */ +}; + +/* The i386 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_i386_dyn_relocs +{ + struct elf_i386_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; +}; + +/* i386 ELF linker hash entry. */ + +struct elf_i386_link_hash_entry +{ + struct elf_link_hash_entry elf; + + /* Track dynamic relocs copied for this symbol. */ + struct elf_i386_dyn_relocs *dyn_relocs; + +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_GD 2 +#define GOT_TLS_IE 4 +#define GOT_TLS_IE_POS 5 +#define GOT_TLS_IE_NEG 6 +#define GOT_TLS_IE_BOTH 7 + unsigned char tls_type; +}; + +#define elf_i386_hash_entry(ent) ((struct elf_i386_link_hash_entry *)(ent)) + +struct elf_i386_obj_tdata +{ + struct elf_obj_tdata root; + + /* tls_type for each local got entry. */ + char *local_got_tls_type; +}; + +#define elf_i386_tdata(abfd) \ + ((struct elf_i386_obj_tdata *) (abfd)->tdata.any) + +#define elf_i386_local_got_tls_type(abfd) \ + (elf_i386_tdata (abfd)->local_got_tls_type) + +static bfd_boolean +elf_i386_mkobject (abfd) + bfd *abfd; +{ + bfd_size_type amt = sizeof (struct elf_i386_obj_tdata); + abfd->tdata.any = bfd_zalloc (abfd, amt); + if (abfd->tdata.any == NULL) + return FALSE; + return TRUE; +} + +static bfd_boolean +elf_i386_object_p (abfd) + bfd *abfd; +{ + /* Allocate our special target data. */ + struct elf_i386_obj_tdata *new_tdata; + bfd_size_type amt = sizeof (struct elf_i386_obj_tdata); + new_tdata = bfd_zalloc (abfd, amt); + if (new_tdata == NULL) + return FALSE; + new_tdata->root = *abfd->tdata.elf_obj_data; + abfd->tdata.any = new_tdata; + return TRUE; +} + +/* i386 ELF linker hash table. */ + +struct elf_i386_link_hash_table +{ + struct elf_link_hash_table elf; + + /* Short-cuts to get to dynamic linker sections. */ + asection *sgot; + asection *sgotplt; + asection *srelgot; + asection *splt; + asection *srelplt; + asection *sdynbss; + asection *srelbss; + + union { + bfd_signed_vma refcount; + bfd_vma offset; + } tls_ldm_got; + + /* Small local sym to section mapping cache. */ + struct sym_sec_cache sym_sec; +}; + +/* Get the i386 ELF linker hash table from a link_info structure. */ + +#define elf_i386_hash_table(p) \ + ((struct elf_i386_link_hash_table *) ((p)->hash)) + +/* Create an entry in an i386 ELF linker hash table. */ + +static struct bfd_hash_entry * +link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = bfd_hash_allocate (table, + sizeof (struct elf_i386_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = _bfd_elf_link_hash_newfunc (entry, table, string); + if (entry != NULL) + { + struct elf_i386_link_hash_entry *eh; + + eh = (struct elf_i386_link_hash_entry *) entry; + eh->dyn_relocs = NULL; + eh->tls_type = GOT_UNKNOWN; + } + + return entry; +} + +/* Create an i386 ELF linker hash table. */ + +static struct bfd_link_hash_table * +elf_i386_link_hash_table_create (abfd) + bfd *abfd; +{ + struct elf_i386_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf_i386_link_hash_table); + + ret = (struct elf_i386_link_hash_table *) bfd_malloc (amt); + if (ret == NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc)) + { + 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->tls_ldm_got.refcount = 0; + ret->sym_sec.abfd = NULL; + + return &ret->elf.root; +} + +/* Create .got, .gotplt, and .rel.got sections in DYNOBJ, and set up + shortcuts to them in our hash table. */ + +static bfd_boolean +create_got_section (dynobj, info) + bfd *dynobj; + struct bfd_link_info *info; +{ + struct elf_i386_link_hash_table *htab; + + if (! _bfd_elf_create_got_section (dynobj, info)) + return FALSE; + + htab = elf_i386_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 (); + + htab->srelgot = bfd_make_section (dynobj, ".rel.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 .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. */ + +static bfd_boolean +elf_i386_create_dynamic_sections (dynobj, info) + bfd *dynobj; + struct bfd_link_info *info; +{ + struct elf_i386_link_hash_table *htab; + + htab = elf_i386_hash_table (info); + 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, ".rel.plt"); + htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); + if (!info->shared) + htab->srelbss = bfd_get_section_by_name (dynobj, ".rel.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 +elf_i386_copy_indirect_symbol (bed, dir, ind) + struct elf_backend_data *bed; + struct elf_link_hash_entry *dir, *ind; +{ + struct elf_i386_link_hash_entry *edir, *eind; + + edir = (struct elf_i386_link_hash_entry *) dir; + eind = (struct elf_i386_link_hash_entry *) ind; + + if (eind->dyn_relocs != NULL) + { + if (edir->dyn_relocs != NULL) + { + struct elf_i386_dyn_relocs **pp; + struct elf_i386_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_i386_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 + && dir->got.refcount <= 0) + { + edir->tls_type = eind->tls_type; + eind->tls_type = GOT_UNKNOWN; + } + + if (ELIMINATE_COPY_RELOCS + && ind->root.type != bfd_link_hash_indirect + && (dir->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + dir->elf_link_hash_flags |= + (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK)); + else + _bfd_elf_link_hash_copy_indirect (bed, dir, ind); +} + +static int +elf_i386_tls_transition (info, r_type, is_local) + struct bfd_link_info *info; + int r_type; + int is_local; +{ + if (info->shared) + return r_type; + + switch (r_type) + { + case R_386_TLS_GD: + case R_386_TLS_IE_32: + if (is_local) + return R_386_TLS_LE_32; + return R_386_TLS_IE_32; + case R_386_TLS_IE: + case R_386_TLS_GOTIE: + if (is_local) + return R_386_TLS_LE_32; + return r_type; + case R_386_TLS_LDM: + return R_386_TLS_LE_32; + } + + return r_type; +} + +/* 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. */ + +static bfd_boolean +elf_i386_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + struct elf_i386_link_hash_table *htab; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + asection *sreloc; + + if (info->relocateable) + return TRUE; + + htab = elf_i386_hash_table (info); + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + + sreloc = NULL; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned int r_type; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = ELF32_R_SYM (rel->r_info); + r_type = ELF32_R_TYPE (rel->r_info); + + if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) + { + (*_bfd_error_handler) (_("%s: bad symbol index: %d"), + bfd_archive_filename (abfd), + r_symndx); + return FALSE; + } + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + r_type = elf_i386_tls_transition (info, r_type, h == NULL); + + switch (r_type) + { + case R_386_TLS_LDM: + htab->tls_ldm_got.refcount += 1; + goto create_got; + + case R_386_PLT32: + /* 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 + never referenced by a dynamic object, in which case we + don't need to generate a procedure linkage table entry + after all. */ + + /* If this is a local symbol, we resolve it directly without + creating a procedure linkage table entry. */ + if (h == NULL) + continue; + + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + h->plt.refcount += 1; + break; + + case R_386_TLS_IE_32: + case R_386_TLS_IE: + case R_386_TLS_GOTIE: + if (info->shared) + info->flags |= DF_STATIC_TLS; + /* Fall through */ + + case R_386_GOT32: + case R_386_TLS_GD: + /* This symbol requires a global offset table entry. */ + { + int tls_type, old_tls_type; + + switch (r_type) + { + default: + case R_386_GOT32: tls_type = GOT_NORMAL; break; + case R_386_TLS_GD: tls_type = GOT_TLS_GD; break; + case R_386_TLS_IE_32: + if (ELF32_R_TYPE (rel->r_info) == r_type) + tls_type = GOT_TLS_IE_NEG; + else + /* If this is a GD->IE transition, we may use either of + R_386_TLS_TPOFF and R_386_TLS_TPOFF32. */ + tls_type = GOT_TLS_IE; + break; + case R_386_TLS_IE: + case R_386_TLS_GOTIE: + tls_type = GOT_TLS_IE_POS; break; + } + + if (h != NULL) + { + h->got.refcount += 1; + old_tls_type = elf_i386_hash_entry(h)->tls_type; + } + 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) + sizeof(char)); + 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; + elf_i386_local_got_tls_type (abfd) + = (char *) (local_got_refcounts + symtab_hdr->sh_info); + } + local_got_refcounts[r_symndx] += 1; + old_tls_type = elf_i386_local_got_tls_type (abfd) [r_symndx]; + } + + if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_IE)) + tls_type |= old_tls_type; + /* If a TLS symbol is accessed using IE at least once, + there is no point to use dynamic model for it. */ + else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN + && (old_tls_type != GOT_TLS_GD + || (tls_type & GOT_TLS_IE) == 0)) + { + if ((old_tls_type & GOT_TLS_IE) && tls_type == GOT_TLS_GD) + tls_type = old_tls_type; + else + { + (*_bfd_error_handler) + (_("%s: `%s' accessed both as normal and thread local symbol"), + bfd_archive_filename (abfd), + h ? h->root.root.string : ""); + return FALSE; + } + } + + if (old_tls_type != tls_type) + { + if (h != NULL) + elf_i386_hash_entry (h)->tls_type = tls_type; + else + elf_i386_local_got_tls_type (abfd) [r_symndx] = tls_type; + } + } + /* Fall through */ + + case R_386_GOTOFF: + case R_386_GOTPC: + create_got: + if (htab->sgot == NULL) + { + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + if (!create_got_section (htab->elf.dynobj, info)) + return FALSE; + } + if (r_type != R_386_TLS_IE) + break; + /* Fall through */ + + case R_386_TLS_LE_32: + case R_386_TLS_LE: + if (!info->shared) + break; + info->flags |= DF_STATIC_TLS; + /* Fall through */ + + case R_386_32: + case R_386_PC32: + if (h != NULL && !info->shared) + { + /* If this reloc is in a read-only section, we might + need a copy reloc. We can't check reliably at this + stage whether the section is read-only, as input + sections have not yet been mapped to output sections. + Tentatively set the flag for now, and correct in + adjust_dynamic_symbol. */ + h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; + + /* We may need a .plt entry if the function this reloc + refers to is in a shared lib. */ + 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). 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 + && (r_type != R_386_PC32 + || (h != NULL + && (! info->symbolic + || h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || (ELIMINATE_COPY_RELOCS + && !info->shared + && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))) + { + struct elf_i386_dyn_relocs *p; + struct elf_i386_dyn_relocs **head; + + /* We must copy these reloc types into the output file. + Create a reloc section in dynobj and make room for + this reloc. */ + if (sreloc == NULL) + { + const char *name; + bfd *dynobj; + unsigned int strndx = elf_elfheader (abfd)->e_shstrndx; + unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name; + + name = bfd_elf_string_from_elf_section (abfd, strndx, shnam); + if (name == NULL) + return FALSE; + + if (strncmp (name, ".rel", 4) != 0 + || strcmp (bfd_get_section_name (abfd, sec), + name + 4) != 0) + { + (*_bfd_error_handler) + (_("%s: bad relocation section name `%s\'"), + bfd_archive_filename (abfd), name); + } + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + + dynobj = htab->elf.dynobj; + 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_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_i386_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; + s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, + sec, r_symndx); + if (s == NULL) + return FALSE; + + head = ((struct elf_i386_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_i386_dyn_relocs *) + bfd_alloc (htab->elf.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 (r_type == R_386_PC32) + p->pc_count += 1; + } + break; + + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + case R_386_GNU_VTINHERIT: + if (!_bfd_elf32_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_386_GNU_VTENTRY: + if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset)) + return FALSE; + break; + + default: + break; + } + } + + return TRUE; +} + +/* Return the section that should be marked against GC for a given + relocation. */ + +static asection * +elf_i386_gc_mark_hook (sec, info, rel, h, sym) + asection *sec; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + 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_386_GNU_VTINHERIT: + case R_386_GNU_VTENTRY: + break; + + default: + 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; + + default: + break; + } + } + } + else + return bfd_section_from_elf_index (sec->owner, sym->st_shndx); + + return NULL; +} + +/* Update the got entry reference counts for the section being removed. */ + +static bfd_boolean +elf_i386_gc_sweep_hook (abfd, info, sec, 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; + 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; + unsigned int r_type; + struct elf_link_hash_entry *h = NULL; + + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + struct elf_i386_link_hash_entry *eh; + struct elf_i386_dyn_relocs **pp; + struct elf_i386_dyn_relocs *p; + + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + eh = (struct elf_i386_link_hash_entry *) h; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) + if (p->sec == sec) + { + /* Everything must go for SEC. */ + *pp = p->next; + break; + } + } + + r_type = ELF32_R_TYPE (rel->r_info); + r_type = elf_i386_tls_transition (info, r_type, h != NULL); + switch (r_type) + { + case R_386_TLS_LDM: + if (elf_i386_hash_table (info)->tls_ldm_got.refcount > 0) + elf_i386_hash_table (info)->tls_ldm_got.refcount -= 1; + break; + + case R_386_TLS_GD: + case R_386_TLS_IE_32: + case R_386_TLS_IE: + case R_386_TLS_GOTIE: + case R_386_GOT32: + if (h != NULL) + { + if (h->got.refcount > 0) + h->got.refcount -= 1; + } + else if (local_got_refcounts != NULL) + { + if (local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + } + break; + + case R_386_32: + case R_386_PC32: + if (info->shared) + break; + /* Fall through */ + + case R_386_PLT32: + if (h != NULL) + { + if (h->plt.refcount > 0) + h->plt.refcount -= 1; + } + break; + + default: + break; + } + } + + return TRUE; +} + +/* 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 +elf_i386_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + struct elf_i386_link_hash_table *htab; + asection *s; + unsigned int power_of_two; + + /* 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->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + { + if (h->plt.refcount <= 0 + || (! info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0 + && h->root.type != bfd_link_hash_undefweak + && h->root.type != bfd_link_hash_undefined)) + { + /* This case can occur if we saw a PLT32 reloc in an input + file, but the symbol was never referred to by a dynamic + object, or if all references were garbage collected. In + such a case, we don't actually need to build a procedure + linkage table, and we can just do a PC32 reloc instead. */ + h->plt.offset = (bfd_vma) -1; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + } + + return TRUE; + } + else + /* It's possible that we incorrectly decided a .plt reloc was + needed for an R_386_PC32 reloc to a non-function sym in + check_relocs. We can't decide accurately between function and + non-function syms in check-relocs; Objects loaded later in + the link may change h->type. So fix it now. */ + 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->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) + h->elf_link_hash_flags + = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF) + | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF)); + 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->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0) + return TRUE; + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + return TRUE; + } + + if (ELIMINATE_COPY_RELOCS) + { + struct elf_i386_link_hash_entry * eh; + struct elf_i386_dyn_relocs *p; + + eh = (struct elf_i386_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) != 0) + break; + } + + /* If we didn't find any dynamic relocs in read-only sections, then + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ + if (p == NULL) + { + h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + 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 = elf_i386_hash_table (info); + + /* We must generate a R_386_COPY reloc to tell the dynamic linker to + copy the initial value out of the dynamic object and into the + runtime process image. */ + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) + { + htab->srelbss->_raw_size += sizeof (Elf32_External_Rel); + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; + } + + /* 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 = htab->sdynbss; + s->_raw_size = BFD_ALIGN (s->_raw_size, (bfd_size_type) (1 << power_of_two)); + if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s)) + { + if (! bfd_set_section_alignment (htab->elf.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->_raw_size; + + /* Increment the section size to make room for the symbol. */ + s->_raw_size += h->size; + + return TRUE; +} + +/* This is the condition under which elf_i386_finish_dynamic_symbol + will be called from elflink.h. If elflink.h doesn't call our + finish_dynamic_symbol routine, we'll need to do something about + initializing any .plt and .got entries in elf_i386_relocate_section. */ +#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \ + ((DYN) \ + && ((SHARED) \ + || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \ + && ((H)->dynindx != -1 \ + || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)) + +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ + +static bfd_boolean +allocate_dynrelocs (h, inf) + struct elf_link_hash_entry *h; + PTR inf; +{ + struct bfd_link_info *info; + struct elf_i386_link_hash_table *htab; + struct elf_i386_link_hash_entry *eh; + struct elf_i386_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 = elf_i386_hash_table (info); + + if (htab->elf.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->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + if (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) + { + asection *s = htab->splt; + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (s->_raw_size == 0) + s->_raw_size += PLT_ENTRY_SIZE; + + h->plt.offset = s->_raw_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->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->_raw_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->_raw_size += 4; + + /* We also need to make an entry in the .rel.plt section. */ + htab->srelplt->_raw_size += sizeof (Elf32_External_Rel); + } + else + { + h->plt.offset = (bfd_vma) -1; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + } + + /* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary, + make it a R_386_TLS_LE_32 requiring no TLS entry. */ + if (h->got.refcount > 0 + && !info->shared + && h->dynindx == -1 + && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE)) + h->got.offset = (bfd_vma) -1; + else if (h->got.refcount > 0) + { + asection *s; + bfd_boolean dyn; + int tls_type = elf_i386_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->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + s = htab->sgot; + h->got.offset = s->_raw_size; + s->_raw_size += 4; + /* R_386_TLS_GD needs 2 consecutive GOT slots. */ + if (tls_type == GOT_TLS_GD || tls_type == GOT_TLS_IE_BOTH) + s->_raw_size += 4; + dyn = htab->elf.dynamic_sections_created; + /* R_386_TLS_IE_32 needs one dynamic relocation, + R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation, + (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we + need two), R_386_TLS_GD needs one if local symbol and two if + global. */ + if (tls_type == GOT_TLS_IE_BOTH) + htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rel); + else if ((tls_type == GOT_TLS_GD && h->dynindx == -1) + || (tls_type & GOT_TLS_IE)) + htab->srelgot->_raw_size += sizeof (Elf32_External_Rel); + else if (tls_type == GOT_TLS_GD) + htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rel); + else if (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) + htab->srelgot->_raw_size += sizeof (Elf32_External_Rel); + } + else + h->got.offset = (bfd_vma) -1; + + eh = (struct elf_i386_link_hash_entry *) h; + 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->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0 + || info->symbolic)) + { + struct elf_i386_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 if (ELIMINATE_COPY_RELOCS) + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. */ + + if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + || (htab->elf.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->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf32_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->_raw_size += p->count * sizeof (Elf32_External_Rel); + } + + return TRUE; +} + +/* Find any dynamic relocs that apply to read-only sections. */ + +static bfd_boolean +readonly_dynrelocs (h, inf) + struct elf_link_hash_entry *h; + PTR inf; +{ + struct elf_i386_link_hash_entry *eh; + struct elf_i386_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_i386_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 +elf_i386_size_dynamic_sections (output_bfd, info) + bfd *output_bfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; +{ + struct elf_i386_link_hash_table *htab; + bfd *dynobj; + asection *s; + bfd_boolean relocs; + bfd *ibfd; + + htab = elf_i386_hash_table (info); + dynobj = htab->elf.dynobj; + if (dynobj == NULL) + abort (); + + if (htab->elf.dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (! info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + if (s == NULL) + abort (); + s->_raw_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; + char *local_tls_type; + 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_i386_dyn_relocs *p; + + for (p = *((struct elf_i386_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->_raw_size += p->count * sizeof (Elf32_External_Rel); + 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; + local_tls_type = elf_i386_local_got_tls_type (ibfd); + s = htab->sgot; + srel = htab->srelgot; + for (; local_got < end_local_got; ++local_got, ++local_tls_type) + { + if (*local_got > 0) + { + *local_got = s->_raw_size; + s->_raw_size += 4; + if (*local_tls_type == GOT_TLS_GD + || *local_tls_type == GOT_TLS_IE_BOTH) + s->_raw_size += 4; + if (info->shared + || *local_tls_type == GOT_TLS_GD + || (*local_tls_type & GOT_TLS_IE)) + { + if (*local_tls_type == GOT_TLS_IE_BOTH) + srel->_raw_size += 2 * sizeof (Elf32_External_Rel); + else + srel->_raw_size += sizeof (Elf32_External_Rel); + } + } + else + *local_got = (bfd_vma) -1; + } + } + + if (htab->tls_ldm_got.refcount > 0) + { + /* Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM + relocs. */ + htab->tls_ldm_got.offset = htab->sgot->_raw_size; + htab->sgot->_raw_size += 8; + htab->srelgot->_raw_size += sizeof (Elf32_External_Rel); + } + else + htab->tls_ldm_got.offset = -1; + + /* Allocate global sym .plt and .got entries, and space for global + sym dynamic relocs. */ + elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) 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) + { + /* Strip this section if we don't need it; see the + comment below. */ + } + else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0) + { + if (s->_raw_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->_raw_size == 0) + { + /* If we don't need this section, strip it from the + output file. This is mostly to handle .rel.bss and + .rel.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. */ + + _bfd_strip_section_from_output (info, s); + 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_386_NONE reloc instead + of garbage. */ + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); + if (s->contents == NULL) + return FALSE; + } + + if (htab->elf.dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in elf_i386_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_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) + + if (! info->shared) + { + if (!add_dynamic_entry (DT_DEBUG, 0)) + return FALSE; + } + + if (htab->splt->_raw_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)) + return FALSE; + } + + if (relocs) + { + if (!add_dynamic_entry (DT_REL, 0) + || !add_dynamic_entry (DT_RELSZ, 0) + || !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel))) + 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->elf, readonly_dynrelocs, + (PTR) info); + + if ((info->flags & DF_TEXTREL) != 0) + { + if (!add_dynamic_entry (DT_TEXTREL, 0)) + return FALSE; + } + } + } +#undef add_dynamic_entry + + return TRUE; +} + +/* Set the correct type for an x86 ELF section. We do this by the + section name, which is a hack, but ought to work. */ + +static bfd_boolean +elf_i386_fake_sections (abfd, hdr, sec) + bfd *abfd ATTRIBUTE_UNUSED; + Elf_Internal_Shdr *hdr; + asection *sec; +{ + register const char *name; + + name = bfd_get_section_name (abfd, sec); + + /* This is an ugly, but unfortunately necessary hack that is + needed when producing EFI binaries on x86. It tells + elf.c:elf_fake_sections() not to consider ".reloc" as a section + containing ELF relocation info. We need this hack in order to + be able to generate ELF binaries that can be translated into + EFI applications (which are essentially COFF objects). Those + files contain a COFF ".reloc" section inside an ELFNN object, + which would normally cause BFD to segfault because it would + attempt to interpret this section as containing relocation + entries for section "oc". With this hack enabled, ".reloc" + will be treated as a normal data section, which will avoid the + segfault. However, you won't be able to create an ELFNN binary + with a section named "oc" that needs relocations, but that's + the kind of ugly side-effects you get when detecting section + types based on their names... In practice, this limitation is + unlikely to bite. */ + if (strcmp (name, ".reloc") == 0) + hdr->sh_type = SHT_PROGBITS; + + return TRUE; +} + +/* Return the base VMA address which should be subtracted from real addresses + when resolving @dtpoff relocation. + This is PT_TLS segment p_vaddr. */ + +static bfd_vma +dtpoff_base (info) + struct bfd_link_info *info; +{ + /* If tls_segment is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_segment == NULL) + return 0; + return elf_hash_table (info)->tls_segment->start; +} + +/* Return the relocation value for @tpoff relocation + if STT_TLS virtual address is ADDRESS. */ + +static bfd_vma +tpoff (info, address) + struct bfd_link_info *info; + bfd_vma address; +{ + struct elf_link_tls_segment *tls_segment + = elf_hash_table (info)->tls_segment; + + /* If tls_segment is NULL, we should have signalled an error already. */ + if (tls_segment == NULL) + return 0; + return (align_power (tls_segment->size, tls_segment->align) + + tls_segment->start - address); +} + +/* Relocate an i386 ELF section. */ + +static bfd_boolean +elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + 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; +{ + struct elf_i386_link_hash_table *htab; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + htab = elf_i386_hash_table (info); + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + local_got_offsets = elf_local_got_offsets (input_bfd); + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + unsigned int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma off; + bfd_vma relocation; + bfd_boolean unresolved_reloc; + bfd_reloc_status_type r; + unsigned int indx; + int tls_type; + + r_type = ELF32_R_TYPE (rel->r_info); + if (r_type == (int) R_386_GNU_VTINHERIT + || r_type == (int) R_386_GNU_VTENTRY) + continue; + + if ((indx = (unsigned) r_type) >= R_386_standard + && ((indx = r_type - R_386_ext_offset) - R_386_standard + >= R_386_ext - R_386_standard) + && ((indx = r_type - R_386_tls_offset) - R_386_ext + >= R_386_tls - R_386_ext)) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + howto = elf_howto_table + indx; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (info->relocateable) + { + bfd_vma val; + bfd_byte *where; + + /* 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 (r_symndx >= symtab_hdr->sh_info) + continue; + + sym = local_syms + r_symndx; + if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) + continue; + + sec = local_sections[r_symndx]; + val = sec->output_offset; + if (val == 0) + continue; + + where = contents + rel->r_offset; + switch (howto->size) + { + /* FIXME: overflow checks. */ + case 0: + val += bfd_get_8 (input_bfd, where); + bfd_put_8 (input_bfd, val, where); + break; + case 1: + val += bfd_get_16 (input_bfd, where); + bfd_put_16 (input_bfd, val, where); + break; + case 2: + val += bfd_get_32 (input_bfd, where); + bfd_put_32 (input_bfd, val, where); + break; + default: + abort (); + } + continue; + } + + /* This is a final link. */ + h = NULL; + sym = NULL; + sec = NULL; + unresolved_reloc = FALSE; + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sec = local_sections[r_symndx]; + relocation = (sec->output_section->vma + + sec->output_offset + + sym->st_value); + if ((sec->flags & SEC_MERGE) + && ELF_ST_TYPE (sym->st_info) == STT_SECTION) + { + asection *msec; + bfd_vma addend; + bfd_byte *where = contents + rel->r_offset; + + switch (howto->size) + { + case 0: + addend = bfd_get_8 (input_bfd, where); + if (howto->pc_relative) + { + addend = (addend ^ 0x80) - 0x80; + addend += 1; + } + break; + case 1: + addend = bfd_get_16 (input_bfd, where); + if (howto->pc_relative) + { + addend = (addend ^ 0x8000) - 0x8000; + addend += 2; + } + break; + case 2: + addend = bfd_get_32 (input_bfd, where); + if (howto->pc_relative) + { + addend = (addend ^ 0x80000000) - 0x80000000; + addend += 4; + } + break; + default: + abort (); + } + + msec = sec; + addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); + addend -= relocation; + addend += msec->output_section->vma + msec->output_offset; + + switch (howto->size) + { + case 0: + /* FIXME: overflow checks. */ + if (howto->pc_relative) + addend -= 1; + bfd_put_8 (input_bfd, addend, where); + break; + case 1: + if (howto->pc_relative) + addend -= 2; + bfd_put_16 (input_bfd, addend, where); + break; + case 2: + if (howto->pc_relative) + addend -= 4; + bfd_put_32 (input_bfd, addend, where); + break; + } + } + } + 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; + + relocation = 0; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + if (sec->output_section == NULL) + /* Set a flag that will be cleared later if we find a + relocation value for this symbol. output_section + is typically NULL for symbols satisfied by a shared + library. */ + unresolved_reloc = TRUE; + else + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + ; + else if (info->shared + && !info->no_undefined + && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) + ; + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset, + (!info->shared || info->no_undefined + || ELF_ST_VISIBILITY (h->other))))) + return FALSE; + } + } + + switch (r_type) + { + case R_386_GOT32: + /* Relocation is to the entry for this symbol in the global + offset table. */ + if (htab->sgot == NULL) + abort (); + + if (h != NULL) + { + bfd_boolean dyn; + + off = h->got.offset; + dyn = htab->elf.dynamic_sections_created; + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + || (info->shared + && (info->symbolic + || h->dynindx == -1 + || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)) + && (h->elf_link_hash_flags & ELF_LINK_HASH_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 .rel.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, + htab->sgot->contents + off); + h->got.offset |= 1; + } + } + else + unresolved_reloc = FALSE; + } + else + { + if (local_got_offsets == NULL) + abort (); + + 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 generated the necessary reloc. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_32 (output_bfd, relocation, + htab->sgot->contents + off); + + if (info->shared) + { + asection *s; + Elf_Internal_Rela outrel; + bfd_byte *loc; + + s = htab->srelgot; + if (s == NULL) + abort (); + + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + loc = s->contents; + loc += s->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + } + + local_got_offsets[r_symndx] |= 1; + } + } + + if (off >= (bfd_vma) -2) + abort (); + + relocation = htab->sgot->output_offset + off; + break; + + case R_386_GOTOFF: + /* Relocation is relative to the start of the global offset + table. */ + + /* Note that sgot->output_offset is not involved in this + calculation. We always want the start of .got. If we + defined _GLOBAL_OFFSET_TABLE in a different way, as is + permitted by the ABI, we might have to change this + calculation. */ + relocation -= htab->sgot->output_section->vma; + break; + + case R_386_GOTPC: + /* Use global offset table as symbol value. */ + relocation = htab->sgot->output_section->vma; + unresolved_reloc = FALSE; + break; + + case R_386_PLT32: + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + + /* Resolve a PLT32 reloc against a local symbol directly, + without using the procedure linkage table. */ + if (h == NULL) + break; + + if (h->plt.offset == (bfd_vma) -1 + || htab->splt == NULL) + { + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + break; + } + + relocation = (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset); + unresolved_reloc = FALSE; + break; + + case R_386_32: + case R_386_PC32: + /* r_symndx will be zero only for relocs against symbols + from removed linkonce sections, or sections discarded by + a linker script. */ + if (r_symndx == 0 + || (input_section->flags & SEC_ALLOC) == 0) + break; + + if ((info->shared + && (r_type != R_386_PC32 + || (h != NULL + && h->dynindx != -1 + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || (ELIMINATE_COPY_RELOCS + && !info->shared + && h != NULL + && h->dynindx != -1 + && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && (((h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0) + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined))) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + bfd_boolean skip, relocate; + asection *sreloc; + + /* When generating a shared object, these relocations + are copied into the output file to be resolved at run + time. */ + + 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 (h != NULL + && h->dynindx != -1 + && (r_type == R_386_PC32 + || !info->shared + || !info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + else + { + /* This symbol is local, or marked to become local. */ + relocate = TRUE; + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + } + + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc == NULL) + abort (); + + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + + /* 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_386_TLS_IE: + if (info->shared) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + asection *sreloc; + + outrel.r_offset = rel->r_offset + + input_section->output_section->vma + + input_section->output_offset; + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc == NULL) + abort (); + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + } + /* Fall through */ + + case R_386_TLS_GD: + case R_386_TLS_IE_32: + case R_386_TLS_GOTIE: + r_type = elf_i386_tls_transition (info, r_type, h == NULL); + tls_type = GOT_UNKNOWN; + if (h == NULL && local_got_offsets) + tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx]; + else if (h != NULL) + { + tls_type = elf_i386_hash_entry(h)->tls_type; + if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE)) + r_type = R_386_TLS_LE_32; + } + if (tls_type == GOT_TLS_IE) + tls_type = GOT_TLS_IE_NEG; + if (r_type == R_386_TLS_GD) + { + if (tls_type == GOT_TLS_IE_POS) + r_type = R_386_TLS_GOTIE; + else if (tls_type & GOT_TLS_IE) + r_type = R_386_TLS_IE_32; + } + + if (r_type == R_386_TLS_LE_32) + { + BFD_ASSERT (! unresolved_reloc); + if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD) + { + unsigned int val, type; + bfd_vma roff; + + /* GD->LE transition. */ + BFD_ASSERT (rel->r_offset >= 2); + type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); + BFD_ASSERT (type == 0x8d || type == 0x04); + BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size); + BFD_ASSERT (bfd_get_8 (input_bfd, + contents + rel->r_offset + 4) + == 0xe8); + BFD_ASSERT (rel + 1 < relend); + BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32); + roff = rel->r_offset + 5; + val = bfd_get_8 (input_bfd, + contents + rel->r_offset - 1); + if (type == 0x04) + { + /* leal foo(,%reg,1), %eax; call ___tls_get_addr + Change it into: + movl %gs:0, %eax; subl $foo@tpoff, %eax + (6 byte form of subl). */ + BFD_ASSERT (rel->r_offset >= 3); + BFD_ASSERT (bfd_get_8 (input_bfd, + contents + rel->r_offset - 3) + == 0x8d); + BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3)); + memcpy (contents + rel->r_offset - 3, + "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); + } + else + { + BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4); + if (rel->r_offset + 10 <= input_section->_raw_size + && bfd_get_8 (input_bfd, + contents + rel->r_offset + 9) == 0x90) + { + /* leal foo(%reg), %eax; call ___tls_get_addr; nop + Change it into: + movl %gs:0, %eax; subl $foo@tpoff, %eax + (6 byte form of subl). */ + memcpy (contents + rel->r_offset - 2, + "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); + roff = rel->r_offset + 6; + } + else + { + /* leal foo(%reg), %eax; call ___tls_get_addr + Change it into: + movl %gs:0, %eax; subl $foo@tpoff, %eax + (5 byte form of subl). */ + memcpy (contents + rel->r_offset - 2, + "\x65\xa1\0\0\0\0\x2d\0\0\0", 11); + } + } + bfd_put_32 (output_bfd, tpoff (info, relocation), + contents + roff); + /* Skip R_386_PLT32. */ + rel++; + continue; + } + else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE) + { + unsigned int val, type; + + /* IE->LE transition: + Originally it can be one of: + movl foo, %eax + movl foo, %reg + addl foo, %reg + We change it into: + movl $foo, %eax + movl $foo, %reg + addl $foo, %reg. */ + BFD_ASSERT (rel->r_offset >= 1); + val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); + BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size); + if (val == 0xa1) + { + /* movl foo, %eax. */ + bfd_put_8 (output_bfd, 0xb8, contents + rel->r_offset - 1); + } + else + { + BFD_ASSERT (rel->r_offset >= 2); + type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); + switch (type) + { + case 0x8b: + /* movl */ + BFD_ASSERT ((val & 0xc7) == 0x05); + bfd_put_8 (output_bfd, 0xc7, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, + 0xc0 | ((val >> 3) & 7), + contents + rel->r_offset - 1); + break; + case 0x03: + /* addl */ + BFD_ASSERT ((val & 0xc7) == 0x05); + bfd_put_8 (output_bfd, 0x81, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, + 0xc0 | ((val >> 3) & 7), + contents + rel->r_offset - 1); + break; + default: + BFD_FAIL (); + break; + } + } + bfd_put_32 (output_bfd, -tpoff (info, relocation), + contents + rel->r_offset); + continue; + } + else + { + unsigned int val, type; + + /* {IE_32,GOTIE}->LE transition: + Originally it can be one of: + subl foo(%reg1), %reg2 + movl foo(%reg1), %reg2 + addl foo(%reg1), %reg2 + We change it into: + subl $foo, %reg2 + movl $foo, %reg2 (6 byte form) + addl $foo, %reg2. */ + BFD_ASSERT (rel->r_offset >= 2); + type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); + val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); + BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size); + BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4); + if (type == 0x8b) + { + /* movl */ + bfd_put_8 (output_bfd, 0xc7, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), + contents + rel->r_offset - 1); + } + else if (type == 0x2b) + { + /* subl */ + bfd_put_8 (output_bfd, 0x81, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, 0xe8 | ((val >> 3) & 7), + contents + rel->r_offset - 1); + } + else if (type == 0x03) + { + /* addl */ + bfd_put_8 (output_bfd, 0x81, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), + contents + rel->r_offset - 1); + } + else + BFD_FAIL (); + if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTIE) + bfd_put_32 (output_bfd, -tpoff (info, relocation), + contents + rel->r_offset); + else + bfd_put_32 (output_bfd, tpoff (info, relocation), + contents + rel->r_offset); + continue; + } + } + + if (htab->sgot == NULL) + abort (); + + if (h != NULL) + off = h->got.offset; + else + { + if (local_got_offsets == NULL) + abort (); + + off = local_got_offsets[r_symndx]; + } + + if ((off & 1) != 0) + off &= ~1; + else + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + int dr_type, indx; + + if (htab->srelgot == NULL) + abort (); + + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + off); + + indx = h && h->dynindx != -1 ? h->dynindx : 0; + if (r_type == R_386_TLS_GD) + dr_type = R_386_TLS_DTPMOD32; + else if (tls_type == GOT_TLS_IE_POS) + dr_type = R_386_TLS_TPOFF; + else + dr_type = R_386_TLS_TPOFF32; + if (dr_type == R_386_TLS_TPOFF && indx == 0) + bfd_put_32 (output_bfd, relocation - dtpoff_base (info), + htab->sgot->contents + off); + else if (dr_type == R_386_TLS_TPOFF32 && indx == 0) + bfd_put_32 (output_bfd, dtpoff_base (info) - relocation, + htab->sgot->contents + off); + else + bfd_put_32 (output_bfd, 0, + htab->sgot->contents + off); + outrel.r_info = ELF32_R_INFO (indx, dr_type); + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + + if (r_type == R_386_TLS_GD) + { + if (indx == 0) + { + BFD_ASSERT (! unresolved_reloc); + bfd_put_32 (output_bfd, + relocation - dtpoff_base (info), + htab->sgot->contents + off + 4); + } + else + { + bfd_put_32 (output_bfd, 0, + htab->sgot->contents + off + 4); + outrel.r_info = ELF32_R_INFO (indx, + R_386_TLS_DTPOFF32); + outrel.r_offset += 4; + htab->srelgot->reloc_count++; + loc += sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + } + } + else if (tls_type == GOT_TLS_IE_BOTH) + { + bfd_put_32 (output_bfd, + indx == 0 ? relocation - dtpoff_base (info) : 0, + htab->sgot->contents + off + 4); + outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); + outrel.r_offset += 4; + htab->srelgot->reloc_count++; + loc += sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + } + + if (h != NULL) + h->got.offset |= 1; + else + local_got_offsets[r_symndx] |= 1; + } + + if (off >= (bfd_vma) -2) + abort (); + if (r_type == ELF32_R_TYPE (rel->r_info)) + { + relocation = htab->sgot->output_offset + off; + if ((r_type == R_386_TLS_IE || r_type == R_386_TLS_GOTIE) + && tls_type == GOT_TLS_IE_BOTH) + relocation += 4; + if (r_type == R_386_TLS_IE) + relocation += htab->sgot->output_section->vma; + unresolved_reloc = FALSE; + } + else + { + unsigned int val, type; + bfd_vma roff; + + /* GD->IE transition. */ + BFD_ASSERT (rel->r_offset >= 2); + type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); + BFD_ASSERT (type == 0x8d || type == 0x04); + BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size); + BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4) + == 0xe8); + BFD_ASSERT (rel + 1 < relend); + BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32); + roff = rel->r_offset - 3; + val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); + if (type == 0x04) + { + /* leal foo(,%reg,1), %eax; call ___tls_get_addr + Change it into: + movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */ + BFD_ASSERT (rel->r_offset >= 3); + BFD_ASSERT (bfd_get_8 (input_bfd, + contents + rel->r_offset - 3) + == 0x8d); + BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3)); + val >>= 3; + } + else + { + /* leal foo(%reg), %eax; call ___tls_get_addr; nop + Change it into: + movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */ + BFD_ASSERT (rel->r_offset + 10 <= input_section->_raw_size); + BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4); + BFD_ASSERT (bfd_get_8 (input_bfd, + contents + rel->r_offset + 9) + == 0x90); + roff = rel->r_offset - 2; + } + memcpy (contents + roff, + "\x65\xa1\0\0\0\0\x2b\x80\0\0\0", 12); + contents[roff + 7] = 0x80 | (val & 7); + /* If foo is used only with foo@gotntpoff(%reg) and + foo@indntpoff, but not with foo@gottpoff(%reg), change + subl $foo@gottpoff(%reg), %eax + into: + addl $foo@gotntpoff(%reg), %eax. */ + if (r_type == R_386_TLS_GOTIE) + { + contents[roff + 6] = 0x03; + if (tls_type == GOT_TLS_IE_BOTH) + off += 4; + } + bfd_put_32 (output_bfd, htab->sgot->output_offset + off, + contents + roff + 8); + /* Skip R_386_PLT32. */ + rel++; + continue; + } + break; + + case R_386_TLS_LDM: + if (! info->shared) + { + unsigned int val; + + /* LD->LE transition: + Ensure it is: + leal foo(%reg), %eax; call ___tls_get_addr. + We change it into: + movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */ + BFD_ASSERT (rel->r_offset >= 2); + BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2) + == 0x8d); + val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); + BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4); + BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size); + BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4) + == 0xe8); + BFD_ASSERT (rel + 1 < relend); + BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32); + memcpy (contents + rel->r_offset - 2, + "\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11); + /* Skip R_386_PLT32. */ + rel++; + continue; + } + + if (htab->sgot == NULL) + abort (); + + off = htab->tls_ldm_got.offset; + if (off & 1) + off &= ~1; + else + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + + if (htab->srelgot == NULL) + abort (); + + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + off); + + bfd_put_32 (output_bfd, 0, + htab->sgot->contents + off); + bfd_put_32 (output_bfd, 0, + htab->sgot->contents + off + 4); + outrel.r_info = ELF32_R_INFO (0, R_386_TLS_DTPMOD32); + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + htab->tls_ldm_got.offset |= 1; + } + relocation = htab->sgot->output_offset + off; + unresolved_reloc = FALSE; + break; + + case R_386_TLS_LDO_32: + if (info->shared || (input_section->flags & SEC_CODE) == 0) + relocation -= dtpoff_base (info); + else + /* When converting LDO to LE, we must negate. */ + relocation = -tpoff (info, relocation); + break; + + case R_386_TLS_LE_32: + case R_386_TLS_LE: + if (info->shared) + { + Elf_Internal_Rela outrel; + asection *sreloc; + bfd_byte *loc; + int indx; + + outrel.r_offset = rel->r_offset + + input_section->output_section->vma + + input_section->output_offset; + if (h != NULL && h->dynindx != -1) + indx = h->dynindx; + else + indx = 0; + if (r_type == R_386_TLS_LE_32) + outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF32); + else + outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc == NULL) + abort (); + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + if (indx) + continue; + else if (r_type == R_386_TLS_LE_32) + relocation = dtpoff_base (info) - relocation; + else + relocation -= dtpoff_base (info); + } + else if (r_type == R_386_TLS_LE_32) + relocation = tpoff (info, relocation); + else + relocation = -tpoff (info, relocation); + break; + + default: + break; + } + + /* Dynamic relocs are not propagated for SEC_DEBUGGING sections + because such sections are not SEC_ALLOC and thus ld.so will + not process them. */ + if (unresolved_reloc + && !((input_section->flags & SEC_DEBUGGING) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) + { + (*_bfd_error_handler) + (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"), + bfd_archive_filename (input_bfd), + bfd_get_section_name (input_bfd, input_section), + (long) rel->r_offset, + h->root.root.string); + return FALSE; + } + + r = _bfd_final_link_relocate (howto, input_bfd, input_section, + contents, rel->r_offset, + relocation, (bfd_vma) 0); + + if (r != bfd_reloc_ok) + { + 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) + return FALSE; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + + if (r == bfd_reloc_overflow) + { + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return FALSE; + } + else + { + (*_bfd_error_handler) + (_("%s(%s+0x%lx): reloc against `%s': error %d"), + bfd_archive_filename (input_bfd), + bfd_get_section_name (input_bfd, input_section), + (long) rel->r_offset, name, (int) r); + return FALSE; + } + } + } + + return TRUE; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static bfd_boolean +elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + struct elf_i386_link_hash_table *htab; + + htab = elf_i386_hash_table (info); + + if (h->plt.offset != (bfd_vma) -1) + { + bfd_vma plt_index; + bfd_vma got_offset; + Elf_Internal_Rela rel; + bfd_byte *loc; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + + if (h->dynindx == -1 + || htab->splt == NULL + || htab->sgotplt == NULL + || htab->srelplt == NULL) + abort (); + + /* 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) + { + memcpy (htab->splt->contents + h->plt.offset, elf_i386_plt_entry, + PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + got_offset), + htab->splt->contents + h->plt.offset + 2); + } + else + { + memcpy (htab->splt->contents + h->plt.offset, elf_i386_pic_plt_entry, + PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, got_offset, + htab->splt->contents + h->plt.offset + 2); + } + + bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel), + htab->splt->contents + h->plt.offset + 7); + bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE), + htab->splt->contents + h->plt.offset + 12); + + /* Fill in the entry in the global offset table. */ + bfd_put_32 (output_bfd, + (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset + + 6), + htab->sgotplt->contents + got_offset); + + /* Fill in the entry in the .rel.plt section. */ + rel.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + got_offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); + loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. This is a clue + for the dynamic linker, to make function pointer + comparisons work between an application and shared + library. */ + sym->st_shndx = SHN_UNDEF; + } + } + + if (h->got.offset != (bfd_vma) -1 + && elf_i386_hash_entry(h)->tls_type != GOT_TLS_GD + && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE) == 0) + { + Elf_Internal_Rela rel; + bfd_byte *loc; + + /* This symbol has an entry in the global offset table. Set it + up. */ + + if (htab->sgot == NULL || htab->srelgot == NULL) + abort (); + + rel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + + (h->got.offset & ~(bfd_vma) 1)); + + /* If this is a static link, or it is a -Bsymbolic link and the + symbol is defined locally or was forced to be local because + of a version file, we just want to emit a RELATIVE reloc. + 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->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + { + BFD_ASSERT((h->got.offset & 1) != 0); + rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + } + else + { + BFD_ASSERT((h->got.offset & 1) == 0); + bfd_put_32 (output_bfd, (bfd_vma) 0, + htab->sgot->contents + h->got.offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); + } + + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + } + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) + { + Elf_Internal_Rela rel; + bfd_byte *loc; + + /* This symbol needs a copy reloc. Set it up. */ + + if (h->dynindx == -1 + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + || htab->srelbss == NULL) + abort (); + + rel.r_offset = (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset); + rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY); + loc = htab->srelbss->contents; + loc += htab->srelbss->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); + } + + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ 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; +} + +/* Used to decide how to sort relocs in an optimal manner for the + dynamic linker, before writing them out. */ + +static enum elf_reloc_type_class +elf_i386_reloc_type_class (rela) + const Elf_Internal_Rela *rela; +{ + switch ((int) ELF32_R_TYPE (rela->r_info)) + { + case R_386_RELATIVE: + return reloc_class_relative; + case R_386_JUMP_SLOT: + return reloc_class_plt; + case R_386_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} + +/* Finish up the dynamic sections. */ + +static bfd_boolean +elf_i386_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + struct elf_i386_link_hash_table *htab; + bfd *dynobj; + asection *sdyn; + + htab = elf_i386_hash_table (info); + dynobj = htab->elf.dynobj; + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (htab->elf.dynamic_sections_created) + { + Elf32_External_Dyn *dyncon, *dynconend; + + if (sdyn == NULL || htab->sgot == NULL) + abort (); + + dyncon = (Elf32_External_Dyn *) sdyn->contents; + dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_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: + dyn.d_un.d_ptr = htab->sgot->output_section->vma; + break; + + case DT_JMPREL: + s = htab->srelplt; + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; + break; + + case DT_PLTRELSZ: + s = htab->srelplt; + dyn.d_un.d_val = s->_raw_size; + break; + + case DT_RELSZ: + /* My reading of the SVR4 ABI indicates that the + procedure linkage table relocs (DT_JMPREL) should be + included in the overall relocs (DT_REL). This is + what Solaris does. However, UnixWare can not handle + that case. Therefore, we override the DT_RELSZ entry + here to make it not include the JMPREL relocs. */ + s = htab->srelplt; + if (s == NULL) + continue; + dyn.d_un.d_val -= s->_raw_size; + break; + + case DT_REL: + /* We may not be using the standard ELF linker script. + If .rel.plt is the first .rel section, we adjust + DT_REL to not include it. */ + s = htab->srelplt; + if (s == NULL) + continue; + if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset) + continue; + dyn.d_un.d_ptr += s->_raw_size; + break; + } + + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + } + + /* Fill in the first entry in the procedure linkage table. */ + if (htab->splt && htab->splt->_raw_size > 0) + { + if (info->shared) + memcpy (htab->splt->contents, + elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE); + else + { + memcpy (htab->splt->contents, + elf_i386_plt0_entry, PLT_ENTRY_SIZE); + bfd_put_32 (output_bfd, + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + 4), + htab->splt->contents + 2); + bfd_put_32 (output_bfd, + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + 8), + htab->splt->contents + 8); + } + + /* UnixWare sets the entsize of .plt to 4, although that doesn't + really seem like the right value. */ + elf_section_data (htab->splt->output_section) + ->this_hdr.sh_entsize = 4; + } + } + + if (htab->sgotplt) + { + /* Fill in the first three entries in the global offset table. */ + if (htab->sgotplt->_raw_size > 0) + { + bfd_put_32 (output_bfd, + (sdyn == NULL ? (bfd_vma) 0 + : sdyn->output_section->vma + sdyn->output_offset), + htab->sgotplt->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 8); + } + + elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize = 4; + } + return TRUE; +} + +#define TARGET_LITTLE_SYM bfd_elf32_i386_vec +#define TARGET_LITTLE_NAME "elf32-i386" +#define ELF_ARCH bfd_arch_i386 +#define ELF_MACHINE_CODE EM_386 +#define ELF_MAXPAGESIZE 0x1000 + +#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_plt_header_size PLT_ENTRY_SIZE + +/* Support RELA for objdump of prelink objects. */ +#define elf_info_to_howto elf_i386_info_to_howto_rel +#define elf_info_to_howto_rel elf_i386_info_to_howto_rel + +#define bfd_elf32_mkobject elf_i386_mkobject +#define elf_backend_object_p elf_i386_object_p + +#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_reloc_type_lookup elf_i386_reloc_type_lookup + +#define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol +#define elf_backend_check_relocs elf_i386_check_relocs +#define elf_backend_copy_indirect_symbol elf_i386_copy_indirect_symbol +#define elf_backend_create_dynamic_sections elf_i386_create_dynamic_sections +#define elf_backend_fake_sections elf_i386_fake_sections +#define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections +#define elf_backend_finish_dynamic_symbol elf_i386_finish_dynamic_symbol +#define elf_backend_gc_mark_hook elf_i386_gc_mark_hook +#define elf_backend_gc_sweep_hook elf_i386_gc_sweep_hook +#define elf_backend_grok_prstatus elf_i386_grok_prstatus +#define elf_backend_grok_psinfo elf_i386_grok_psinfo +#define elf_backend_reloc_type_class elf_i386_reloc_type_class +#define elf_backend_relocate_section elf_i386_relocate_section +#define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections + +#include "elf32-target.h" + +/* FreeBSD support. */ + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM bfd_elf32_i386_freebsd_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf32-i386-freebsd" + +/* The kernel recognizes executables as valid only if they carry a + "FreeBSD" label in the ELF header. So we put this label on all + executables and (for simplicity) also all other object files. */ + +static void elf_i386_post_process_headers + PARAMS ((bfd *, struct bfd_link_info *)); + +static void +elf_i386_post_process_headers (abfd, link_info) + bfd *abfd; + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; +{ + Elf_Internal_Ehdr *i_ehdrp; + + i_ehdrp = elf_elfheader (abfd); + + /* Put an ABI label supported by FreeBSD >= 4.1. */ + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; +#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); +#endif +} + +#undef elf_backend_post_process_headers +#define elf_backend_post_process_headers elf_i386_post_process_headers +#undef elf32_bed +#define elf32_bed elf32_i386_fbsd_bed + +#include "elf32-target.h" diff --git a/contrib/binutils-2.14/bfd/elf32.c b/contrib/binutils-2.14/bfd/elf32.c new file mode 100644 index 0000000000..bfadd5cb01 --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf32.c @@ -0,0 +1,22 @@ +/* ELF 32-bit executable support for BFD. + Copyright 1993, 2001 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 32 + +#include "elfcode.h" diff --git a/contrib/binutils-2.14/bfd/elf64-gen.c b/contrib/binutils-2.14/bfd/elf64-gen.c new file mode 100644 index 0000000000..590456ccbf --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf64-gen.c @@ -0,0 +1,105 @@ +/* Generic support for 64-bit ELF + Copyright 1993, 1995, 1998, 1999, 2001, 2002 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "elf-bfd.h" + +/* This does not include any relocation information, but should be + good enough for GDB or objdump to read the file. */ + +static reloc_howto_type dummy = + HOWTO (0, /* type */ + 0, /* rightshift */ + 0, /* size (0 = byte, 1 = short, 2 = long) */ + 0, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + NULL, /* special_function */ + "UNKNOWN", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0, /* dst_mask */ + FALSE); /* pcrel_offset */ + +static void elf_generic_info_to_howto + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); +static void elf_generic_info_to_howto_rel + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); +static bfd_boolean elf64_generic_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); + +static void +elf_generic_info_to_howto (abfd, bfd_reloc, elf_reloc) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *bfd_reloc; + Elf_Internal_Rela *elf_reloc ATTRIBUTE_UNUSED; +{ + bfd_reloc->howto = &dummy; +} + +static void +elf_generic_info_to_howto_rel (abfd, bfd_reloc, elf_reloc) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *bfd_reloc; + Elf_Internal_Rela *elf_reloc ATTRIBUTE_UNUSED; +{ + bfd_reloc->howto = &dummy; +} + +static bfd_boolean +elf64_generic_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + asection *o; + + /* Check if there are any relocations. */ + for (o = abfd->sections; o != NULL; o = o->next) + if ((o->flags & SEC_RELOC) != 0) + { + Elf_Internal_Ehdr *ehdrp; + + ehdrp = elf_elfheader (abfd); + (*_bfd_error_handler) (_("%s: Relocations in generic ELF (EM: %d)"), + bfd_archive_filename (abfd), + ehdrp->e_machine); + + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + return bfd_elf64_bfd_link_add_symbols (abfd, info); +} + +#define TARGET_LITTLE_SYM bfd_elf64_little_generic_vec +#define TARGET_LITTLE_NAME "elf64-little" +#define TARGET_BIG_SYM bfd_elf64_big_generic_vec +#define TARGET_BIG_NAME "elf64-big" +#define ELF_ARCH bfd_arch_unknown +#define ELF_MACHINE_CODE EM_NONE +#define ELF_MAXPAGESIZE 0x1 +#define bfd_elf64_bfd_reloc_type_lookup bfd_default_reloc_type_lookup +#define bfd_elf64_bfd_link_add_symbols elf64_generic_link_add_symbols +#define elf_info_to_howto elf_generic_info_to_howto +#define elf_info_to_howto_rel elf_generic_info_to_howto_rel + +#include "elf64-target.h" diff --git a/contrib/binutils-2.14/bfd/elf64-x86-64.c b/contrib/binutils-2.14/bfd/elf64-x86-64.c new file mode 100644 index 0000000000..5ed6b518db --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf64-x86-64.c @@ -0,0 +1,2947 @@ +/* X86-64 specific support for 64-bit ELF + Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by Jan Hubicka . + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" + +#include "elf/x86-64.h" + +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ +#define MINUS_ONE (~ (bfd_vma) 0) + +/* The relocation "howto" table. Order of fields: + type, size, bitsize, pc_relative, complain_on_overflow, + special_function, name, partial_inplace, src_mask, dst_pack, pcrel_offset. */ +static reloc_howto_type x86_64_elf_howto_table[] = +{ + HOWTO(R_X86_64_NONE, 0, 0, 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, + bfd_elf_generic_reloc, "R_X86_64_64", FALSE, MINUS_ONE, MINUS_ONE, + FALSE), + HOWTO(R_X86_64_PC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_PC32", FALSE, 0xffffffff, 0xffffffff, + TRUE), + HOWTO(R_X86_64_GOT32, 0, 2, 32, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOT32", FALSE, 0xffffffff, 0xffffffff, + FALSE), + HOWTO(R_X86_64_PLT32, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_PLT32", FALSE, 0xffffffff, 0xffffffff, + TRUE), + HOWTO(R_X86_64_COPY, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_COPY", FALSE, 0xffffffff, 0xffffffff, + FALSE), + HOWTO(R_X86_64_GLOB_DAT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_GLOB_DAT", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + HOWTO(R_X86_64_JUMP_SLOT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_JUMP_SLOT", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + HOWTO(R_X86_64_RELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_RELATIVE", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + HOWTO(R_X86_64_GOTPCREL, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPCREL", FALSE, 0xffffffff, + 0xffffffff, TRUE), + HOWTO(R_X86_64_32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned, + bfd_elf_generic_reloc, "R_X86_64_32", FALSE, 0xffffffff, 0xffffffff, + FALSE), + HOWTO(R_X86_64_32S, 0, 2, 32, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_32S", FALSE, 0xffffffff, 0xffffffff, + FALSE), + HOWTO(R_X86_64_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_16", FALSE, 0xffff, 0xffff, FALSE), + HOWTO(R_X86_64_PC16,0, 1, 16, TRUE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_PC16", FALSE, 0xffff, 0xffff, TRUE), + HOWTO(R_X86_64_8, 0, 0, 8, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_8", FALSE, 0xff, 0xff, FALSE), + HOWTO(R_X86_64_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_PC8", FALSE, 0xff, 0xff, TRUE), + HOWTO(R_X86_64_DTPMOD64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_DTPMOD64", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + HOWTO(R_X86_64_DTPOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_DTPOFF64", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + HOWTO(R_X86_64_TPOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_TPOFF64", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + HOWTO(R_X86_64_TLSGD, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_TLSGD", FALSE, 0xffffffff, + 0xffffffff, TRUE), + HOWTO(R_X86_64_TLSLD, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_TLSLD", FALSE, 0xffffffff, + 0xffffffff, TRUE), + HOWTO(R_X86_64_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_X86_64_DTPOFF32", FALSE, 0xffffffff, + 0xffffffff, FALSE), + HOWTO(R_X86_64_GOTTPOFF, 0, 2, 32, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTTPOFF", FALSE, 0xffffffff, + 0xffffffff, TRUE), + HOWTO(R_X86_64_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_TPOFF32", FALSE, 0xffffffff, + 0xffffffff, FALSE), + +/* GNU extension to record C++ vtable hierarchy. */ + HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, FALSE, 0, complain_overflow_dont, + NULL, "R_X86_64_GNU_VTINHERIT", FALSE, 0, 0, FALSE), + +/* GNU extension to record C++ vtable member usage. */ + HOWTO (R_X86_64_GNU_VTENTRY, 0, 4, 0, FALSE, 0, complain_overflow_dont, + _bfd_elf_rel_vtable_reloc_fn, "R_X86_64_GNU_VTENTRY", FALSE, 0, 0, + FALSE) +}; + +/* Map BFD relocs to the x86_64 elf relocs. */ +struct elf_reloc_map +{ + bfd_reloc_code_real_type bfd_reloc_val; + unsigned char elf_reloc_val; +}; + +static const struct elf_reloc_map x86_64_reloc_map[] = +{ + { BFD_RELOC_NONE, R_X86_64_NONE, }, + { BFD_RELOC_64, R_X86_64_64, }, + { BFD_RELOC_32_PCREL, R_X86_64_PC32, }, + { BFD_RELOC_X86_64_GOT32, R_X86_64_GOT32,}, + { BFD_RELOC_X86_64_PLT32, R_X86_64_PLT32,}, + { BFD_RELOC_X86_64_COPY, R_X86_64_COPY, }, + { BFD_RELOC_X86_64_GLOB_DAT, R_X86_64_GLOB_DAT, }, + { BFD_RELOC_X86_64_JUMP_SLOT, R_X86_64_JUMP_SLOT, }, + { BFD_RELOC_X86_64_RELATIVE, R_X86_64_RELATIVE, }, + { BFD_RELOC_X86_64_GOTPCREL, R_X86_64_GOTPCREL, }, + { BFD_RELOC_32, R_X86_64_32, }, + { BFD_RELOC_X86_64_32S, R_X86_64_32S, }, + { BFD_RELOC_16, R_X86_64_16, }, + { BFD_RELOC_16_PCREL, R_X86_64_PC16, }, + { BFD_RELOC_8, R_X86_64_8, }, + { BFD_RELOC_8_PCREL, R_X86_64_PC8, }, + { BFD_RELOC_X86_64_DTPMOD64, R_X86_64_DTPMOD64, }, + { BFD_RELOC_X86_64_DTPOFF64, R_X86_64_DTPOFF64, }, + { BFD_RELOC_X86_64_TPOFF64, R_X86_64_TPOFF64, }, + { BFD_RELOC_X86_64_TLSGD, R_X86_64_TLSGD, }, + { BFD_RELOC_X86_64_TLSLD, R_X86_64_TLSLD, }, + { BFD_RELOC_X86_64_DTPOFF32, R_X86_64_DTPOFF32, }, + { BFD_RELOC_X86_64_GOTTPOFF, R_X86_64_GOTTPOFF, }, + { BFD_RELOC_X86_64_TPOFF32, R_X86_64_TPOFF32, }, + { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, + { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, +}; + +static reloc_howto_type *elf64_x86_64_reloc_type_lookup + PARAMS ((bfd *, bfd_reloc_code_real_type)); +static void elf64_x86_64_info_to_howto + PARAMS ((bfd *, arelent *, Elf_Internal_Rela *)); +static bfd_boolean elf64_x86_64_grok_prstatus + PARAMS ((bfd *, Elf_Internal_Note *)); +static bfd_boolean elf64_x86_64_grok_psinfo + PARAMS ((bfd *, Elf_Internal_Note *)); +static struct bfd_link_hash_table *elf64_x86_64_link_hash_table_create + PARAMS ((bfd *)); +static int elf64_x86_64_tls_transition + PARAMS ((struct bfd_link_info *, int, int)); +static bfd_boolean elf64_x86_64_mkobject + PARAMS((bfd *)); +static bfd_boolean elf64_x86_64_elf_object_p PARAMS ((bfd *abfd)); +static bfd_boolean create_got_section + PARAMS((bfd *, struct bfd_link_info *)); +static bfd_boolean elf64_x86_64_create_dynamic_sections + PARAMS((bfd *, struct bfd_link_info *)); +static void elf64_x86_64_copy_indirect_symbol + PARAMS ((struct elf_backend_data *, struct elf_link_hash_entry *, + struct elf_link_hash_entry *)); +static bfd_boolean elf64_x86_64_check_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection *sec, + const Elf_Internal_Rela *)); +static asection *elf64_x86_64_gc_mark_hook + PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *, Elf_Internal_Sym *)); + +static bfd_boolean elf64_x86_64_gc_sweep_hook + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); + +static struct bfd_hash_entry *link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static bfd_boolean elf64_x86_64_adjust_dynamic_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); + +static bfd_boolean allocate_dynrelocs + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean readonly_dynrelocs + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf64_x86_64_size_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_vma dtpoff_base + PARAMS ((struct bfd_link_info *)); +static bfd_vma tpoff + PARAMS ((struct bfd_link_info *, bfd_vma)); +static bfd_boolean elf64_x86_64_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); +static bfd_boolean elf64_x86_64_finish_dynamic_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + Elf_Internal_Sym *sym)); +static bfd_boolean elf64_x86_64_finish_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); +static enum elf_reloc_type_class elf64_x86_64_reloc_type_class + PARAMS ((const Elf_Internal_Rela *)); + +/* Given a BFD reloc type, return a HOWTO structure. */ +static reloc_howto_type * +elf64_x86_64_reloc_type_lookup (abfd, code) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_reloc_code_real_type code; +{ + unsigned int i; + for (i = 0; i < sizeof (x86_64_reloc_map) / sizeof (struct elf_reloc_map); + i++) + { + if (x86_64_reloc_map[i].bfd_reloc_val == code) + return &x86_64_elf_howto_table[i]; + } + return 0; +} + +/* Given an x86_64 ELF reloc type, fill in an arelent structure. */ + +static void +elf64_x86_64_info_to_howto (abfd, cache_ptr, dst) + bfd *abfd ATTRIBUTE_UNUSED; + arelent *cache_ptr; + Elf_Internal_Rela *dst; +{ + unsigned r_type, i; + + r_type = ELF64_R_TYPE (dst->r_info); + if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT) + { + BFD_ASSERT (r_type <= (unsigned int) R_X86_64_TPOFF32); + i = r_type; + } + else + { + BFD_ASSERT (r_type < (unsigned int) R_X86_64_max); + i = r_type - ((unsigned int) R_X86_64_GNU_VTINHERIT - R_X86_64_TPOFF32 - 1); + } + cache_ptr->howto = &x86_64_elf_howto_table[i]; + BFD_ASSERT (r_type == cache_ptr->howto->type); +} + +/* Support for core dump NOTE sections. */ +static bfd_boolean +elf64_x86_64_grok_prstatus (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + int offset; + size_t raw_size; + + switch (note->descsz) + { + default: + return FALSE; + + case 336: /* sizeof(istruct elf_prstatus) on Linux/x86_64 */ + /* 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 + 32); + + /* pr_reg */ + offset = 112; + raw_size = 216; + + break; + } + + /* Make a ".reg/999" section. */ + return _bfd_elfcore_make_pseudosection (abfd, ".reg", + raw_size, note->descpos + offset); +} + +static bfd_boolean +elf64_x86_64_grok_psinfo (abfd, note) + bfd *abfd; + Elf_Internal_Note *note; +{ + switch (note->descsz) + { + default: + return FALSE; + + case 136: /* sizeof(struct elf_prpsinfo) on Linux/x86_64 */ + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); + } + + /* 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; +} + +/* Functions for the x86-64 ELF linker. */ + +/* The name of the dynamic interpreter. This is put in the .interp + section. */ + +#define ELF_DYNAMIC_INTERPRETER "/lib/ld64.so.1" + +/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid + copying dynamic variables from a shared lib into an app's dynbss + section, and instead use a dynamic relocation to point into the + shared lib. */ +#define ELIMINATE_COPY_RELOCS 1 + +/* The size in bytes of an entry in the global offset table. */ + +#define GOT_ENTRY_SIZE 8 + +/* The size in bytes of an entry in the procedure linkage table. */ + +#define PLT_ENTRY_SIZE 16 + +/* The first entry in a procedure linkage table looks like this. See the + SVR4 ABI i386 supplement and the x86-64 ABI to see how this works. */ + +static const bfd_byte elf64_x86_64_plt0_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ + 0xff, 0x25, 16, 0, 0, 0, /* jmpq *GOT+16(%rip) */ + 0x90, 0x90, 0x90, 0x90 /* pad out to 16 bytes with nops. */ +}; + +/* Subsequent entries in a procedure linkage table look like this. */ + +static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] = +{ + 0xff, 0x25, /* jmpq *name@GOTPC(%rip) */ + 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ + 0x68, /* pushq immediate */ + 0, 0, 0, 0, /* replaced with index into relocation table. */ + 0xe9, /* jmp relative */ + 0, 0, 0, 0 /* replaced with offset to start of .plt0. */ +}; + +/* The x86-64 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 elf64_x86_64_dyn_relocs +{ + /* Next section. */ + struct elf64_x86_64_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; +}; + +/* x86-64 ELF linker hash entry. */ + +struct elf64_x86_64_link_hash_entry +{ + struct elf_link_hash_entry elf; + + /* Track dynamic relocs copied for this symbol. */ + struct elf64_x86_64_dyn_relocs *dyn_relocs; + +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_GD 2 +#define GOT_TLS_IE 3 + unsigned char tls_type; +}; + +#define elf64_x86_64_hash_entry(ent) \ + ((struct elf64_x86_64_link_hash_entry *)(ent)) + +struct elf64_x86_64_obj_tdata +{ + struct elf_obj_tdata root; + + /* tls_type for each local got entry. */ + char *local_got_tls_type; +}; + +#define elf64_x86_64_tdata(abfd) \ + ((struct elf64_x86_64_obj_tdata *) (abfd)->tdata.any) + +#define elf64_x86_64_local_got_tls_type(abfd) \ + (elf64_x86_64_tdata (abfd)->local_got_tls_type) + + +/* x86-64 ELF linker hash table. */ + +struct elf64_x86_64_link_hash_table +{ + struct elf_link_hash_table elf; + + /* Short-cuts to get to dynamic linker sections. */ + asection *sgot; + asection *sgotplt; + asection *srelgot; + asection *splt; + asection *srelplt; + asection *sdynbss; + asection *srelbss; + + union { + bfd_signed_vma refcount; + bfd_vma offset; + } tls_ld_got; + + /* Small local sym to section mapping cache. */ + struct sym_sec_cache sym_sec; +}; + +/* Get the x86-64 ELF linker hash table from a link_info structure. */ + +#define elf64_x86_64_hash_table(p) \ + ((struct elf64_x86_64_link_hash_table *) ((p)->hash)) + +/* Create an entry in an x86-64 ELF linker hash table. */ + +static struct bfd_hash_entry * +link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = bfd_hash_allocate (table, + sizeof (struct elf64_x86_64_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = _bfd_elf_link_hash_newfunc (entry, table, string); + if (entry != NULL) + { + struct elf64_x86_64_link_hash_entry *eh; + + eh = (struct elf64_x86_64_link_hash_entry *) entry; + eh->dyn_relocs = NULL; + eh->tls_type = GOT_UNKNOWN; + } + + return entry; +} + +/* Create an X86-64 ELF linker hash table. */ + +static struct bfd_link_hash_table * +elf64_x86_64_link_hash_table_create (abfd) + bfd *abfd; +{ + struct elf64_x86_64_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf64_x86_64_link_hash_table); + + ret = (struct elf64_x86_64_link_hash_table *) bfd_malloc (amt); + if (ret == NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc)) + { + 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_sec.abfd = NULL; + ret->tls_ld_got.refcount = 0; + + return &ret->elf.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 (dynobj, info) + bfd *dynobj; + struct bfd_link_info *info; +{ + struct elf64_x86_64_link_hash_table *htab; + + if (! _bfd_elf_create_got_section (dynobj, info)) + return FALSE; + + htab = elf64_x86_64_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 (); + + htab->srelgot = bfd_make_section (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, 3)) + return FALSE; + return TRUE; +} + +/* 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. */ + +static bfd_boolean +elf64_x86_64_create_dynamic_sections (dynobj, info) + bfd *dynobj; + struct bfd_link_info *info; +{ + struct elf64_x86_64_link_hash_table *htab; + + htab = elf64_x86_64_hash_table (info); + 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 +elf64_x86_64_copy_indirect_symbol (bed, dir, ind) + struct elf_backend_data *bed; + struct elf_link_hash_entry *dir, *ind; +{ + struct elf64_x86_64_link_hash_entry *edir, *eind; + + edir = (struct elf64_x86_64_link_hash_entry *) dir; + eind = (struct elf64_x86_64_link_hash_entry *) ind; + + if (eind->dyn_relocs != NULL) + { + if (edir->dyn_relocs != NULL) + { + struct elf64_x86_64_dyn_relocs **pp; + struct elf64_x86_64_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 elf64_x86_64_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 + && dir->got.refcount <= 0) + { + edir->tls_type = eind->tls_type; + eind->tls_type = GOT_UNKNOWN; + } + + if (ELIMINATE_COPY_RELOCS + && ind->root.type != bfd_link_hash_indirect + && (dir->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + dir->elf_link_hash_flags |= + (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK)); + else + _bfd_elf_link_hash_copy_indirect (bed, dir, ind); +} + +static bfd_boolean +elf64_x86_64_mkobject (abfd) + bfd *abfd; +{ + bfd_size_type amt = sizeof (struct elf64_x86_64_obj_tdata); + abfd->tdata.any = bfd_zalloc (abfd, amt); + if (abfd->tdata.any == NULL) + return FALSE; + return TRUE; +} + +static bfd_boolean +elf64_x86_64_elf_object_p (abfd) + bfd *abfd; +{ + /* Allocate our special target data. */ + struct elf64_x86_64_obj_tdata *new_tdata; + bfd_size_type amt = sizeof (struct elf64_x86_64_obj_tdata); + new_tdata = bfd_zalloc (abfd, amt); + if (new_tdata == NULL) + return FALSE; + new_tdata->root = *abfd->tdata.elf_obj_data; + abfd->tdata.any = new_tdata; + /* Set the right machine number for an x86-64 elf64 file. */ + bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64); + return TRUE; +} + +static int +elf64_x86_64_tls_transition (info, r_type, is_local) + struct bfd_link_info *info; + int r_type; + int is_local; +{ + if (info->shared) + return r_type; + + switch (r_type) + { + case R_X86_64_TLSGD: + case R_X86_64_GOTTPOFF: + if (is_local) + return R_X86_64_TPOFF32; + return R_X86_64_GOTTPOFF; + case R_X86_64_TLSLD: + return R_X86_64_TPOFF32; + } + + return r_type; +} + +/* 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. */ + +static bfd_boolean +elf64_x86_64_check_relocs (abfd, info, sec, relocs) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; +{ + struct elf64_x86_64_link_hash_table *htab; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + const Elf_Internal_Rela *rel; + const Elf_Internal_Rela *rel_end; + asection *sreloc; + + if (info->relocateable) + return TRUE; + + htab = elf64_x86_64_hash_table (info); + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + + sreloc = NULL; + + rel_end = relocs + sec->reloc_count; + for (rel = relocs; rel < rel_end; rel++) + { + unsigned int r_type; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + + r_symndx = ELF64_R_SYM (rel->r_info); + r_type = ELF64_R_TYPE (rel->r_info); + + if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) + { + (*_bfd_error_handler) (_("%s: bad symbol index: %d"), + bfd_archive_filename (abfd), + r_symndx); + return FALSE; + } + + if (r_symndx < symtab_hdr->sh_info) + h = NULL; + else + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + + r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL); + switch (r_type) + { + case R_X86_64_TLSLD: + htab->tls_ld_got.refcount += 1; + goto create_got; + + case R_X86_64_TPOFF32: + if (info->shared) + { + (*_bfd_error_handler) + (_("%s: relocation %s can not be used when making a shared object; recompile with -fPIC"), + bfd_archive_filename (abfd), + x86_64_elf_howto_table[r_type].name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + break; + + case R_X86_64_GOTTPOFF: + if (info->shared) + info->flags |= DF_STATIC_TLS; + /* Fall through */ + + case R_X86_64_GOT32: + case R_X86_64_GOTPCREL: + case R_X86_64_TLSGD: + /* This symbol requires a global offset table entry. */ + { + int tls_type, old_tls_type; + + switch (r_type) + { + default: tls_type = GOT_NORMAL; break; + case R_X86_64_TLSGD: tls_type = GOT_TLS_GD; break; + case R_X86_64_GOTTPOFF: tls_type = GOT_TLS_IE; break; + } + + if (h != NULL) + { + h->got.refcount += 1; + old_tls_type = elf64_x86_64_hash_entry (h)->tls_type; + } + 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) + sizeof (char); + 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; + elf64_x86_64_local_got_tls_type (abfd) + = (char *) (local_got_refcounts + symtab_hdr->sh_info); + } + local_got_refcounts[r_symndx] += 1; + old_tls_type + = elf64_x86_64_local_got_tls_type (abfd) [r_symndx]; + } + + /* If a TLS symbol is accessed using IE at least once, + there is no point to use dynamic model for it. */ + if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN + && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE)) + { + if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD) + tls_type = old_tls_type; + else + { + (*_bfd_error_handler) + (_("%s: %s' accessed both as normal and thread local symbol"), + bfd_archive_filename (abfd), + h ? h->root.root.string : ""); + return FALSE; + } + } + + if (old_tls_type != tls_type) + { + if (h != NULL) + elf64_x86_64_hash_entry (h)->tls_type = tls_type; + else + elf64_x86_64_local_got_tls_type (abfd) [r_symndx] = tls_type; + } + } + /* Fall through */ + + //case R_X86_64_GOTPCREL: + create_got: + if (htab->sgot == NULL) + { + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + if (!create_got_section (htab->elf.dynobj, info)) + return FALSE; + } + break; + + case R_X86_64_PLT32: + /* 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 + never referenced by a dynamic object, in which case we + don't need to generate a procedure linkage table entry + after all. */ + + /* If this is a local symbol, we resolve it directly without + creating a procedure linkage table entry. */ + if (h == NULL) + continue; + + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + h->plt.refcount += 1; + break; + + case R_X86_64_8: + case R_X86_64_16: + case R_X86_64_32: + case R_X86_64_32S: + /* Let's help debug shared library creation. These relocs + cannot be used in shared libs. Don't error out for + sections we don't care about, such as debug sections or + non-constant sections. */ + if (info->shared + && (sec->flags & SEC_ALLOC) != 0 + && (sec->flags & SEC_READONLY) != 0) + { + (*_bfd_error_handler) + (_("%s: relocation %s can not be used when making a shared object; recompile with -fPIC"), + bfd_archive_filename (abfd), + x86_64_elf_howto_table[r_type].name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + /* Fall through. */ + + case R_X86_64_PC8: + case R_X86_64_PC16: + case R_X86_64_PC32: + case R_X86_64_64: + if (h != NULL && !info->shared) + { + /* If this reloc is in a read-only section, we might + need a copy reloc. We can't check reliably at this + stage whether the section is read-only, as input + sections have not yet been mapped to output sections. + Tentatively set the flag for now, and correct in + adjust_dynamic_symbol. */ + h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; + + /* We may need a .plt entry if the function this reloc + refers to is in a shared lib. */ + 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). 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 + && (((r_type != R_X86_64_PC8) + && (r_type != R_X86_64_PC16) + && (r_type != R_X86_64_PC32)) + || (h != NULL + && (! info->symbolic + || h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || (ELIMINATE_COPY_RELOCS + && !info->shared + && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))) + { + struct elf64_x86_64_dyn_relocs *p; + struct elf64_x86_64_dyn_relocs **head; + + /* We must copy these reloc types into the output file. + Create a reloc section in dynobj and make room for + this reloc. */ + if (sreloc == NULL) + { + const char *name; + bfd *dynobj; + + name = (bfd_elf_string_from_elf_section + (abfd, + elf_elfheader (abfd)->e_shstrndx, + elf_section_data (sec)->rel_hdr.sh_name)); + if (name == NULL) + return FALSE; + + if (strncmp (name, ".rela", 5) != 0 + || strcmp (bfd_get_section_name (abfd, sec), + name + 5) != 0) + { + (*_bfd_error_handler) + (_("%s: bad relocation section name `%s\'"), + bfd_archive_filename (abfd), name); + } + + if (htab->elf.dynobj == NULL) + htab->elf.dynobj = abfd; + + dynobj = htab->elf.dynobj; + + 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, 3)) + 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 elf64_x86_64_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; + s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, + sec, r_symndx); + if (s == NULL) + return FALSE; + + head = ((struct elf64_x86_64_dyn_relocs **) + &elf_section_data (s)->local_dynrel); + } + + p = *head; + if (p == NULL || p->sec != sec) + { + bfd_size_type amt = sizeof *p; + p = ((struct elf64_x86_64_dyn_relocs *) + bfd_alloc (htab->elf.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 (r_type == R_X86_64_PC8 + || r_type == R_X86_64_PC16 + || r_type == R_X86_64_PC32) + p->pc_count += 1; + } + break; + + /* This relocation describes the C++ object vtable hierarchy. + Reconstruct it for later use during GC. */ + case R_X86_64_GNU_VTINHERIT: + if (!_bfd_elf64_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_X86_64_GNU_VTENTRY: + if (!_bfd_elf64_gc_record_vtentry (abfd, sec, h, rel->r_addend)) + return FALSE; + break; + + default: + break; + } + } + + return TRUE; +} + +/* Return the section that should be marked against GC for a given + relocation. */ + +static asection * +elf64_x86_64_gc_mark_hook (sec, info, rel, h, sym) + asection *sec; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + Elf_Internal_Rela *rel; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + if (h != NULL) + { + switch (ELF64_R_TYPE (rel->r_info)) + { + case R_X86_64_GNU_VTINHERIT: + case R_X86_64_GNU_VTENTRY: + break; + + default: + 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; + + default: + break; + } + } + } + else + return bfd_section_from_elf_index (sec->owner, sym->st_shndx); + + return NULL; +} + +/* Update the got entry reference counts for the section being removed. */ + +static bfd_boolean +elf64_x86_64_gc_sweep_hook (abfd, info, sec, 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; + 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; + unsigned int r_type; + struct elf_link_hash_entry *h = NULL; + + r_symndx = ELF64_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + struct elf64_x86_64_link_hash_entry *eh; + struct elf64_x86_64_dyn_relocs **pp; + struct elf64_x86_64_dyn_relocs *p; + + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + eh = (struct elf64_x86_64_link_hash_entry *) h; + + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) + if (p->sec == sec) + { + /* Everything must go for SEC. */ + *pp = p->next; + break; + } + } + + r_type = ELF64_R_TYPE (rel->r_info); + r_type = elf64_x86_64_tls_transition (info, r_type, h != NULL); + switch (r_type) + { + case R_X86_64_TLSLD: + if (elf64_x86_64_hash_table (info)->tls_ld_got.refcount > 0) + elf64_x86_64_hash_table (info)->tls_ld_got.refcount -= 1; + break; + + case R_X86_64_TLSGD: + case R_X86_64_GOTTPOFF: + case R_X86_64_GOT32: + case R_X86_64_GOTPCREL: + if (h != NULL) + { + if (h->got.refcount > 0) + h->got.refcount -= 1; + } + else if (local_got_refcounts != NULL) + { + if (local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + } + break; + + case R_X86_64_8: + case R_X86_64_16: + case R_X86_64_32: + case R_X86_64_64: + case R_X86_64_32S: + case R_X86_64_PC8: + case R_X86_64_PC16: + case R_X86_64_PC32: + if (info->shared) + break; + /* Fall thru */ + + case R_X86_64_PLT32: + if (h != NULL) + { + if (h->plt.refcount > 0) + h->plt.refcount -= 1; + } + break; + + default: + break; + } + } + + return TRUE; +} + +/* 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 +elf64_x86_64_adjust_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + struct elf64_x86_64_link_hash_table *htab; + asection *s; + unsigned int power_of_two; + + /* 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->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + { + if (h->plt.refcount <= 0 + || (! info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0 + && h->root.type != bfd_link_hash_undefweak + && h->root.type != bfd_link_hash_undefined)) + { + /* This case can occur if we saw a PLT32 reloc in an input + file, but the symbol was never referred to by a dynamic + object, or if all references were garbage collected. In + such a case, we don't actually need to build a procedure + linkage table, and we can just do a PC32 reloc instead. */ + h->plt.offset = (bfd_vma) -1; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + } + + return TRUE; + } + else + /* It's possible that we incorrectly decided a .plt reloc was + needed for an R_X86_64_PC32 reloc to a non-function sym in + check_relocs. We can't decide accurately between function and + non-function syms in check-relocs; Objects loaded later in + the link may change h->type. So fix it now. */ + 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->weakdef != NULL) + { + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->weakdef->root.u.def.section; + h->root.u.def.value = h->weakdef->root.u.def.value; + if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) + h->elf_link_hash_flags + = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF) + | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF)); + 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->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0) + return TRUE; + + /* If -z nocopyreloc was given, we won't generate them either. */ + if (info->nocopyreloc) + { + h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + return TRUE; + } + + if (ELIMINATE_COPY_RELOCS) + { + struct elf64_x86_64_link_hash_entry * eh; + struct elf64_x86_64_dyn_relocs *p; + + eh = (struct elf64_x86_64_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) != 0) + break; + } + + /* If we didn't find any dynamic relocs in read-only sections, then + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ + if (p == NULL) + { + h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + 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 = elf64_x86_64_hash_table (info); + + /* We must generate a R_X86_64_COPY reloc to tell the dynamic linker + to copy the initial value out of the dynamic object and into the + runtime process image. */ + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) + { + htab->srelbss->_raw_size += sizeof (Elf64_External_Rela); + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; + } + + /* We need to figure out the alignment required for this symbol. I + have no idea how ELF linkers handle this. 16-bytes is the size + of the largest type that requires hard alignment -- long double. */ + /* FIXME: This is VERY ugly. Should be fixed for all architectures using + this construct. */ + power_of_two = bfd_log2 (h->size); + if (power_of_two > 4) + power_of_two = 4; + + /* Apply the required alignment. */ + s = htab->sdynbss; + s->_raw_size = BFD_ALIGN (s->_raw_size, (bfd_size_type) (1 << power_of_two)); + if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s)) + { + if (! bfd_set_section_alignment (htab->elf.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->_raw_size; + + /* Increment the section size to make room for the symbol. */ + s->_raw_size += h->size; + + return TRUE; +} + +/* This is the condition under which elf64_x86_64_finish_dynamic_symbol + will be called from elflink.h. If elflink.h doesn't call our + finish_dynamic_symbol routine, we'll need to do something about + initializing any .plt and .got entries in elf64_x86_64_relocate_section. */ +#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, INFO, H) \ + ((DYN) \ + && ((INFO)->shared \ + || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \ + && ((H)->dynindx != -1 \ + || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)) + +/* Allocate space in .plt, .got and associated reloc sections for + dynamic relocs. */ + +static bfd_boolean +allocate_dynrelocs (h, inf) + struct elf_link_hash_entry *h; + PTR inf; +{ + struct bfd_link_info *info; + struct elf64_x86_64_link_hash_table *htab; + struct elf64_x86_64_link_hash_entry *eh; + struct elf64_x86_64_dyn_relocs *p; + + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + info = (struct bfd_link_info *) inf; + htab = elf64_x86_64_hash_table (info); + + if (htab->elf.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->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf64_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h)) + { + asection *s = htab->splt; + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (s->_raw_size == 0) + s->_raw_size += PLT_ENTRY_SIZE; + + h->plt.offset = s->_raw_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->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->_raw_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->_raw_size += GOT_ENTRY_SIZE; + + /* We also need to make an entry in the .rela.plt section. */ + htab->srelplt->_raw_size += sizeof (Elf64_External_Rela); + } + else + { + h->plt.offset = (bfd_vma) -1; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + } + + /* If R_X86_64_GOTTPOFF symbol is now local to the binary, + make it a R_X86_64_TPOFF32 requiring no GOT entry. */ + if (h->got.refcount > 0 + && !info->shared + && h->dynindx == -1 + && elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE) + h->got.offset = (bfd_vma) -1; + else if (h->got.refcount > 0) + { + asection *s; + bfd_boolean dyn; + int tls_type = elf64_x86_64_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->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf64_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + s = htab->sgot; + h->got.offset = s->_raw_size; + s->_raw_size += GOT_ENTRY_SIZE; + /* R_X86_64_TLSGD needs 2 consecutive GOT slots. */ + if (tls_type == GOT_TLS_GD) + s->_raw_size += GOT_ENTRY_SIZE; + dyn = htab->elf.dynamic_sections_created; + /* R_X86_64_TLSGD needs one dynamic relocation if local symbol + and two if global. + R_X86_64_GOTTPOFF needs one dynamic relocation. */ + if ((tls_type == GOT_TLS_GD && h->dynindx == -1) + || tls_type == GOT_TLS_IE) + htab->srelgot->_raw_size += sizeof (Elf64_External_Rela); + else if (tls_type == GOT_TLS_GD) + htab->srelgot->_raw_size += 2 * sizeof (Elf64_External_Rela); + else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)) + htab->srelgot->_raw_size += sizeof (Elf64_External_Rela); + } + else + h->got.offset = (bfd_vma) -1; + + eh = (struct elf64_x86_64_link_hash_entry *) h; + 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->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0 + || info->symbolic)) + { + struct elf64_x86_64_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 if (ELIMINATE_COPY_RELOCS) + { + /* For the non-shared case, discard space for relocs against + symbols which turn out to need copy relocs or are not + dynamic. */ + + if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + || (htab->elf.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->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf64_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->_raw_size += p->count * sizeof (Elf64_External_Rela); + } + + return TRUE; +} + +/* Find any dynamic relocs that apply to read-only sections. */ + +static bfd_boolean +readonly_dynrelocs (h, inf) + struct elf_link_hash_entry *h; + PTR inf; +{ + struct elf64_x86_64_link_hash_entry *eh; + struct elf64_x86_64_dyn_relocs *p; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + eh = (struct elf64_x86_64_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 +elf64_x86_64_size_dynamic_sections (output_bfd, info) + bfd *output_bfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; +{ + struct elf64_x86_64_link_hash_table *htab; + bfd *dynobj; + asection *s; + bfd_boolean relocs; + bfd *ibfd; + + htab = elf64_x86_64_hash_table (info); + dynobj = htab->elf.dynobj; + if (dynobj == NULL) + abort (); + + if (htab->elf.dynamic_sections_created) + { + /* Set the contents of the .interp section to the interpreter. */ + if (! info->shared) + { + s = bfd_get_section_by_name (dynobj, ".interp"); + if (s == NULL) + abort (); + s->_raw_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; + char *local_tls_type; + 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 elf64_x86_64_dyn_relocs *p; + + for (p = *((struct elf64_x86_64_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->_raw_size += p->count * sizeof (Elf64_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; + local_tls_type = elf64_x86_64_local_got_tls_type (ibfd); + s = htab->sgot; + srel = htab->srelgot; + for (; local_got < end_local_got; ++local_got, ++local_tls_type) + { + if (*local_got > 0) + { + *local_got = s->_raw_size; + s->_raw_size += GOT_ENTRY_SIZE; + if (*local_tls_type == GOT_TLS_GD) + s->_raw_size += GOT_ENTRY_SIZE; + if (info->shared + || *local_tls_type == GOT_TLS_GD + || *local_tls_type == GOT_TLS_IE) + srel->_raw_size += sizeof (Elf64_External_Rela); + } + else + *local_got = (bfd_vma) -1; + } + } + + if (htab->tls_ld_got.refcount > 0) + { + /* Allocate 2 got entries and 1 dynamic reloc for R_X86_64_TLSLD + relocs. */ + htab->tls_ld_got.offset = htab->sgot->_raw_size; + htab->sgot->_raw_size += 2 * GOT_ENTRY_SIZE; + htab->srelgot->_raw_size += sizeof (Elf64_External_Rela); + } + else + htab->tls_ld_got.offset = -1; + + /* Allocate global sym .plt and .got entries, and space for global + sym dynamic relocs. */ + elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) 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) + { + /* Strip this section if we don't need it; see the + comment below. */ + } + else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0) + { + if (s->_raw_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->_raw_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. */ + + _bfd_strip_section_from_output (info, s); + 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_X86_64_NONE reloc instead + of garbage. */ + s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); + if (s->contents == NULL) + return FALSE; + } + + if (htab->elf.dynamic_sections_created) + { + /* Add some entries to the .dynamic section. We fill in the + values later, in elf64_x86_64_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_elf64_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) + + if (! info->shared) + { + if (!add_dynamic_entry (DT_DEBUG, 0)) + return FALSE; + } + + if (htab->splt->_raw_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 (Elf64_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->elf, readonly_dynrelocs, + (PTR) info); + + if ((info->flags & DF_TEXTREL) != 0) + { + if (!add_dynamic_entry (DT_TEXTREL, 0)) + return FALSE; + } + } + } +#undef add_dynamic_entry + + return TRUE; +} + +/* Return the base VMA address which should be subtracted from real addresses + when resolving @dtpoff relocation. + This is PT_TLS segment p_vaddr. */ + +static bfd_vma +dtpoff_base (info) + struct bfd_link_info *info; +{ + /* If tls_segment is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_segment == NULL) + return 0; + return elf_hash_table (info)->tls_segment->start; +} + +/* Return the relocation value for @tpoff relocation + if STT_TLS virtual address is ADDRESS. */ + +static bfd_vma +tpoff (info, address) + struct bfd_link_info *info; + bfd_vma address; +{ + struct elf_link_tls_segment *tls_segment + = elf_hash_table (info)->tls_segment; + + /* If tls_segment is NULL, we should have signalled an error already. */ + if (tls_segment == NULL) + return 0; + return address - align_power (tls_segment->size, tls_segment->align) + - tls_segment->start; +} + +/* Relocate an x86_64 ELF section. */ + +static bfd_boolean +elf64_x86_64_relocate_section (output_bfd, info, input_bfd, input_section, + contents, relocs, local_syms, local_sections) + 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; +{ + struct elf64_x86_64_link_hash_table *htab; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_vma *local_got_offsets; + Elf_Internal_Rela *rel; + Elf_Internal_Rela *relend; + + if (info->relocateable) + return TRUE; + + htab = elf64_x86_64_hash_table (info); + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + local_got_offsets = elf_local_got_offsets (input_bfd); + + rel = relocs; + relend = relocs + input_section->reloc_count; + for (; rel < relend; rel++) + { + unsigned int r_type; + reloc_howto_type *howto; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sec; + bfd_vma off; + bfd_vma relocation; + bfd_boolean unresolved_reloc; + bfd_reloc_status_type r; + int tls_type; + + r_type = ELF64_R_TYPE (rel->r_info); + if (r_type == (int) R_X86_64_GNU_VTINHERIT + || r_type == (int) R_X86_64_GNU_VTENTRY) + continue; + + if (r_type >= R_X86_64_max) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + howto = x86_64_elf_howto_table + r_type; + r_symndx = ELF64_R_SYM (rel->r_info); + h = NULL; + sym = NULL; + sec = NULL; + unresolved_reloc = FALSE; + 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); + } + 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; + + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sec = h->root.u.def.section; + if (sec->output_section == NULL) + { + /* Set a flag that will be cleared later if we find a + relocation value for this symbol. output_section + is typically NULL for symbols satisfied by a shared + library. */ + unresolved_reloc = TRUE; + relocation = 0; + } + else + relocation = (h->root.u.def.value + + sec->output_section->vma + + sec->output_offset); + } + else if (h->root.type == bfd_link_hash_undefweak) + relocation = 0; + else if (info->shared + && !info->no_undefined + && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) + relocation = 0; + else + { + if (! ((*info->callbacks->undefined_symbol) + (info, h->root.root.string, input_bfd, + input_section, rel->r_offset, + (!info->shared || info->no_undefined + || ELF_ST_VISIBILITY (h->other))))) + return FALSE; + relocation = 0; + } + } + /* When generating a shared object, the relocations handled here are + copied into the output file to be resolved at run time. */ + switch (r_type) + { + case R_X86_64_GOT32: + /* Relocation is to the entry for this symbol in the global + offset table. */ + case R_X86_64_GOTPCREL: + /* Use global offset table as symbol value. */ + if (htab->sgot == NULL) + abort (); + + if (h != NULL) + { + bfd_boolean dyn; + + off = h->got.offset; + dyn = htab->elf.dynamic_sections_created; + + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h) + || (info->shared + && (info->symbolic + || h->dynindx == -1 + || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)) + && (h->elf_link_hash_flags & ELF_LINK_HASH_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 8, 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_64 (output_bfd, relocation, + htab->sgot->contents + off); + h->got.offset |= 1; + } + } + else + unresolved_reloc = FALSE; + } + else + { + if (local_got_offsets == NULL) + abort (); + + off = local_got_offsets[r_symndx]; + + /* The offset must always be a multiple of 8. We use + the least significant bit to record whether we have + already generated the necessary reloc. */ + if ((off & 1) != 0) + off &= ~1; + else + { + bfd_put_64 (output_bfd, relocation, + htab->sgot->contents + off); + + if (info->shared) + { + asection *s; + Elf_Internal_Rela outrel; + bfd_byte *loc; + + /* We need to generate a R_X86_64_RELATIVE reloc + for the dynamic linker. */ + s = htab->srelgot; + if (s == NULL) + abort (); + + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + + off); + outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE); + outrel.r_addend = relocation; + loc = s->contents; + loc += s->reloc_count++ * sizeof (Elf64_External_Rela); + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + } + + local_got_offsets[r_symndx] |= 1; + } + } + + if (off >= (bfd_vma) -2) + abort (); + + relocation = htab->sgot->output_offset + off; + if (r_type == R_X86_64_GOTPCREL) + relocation += htab->sgot->output_section->vma; + + break; + + case R_X86_64_PLT32: + /* Relocation is to the entry for this symbol in the + procedure linkage table. */ + + /* Resolve a PLT32 reloc against a local symbol directly, + without using the procedure linkage table. */ + if (h == NULL) + break; + + if (h->plt.offset == (bfd_vma) -1 + || htab->splt == NULL) + { + /* We didn't make a PLT entry for this symbol. This + happens when statically linking PIC code, or when + using -Bsymbolic. */ + break; + } + + relocation = (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset); + unresolved_reloc = FALSE; + break; + + case R_X86_64_PC8: + case R_X86_64_PC16: + case R_X86_64_PC32: + case R_X86_64_8: + case R_X86_64_16: + case R_X86_64_32: + case R_X86_64_64: + /* FIXME: The ABI says the linker should make sure the value is + the same when it's zeroextended to 64 bit. */ + + /* r_symndx will be zero only for relocs against symbols + from removed linkonce sections, or sections discarded by + a linker script. */ + if (r_symndx == 0 + || (input_section->flags & SEC_ALLOC) == 0) + break; + + if ((info->shared + && ((r_type != R_X86_64_PC8 + && r_type != R_X86_64_PC16 + && r_type != R_X86_64_PC32) + || (h != NULL + && h->dynindx != -1 + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || (ELIMINATE_COPY_RELOCS + && !info->shared + && h != NULL + && h->dynindx != -1 + && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && (((h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0) + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined))) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + bfd_boolean skip, relocate; + asection *sreloc; + + /* When generating a shared object, these relocations + are copied into the output file to be resolved at run + time. */ + 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); + + /* h->dynindx may be -1 if this symbol was marked to + become local. */ + else if (h != NULL + && h->dynindx != -1 + && (r_type == R_X86_64_PC8 + || r_type == R_X86_64_PC16 + || r_type == R_X86_64_PC32 + || !info->shared + || !info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + { + outrel.r_info = ELF64_R_INFO (h->dynindx, r_type); + outrel.r_addend = rel->r_addend; + } + else + { + /* This symbol is local, or marked to become local. */ + if (r_type == R_X86_64_64) + { + relocate = TRUE; + outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE); + outrel.r_addend = relocation + rel->r_addend; + } + else + { + long sindx; + + if (h == NULL) + sec = local_sections[r_symndx]; + else + { + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || (h->root.type + == bfd_link_hash_defweak)); + sec = h->root.u.def.section; + } + if (sec != NULL && bfd_is_abs_section (sec)) + sindx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else + { + asection *osec; + + osec = sec->output_section; + sindx = elf_section_data (osec)->dynindx; + BFD_ASSERT (sindx > 0); + } + + outrel.r_info = ELF64_R_INFO (sindx, r_type); + outrel.r_addend = relocation + rel->r_addend; + } + } + + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc == NULL) + abort (); + + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela); + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + + /* 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_X86_64_TLSGD: + case R_X86_64_GOTTPOFF: + r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL); + tls_type = GOT_UNKNOWN; + if (h == NULL && local_got_offsets) + tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx]; + else if (h != NULL) + { + tls_type = elf64_x86_64_hash_entry (h)->tls_type; + if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE) + r_type = R_X86_64_TPOFF32; + } + if (r_type == R_X86_64_TLSGD) + { + if (tls_type == GOT_TLS_IE) + r_type = R_X86_64_GOTTPOFF; + } + + if (r_type == R_X86_64_TPOFF32) + { + BFD_ASSERT (! unresolved_reloc); + if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD) + { + unsigned int i; + static unsigned char tlsgd[8] + = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 }; + + /* GD->LE transition. + .byte 0x66; leaq foo@tlsgd(%rip), %rdi + .word 0x6666; rex64; call __tls_get_addr@plt + Change it into: + movq %fs:0, %rax + leaq foo@tpoff(%rax), %rax */ + BFD_ASSERT (rel->r_offset >= 4); + for (i = 0; i < 4; i++) + BFD_ASSERT (bfd_get_8 (input_bfd, + contents + rel->r_offset - 4 + i) + == tlsgd[i]); + BFD_ASSERT (rel->r_offset + 12 <= input_section->_raw_size); + for (i = 0; i < 4; i++) + BFD_ASSERT (bfd_get_8 (input_bfd, + contents + rel->r_offset + 4 + i) + == tlsgd[i+4]); + BFD_ASSERT (rel + 1 < relend); + BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); + memcpy (contents + rel->r_offset - 4, + "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", + 16); + bfd_put_32 (output_bfd, tpoff (info, relocation), + contents + rel->r_offset + 8); + /* Skip R_X86_64_PLT32. */ + rel++; + continue; + } + else + { + unsigned int val, type, reg; + + /* IE->LE transition: + 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. */ + BFD_ASSERT (rel->r_offset >= 3); + val = bfd_get_8 (input_bfd, contents + rel->r_offset - 3); + BFD_ASSERT (val == 0x48 || val == 0x4c); + type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); + BFD_ASSERT (type == 0x8b || type == 0x03); + reg = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); + BFD_ASSERT ((reg & 0xc7) == 5); + reg >>= 3; + BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size); + if (type == 0x8b) + { + /* movq */ + if (val == 0x4c) + bfd_put_8 (output_bfd, 0x49, + contents + rel->r_offset - 3); + bfd_put_8 (output_bfd, 0xc7, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, 0xc0 | reg, + contents + rel->r_offset - 1); + } + else if (reg == 4) + { + /* addq -> addq - addressing with %rsp/%r12 is + special */ + if (val == 0x4c) + bfd_put_8 (output_bfd, 0x49, + contents + rel->r_offset - 3); + bfd_put_8 (output_bfd, 0x81, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, 0xc0 | reg, + contents + rel->r_offset - 1); + } + else + { + /* addq -> leaq */ + if (val == 0x4c) + bfd_put_8 (output_bfd, 0x4d, + contents + rel->r_offset - 3); + bfd_put_8 (output_bfd, 0x8d, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3), + contents + rel->r_offset - 1); + } + bfd_put_32 (output_bfd, tpoff (info, relocation), + contents + rel->r_offset); + continue; + } + } + + if (htab->sgot == NULL) + abort (); + + if (h != NULL) + off = h->got.offset; + else + { + if (local_got_offsets == NULL) + abort (); + + off = local_got_offsets[r_symndx]; + } + + if ((off & 1) != 0) + off &= ~1; + else + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + int dr_type, indx; + + if (htab->srelgot == NULL) + abort (); + + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + off); + + indx = h && h->dynindx != -1 ? h->dynindx : 0; + if (r_type == R_X86_64_TLSGD) + dr_type = R_X86_64_DTPMOD64; + else + dr_type = R_X86_64_TPOFF64; + + bfd_put_64 (output_bfd, 0, htab->sgot->contents + off); + outrel.r_addend = 0; + if (dr_type == R_X86_64_TPOFF64 && indx == 0) + outrel.r_addend = relocation - dtpoff_base (info); + outrel.r_info = ELF64_R_INFO (indx, dr_type); + + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela); + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + + if (r_type == R_X86_64_TLSGD) + { + if (indx == 0) + { + BFD_ASSERT (! unresolved_reloc); + bfd_put_64 (output_bfd, + relocation - dtpoff_base (info), + htab->sgot->contents + off + GOT_ENTRY_SIZE); + } + else + { + bfd_put_64 (output_bfd, 0, + htab->sgot->contents + off + GOT_ENTRY_SIZE); + outrel.r_info = ELF64_R_INFO (indx, + R_X86_64_DTPOFF64); + outrel.r_offset += GOT_ENTRY_SIZE; + htab->srelgot->reloc_count++; + loc += sizeof (Elf64_External_Rela); + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + } + } + + if (h != NULL) + h->got.offset |= 1; + else + local_got_offsets[r_symndx] |= 1; + } + + if (off >= (bfd_vma) -2) + abort (); + if (r_type == ELF64_R_TYPE (rel->r_info)) + { + relocation = htab->sgot->output_section->vma + + htab->sgot->output_offset + off; + unresolved_reloc = FALSE; + } + else + { + unsigned int i; + static unsigned char tlsgd[8] + = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 }; + + /* GD->IE transition. + .byte 0x66; leaq foo@tlsgd(%rip), %rdi + .word 0x6666; rex64; call __tls_get_addr@plt + Change it into: + movq %fs:0, %rax + addq foo@gottpoff(%rip), %rax */ + BFD_ASSERT (rel->r_offset >= 4); + for (i = 0; i < 4; i++) + BFD_ASSERT (bfd_get_8 (input_bfd, + contents + rel->r_offset - 4 + i) + == tlsgd[i]); + BFD_ASSERT (rel->r_offset + 12 <= input_section->_raw_size); + for (i = 0; i < 4; i++) + BFD_ASSERT (bfd_get_8 (input_bfd, + contents + rel->r_offset + 4 + i) + == tlsgd[i+4]); + BFD_ASSERT (rel + 1 < relend); + BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); + memcpy (contents + rel->r_offset - 4, + "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", + 16); + + relocation = (htab->sgot->output_section->vma + + htab->sgot->output_offset + off + - rel->r_offset + - input_section->output_section->vma + - input_section->output_offset + - 12); + bfd_put_32 (output_bfd, relocation, + contents + rel->r_offset + 8); + /* Skip R_X86_64_PLT32. */ + rel++; + continue; + } + break; + + case R_X86_64_TLSLD: + if (! info->shared) + { + /* LD->LE transition: + Ensure it is: + leaq foo@tlsld(%rip), %rdi; call __tls_get_addr@plt. + We change it into: + .word 0x6666; .byte 0x66; movl %fs:0, %rax. */ + BFD_ASSERT (rel->r_offset >= 3); + BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 3) + == 0x48); + BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2) + == 0x8d); + BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 1) + == 0x3d); + BFD_ASSERT (rel->r_offset + 9 <= input_section->_raw_size); + BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4) + == 0xe8); + BFD_ASSERT (rel + 1 < relend); + BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); + memcpy (contents + rel->r_offset - 3, + "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); + /* Skip R_X86_64_PLT32. */ + rel++; + continue; + } + + if (htab->sgot == NULL) + abort (); + + off = htab->tls_ld_got.offset; + if (off & 1) + off &= ~1; + else + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + + if (htab->srelgot == NULL) + abort (); + + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + off); + + bfd_put_64 (output_bfd, 0, + htab->sgot->contents + off); + bfd_put_64 (output_bfd, 0, + htab->sgot->contents + off + GOT_ENTRY_SIZE); + outrel.r_info = ELF64_R_INFO (0, R_X86_64_DTPMOD64); + outrel.r_addend = 0; + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela); + bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); + htab->tls_ld_got.offset |= 1; + } + relocation = htab->sgot->output_section->vma + + htab->sgot->output_offset + off; + unresolved_reloc = FALSE; + break; + + case R_X86_64_DTPOFF32: + if (info->shared || (input_section->flags & SEC_CODE) == 0) + relocation -= dtpoff_base (info); + else + relocation = tpoff (info, relocation); + break; + + case R_X86_64_TPOFF32: + BFD_ASSERT (! info->shared); + relocation = tpoff (info, relocation); + break; + + default: + break; + } + + /* Dynamic relocs are not propagated for SEC_DEBUGGING sections + because such sections are not SEC_ALLOC and thus ld.so will + not process them. */ + if (unresolved_reloc + && !((input_section->flags & SEC_DEBUGGING) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) + (*_bfd_error_handler) + (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"), + bfd_archive_filename (input_bfd), + bfd_get_section_name (input_bfd, input_section), + (long) rel->r_offset, + h->root.root.string); + + 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 *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) + return FALSE; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); + } + + if (r == bfd_reloc_overflow) + { + + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return FALSE; + } + else + { + (*_bfd_error_handler) + (_("%s(%s+0x%lx): reloc against `%s': error %d"), + bfd_archive_filename (input_bfd), + bfd_get_section_name (input_bfd, input_section), + (long) rel->r_offset, name, (int) r); + return FALSE; + } + } + } + + return TRUE; +} + +/* Finish up dynamic symbol handling. We set the contents of various + dynamic sections here. */ + +static bfd_boolean +elf64_x86_64_finish_dynamic_symbol (output_bfd, info, h, sym) + bfd *output_bfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; +{ + struct elf64_x86_64_link_hash_table *htab; + + htab = elf64_x86_64_hash_table (info); + + if (h->plt.offset != (bfd_vma) -1) + { + bfd_vma plt_index; + bfd_vma got_offset; + Elf_Internal_Rela rela; + bfd_byte *loc; + + /* This symbol has an entry in the procedure linkage table. Set + it up. */ + if (h->dynindx == -1 + || htab->splt == NULL + || htab->sgotplt == NULL + || htab->srelplt == NULL) + abort (); + + /* 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 GOT_ENTRY_SIZE + bytes. The first three are reserved for the dynamic linker. */ + got_offset = (plt_index + 3) * GOT_ENTRY_SIZE; + + /* Fill in the entry in the procedure linkage table. */ + memcpy (htab->splt->contents + h->plt.offset, elf64_x86_64_plt_entry, + PLT_ENTRY_SIZE); + + /* Insert the relocation positions of the plt section. The magic + numbers at the end of the statements are the positions of the + relocations in the plt section. */ + /* Put offset for jmp *name@GOTPCREL(%rip), since the + instruction uses 6 bytes, subtract this value. */ + bfd_put_32 (output_bfd, + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + got_offset + - htab->splt->output_section->vma + - htab->splt->output_offset + - h->plt.offset + - 6), + htab->splt->contents + h->plt.offset + 2); + /* Put relocation index. */ + bfd_put_32 (output_bfd, plt_index, + htab->splt->contents + h->plt.offset + 7); + /* Put offset for jmp .PLT0. */ + bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE), + htab->splt->contents + h->plt.offset + 12); + + /* Fill in the entry in the global offset table, initially this + points to the pushq instruction in the PLT which is at offset 6. */ + bfd_put_64 (output_bfd, (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset + 6), + htab->sgotplt->contents + got_offset); + + /* Fill in the entry in the .rela.plt section. */ + rela.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + got_offset); + rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT); + rela.r_addend = 0; + loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela); + bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + /* Mark the symbol as undefined, rather than as defined in + the .plt section. Leave the value alone. This is a clue + for the dynamic linker, to make function pointer + comparisons work between an application and shared + library. */ + sym->st_shndx = SHN_UNDEF; + } + } + + if (h->got.offset != (bfd_vma) -1 + && elf64_x86_64_hash_entry (h)->tls_type != GOT_TLS_GD + && elf64_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE) + { + Elf_Internal_Rela rela; + bfd_byte *loc; + + /* This symbol has an entry in the global offset table. Set it + up. */ + if (htab->sgot == NULL || htab->srelgot == NULL) + abort (); + + rela.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + + (h->got.offset &~ (bfd_vma) 1)); + + /* If this is a static link, or it is a -Bsymbolic link and the + symbol is defined locally or was forced to be local because + of a version file, we just want to emit a RELATIVE reloc. + 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->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + { + BFD_ASSERT((h->got.offset & 1) != 0); + rela.r_info = ELF64_R_INFO (0, R_X86_64_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_64 (output_bfd, (bfd_vma) 0, + htab->sgot->contents + h->got.offset); + rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_GLOB_DAT); + rela.r_addend = 0; + } + + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela); + bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); + } + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) + { + Elf_Internal_Rela rela; + bfd_byte *loc; + + /* This symbol needs a copy reloc. Set it up. */ + + if (h->dynindx == -1 + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + || htab->srelbss == NULL) + abort (); + + 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 = ELF64_R_INFO (h->dynindx, R_X86_64_COPY); + rela.r_addend = 0; + loc = htab->srelbss->contents; + loc += htab->srelbss->reloc_count++ * sizeof (Elf64_External_Rela); + bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); + } + + /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ 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; +} + +/* Used to decide how to sort relocs in an optimal manner for the + dynamic linker, before writing them out. */ + +static enum elf_reloc_type_class +elf64_x86_64_reloc_type_class (rela) + const Elf_Internal_Rela *rela; +{ + switch ((int) ELF64_R_TYPE (rela->r_info)) + { + case R_X86_64_RELATIVE: + return reloc_class_relative; + case R_X86_64_JUMP_SLOT: + return reloc_class_plt; + case R_X86_64_COPY: + return reloc_class_copy; + default: + return reloc_class_normal; + } +} + +/* Finish up the dynamic sections. */ + +static bfd_boolean +elf64_x86_64_finish_dynamic_sections (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + struct elf64_x86_64_link_hash_table *htab; + bfd *dynobj; + asection *sdyn; + + htab = elf64_x86_64_hash_table (info); + dynobj = htab->elf.dynobj; + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + + if (htab->elf.dynamic_sections_created) + { + Elf64_External_Dyn *dyncon, *dynconend; + + if (sdyn == NULL || htab->sgot == NULL) + abort (); + + dyncon = (Elf64_External_Dyn *) sdyn->contents; + dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + asection *s; + + bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + continue; + + case DT_PLTGOT: + dyn.d_un.d_ptr = htab->sgot->output_section->vma; + break; + + case DT_JMPREL: + dyn.d_un.d_ptr = htab->srelplt->output_section->vma; + break; + + case DT_PLTRELSZ: + s = htab->srelplt->output_section; + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size; + else + dyn.d_un.d_val = s->_raw_size; + break; + + case DT_RELASZ: + /* The procedure linkage table relocs (DT_JMPREL) should + not be included in the overall relocs (DT_RELA). + 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; + if (s->_cooked_size != 0) + dyn.d_un.d_val -= s->_cooked_size; + else + dyn.d_un.d_val -= s->_raw_size; + } + break; + } + + bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); + } + + /* Fill in the special first entry in the procedure linkage table. */ + if (htab->splt && htab->splt->_raw_size > 0) + { + /* Fill in the first entry in the procedure linkage table. */ + memcpy (htab->splt->contents, elf64_x86_64_plt0_entry, + PLT_ENTRY_SIZE); + /* Add offset for pushq GOT+8(%rip), since the instruction + uses 6 bytes subtract this value. */ + bfd_put_32 (output_bfd, + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + 8 + - htab->splt->output_section->vma + - htab->splt->output_offset + - 6), + htab->splt->contents + 2); + /* Add offset for jmp *GOT+16(%rip). The 12 is the offset to + the end of the instruction. */ + bfd_put_32 (output_bfd, + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + 16 + - htab->splt->output_section->vma + - htab->splt->output_offset + - 12), + htab->splt->contents + 8); + + elf_section_data (htab->splt->output_section)->this_hdr.sh_entsize = + PLT_ENTRY_SIZE; + } + } + + if (htab->sgotplt) + { + /* Fill in the first three entries in the global offset table. */ + if (htab->sgotplt->_raw_size > 0) + { + /* Set the first entry in the global offset table to the address of + the dynamic section. */ + if (sdyn == NULL) + bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents); + else + bfd_put_64 (output_bfd, + sdyn->output_section->vma + sdyn->output_offset, + htab->sgotplt->contents); + /* Write GOT[1] and GOT[2], needed for the dynamic linker. */ + bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + GOT_ENTRY_SIZE); + bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + GOT_ENTRY_SIZE*2); + } + + elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize = + GOT_ENTRY_SIZE; + } + + return TRUE; +} + + +#define TARGET_LITTLE_SYM bfd_elf64_x86_64_vec +#define TARGET_LITTLE_NAME "elf64-x86-64" +#define ELF_ARCH bfd_arch_i386 +#define ELF_MACHINE_CODE EM_X86_64 +#define ELF_MAXPAGESIZE 0x100000 + +#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 (GOT_ENTRY_SIZE*3) +#define elf_backend_plt_header_size PLT_ENTRY_SIZE +#define elf_backend_rela_normal 1 + +#define elf_info_to_howto elf64_x86_64_info_to_howto + +#define bfd_elf64_bfd_link_hash_table_create \ + elf64_x86_64_link_hash_table_create +#define bfd_elf64_bfd_reloc_type_lookup elf64_x86_64_reloc_type_lookup + +#define elf_backend_adjust_dynamic_symbol elf64_x86_64_adjust_dynamic_symbol +#define elf_backend_check_relocs elf64_x86_64_check_relocs +#define elf_backend_copy_indirect_symbol elf64_x86_64_copy_indirect_symbol +#define elf_backend_create_dynamic_sections elf64_x86_64_create_dynamic_sections +#define elf_backend_finish_dynamic_sections elf64_x86_64_finish_dynamic_sections +#define elf_backend_finish_dynamic_symbol elf64_x86_64_finish_dynamic_symbol +#define elf_backend_gc_mark_hook elf64_x86_64_gc_mark_hook +#define elf_backend_gc_sweep_hook elf64_x86_64_gc_sweep_hook +#define elf_backend_grok_prstatus elf64_x86_64_grok_prstatus +#define elf_backend_grok_psinfo elf64_x86_64_grok_psinfo +#define elf_backend_reloc_type_class elf64_x86_64_reloc_type_class +#define elf_backend_relocate_section elf64_x86_64_relocate_section +#define elf_backend_size_dynamic_sections elf64_x86_64_size_dynamic_sections +#define elf_backend_object_p elf64_x86_64_elf_object_p +#define bfd_elf64_mkobject elf64_x86_64_mkobject + +#include "elf64-target.h" diff --git a/contrib/binutils-2.14/bfd/elf64.c b/contrib/binutils-2.14/bfd/elf64.c new file mode 100644 index 0000000000..69fb5b5e6e --- /dev/null +++ b/contrib/binutils-2.14/bfd/elf64.c @@ -0,0 +1,22 @@ +/* ELF 64-bit executable support for BFD. + Copyright 1993 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define ARCH_SIZE 64 + +#include "elfcode.h" diff --git a/contrib/binutils-2.14/bfd/elfcode.h b/contrib/binutils-2.14/bfd/elfcode.h new file mode 100644 index 0000000000..1400d2dcd6 --- /dev/null +++ b/contrib/binutils-2.14/bfd/elfcode.h @@ -0,0 +1,1605 @@ +/* ELF executable support for BFD. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002 Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". Sufficient support for gdb. + + Rewritten by Mark Eichin @ Cygnus Support, from information + published in "System V Application Binary Interface", chapters 4 + and 5, as well as the various "Processor Supplement" documents + derived from it. Added support for assembler and other object file + utilities. Further work done by Ken Raeburn (Cygnus Support), Michael + Meissner (Open Software Foundation), and Peter Hoogenboom (University + of Utah) to finish and extend this. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Problems and other issues to resolve. + + (1) BFD expects there to be some fixed number of "sections" in + the object file. I.E. there is a "section_count" variable in the + bfd structure which contains the number of sections. However, ELF + supports multiple "views" of a file. In particular, with current + implementations, executable files typically have two tables, a + program header table and a section header table, both of which + partition the executable. + + In ELF-speak, the "linking view" of the file uses the section header + table to access "sections" within the file, and the "execution view" + uses the program header table to access "segments" within the file. + "Segments" typically may contain all the data from one or more + "sections". + + Note that the section header table is optional in ELF executables, + but it is this information that is most useful to gdb. If the + section header table is missing, then gdb should probably try + to make do with the program header table. (FIXME) + + (2) The code in this file is compiled twice, once in 32-bit mode and + once in 64-bit mode. More of it should be made size-independent + and moved into elf.c. + + (3) ELF section symbols are handled rather sloppily now. This should + be cleaned up, and ELF section symbols reconciled with BFD section + symbols. + + (4) We need a published spec for 64-bit ELF. We've got some stuff here + that we're using for SPARC V9 64-bit chips, but don't assume that + it's cast in stone. + */ + +#include "bfd.h" +#include "sysdep.h" +#include "libiberty.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" + +/* Renaming structures, typedefs, macros and functions to be size-specific. */ +#define Elf_External_Ehdr NAME(Elf,External_Ehdr) +#define Elf_External_Sym NAME(Elf,External_Sym) +#define Elf_External_Shdr NAME(Elf,External_Shdr) +#define Elf_External_Phdr NAME(Elf,External_Phdr) +#define Elf_External_Rel NAME(Elf,External_Rel) +#define Elf_External_Rela NAME(Elf,External_Rela) +#define Elf_External_Dyn NAME(Elf,External_Dyn) + +#define elf_core_file_failing_command NAME(bfd_elf,core_file_failing_command) +#define elf_core_file_failing_signal NAME(bfd_elf,core_file_failing_signal) +#define elf_core_file_matches_executable_p \ + NAME(bfd_elf,core_file_matches_executable_p) +#define elf_object_p NAME(bfd_elf,object_p) +#define elf_core_file_p NAME(bfd_elf,core_file_p) +#define elf_get_symtab_upper_bound NAME(bfd_elf,get_symtab_upper_bound) +#define elf_get_dynamic_symtab_upper_bound \ + NAME(bfd_elf,get_dynamic_symtab_upper_bound) +#define elf_swap_reloc_in NAME(bfd_elf,swap_reloc_in) +#define elf_swap_reloca_in NAME(bfd_elf,swap_reloca_in) +#define elf_swap_reloc_out NAME(bfd_elf,swap_reloc_out) +#define elf_swap_reloca_out NAME(bfd_elf,swap_reloca_out) +#define elf_swap_symbol_in NAME(bfd_elf,swap_symbol_in) +#define elf_swap_symbol_out NAME(bfd_elf,swap_symbol_out) +#define elf_swap_phdr_in NAME(bfd_elf,swap_phdr_in) +#define elf_swap_phdr_out NAME(bfd_elf,swap_phdr_out) +#define elf_swap_dyn_in NAME(bfd_elf,swap_dyn_in) +#define elf_swap_dyn_out NAME(bfd_elf,swap_dyn_out) +#define elf_get_reloc_upper_bound NAME(bfd_elf,get_reloc_upper_bound) +#define elf_canonicalize_reloc NAME(bfd_elf,canonicalize_reloc) +#define elf_slurp_symbol_table NAME(bfd_elf,slurp_symbol_table) +#define elf_get_symtab NAME(bfd_elf,get_symtab) +#define elf_canonicalize_dynamic_symtab \ + NAME(bfd_elf,canonicalize_dynamic_symtab) +#define elf_make_empty_symbol NAME(bfd_elf,make_empty_symbol) +#define elf_get_symbol_info NAME(bfd_elf,get_symbol_info) +#define elf_get_lineno NAME(bfd_elf,get_lineno) +#define elf_set_arch_mach NAME(bfd_elf,set_arch_mach) +#define elf_find_nearest_line NAME(bfd_elf,find_nearest_line) +#define elf_sizeof_headers NAME(bfd_elf,sizeof_headers) +#define elf_set_section_contents NAME(bfd_elf,set_section_contents) +#define elf_no_info_to_howto NAME(bfd_elf,no_info_to_howto) +#define elf_no_info_to_howto_rel NAME(bfd_elf,no_info_to_howto_rel) +#define elf_find_section NAME(bfd_elf,find_section) +#define elf_bfd_link_add_symbols NAME(bfd_elf,bfd_link_add_symbols) +#define elf_add_dynamic_entry NAME(bfd_elf,add_dynamic_entry) +#define elf_write_shdrs_and_ehdr NAME(bfd_elf,write_shdrs_and_ehdr) +#define elf_write_out_phdrs NAME(bfd_elf,write_out_phdrs) +#define elf_write_relocs NAME(bfd_elf,write_relocs) +#define elf_slurp_reloc_table NAME(bfd_elf,slurp_reloc_table) +#define elf_link_create_dynamic_sections \ + NAME(bfd_elf,link_create_dynamic_sections) +#define elf_bfd_discard_info NAME(bfd_elf,discard_info) +#define elf_reloc_symbol_deleted_p NAME(_bfd_elf,reloc_symbol_deleted_p) +#define elf_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol +#define elf_bfd_final_link NAME(bfd_elf,bfd_final_link) +#define elf_create_pointer_linker_section NAME(bfd_elf,create_pointer_linker_section) +#define elf_finish_pointer_linker_section NAME(bfd_elf,finish_pointer_linker_section) +#define elf_gc_sections NAME(_bfd_elf,gc_sections) +#define elf_gc_common_finalize_got_offsets \ + NAME(_bfd_elf,gc_common_finalize_got_offsets) +#define elf_gc_common_final_link NAME(_bfd_elf,gc_common_final_link) +#define elf_gc_record_vtinherit NAME(_bfd_elf,gc_record_vtinherit) +#define elf_gc_record_vtentry NAME(_bfd_elf,gc_record_vtentry) +#define elf_link_record_local_dynamic_symbol \ + NAME(_bfd_elf,link_record_local_dynamic_symbol) + +#if ARCH_SIZE == 64 +#define ELF_R_INFO(X,Y) ELF64_R_INFO(X,Y) +#define ELF_R_SYM(X) ELF64_R_SYM(X) +#define ELF_R_TYPE(X) ELF64_R_TYPE(X) +#define ELFCLASS ELFCLASS64 +#define FILE_ALIGN 8 +#define LOG_FILE_ALIGN 3 +#endif +#if ARCH_SIZE == 32 +#define ELF_R_INFO(X,Y) ELF32_R_INFO(X,Y) +#define ELF_R_SYM(X) ELF32_R_SYM(X) +#define ELF_R_TYPE(X) ELF32_R_TYPE(X) +#define ELFCLASS ELFCLASS32 +#define FILE_ALIGN 4 +#define LOG_FILE_ALIGN 2 +#endif + +/* Static functions */ + +static void elf_swap_ehdr_in + PARAMS ((bfd *, const Elf_External_Ehdr *, Elf_Internal_Ehdr *)); +static void elf_swap_ehdr_out + PARAMS ((bfd *, const Elf_Internal_Ehdr *, Elf_External_Ehdr *)); +static void elf_swap_shdr_in + PARAMS ((bfd *, const Elf_External_Shdr *, Elf_Internal_Shdr *)); +static void elf_swap_shdr_out + PARAMS ((bfd *, const Elf_Internal_Shdr *, Elf_External_Shdr *)); + +#define elf_stringtab_init _bfd_elf_stringtab_init + +#define section_from_elf_index bfd_section_from_elf_index + +static bfd_boolean elf_slurp_reloc_table_from_section + PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, bfd_size_type, + arelent *, asymbol **, bfd_boolean)); + +static bfd_boolean elf_file_p PARAMS ((Elf_External_Ehdr *)); + +#ifdef DEBUG +static void elf_debug_section PARAMS ((int, Elf_Internal_Shdr *)); +static void elf_debug_file PARAMS ((Elf_Internal_Ehdr *)); +static char *elf_symbol_flags PARAMS ((flagword)); +#endif + +/* Structure swapping routines */ + +/* Should perhaps use put_offset, put_word, etc. For now, the two versions + can be handled by explicitly specifying 32 bits or "the long type". */ +#if ARCH_SIZE == 64 +#define H_PUT_WORD H_PUT_64 +#define H_PUT_SIGNED_WORD H_PUT_S64 +#define H_GET_WORD H_GET_64 +#define H_GET_SIGNED_WORD H_GET_S64 +#endif +#if ARCH_SIZE == 32 +#define H_PUT_WORD H_PUT_32 +#define H_PUT_SIGNED_WORD H_PUT_S32 +#define H_GET_WORD H_GET_32 +#define H_GET_SIGNED_WORD H_GET_S32 +#endif + +/* Translate an ELF symbol in external format into an ELF symbol in internal + format. */ + +void +elf_swap_symbol_in (abfd, psrc, pshn, dst) + bfd *abfd; + const PTR psrc; + const PTR pshn; + Elf_Internal_Sym *dst; +{ + const Elf_External_Sym *src = (const Elf_External_Sym *) psrc; + const Elf_External_Sym_Shndx *shndx = (const Elf_External_Sym_Shndx *) pshn; + int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; + + dst->st_name = H_GET_32 (abfd, src->st_name); + if (signed_vma) + dst->st_value = H_GET_SIGNED_WORD (abfd, src->st_value); + else + dst->st_value = H_GET_WORD (abfd, src->st_value); + dst->st_size = H_GET_WORD (abfd, src->st_size); + dst->st_info = H_GET_8 (abfd, src->st_info); + dst->st_other = H_GET_8 (abfd, src->st_other); + dst->st_shndx = H_GET_16 (abfd, src->st_shndx); + if (dst->st_shndx == SHN_XINDEX) + { + if (shndx == NULL) + abort (); + dst->st_shndx = H_GET_32 (abfd, shndx->est_shndx); + } +} + +/* Translate an ELF symbol in internal format into an ELF symbol in external + format. */ + +void +elf_swap_symbol_out (abfd, src, cdst, shndx) + bfd *abfd; + const Elf_Internal_Sym *src; + PTR cdst; + PTR shndx; +{ + unsigned int tmp; + Elf_External_Sym *dst = (Elf_External_Sym *) cdst; + H_PUT_32 (abfd, src->st_name, dst->st_name); + H_PUT_WORD (abfd, src->st_value, dst->st_value); + H_PUT_WORD (abfd, src->st_size, dst->st_size); + H_PUT_8 (abfd, src->st_info, dst->st_info); + H_PUT_8 (abfd, src->st_other, dst->st_other); + tmp = src->st_shndx; + if (tmp > SHN_HIRESERVE) + { + if (shndx == NULL) + abort (); + H_PUT_32 (abfd, tmp, shndx); + tmp = SHN_XINDEX; + } + H_PUT_16 (abfd, tmp, dst->st_shndx); +} + +/* Translate an ELF file header in external format into an ELF file header in + internal format. */ + +static void +elf_swap_ehdr_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Ehdr *src; + Elf_Internal_Ehdr *dst; +{ + int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; + memcpy (dst->e_ident, src->e_ident, EI_NIDENT); + dst->e_type = H_GET_16 (abfd, src->e_type); + dst->e_machine = H_GET_16 (abfd, src->e_machine); + dst->e_version = H_GET_32 (abfd, src->e_version); + if (signed_vma) + dst->e_entry = H_GET_SIGNED_WORD (abfd, src->e_entry); + else + dst->e_entry = H_GET_WORD (abfd, src->e_entry); + dst->e_phoff = H_GET_WORD (abfd, src->e_phoff); + dst->e_shoff = H_GET_WORD (abfd, src->e_shoff); + dst->e_flags = H_GET_32 (abfd, src->e_flags); + dst->e_ehsize = H_GET_16 (abfd, src->e_ehsize); + dst->e_phentsize = H_GET_16 (abfd, src->e_phentsize); + dst->e_phnum = H_GET_16 (abfd, src->e_phnum); + dst->e_shentsize = H_GET_16 (abfd, src->e_shentsize); + dst->e_shnum = H_GET_16 (abfd, src->e_shnum); + dst->e_shstrndx = H_GET_16 (abfd, src->e_shstrndx); +} + +/* Translate an ELF file header in internal format into an ELF file header in + external format. */ + +static void +elf_swap_ehdr_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Ehdr *src; + Elf_External_Ehdr *dst; +{ + unsigned int tmp; + int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; + memcpy (dst->e_ident, src->e_ident, EI_NIDENT); + /* note that all elements of dst are *arrays of unsigned char* already... */ + H_PUT_16 (abfd, src->e_type, dst->e_type); + H_PUT_16 (abfd, src->e_machine, dst->e_machine); + H_PUT_32 (abfd, src->e_version, dst->e_version); + if (signed_vma) + H_PUT_SIGNED_WORD (abfd, src->e_entry, dst->e_entry); + else + H_PUT_WORD (abfd, src->e_entry, dst->e_entry); + H_PUT_WORD (abfd, src->e_phoff, dst->e_phoff); + H_PUT_WORD (abfd, src->e_shoff, dst->e_shoff); + H_PUT_32 (abfd, src->e_flags, dst->e_flags); + H_PUT_16 (abfd, src->e_ehsize, dst->e_ehsize); + H_PUT_16 (abfd, src->e_phentsize, dst->e_phentsize); + H_PUT_16 (abfd, src->e_phnum, dst->e_phnum); + H_PUT_16 (abfd, src->e_shentsize, dst->e_shentsize); + tmp = src->e_shnum; + if (tmp >= SHN_LORESERVE) + tmp = SHN_UNDEF; + H_PUT_16 (abfd, tmp, dst->e_shnum); + tmp = src->e_shstrndx; + if (tmp >= SHN_LORESERVE) + tmp = SHN_XINDEX; + H_PUT_16 (abfd, tmp, dst->e_shstrndx); +} + +/* Translate an ELF section header table entry in external format into an + ELF section header table entry in internal format. */ + +static void +elf_swap_shdr_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Shdr *src; + Elf_Internal_Shdr *dst; +{ + int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; + + dst->sh_name = H_GET_32 (abfd, src->sh_name); + dst->sh_type = H_GET_32 (abfd, src->sh_type); + dst->sh_flags = H_GET_WORD (abfd, src->sh_flags); + if (signed_vma) + dst->sh_addr = H_GET_SIGNED_WORD (abfd, src->sh_addr); + else + dst->sh_addr = H_GET_WORD (abfd, src->sh_addr); + dst->sh_offset = H_GET_WORD (abfd, src->sh_offset); + dst->sh_size = H_GET_WORD (abfd, src->sh_size); + dst->sh_link = H_GET_32 (abfd, src->sh_link); + dst->sh_info = H_GET_32 (abfd, src->sh_info); + dst->sh_addralign = H_GET_WORD (abfd, src->sh_addralign); + dst->sh_entsize = H_GET_WORD (abfd, src->sh_entsize); + dst->bfd_section = NULL; + dst->contents = NULL; +} + +/* Translate an ELF section header table entry in internal format into an + ELF section header table entry in external format. */ + +static void +elf_swap_shdr_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Shdr *src; + Elf_External_Shdr *dst; +{ + /* note that all elements of dst are *arrays of unsigned char* already... */ + H_PUT_32 (abfd, src->sh_name, dst->sh_name); + H_PUT_32 (abfd, src->sh_type, dst->sh_type); + H_PUT_WORD (abfd, src->sh_flags, dst->sh_flags); + H_PUT_WORD (abfd, src->sh_addr, dst->sh_addr); + H_PUT_WORD (abfd, src->sh_offset, dst->sh_offset); + H_PUT_WORD (abfd, src->sh_size, dst->sh_size); + H_PUT_32 (abfd, src->sh_link, dst->sh_link); + H_PUT_32 (abfd, src->sh_info, dst->sh_info); + H_PUT_WORD (abfd, src->sh_addralign, dst->sh_addralign); + H_PUT_WORD (abfd, src->sh_entsize, dst->sh_entsize); +} + +/* Translate an ELF program header table entry in external format into an + ELF program header table entry in internal format. */ + +void +elf_swap_phdr_in (abfd, src, dst) + bfd *abfd; + const Elf_External_Phdr *src; + Elf_Internal_Phdr *dst; +{ + int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma; + + dst->p_type = H_GET_32 (abfd, src->p_type); + dst->p_flags = H_GET_32 (abfd, src->p_flags); + dst->p_offset = H_GET_WORD (abfd, src->p_offset); + if (signed_vma) + { + dst->p_vaddr = H_GET_SIGNED_WORD (abfd, src->p_vaddr); + dst->p_paddr = H_GET_SIGNED_WORD (abfd, src->p_paddr); + } + else + { + dst->p_vaddr = H_GET_WORD (abfd, src->p_vaddr); + dst->p_paddr = H_GET_WORD (abfd, src->p_paddr); + } + dst->p_filesz = H_GET_WORD (abfd, src->p_filesz); + dst->p_memsz = H_GET_WORD (abfd, src->p_memsz); + dst->p_align = H_GET_WORD (abfd, src->p_align); +} + +void +elf_swap_phdr_out (abfd, src, dst) + bfd *abfd; + const Elf_Internal_Phdr *src; + Elf_External_Phdr *dst; +{ + /* note that all elements of dst are *arrays of unsigned char* already... */ + H_PUT_32 (abfd, src->p_type, dst->p_type); + H_PUT_WORD (abfd, src->p_offset, dst->p_offset); + H_PUT_WORD (abfd, src->p_vaddr, dst->p_vaddr); + H_PUT_WORD (abfd, src->p_paddr, dst->p_paddr); + H_PUT_WORD (abfd, src->p_filesz, dst->p_filesz); + H_PUT_WORD (abfd, src->p_memsz, dst->p_memsz); + H_PUT_32 (abfd, src->p_flags, dst->p_flags); + H_PUT_WORD (abfd, src->p_align, dst->p_align); +} + +/* Translate an ELF reloc from external format to internal format. */ +void +elf_swap_reloc_in (abfd, s, dst) + bfd *abfd; + const bfd_byte *s; + Elf_Internal_Rela *dst; +{ + const Elf_External_Rel *src = (const Elf_External_Rel *) s; + dst->r_offset = H_GET_WORD (abfd, src->r_offset); + dst->r_info = H_GET_WORD (abfd, src->r_info); + dst->r_addend = 0; +} + +void +elf_swap_reloca_in (abfd, s, dst) + bfd *abfd; + const bfd_byte *s; + Elf_Internal_Rela *dst; +{ + const Elf_External_Rela *src = (const Elf_External_Rela *) s; + dst->r_offset = H_GET_WORD (abfd, src->r_offset); + dst->r_info = H_GET_WORD (abfd, src->r_info); + dst->r_addend = H_GET_SIGNED_WORD (abfd, src->r_addend); +} + +/* Translate an ELF reloc from internal format to external format. */ +void +elf_swap_reloc_out (abfd, src, d) + bfd *abfd; + const Elf_Internal_Rela *src; + bfd_byte *d; +{ + Elf_External_Rel *dst = (Elf_External_Rel *) d; + H_PUT_WORD (abfd, src->r_offset, dst->r_offset); + H_PUT_WORD (abfd, src->r_info, dst->r_info); +} + +void +elf_swap_reloca_out (abfd, src, d) + bfd *abfd; + const Elf_Internal_Rela *src; + bfd_byte *d; +{ + Elf_External_Rela *dst = (Elf_External_Rela *) d; + H_PUT_WORD (abfd, src->r_offset, dst->r_offset); + H_PUT_WORD (abfd, src->r_info, dst->r_info); + H_PUT_SIGNED_WORD (abfd, src->r_addend, dst->r_addend); +} + +INLINE void +elf_swap_dyn_in (abfd, p, dst) + bfd *abfd; + const PTR p; + Elf_Internal_Dyn *dst; +{ + const Elf_External_Dyn *src = (const Elf_External_Dyn *) p; + + dst->d_tag = H_GET_WORD (abfd, src->d_tag); + dst->d_un.d_val = H_GET_WORD (abfd, src->d_un.d_val); +} + +INLINE void +elf_swap_dyn_out (abfd, src, p) + bfd *abfd; + const Elf_Internal_Dyn *src; + PTR p; +{ + Elf_External_Dyn *dst = (Elf_External_Dyn *) p; + + H_PUT_WORD (abfd, src->d_tag, dst->d_tag); + H_PUT_WORD (abfd, src->d_un.d_val, dst->d_un.d_val); +} + +/* ELF .o/exec file reading */ + +/* Begin processing a given object. + + First we validate the file by reading in the ELF header and checking + the magic number. */ + +static INLINE bfd_boolean +elf_file_p (x_ehdrp) + Elf_External_Ehdr *x_ehdrp; +{ + return ((x_ehdrp->e_ident[EI_MAG0] == ELFMAG0) + && (x_ehdrp->e_ident[EI_MAG1] == ELFMAG1) + && (x_ehdrp->e_ident[EI_MAG2] == ELFMAG2) + && (x_ehdrp->e_ident[EI_MAG3] == ELFMAG3)); +} + +/* Check to see if the file associated with ABFD matches the target vector + that ABFD points to. + + Note that we may be called several times with the same ABFD, but different + target vectors, most of which will not match. We have to avoid leaving + any side effects in ABFD, or any data it points to (like tdata), if the + file does not match the target vector. */ + +const bfd_target * +elf_object_p (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_External_Shdr x_shdr; /* Section header table entry, external form */ + Elf_Internal_Shdr i_shdr; + Elf_Internal_Shdr *i_shdrp; /* Section header table, internal form */ + unsigned int shindex; + char *shstrtab; /* Internal copy of section header stringtab */ + struct elf_backend_data *ebd; + struct bfd_preserve preserve; + asection *s; + bfd_size_type amt; + + preserve.marker = NULL; + + /* Read in the ELF header in external format. */ + + if (bfd_bread ((PTR) & x_ehdr, (bfd_size_type) sizeof (x_ehdr), abfd) + != sizeof (x_ehdr)) + { + if (bfd_get_error () != bfd_error_system_call) + goto got_wrong_format_error; + else + goto got_no_match; + } + + /* Now check to see if we have a valid ELF file, and one that BFD can + make use of. The magic number must match, the address size ('class') + and byte-swapping must match our XVEC entry, and it must have a + section header table (FIXME: See comments re sections at top of this + file). */ + + if (! elf_file_p (&x_ehdr) + || x_ehdr.e_ident[EI_VERSION] != EV_CURRENT + || x_ehdr.e_ident[EI_CLASS] != ELFCLASS) + goto got_wrong_format_error; + + /* Check that file's byte order matches xvec's */ + switch (x_ehdr.e_ident[EI_DATA]) + { + case ELFDATA2MSB: /* Big-endian */ + if (! bfd_header_big_endian (abfd)) + goto got_wrong_format_error; + break; + case ELFDATA2LSB: /* Little-endian */ + if (! bfd_header_little_endian (abfd)) + goto got_wrong_format_error; + break; + case ELFDATANONE: /* No data encoding specified */ + default: /* Unknown data encoding specified */ + goto got_wrong_format_error; + } + + /* Allocate an instance of the elf_obj_tdata structure and hook it up to + the tdata pointer in the bfd. */ + + amt = sizeof (struct elf_obj_tdata); + preserve.marker = bfd_zalloc (abfd, amt); + if (preserve.marker == NULL) + goto got_no_match; + if (!bfd_preserve_save (abfd, &preserve)) + goto got_no_match; + + elf_tdata (abfd) = preserve.marker; + + /* Now that we know the byte order, swap in the rest of the header */ + i_ehdrp = elf_elfheader (abfd); + elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp); +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + + /* Reject ET_CORE (header indicates core file, not object file) */ + if (i_ehdrp->e_type == ET_CORE) + goto got_wrong_format_error; + + /* If this is a relocatable file and there is no section header + table, then we're hosed. */ + if (i_ehdrp->e_shoff == 0 && i_ehdrp->e_type == ET_REL) + goto got_wrong_format_error; + + /* As a simple sanity check, verify that the what BFD thinks is the + size of each section header table entry actually matches the size + recorded in the file, but only if there are any sections. */ + if (i_ehdrp->e_shentsize != sizeof (x_shdr) && i_ehdrp->e_shnum != 0) + goto got_wrong_format_error; + + /* Further sanity check. */ + if (i_ehdrp->e_shoff == 0 && i_ehdrp->e_shnum != 0) + goto got_wrong_format_error; + + ebd = get_elf_backend_data (abfd); + + /* Check that the ELF e_machine field matches what this particular + BFD format expects. */ + if (ebd->elf_machine_code != i_ehdrp->e_machine + && (ebd->elf_machine_alt1 == 0 + || i_ehdrp->e_machine != ebd->elf_machine_alt1) + && (ebd->elf_machine_alt2 == 0 + || i_ehdrp->e_machine != ebd->elf_machine_alt2)) + { + const bfd_target * const *target_ptr; + + if (ebd->elf_machine_code != EM_NONE) + goto got_wrong_format_error; + + /* This is the generic ELF target. Let it match any ELF target + for which we do not have a specific backend. */ + for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++) + { + struct elf_backend_data *back; + + if ((*target_ptr)->flavour != bfd_target_elf_flavour) + continue; + back = (struct elf_backend_data *) (*target_ptr)->backend_data; + if (back->elf_machine_code == i_ehdrp->e_machine + || (back->elf_machine_alt1 != 0 + && back->elf_machine_alt1 == i_ehdrp->e_machine) + || (back->elf_machine_alt2 != 0 + && back->elf_machine_alt2 == i_ehdrp->e_machine)) + { + /* target_ptr is an ELF backend which matches this + object file, so reject the generic ELF target. */ + goto got_wrong_format_error; + } + } + } + + if (i_ehdrp->e_type == ET_EXEC) + abfd->flags |= EXEC_P; + else if (i_ehdrp->e_type == ET_DYN) + abfd->flags |= DYNAMIC; + + if (i_ehdrp->e_phnum > 0) + abfd->flags |= D_PAGED; + + if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0)) + { + /* It's OK if this fails for the generic target. */ + if (ebd->elf_machine_code != EM_NONE) + goto got_no_match; + } + + /* Remember the entry point specified in the ELF file header. */ + bfd_set_start_address (abfd, i_ehdrp->e_entry); + + if (i_ehdrp->e_shoff != 0) + { + /* Seek to the section header table in the file. */ + if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0) + goto got_no_match; + + /* Read the first section header at index 0, and convert to internal + form. */ + if (bfd_bread ((PTR) & x_shdr, (bfd_size_type) sizeof x_shdr, abfd) + != sizeof (x_shdr)) + goto got_no_match; + elf_swap_shdr_in (abfd, &x_shdr, &i_shdr); + + /* If the section count is zero, the actual count is in the first + section header. */ + if (i_ehdrp->e_shnum == SHN_UNDEF) + i_ehdrp->e_shnum = i_shdr.sh_size; + + /* And similarly for the string table index. */ + if (i_ehdrp->e_shstrndx == SHN_XINDEX) + i_ehdrp->e_shstrndx = i_shdr.sh_link; + } + + /* Allocate space for a copy of the section header table in + internal form. */ + if (i_ehdrp->e_shnum != 0) + { + Elf_Internal_Shdr *shdrp; + unsigned int num_sec; + + amt = sizeof (*i_shdrp) * i_ehdrp->e_shnum; + i_shdrp = (Elf_Internal_Shdr *) bfd_alloc (abfd, amt); + if (!i_shdrp) + goto got_no_match; + num_sec = i_ehdrp->e_shnum; + if (num_sec > SHN_LORESERVE) + num_sec += SHN_HIRESERVE + 1 - SHN_LORESERVE; + elf_numsections (abfd) = num_sec; + amt = sizeof (i_shdrp) * num_sec; + elf_elfsections (abfd) = (Elf_Internal_Shdr **) bfd_alloc (abfd, amt); + if (!elf_elfsections (abfd)) + goto got_no_match; + + memcpy (i_shdrp, &i_shdr, sizeof (*i_shdrp)); + shdrp = i_shdrp; + shindex = 0; + if (num_sec > SHN_LORESERVE) + { + for ( ; shindex < SHN_LORESERVE; shindex++) + elf_elfsections (abfd)[shindex] = shdrp++; + for ( ; shindex < SHN_HIRESERVE + 1; shindex++) + elf_elfsections (abfd)[shindex] = i_shdrp; + } + for ( ; shindex < num_sec; shindex++) + elf_elfsections (abfd)[shindex] = shdrp++; + + /* Read in the rest of the section header table and convert it + to internal form. */ + for (shindex = 1; shindex < i_ehdrp->e_shnum; shindex++) + { + if (bfd_bread ((PTR) & x_shdr, (bfd_size_type) sizeof x_shdr, abfd) + != sizeof (x_shdr)) + goto got_no_match; + elf_swap_shdr_in (abfd, &x_shdr, i_shdrp + shindex); + + /* If the section is loaded, but not page aligned, clear + D_PAGED. */ + if (i_shdrp[shindex].sh_size != 0 + && (i_shdrp[shindex].sh_flags & SHF_ALLOC) != 0 + && i_shdrp[shindex].sh_type != SHT_NOBITS + && (((i_shdrp[shindex].sh_addr - i_shdrp[shindex].sh_offset) + % ebd->maxpagesize) + != 0)) + abfd->flags &= ~D_PAGED; + } + } + + if (i_ehdrp->e_shstrndx && i_ehdrp->e_shoff) + { + if (! bfd_section_from_shdr (abfd, i_ehdrp->e_shstrndx)) + goto got_no_match; + } + + /* Read in the program headers. */ + if (i_ehdrp->e_phnum == 0) + elf_tdata (abfd)->phdr = NULL; + else + { + Elf_Internal_Phdr *i_phdr; + unsigned int i; + + amt = i_ehdrp->e_phnum * sizeof (Elf_Internal_Phdr); + elf_tdata (abfd)->phdr = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt); + if (elf_tdata (abfd)->phdr == NULL) + goto got_no_match; + if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_phoff, SEEK_SET) != 0) + goto got_no_match; + i_phdr = elf_tdata (abfd)->phdr; + for (i = 0; i < i_ehdrp->e_phnum; i++, i_phdr++) + { + Elf_External_Phdr x_phdr; + + if (bfd_bread ((PTR) &x_phdr, (bfd_size_type) sizeof x_phdr, abfd) + != sizeof x_phdr) + goto got_no_match; + elf_swap_phdr_in (abfd, &x_phdr, i_phdr); + } + } + + /* Read in the string table containing the names of the sections. We + will need the base pointer to this table later. */ + /* We read this inline now, so that we don't have to go through + bfd_section_from_shdr with it (since this particular strtab is + used to find all of the ELF section names.) */ + + if (i_ehdrp->e_shstrndx != 0 && i_ehdrp->e_shoff) + { + unsigned int num_sec; + + shstrtab = bfd_elf_get_str_section (abfd, i_ehdrp->e_shstrndx); + if (!shstrtab) + goto got_no_match; + + /* Once all of the section headers have been read and converted, we + can start processing them. Note that the first section header is + a dummy placeholder entry, so we ignore it. */ + num_sec = elf_numsections (abfd); + for (shindex = 1; shindex < num_sec; shindex++) + { + if (! bfd_section_from_shdr (abfd, shindex)) + goto got_no_match; + if (shindex == SHN_LORESERVE - 1) + shindex += SHN_HIRESERVE + 1 - SHN_LORESERVE; + } + } + + /* Let the backend double check the format and override global + information. */ + if (ebd->elf_backend_object_p) + { + if (! (*ebd->elf_backend_object_p) (abfd)) + goto got_wrong_format_error; + } + + /* If we have created any reloc sections that are associated with + debugging sections, mark the reloc sections as debugging as well. */ + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((elf_section_data (s)->this_hdr.sh_type == SHT_REL + || elf_section_data (s)->this_hdr.sh_type == SHT_RELA) + && elf_section_data (s)->this_hdr.sh_info > 0) + { + unsigned long targ_index; + asection *targ_sec; + + targ_index = elf_section_data (s)->this_hdr.sh_info; + targ_sec = bfd_section_from_elf_index (abfd, targ_index); + if (targ_sec != NULL + && (targ_sec->flags & SEC_DEBUGGING) != 0) + s->flags |= SEC_DEBUGGING; + } + } + + bfd_preserve_finish (abfd, &preserve); + return abfd->xvec; + + got_wrong_format_error: + /* There is way too much undoing of half-known state here. The caller, + bfd_check_format_matches, really shouldn't iterate on live bfd's to + check match/no-match like it does. We have to rely on that a call to + bfd_default_set_arch_mach with the previously known mach, undoes what + was done by the first bfd_default_set_arch_mach (with mach 0) here. + For this to work, only elf-data and the mach may be changed by the + target-specific elf_backend_object_p function. Note that saving the + whole bfd here and restoring it would be even worse; the first thing + you notice is that the cached bfd file position gets out of sync. */ + bfd_set_error (bfd_error_wrong_format); + + got_no_match: + if (preserve.marker != NULL) + bfd_preserve_restore (abfd, &preserve); + return NULL; +} + +/* ELF .o/exec file writing */ + +/* Write out the relocs. */ + +void +elf_write_relocs (abfd, sec, data) + bfd *abfd; + asection *sec; + PTR data; +{ + bfd_boolean *failedp = (bfd_boolean *) data; + Elf_Internal_Shdr *rela_hdr; + bfd_vma addr_offset; + void (*swap_out) PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); + size_t extsize; + bfd_byte *dst_rela; + unsigned int idx; + asymbol *last_sym; + int last_sym_idx; + + /* If we have already failed, don't do anything. */ + if (*failedp) + return; + + if ((sec->flags & SEC_RELOC) == 0) + return; + + /* The linker backend writes the relocs out itself, and sets the + reloc_count field to zero to inhibit writing them here. Also, + sometimes the SEC_RELOC flag gets set even when there aren't any + relocs. */ + if (sec->reloc_count == 0) + return; + + rela_hdr = &elf_section_data (sec)->rel_hdr; + + rela_hdr->sh_size = rela_hdr->sh_entsize * sec->reloc_count; + rela_hdr->contents = (PTR) bfd_alloc (abfd, rela_hdr->sh_size); + if (rela_hdr->contents == NULL) + { + *failedp = TRUE; + return; + } + + /* Figure out whether the relocations are RELA or REL relocations. */ + if (rela_hdr->sh_type == SHT_RELA) + { + swap_out = elf_swap_reloca_out; + extsize = sizeof (Elf_External_Rela); + } + else if (rela_hdr->sh_type == SHT_REL) + { + swap_out = elf_swap_reloc_out; + extsize = sizeof (Elf_External_Rel); + } + else + /* Every relocation section should be either an SHT_RELA or an + SHT_REL section. */ + abort (); + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a BFD reloc is always section relative. */ + addr_offset = 0; + if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) + addr_offset = sec->vma; + + /* orelocation has the data, reloc_count has the count... */ + last_sym = 0; + last_sym_idx = 0; + dst_rela = rela_hdr->contents; + + for (idx = 0; idx < sec->reloc_count; idx++, dst_rela += extsize) + { + Elf_Internal_Rela src_rela; + arelent *ptr; + asymbol *sym; + int n; + + ptr = sec->orelocation[idx]; + sym = *ptr->sym_ptr_ptr; + if (sym == last_sym) + n = last_sym_idx; + else if (bfd_is_abs_section (sym->section) && sym->value == 0) + n = STN_UNDEF; + else + { + last_sym = sym; + n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym); + if (n < 0) + { + *failedp = TRUE; + return; + } + last_sym_idx = n; + } + + if ((*ptr->sym_ptr_ptr)->the_bfd != NULL + && (*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec + && ! _bfd_elf_validate_reloc (abfd, ptr)) + { + *failedp = TRUE; + return; + } + + src_rela.r_offset = ptr->address + addr_offset; + src_rela.r_info = ELF_R_INFO (n, ptr->howto->type); + src_rela.r_addend = ptr->addend; + (*swap_out) (abfd, &src_rela, dst_rela); + } +} + +/* Write out the program headers. */ + +int +elf_write_out_phdrs (abfd, phdr, count) + bfd *abfd; + const Elf_Internal_Phdr *phdr; + unsigned int count; +{ + while (count--) + { + Elf_External_Phdr extphdr; + elf_swap_phdr_out (abfd, phdr, &extphdr); + if (bfd_bwrite (&extphdr, (bfd_size_type) sizeof (Elf_External_Phdr), + abfd) != sizeof (Elf_External_Phdr)) + return -1; + phdr++; + } + return 0; +} + +/* Write out the section headers and the ELF file header. */ + +bfd_boolean +elf_write_shdrs_and_ehdr (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form */ + Elf_External_Shdr *x_shdrp; /* Section header table, external form */ + Elf_Internal_Shdr **i_shdrp; /* Section header table, internal form */ + unsigned int count; + bfd_size_type amt; + + i_ehdrp = elf_elfheader (abfd); + i_shdrp = elf_elfsections (abfd); + + /* swap the header before spitting it out... */ + +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + elf_swap_ehdr_out (abfd, i_ehdrp, &x_ehdr); + amt = sizeof (x_ehdr); + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || bfd_bwrite ((PTR) & x_ehdr, amt, abfd) != amt) + return FALSE; + + /* Some fields in the first section header handle overflow of ehdr + fields. */ + if (i_ehdrp->e_shnum >= SHN_LORESERVE) + i_shdrp[0]->sh_size = i_ehdrp->e_shnum; + if (i_ehdrp->e_shstrndx >= SHN_LORESERVE) + i_shdrp[0]->sh_link = i_ehdrp->e_shstrndx; + + /* at this point we've concocted all the ELF sections... */ + amt = i_ehdrp->e_shnum; + amt *= sizeof (*x_shdrp); + x_shdrp = (Elf_External_Shdr *) bfd_alloc (abfd, amt); + if (!x_shdrp) + return FALSE; + + for (count = 0; count < i_ehdrp->e_shnum; i_shdrp++, count++) + { +#if DEBUG & 2 + elf_debug_section (count, *i_shdrp); +#endif + elf_swap_shdr_out (abfd, *i_shdrp, x_shdrp + count); + + if (count == SHN_LORESERVE - 1) + i_shdrp += SHN_HIRESERVE + 1 - SHN_LORESERVE; + } + if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_shoff, SEEK_SET) != 0 + || bfd_bwrite ((PTR) x_shdrp, amt, abfd) != amt) + return FALSE; + + /* need to dump the string table too... */ + + return TRUE; +} + +long +elf_slurp_symbol_table (abfd, symptrs, dynamic) + bfd *abfd; + asymbol **symptrs; /* Buffer for generated bfd symbols */ + bfd_boolean dynamic; +{ + Elf_Internal_Shdr *hdr; + Elf_Internal_Shdr *verhdr; + unsigned long symcount; /* Number of external ELF symbols */ + elf_symbol_type *sym; /* Pointer to current bfd symbol */ + elf_symbol_type *symbase; /* Buffer for generated bfd symbols */ + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + Elf_Internal_Sym *isymbuf = NULL; + Elf_External_Versym *xver; + Elf_External_Versym *xverbuf = NULL; + struct elf_backend_data *ebd; + bfd_size_type amt; + + /* Read each raw ELF symbol, converting from external ELF form to + internal ELF form, and then using the information to create a + canonical bfd symbol table entry. + + Note that we allocate the initial bfd canonical symbol buffer + based on a one-to-one mapping of the ELF symbols to canonical + symbols. We actually use all the ELF symbols, so there will be no + space left over at the end. When we have all the symbols, we + build the caller's pointer vector. */ + + if (! dynamic) + { + hdr = &elf_tdata (abfd)->symtab_hdr; + verhdr = NULL; + } + else + { + hdr = &elf_tdata (abfd)->dynsymtab_hdr; + if (elf_dynversym (abfd) == 0) + verhdr = NULL; + else + verhdr = &elf_tdata (abfd)->dynversym_hdr; + if ((elf_tdata (abfd)->dynverdef_section != 0 + && elf_tdata (abfd)->verdef == NULL) + || (elf_tdata (abfd)->dynverref_section != 0 + && elf_tdata (abfd)->verref == NULL)) + { + if (! _bfd_elf_slurp_version_tables (abfd)) + return -1; + } + } + + ebd = get_elf_backend_data (abfd); + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + if (symcount == 0) + sym = symbase = NULL; + else + { + isymbuf = bfd_elf_get_elf_syms (abfd, hdr, symcount, 0, + NULL, NULL, NULL); + if (isymbuf == NULL) + return -1; + + amt = symcount; + amt *= sizeof (elf_symbol_type); + symbase = (elf_symbol_type *) bfd_zalloc (abfd, amt); + if (symbase == (elf_symbol_type *) NULL) + goto error_return; + + /* Read the raw ELF version symbol information. */ + if (verhdr != NULL + && verhdr->sh_size / sizeof (Elf_External_Versym) != symcount) + { + (*_bfd_error_handler) + (_("%s: version count (%ld) does not match symbol count (%ld)"), + abfd->filename, + (long) (verhdr->sh_size / sizeof (Elf_External_Versym)), + symcount); + + /* Slurp in the symbols without the version information, + since that is more helpful than just quitting. */ + verhdr = NULL; + } + + if (verhdr != NULL) + { + if (bfd_seek (abfd, verhdr->sh_offset, SEEK_SET) != 0) + goto error_return; + + xverbuf = (Elf_External_Versym *) bfd_malloc (verhdr->sh_size); + if (xverbuf == NULL && verhdr->sh_size != 0) + goto error_return; + + if (bfd_bread ((PTR) xverbuf, verhdr->sh_size, abfd) + != verhdr->sh_size) + goto error_return; + } + + /* Skip first symbol, which is a null dummy. */ + xver = xverbuf; + if (xver != NULL) + ++xver; + isymend = isymbuf + symcount; + 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.name = bfd_elf_string_from_elf_section (abfd, + hdr->sh_link, + isym->st_name); + + sym->symbol.value = isym->st_value; + + if (isym->st_shndx == SHN_UNDEF) + { + sym->symbol.section = bfd_und_section_ptr; + } + else if (isym->st_shndx < SHN_LORESERVE + || isym->st_shndx > SHN_HIRESERVE) + { + sym->symbol.section = section_from_elf_index (abfd, + isym->st_shndx); + if (sym->symbol.section == NULL) + { + /* This symbol is in a section for which we did not + create a BFD section. Just use bfd_abs_section, + although it is wrong. FIXME. */ + sym->symbol.section = bfd_abs_section_ptr; + } + } + else if (isym->st_shndx == SHN_ABS) + { + sym->symbol.section = bfd_abs_section_ptr; + } + else if (isym->st_shndx == SHN_COMMON) + { + sym->symbol.section = bfd_com_section_ptr; + /* Elf puts the alignment into the `value' field, and + the size into the `size' field. BFD wants to see the + size in the value field, and doesn't care (at the + moment) about the alignment. */ + sym->symbol.value = isym->st_size; + } + else + sym->symbol.section = bfd_abs_section_ptr; + + /* If this is a relocateable file, then the symbol value is + already section relative. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) + sym->symbol.value -= sym->symbol.section->vma; + + switch (ELF_ST_BIND (isym->st_info)) + { + case STB_LOCAL: + sym->symbol.flags |= BSF_LOCAL; + break; + case STB_GLOBAL: + if (isym->st_shndx != SHN_UNDEF && isym->st_shndx != SHN_COMMON) + sym->symbol.flags |= BSF_GLOBAL; + break; + case STB_WEAK: + sym->symbol.flags |= BSF_WEAK; + break; + } + + switch (ELF_ST_TYPE (isym->st_info)) + { + case STT_SECTION: + sym->symbol.flags |= BSF_SECTION_SYM | BSF_DEBUGGING; + break; + case STT_FILE: + sym->symbol.flags |= BSF_FILE | BSF_DEBUGGING; + break; + case STT_FUNC: + sym->symbol.flags |= BSF_FUNCTION; + break; + case STT_OBJECT: + sym->symbol.flags |= BSF_OBJECT; + break; + } + + if (dynamic) + sym->symbol.flags |= BSF_DYNAMIC; + + if (xver != NULL) + { + Elf_Internal_Versym iversym; + + _bfd_elf_swap_versym_in (abfd, xver, &iversym); + sym->version = iversym.vs_vers; + xver++; + } + + /* Do some backend-specific processing on this symbol. */ + if (ebd->elf_backend_symbol_processing) + (*ebd->elf_backend_symbol_processing) (abfd, &sym->symbol); + } + } + + /* Do some backend-specific processing on this symbol table. */ + if (ebd->elf_backend_symbol_table_processing) + (*ebd->elf_backend_symbol_table_processing) (abfd, symbase, symcount); + + /* We rely on the zalloc to clear out the final symbol entry. */ + + symcount = sym - symbase; + + /* Fill in the user's symbol pointer vector if needed. */ + if (symptrs) + { + long l = symcount; + + sym = symbase; + while (l-- > 0) + { + *symptrs++ = &sym->symbol; + sym++; + } + *symptrs = 0; /* Final null pointer */ + } + + if (xverbuf != NULL) + free (xverbuf); + if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf) + free (isymbuf); + return symcount; + +error_return: + if (xverbuf != NULL) + free (xverbuf); + if (isymbuf != NULL && hdr->contents != (unsigned char *) isymbuf) + free (isymbuf); + return -1; +} + +/* Read relocations for ASECT from REL_HDR. There are RELOC_COUNT of + them. */ + +static bfd_boolean +elf_slurp_reloc_table_from_section (abfd, asect, rel_hdr, reloc_count, + relents, symbols, dynamic) + bfd *abfd; + asection *asect; + Elf_Internal_Shdr *rel_hdr; + bfd_size_type reloc_count; + arelent *relents; + asymbol **symbols; + bfd_boolean dynamic; +{ + struct elf_backend_data * const ebd = get_elf_backend_data (abfd); + PTR allocated = NULL; + bfd_byte *native_relocs; + arelent *relent; + unsigned int i; + int entsize; + unsigned int symcount; + + allocated = (PTR) bfd_malloc (rel_hdr->sh_size); + if (allocated == NULL) + goto error_return; + + if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0 + || (bfd_bread (allocated, rel_hdr->sh_size, abfd) + != rel_hdr->sh_size)) + goto error_return; + + native_relocs = (bfd_byte *) allocated; + + entsize = rel_hdr->sh_entsize; + BFD_ASSERT (entsize == sizeof (Elf_External_Rel) + || entsize == sizeof (Elf_External_Rela)); + + if (dynamic) + symcount = bfd_get_dynamic_symcount (abfd); + else + symcount = bfd_get_symcount (abfd); + + for (i = 0, relent = relents; + i < reloc_count; + i++, relent++, native_relocs += entsize) + { + Elf_Internal_Rela rela; + + if (entsize == sizeof (Elf_External_Rela)) + elf_swap_reloca_in (abfd, native_relocs, &rela); + else + elf_swap_reloc_in (abfd, native_relocs, &rela); + + /* The address of an ELF reloc is section relative for an object + file, and absolute for an executable file or shared library. + The address of a normal BFD reloc is always section relative, + and the address of a dynamic reloc is absolute.. */ + if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic) + relent->address = rela.r_offset; + else + relent->address = rela.r_offset - asect->vma; + + if (ELF_R_SYM (rela.r_info) == 0) + relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; + else if (ELF_R_SYM (rela.r_info) > symcount) + { + (*_bfd_error_handler) + (_("%s(%s): relocation %d has invalid symbol index %ld"), + abfd->filename, asect->name, i, ELF_R_SYM (rela.r_info)); + relent->sym_ptr_ptr = bfd_abs_section.symbol_ptr_ptr; + } + else + { + asymbol **ps, *s; + + ps = symbols + ELF_R_SYM (rela.r_info) - 1; + s = *ps; + + /* Canonicalize ELF section symbols. FIXME: Why? */ + if ((s->flags & BSF_SECTION_SYM) == 0) + relent->sym_ptr_ptr = ps; + else + relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; + } + + relent->addend = rela.r_addend; + + if ((entsize == sizeof (Elf_External_Rela) + && ebd->elf_info_to_howto != NULL) + || ebd->elf_info_to_howto_rel == NULL) + (*ebd->elf_info_to_howto) (abfd, relent, &rela); + else + (*ebd->elf_info_to_howto_rel) (abfd, relent, &rela); + } + + if (allocated != NULL) + free (allocated); + + return TRUE; + + error_return: + if (allocated != NULL) + free (allocated); + return FALSE; +} + +/* Read in and swap the external relocs. */ + +bfd_boolean +elf_slurp_reloc_table (abfd, asect, symbols, dynamic) + bfd *abfd; + asection *asect; + asymbol **symbols; + bfd_boolean dynamic; +{ + struct bfd_elf_section_data * const d = elf_section_data (asect); + Elf_Internal_Shdr *rel_hdr; + Elf_Internal_Shdr *rel_hdr2; + bfd_size_type reloc_count; + bfd_size_type reloc_count2; + arelent *relents; + bfd_size_type amt; + + if (asect->relocation != NULL) + return TRUE; + + if (! dynamic) + { + if ((asect->flags & SEC_RELOC) == 0 + || asect->reloc_count == 0) + return TRUE; + + rel_hdr = &d->rel_hdr; + reloc_count = NUM_SHDR_ENTRIES (rel_hdr); + rel_hdr2 = d->rel_hdr2; + reloc_count2 = (rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0); + + BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2); + BFD_ASSERT (asect->rel_filepos == rel_hdr->sh_offset + || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset)); + + } + else + { + /* Note that ASECT->RELOC_COUNT tends not to be accurate in this + case because relocations against this section may use the + dynamic symbol table, and in that case bfd_section_from_shdr + in elf.c does not update the RELOC_COUNT. */ + if (asect->_raw_size == 0) + return TRUE; + + rel_hdr = &d->this_hdr; + reloc_count = NUM_SHDR_ENTRIES (rel_hdr); + rel_hdr2 = NULL; + reloc_count2 = 0; + } + + amt = (reloc_count + reloc_count2) * sizeof (arelent); + relents = (arelent *) bfd_alloc (abfd, amt); + if (relents == NULL) + return FALSE; + + if (!elf_slurp_reloc_table_from_section (abfd, asect, + rel_hdr, reloc_count, + relents, + symbols, dynamic)) + return FALSE; + + if (rel_hdr2 + && !elf_slurp_reloc_table_from_section (abfd, asect, + rel_hdr2, reloc_count2, + relents + reloc_count, + symbols, dynamic)) + return FALSE; + + asect->relocation = relents; + return TRUE; +} + +#ifdef DEBUG +static void +elf_debug_section (num, hdr) + int num; + Elf_Internal_Shdr *hdr; +{ + fprintf (stderr, "\nSection#%d '%s' 0x%.8lx\n", num, + hdr->bfd_section != NULL ? hdr->bfd_section->name : "", + (long) hdr); + fprintf (stderr, + "sh_name = %ld\tsh_type = %ld\tsh_flags = %ld\n", + (long) hdr->sh_name, + (long) hdr->sh_type, + (long) hdr->sh_flags); + fprintf (stderr, + "sh_addr = %ld\tsh_offset = %ld\tsh_size = %ld\n", + (long) hdr->sh_addr, + (long) hdr->sh_offset, + (long) hdr->sh_size); + fprintf (stderr, + "sh_link = %ld\tsh_info = %ld\tsh_addralign = %ld\n", + (long) hdr->sh_link, + (long) hdr->sh_info, + (long) hdr->sh_addralign); + fprintf (stderr, "sh_entsize = %ld\n", + (long) hdr->sh_entsize); + fflush (stderr); +} + +static void +elf_debug_file (ehdrp) + Elf_Internal_Ehdr *ehdrp; +{ + fprintf (stderr, "e_entry = 0x%.8lx\n", (long) ehdrp->e_entry); + fprintf (stderr, "e_phoff = %ld\n", (long) ehdrp->e_phoff); + fprintf (stderr, "e_phnum = %ld\n", (long) ehdrp->e_phnum); + fprintf (stderr, "e_phentsize = %ld\n", (long) ehdrp->e_phentsize); + fprintf (stderr, "e_shoff = %ld\n", (long) ehdrp->e_shoff); + fprintf (stderr, "e_shnum = %ld\n", (long) ehdrp->e_shnum); + fprintf (stderr, "e_shentsize = %ld\n", (long) ehdrp->e_shentsize); +} + +static char * +elf_symbol_flags (flags) + flagword flags; +{ + static char buffer[1024]; + + buffer[0] = '\0'; + if (flags & BSF_LOCAL) + strcat (buffer, " local"); + + if (flags & BSF_GLOBAL) + strcat (buffer, " global"); + + if (flags & BSF_DEBUGGING) + strcat (buffer, " debug"); + + if (flags & BSF_FUNCTION) + strcat (buffer, " function"); + + if (flags & BSF_KEEP) + strcat (buffer, " keep"); + + if (flags & BSF_KEEP_G) + strcat (buffer, " keep_g"); + + if (flags & BSF_WEAK) + strcat (buffer, " weak"); + + if (flags & BSF_SECTION_SYM) + strcat (buffer, " section-sym"); + + if (flags & BSF_OLD_COMMON) + strcat (buffer, " old-common"); + + if (flags & BSF_NOT_AT_END) + strcat (buffer, " not-at-end"); + + if (flags & BSF_CONSTRUCTOR) + strcat (buffer, " constructor"); + + if (flags & BSF_WARNING) + strcat (buffer, " warning"); + + if (flags & BSF_INDIRECT) + strcat (buffer, " indirect"); + + if (flags & BSF_FILE) + strcat (buffer, " file"); + + if (flags & DYNAMIC) + strcat (buffer, " dynamic"); + + if (flags & ~(BSF_LOCAL + | BSF_GLOBAL + | BSF_DEBUGGING + | BSF_FUNCTION + | BSF_KEEP + | BSF_KEEP_G + | BSF_WEAK + | BSF_SECTION_SYM + | BSF_OLD_COMMON + | BSF_NOT_AT_END + | BSF_CONSTRUCTOR + | BSF_WARNING + | BSF_INDIRECT + | BSF_FILE + | BSF_DYNAMIC)) + strcat (buffer, " unknown-bits"); + + return buffer; +} +#endif + +#include "elfcore.h" +#include "elflink.h" + +/* Size-dependent data and functions. */ +const struct elf_size_info NAME(_bfd_elf,size_info) = { + sizeof (Elf_External_Ehdr), + sizeof (Elf_External_Phdr), + sizeof (Elf_External_Shdr), + sizeof (Elf_External_Rel), + sizeof (Elf_External_Rela), + sizeof (Elf_External_Sym), + sizeof (Elf_External_Dyn), + sizeof (Elf_External_Note), + 4, + 1, + ARCH_SIZE, FILE_ALIGN, + ELFCLASS, EV_CURRENT, + elf_write_out_phdrs, + elf_write_shdrs_and_ehdr, + elf_write_relocs, + elf_swap_symbol_in, + elf_swap_symbol_out, + elf_slurp_reloc_table, + elf_slurp_symbol_table, + elf_swap_dyn_in, + elf_swap_dyn_out, + elf_swap_reloc_in, + elf_swap_reloc_out, + elf_swap_reloca_in, + elf_swap_reloca_out +}; diff --git a/contrib/binutils-2.14/bfd/elfcore.h b/contrib/binutils-2.14/bfd/elfcore.h new file mode 100644 index 0000000000..724d607d3a --- /dev/null +++ b/contrib/binutils-2.14/bfd/elfcore.h @@ -0,0 +1,259 @@ +/* ELF core file support for BFD. + Copyright 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +char* +elf_core_file_failing_command (abfd) + bfd *abfd; +{ + return elf_tdata (abfd)->core_command; +} + +int +elf_core_file_failing_signal (abfd) + bfd *abfd; +{ + return elf_tdata (abfd)->core_signal; +} + +bfd_boolean +elf_core_file_matches_executable_p (core_bfd, exec_bfd) + bfd *core_bfd; + bfd *exec_bfd; +{ + char* corename; + + /* xvecs must match if both are ELF files for the same target. */ + + if (core_bfd->xvec != exec_bfd->xvec) + { + bfd_set_error (bfd_error_system_call); + return FALSE; + } + + /* See if the name in the corefile matches the executable name. */ + corename = elf_tdata (core_bfd)->core_program; + if (corename != NULL) + { + const char* execname = strrchr (exec_bfd->filename, '/'); + + execname = execname ? execname + 1 : exec_bfd->filename; + + if (strcmp(execname, corename) != 0) + return FALSE; + } + + return TRUE; +} + +/* Core files are simply standard ELF formatted files that partition + the file using the execution view of the file (program header table) + rather than the linking view. In fact, there is no section header + table in a core file. + + The process status information (including the contents of the general + register set) and the floating point register set are stored in a + segment of type PT_NOTE. We handcraft a couple of extra bfd sections + that allow standard bfd access to the general registers (.reg) and the + floating point registers (.reg2). */ + +const bfd_target * +elf_core_file_p (abfd) + bfd *abfd; +{ + Elf_External_Ehdr x_ehdr; /* Elf file header, external form. */ + Elf_Internal_Ehdr *i_ehdrp; /* Elf file header, internal form. */ + Elf_Internal_Phdr *i_phdrp; /* Elf program header, internal form. */ + unsigned int phindex; + struct elf_backend_data *ebd; + struct bfd_preserve preserve; + bfd_size_type amt; + + preserve.marker = NULL; + + /* Read in the ELF header in external format. */ + if (bfd_bread ((PTR) &x_ehdr, (bfd_size_type) sizeof (x_ehdr), abfd) + != sizeof (x_ehdr)) + { + if (bfd_get_error () != bfd_error_system_call) + goto wrong; + else + goto fail; + } + + /* Check the magic number. */ + if (! elf_file_p (&x_ehdr)) + goto wrong; + + /* FIXME: Check EI_VERSION here ! */ + + /* Check the address size ("class"). */ + if (x_ehdr.e_ident[EI_CLASS] != ELFCLASS) + goto wrong; + + /* Check the byteorder. */ + switch (x_ehdr.e_ident[EI_DATA]) + { + case ELFDATA2MSB: /* Big-endian. */ + if (! bfd_big_endian (abfd)) + goto wrong; + break; + case ELFDATA2LSB: /* Little-endian. */ + if (! bfd_little_endian (abfd)) + goto wrong; + break; + default: + goto wrong; + } + + /* Give abfd an elf_obj_tdata. */ + amt = sizeof (struct elf_obj_tdata); + preserve.marker = bfd_zalloc (abfd, amt); + if (preserve.marker == NULL) + goto fail; + if (!bfd_preserve_save (abfd, &preserve)) + goto fail; + + elf_tdata (abfd) = preserve.marker; + + /* Swap in the rest of the header, now that we have the byte order. */ + i_ehdrp = elf_elfheader (abfd); + elf_swap_ehdr_in (abfd, &x_ehdr, i_ehdrp); + +#if DEBUG & 1 + elf_debug_file (i_ehdrp); +#endif + + ebd = get_elf_backend_data (abfd); + + /* Check that the ELF e_machine field matches what this particular + BFD format expects. */ + + if (ebd->elf_machine_code != i_ehdrp->e_machine + && (ebd->elf_machine_alt1 == 0 + || i_ehdrp->e_machine != ebd->elf_machine_alt1) + && (ebd->elf_machine_alt2 == 0 + || i_ehdrp->e_machine != ebd->elf_machine_alt2)) + { + const bfd_target * const *target_ptr; + + if (ebd->elf_machine_code != EM_NONE) + goto wrong; + + /* This is the generic ELF target. Let it match any ELF target + for which we do not have a specific backend. */ + + for (target_ptr = bfd_target_vector; *target_ptr != NULL; target_ptr++) + { + struct elf_backend_data *back; + + if ((*target_ptr)->flavour != bfd_target_elf_flavour) + continue; + back = (struct elf_backend_data *) (*target_ptr)->backend_data; + if (back->elf_machine_code == i_ehdrp->e_machine + || (back->elf_machine_alt1 != 0 + && i_ehdrp->e_machine == back->elf_machine_alt1) + || (back->elf_machine_alt2 != 0 + && i_ehdrp->e_machine == back->elf_machine_alt2)) + { + /* target_ptr is an ELF backend which matches this + object file, so reject the generic ELF target. */ + goto wrong; + } + } + } + + /* If there is no program header, or the type is not a core file, then + we are hosed. */ + if (i_ehdrp->e_phoff == 0 || i_ehdrp->e_type != ET_CORE) + goto wrong; + + /* Does BFD's idea of the phdr size match the size + recorded in the file? */ + if (i_ehdrp->e_phentsize != sizeof (Elf_External_Phdr)) + goto wrong; + + /* Move to the start of the program headers. */ + if (bfd_seek (abfd, (file_ptr) i_ehdrp->e_phoff, SEEK_SET) != 0) + goto wrong; + + /* Allocate space for the program headers. */ + amt = sizeof (*i_phdrp) * i_ehdrp->e_phnum; + i_phdrp = (Elf_Internal_Phdr *) bfd_alloc (abfd, amt); + if (!i_phdrp) + goto fail; + + elf_tdata (abfd)->phdr = i_phdrp; + + /* Read and convert to internal form. */ + for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) + { + Elf_External_Phdr x_phdr; + + if (bfd_bread ((PTR) &x_phdr, (bfd_size_type) sizeof (x_phdr), abfd) + != sizeof (x_phdr)) + goto fail; + + elf_swap_phdr_in (abfd, &x_phdr, i_phdrp + phindex); + } + + /* Set the machine architecture. Do this before processing the + program headers since we need to know the architecture type + when processing the notes of some systems' core files. */ + if (! bfd_default_set_arch_mach (abfd, ebd->arch, 0)) + { + /* It's OK if this fails for the generic target. */ + if (ebd->elf_machine_code != EM_NONE) + goto fail; + } + + /* Process each program header. */ + for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) + if (! bfd_section_from_phdr (abfd, i_phdrp + phindex, (int) phindex)) + goto fail; + + /* Save the entry point from the ELF header. */ + bfd_get_start_address (abfd) = i_ehdrp->e_entry; + + /* Let the backend double check the format and override global + information. */ + if (ebd->elf_backend_object_p + && (! (*ebd->elf_backend_object_p) (abfd))) + goto wrong; + + bfd_preserve_finish (abfd, &preserve); + return abfd->xvec; + +wrong: + /* There is way too much undoing of half-known state here. The caller, + bfd_check_format_matches, really shouldn't iterate on live bfd's to + check match/no-match like it does. We have to rely on that a call to + bfd_default_set_arch_mach with the previously known mach, undoes what + was done by the first bfd_default_set_arch_mach (with mach 0) here. + For this to work, only elf-data and the mach may be changed by the + target-specific elf_backend_object_p function. Note that saving the + whole bfd here and restoring it would be even worse; the first thing + you notice is that the cached bfd file position gets out of sync. */ + bfd_set_error (bfd_error_wrong_format); + +fail: + if (preserve.marker != NULL) + bfd_preserve_restore (abfd, &preserve); + return NULL; +} diff --git a/contrib/binutils-2.14/bfd/elflink.c b/contrib/binutils-2.14/bfd/elflink.c new file mode 100644 index 0000000000..962c104411 --- /dev/null +++ b/contrib/binutils-2.14/bfd/elflink.c @@ -0,0 +1,652 @@ +/* ELF linking support for BFD. + Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +#define ARCH_SIZE 0 +#include "elf-bfd.h" + +bfd_boolean +_bfd_elf_create_got_section (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + asection *s; + struct elf_link_hash_entry *h; + struct bfd_link_hash_entry *bh; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + int ptralign; + + /* This function may be called more than once. */ + s = bfd_get_section_by_name (abfd, ".got"); + if (s != NULL && (s->flags & SEC_LINKER_CREATED) != 0) + return TRUE; + + switch (bed->s->arch_size) + { + case 32: + ptralign = 2; + break; + + case 64: + ptralign = 3; + break; + + default: + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + s = bfd_make_section (abfd, ".got"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags) + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + + if (bed->want_got_plt) + { + s = bfd_make_section (abfd, ".got.plt"); + if (s == NULL + || !bfd_set_section_flags (abfd, s, flags) + || !bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + } + + if (bed->want_got_sym) + { + /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got + (or .got.plt) section. We don't do this in the linker script + because we don't want to define the symbol if we are not creating + a global offset table. */ + bh = NULL; + if (!(_bfd_generic_link_add_one_symbol + (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, + bed->got_symbol_offset, (const char *) NULL, FALSE, + bed->collect, &bh))) + return FALSE; + h = (struct elf_link_hash_entry *) bh; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + elf_hash_table (info)->hgot = h; + } + + /* The first bit of the global offset table is the header. */ + s->_raw_size += bed->got_header_size + bed->got_symbol_offset; + + return TRUE; +} + +/* Create dynamic sections when linking against a dynamic object. */ + +bfd_boolean +_bfd_elf_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags, pltflags; + asection *s; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + int ptralign; + + switch (bed->s->arch_size) + { + case 32: + ptralign = 2; + break; + + case 64: + ptralign = 3; + break; + + default: + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* 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_CODE | SEC_LOAD | SEC_HAS_CONTENTS); + if (bed->plt_readonly) + pltflags |= SEC_READONLY; + + s = bfd_make_section (abfd, ".plt"); + 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 elf_link_hash_entry *h; + struct bfd_link_hash_entry *bh = NULL; + + 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->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + 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"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + + if (! _bfd_elf_create_got_section (abfd, info)) + 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"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) + 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")); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, ptralign)) + return FALSE; + } + } + + return TRUE; +} + +/* Record a new dynamic symbol. We record the dynamic symbols as we + read the input files, since we need to have a list of all of them + before we can determine the final sizes of the output sections. + Note that we may actually call this function even though we are not + going to output any dynamic symbols; in some cases we know that a + symbol should be in the dynamic symbol table, but only if there is + one. */ + +bfd_boolean +_bfd_elf_link_record_dynamic_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + if (h->dynindx == -1) + { + struct elf_strtab_hash *dynstr; + char *p, *alc; + const char *name; + bfd_boolean copy; + bfd_size_type indx; + + /* XXX: The ABI draft says the linker must turn hidden and + internal symbols into STB_LOCAL symbols when producing the + DSO. However, if ld.so honors st_other in the dynamic table, + this would not be necessary. */ + switch (ELF_ST_VISIBILITY (h->other)) + { + case STV_INTERNAL: + case STV_HIDDEN: + if (h->root.type != bfd_link_hash_undefined + && h->root.type != bfd_link_hash_undefweak) + { + h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL; + return TRUE; + } + + default: + break; + } + + h->dynindx = elf_hash_table (info)->dynsymcount; + ++elf_hash_table (info)->dynsymcount; + + dynstr = elf_hash_table (info)->dynstr; + if (dynstr == NULL) + { + /* Create a strtab to hold the dynamic symbol names. */ + elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init (); + if (dynstr == NULL) + return FALSE; + } + + /* We don't put any version information in the dynamic string + table. */ + name = h->root.root.string; + p = strchr (name, ELF_VER_CHR); + if (p == NULL) + { + alc = NULL; + copy = FALSE; + } + else + { + size_t len = p - name + 1; + + alc = bfd_malloc ((bfd_size_type) len); + if (alc == NULL) + return FALSE; + memcpy (alc, name, len - 1); + alc[len - 1] = '\0'; + name = alc; + copy = TRUE; + } + + indx = _bfd_elf_strtab_add (dynstr, name, copy); + + if (alc != NULL) + free (alc); + + if (indx == (bfd_size_type) -1) + return FALSE; + h->dynstr_index = indx; + } + + return TRUE; +} + +/* Record a new local dynamic symbol. Returns 0 on failure, 1 on + success, and 2 on a failure caused by attempting to record a symbol + in a discarded section, eg. a discarded link-once section symbol. */ + +int +elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx) + struct bfd_link_info *info; + bfd *input_bfd; + long input_indx; +{ + bfd_size_type amt; + struct elf_link_local_dynamic_entry *entry; + struct elf_link_hash_table *eht; + struct elf_strtab_hash *dynstr; + unsigned long dynstr_index; + char *name; + Elf_External_Sym_Shndx eshndx; + char esym[sizeof (Elf64_External_Sym)]; + + if (! is_elf_hash_table (info)) + return 0; + + /* See if the entry exists already. */ + for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next) + if (entry->input_bfd == input_bfd && entry->input_indx == input_indx) + return 1; + + amt = sizeof (*entry); + entry = (struct elf_link_local_dynamic_entry *) bfd_alloc (input_bfd, amt); + if (entry == NULL) + return 0; + + /* Go find the symbol, so that we can find it's name. */ + if (!bfd_elf_get_elf_syms (input_bfd, &elf_tdata (input_bfd)->symtab_hdr, + (size_t) 1, (size_t) input_indx, + &entry->isym, esym, &eshndx)) + { + bfd_release (input_bfd, entry); + return 0; + } + + if (entry->isym.st_shndx != SHN_UNDEF + && (entry->isym.st_shndx < SHN_LORESERVE + || entry->isym.st_shndx > SHN_HIRESERVE)) + { + asection *s; + + s = bfd_section_from_elf_index (input_bfd, entry->isym.st_shndx); + if (s == NULL || bfd_is_abs_section (s->output_section)) + { + /* We can still bfd_release here as nothing has done another + bfd_alloc. We can't do this later in this function. */ + bfd_release (input_bfd, entry); + return 2; + } + } + + name = (bfd_elf_string_from_elf_section + (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link, + entry->isym.st_name)); + + dynstr = elf_hash_table (info)->dynstr; + if (dynstr == NULL) + { + /* Create a strtab to hold the dynamic symbol names. */ + elf_hash_table (info)->dynstr = dynstr = _bfd_elf_strtab_init (); + if (dynstr == NULL) + return 0; + } + + dynstr_index = _bfd_elf_strtab_add (dynstr, name, FALSE); + if (dynstr_index == (unsigned long) -1) + return 0; + entry->isym.st_name = dynstr_index; + + eht = elf_hash_table (info); + + entry->next = eht->dynlocal; + eht->dynlocal = entry; + entry->input_bfd = input_bfd; + entry->input_indx = input_indx; + eht->dynsymcount++; + + /* Whatever binding the symbol had before, it's now local. */ + entry->isym.st_info + = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info)); + + /* The dynindx will be set at the end of size_dynamic_sections. */ + + return 1; +} + +/* Return the dynindex of a local dynamic symbol. */ + +long +_bfd_elf_link_lookup_local_dynindx (info, input_bfd, input_indx) + struct bfd_link_info *info; + bfd *input_bfd; + long input_indx; +{ + struct elf_link_local_dynamic_entry *e; + + for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) + if (e->input_bfd == input_bfd && e->input_indx == input_indx) + return e->dynindx; + return -1; +} + +/* This function is used to renumber the dynamic symbols, if some of + them are removed because they are marked as local. This is called + via elf_link_hash_traverse. */ + +static bfd_boolean elf_link_renumber_hash_table_dynsyms + PARAMS ((struct elf_link_hash_entry *, PTR)); + +static bfd_boolean +elf_link_renumber_hash_table_dynsyms (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + size_t *count = (size_t *) data; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->dynindx != -1) + h->dynindx = ++(*count); + + return TRUE; +} + +/* Assign dynsym indices. In a shared library we generate a section + symbol for each output section, which come first. Next come all of + the back-end allocated local dynamic syms, followed by the rest of + the global symbols. */ + +unsigned long +_bfd_elf_link_renumber_dynsyms (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + unsigned long dynsymcount = 0; + + if (info->shared) + { + asection *p; + for (p = output_bfd->sections; p ; p = p->next) + if ((p->flags & SEC_EXCLUDE) == 0) + elf_section_data (p)->dynindx = ++dynsymcount; + } + + if (elf_hash_table (info)->dynlocal) + { + struct elf_link_local_dynamic_entry *p; + for (p = elf_hash_table (info)->dynlocal; p ; p = p->next) + p->dynindx = ++dynsymcount; + } + + elf_link_hash_traverse (elf_hash_table (info), + elf_link_renumber_hash_table_dynsyms, + &dynsymcount); + + /* There is an unused NULL entry at the head of the table which + we must account for in our count. Unless there weren't any + symbols, which means we'll have no table at all. */ + if (dynsymcount != 0) + ++dynsymcount; + + return elf_hash_table (info)->dynsymcount = dynsymcount; +} + +/* Create a special linker section, or return a pointer to a linker + section already created */ + +elf_linker_section_t * +_bfd_elf_create_linker_section (abfd, info, which, defaults) + bfd *abfd; + struct bfd_link_info *info; + enum elf_linker_section_enum which; + elf_linker_section_t *defaults; +{ + bfd *dynobj = elf_hash_table (info)->dynobj; + elf_linker_section_t *lsect; + + /* Record the first bfd section that needs the special section */ + if (!dynobj) + dynobj = elf_hash_table (info)->dynobj = abfd; + + /* If this is the first time, create the section */ + lsect = elf_linker_section (dynobj, which); + if (!lsect) + { + asection *s; + bfd_size_type amt = sizeof (elf_linker_section_t); + + lsect = (elf_linker_section_t *) bfd_alloc (dynobj, amt); + + *lsect = *defaults; + elf_linker_section (dynobj, which) = lsect; + lsect->which = which; + lsect->hole_written_p = FALSE; + + /* See if the sections already exist */ + lsect->section = s = bfd_get_section_by_name (dynobj, lsect->name); + if (!s || (s->flags & defaults->flags) != defaults->flags) + { + lsect->section = s = bfd_make_section_anyway (dynobj, lsect->name); + + if (s == NULL) + return (elf_linker_section_t *)0; + + bfd_set_section_flags (dynobj, s, defaults->flags); + bfd_set_section_alignment (dynobj, s, lsect->alignment); + } + else if (bfd_get_section_alignment (dynobj, s) < lsect->alignment) + bfd_set_section_alignment (dynobj, s, lsect->alignment); + + s->_raw_size = align_power (s->_raw_size, lsect->alignment); + + /* Is there a hole we have to provide? If so check whether the + segment is too big already */ + if (lsect->hole_size) + { + lsect->hole_offset = s->_raw_size; + s->_raw_size += lsect->hole_size; + if (lsect->hole_offset > lsect->max_hole_offset) + { + (*_bfd_error_handler) + (_("%s: Section %s is too large to add hole of %ld bytes"), + bfd_get_filename (abfd), + lsect->name, + (long) lsect->hole_size); + + bfd_set_error (bfd_error_bad_value); + return (elf_linker_section_t *)0; + } + } + +#ifdef DEBUG + fprintf (stderr, "Creating section %s, current size = %ld\n", + lsect->name, (long)s->_raw_size); +#endif + + if (lsect->sym_name) + { + struct elf_link_hash_entry *h; + struct bfd_link_hash_entry *bh; + +#ifdef DEBUG + fprintf (stderr, "Adding %s to section %s\n", + lsect->sym_name, + lsect->name); +#endif + bh = bfd_link_hash_lookup (info->hash, lsect->sym_name, + FALSE, FALSE, FALSE); + + if ((bh == NULL || bh->type == bfd_link_hash_undefined) + && !(_bfd_generic_link_add_one_symbol + (info, abfd, lsect->sym_name, BSF_GLOBAL, s, + (lsect->hole_size + ? s->_raw_size - lsect->hole_size + lsect->sym_offset + : lsect->sym_offset), + (const char *) NULL, FALSE, + get_elf_backend_data (abfd)->collect, &bh))) + return (elf_linker_section_t *) 0; + h = (struct elf_link_hash_entry *) bh; + + if ((defaults->which != LINKER_SECTION_SDATA) + && (defaults->which != LINKER_SECTION_SDATA2)) + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC; + + h->type = STT_OBJECT; + lsect->sym_hash = h; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return (elf_linker_section_t *) 0; + } + } + +#if 0 + /* This does not make sense. The sections which may exist in the + object file have nothing to do with the sections we want to + create. */ + + /* Find the related sections if they have been created */ + if (lsect->bss_name && !lsect->bss_section) + lsect->bss_section = bfd_get_section_by_name (dynobj, lsect->bss_name); + + if (lsect->rel_name && !lsect->rel_section) + lsect->rel_section = bfd_get_section_by_name (dynobj, lsect->rel_name); +#endif + + return lsect; +} + +/* Find a linker generated pointer with a given addend and type. */ + +elf_linker_section_pointers_t * +_bfd_elf_find_pointer_linker_section (linker_pointers, addend, which) + elf_linker_section_pointers_t *linker_pointers; + bfd_vma addend; + elf_linker_section_enum_t which; +{ + for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) + { + if (which == linker_pointers->which && addend == linker_pointers->addend) + return linker_pointers; + } + + return (elf_linker_section_pointers_t *)0; +} + +/* Make the .rela section corresponding to the generated linker section. */ + +bfd_boolean +_bfd_elf_make_linker_section_rela (dynobj, lsect, alignment) + bfd *dynobj; + elf_linker_section_t *lsect; + int alignment; +{ + if (lsect->rel_section) + return TRUE; + + lsect->rel_section = bfd_get_section_by_name (dynobj, lsect->rel_name); + if (lsect->rel_section == NULL) + { + lsect->rel_section = bfd_make_section (dynobj, lsect->rel_name); + if (lsect->rel_section == NULL + || ! bfd_set_section_flags (dynobj, + lsect->rel_section, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, lsect->rel_section, alignment)) + return FALSE; + } + + return TRUE; +} diff --git a/contrib/binutils-2.14/bfd/elflink.h b/contrib/binutils-2.14/bfd/elflink.h new file mode 100644 index 0000000000..9b7bcff820 --- /dev/null +++ b/contrib/binutils-2.14/bfd/elflink.h @@ -0,0 +1,8745 @@ +/* ELF linker support. + Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ELF linker code. */ + +/* This struct is used to pass information to routines called via + elf_link_hash_traverse which must return failure. */ + +struct elf_info_failed +{ + bfd_boolean failed; + struct bfd_link_info *info; + struct bfd_elf_version_tree *verdefs; +}; + +static bfd_boolean is_global_data_symbol_definition + PARAMS ((bfd *, Elf_Internal_Sym *)); +static bfd_boolean elf_link_is_defined_archive_symbol + PARAMS ((bfd *, carsym *)); +static bfd_boolean elf_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_boolean elf_link_add_archive_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_boolean elf_merge_symbol + PARAMS ((bfd *, struct bfd_link_info *, const char *, + Elf_Internal_Sym *, asection **, bfd_vma *, + struct elf_link_hash_entry **, bfd_boolean *, bfd_boolean *, + bfd_boolean *, bfd_boolean *, bfd_boolean)); +static bfd_boolean elf_add_default_symbol + PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + const char *, Elf_Internal_Sym *, asection **, bfd_vma *, + bfd_boolean *, bfd_boolean, bfd_boolean)); +static bfd_boolean elf_export_symbol + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_finalize_dynstr + PARAMS ((bfd *, struct bfd_link_info *)); +static bfd_boolean elf_fix_symbol_flags + PARAMS ((struct elf_link_hash_entry *, struct elf_info_failed *)); +static bfd_boolean elf_adjust_dynamic_symbol + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_link_find_version_dependencies + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_link_assign_sym_version + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_collect_hash_codes + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_link_read_relocs_from_section + PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *)); +static size_t compute_bucket_count + PARAMS ((struct bfd_link_info *)); +static bfd_boolean elf_link_output_relocs + PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *)); +static bfd_boolean elf_link_size_reloc_section + PARAMS ((bfd *, Elf_Internal_Shdr *, asection *)); +static void elf_link_adjust_relocs + PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int, + struct elf_link_hash_entry **)); +static int elf_link_sort_cmp1 + PARAMS ((const void *, const void *)); +static int elf_link_sort_cmp2 + PARAMS ((const void *, const void *)); +static size_t elf_link_sort_relocs + PARAMS ((bfd *, struct bfd_link_info *, asection **)); +static bfd_boolean elf_section_ignore_discarded_relocs + PARAMS ((asection *)); + +/* Given an ELF BFD, add symbols to the global hash table as + appropriate. */ + +bfd_boolean +elf_bfd_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + switch (bfd_get_format (abfd)) + { + case bfd_object: + return elf_link_add_object_symbols (abfd, info); + case bfd_archive: + return elf_link_add_archive_symbols (abfd, info); + default: + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } +} + +/* Return TRUE iff this is a non-common, definition of a non-function symbol. */ +static bfd_boolean +is_global_data_symbol_definition (abfd, sym) + bfd * abfd ATTRIBUTE_UNUSED; + Elf_Internal_Sym * sym; +{ + /* Local symbols do not count, but target specific ones might. */ + if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL + && ELF_ST_BIND (sym->st_info) < STB_LOOS) + return FALSE; + + /* Function symbols do not count. */ + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC) + return FALSE; + + /* If the section is undefined, then so is the symbol. */ + if (sym->st_shndx == SHN_UNDEF) + return FALSE; + + /* If the symbol is defined in the common section, then + it is a common definition and so does not count. */ + if (sym->st_shndx == SHN_COMMON) + return FALSE; + + /* If the symbol is in a target specific section then we + must rely upon the backend to tell us what it is. */ + if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS) + /* FIXME - this function is not coded yet: + + return _bfd_is_global_symbol_definition (abfd, sym); + + Instead for now assume that the definition is not global, + Even if this is wrong, at least the linker will behave + in the same way that it used to do. */ + return FALSE; + + return TRUE; +} + +/* Search the symbol table of the archive element of the archive ABFD + whose archive map contains a mention of SYMDEF, and determine if + the symbol is defined in this element. */ +static bfd_boolean +elf_link_is_defined_archive_symbol (abfd, symdef) + bfd * abfd; + carsym * symdef; +{ + Elf_Internal_Shdr * hdr; + bfd_size_type symcount; + bfd_size_type extsymcount; + bfd_size_type extsymoff; + Elf_Internal_Sym *isymbuf; + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + bfd_boolean result; + + abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset); + if (abfd == (bfd *) NULL) + return FALSE; + + if (! bfd_check_format (abfd, bfd_object)) + 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) + return FALSE; + + /* Select the appropriate symbol table. */ + if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0) + hdr = &elf_tdata (abfd)->symtab_hdr; + else + hdr = &elf_tdata (abfd)->dynsymtab_hdr; + + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + + /* The sh_info field of the symtab header tells us where the + external symbols start. We don't care about the local symbols. */ + if (elf_bad_symtab (abfd)) + { + extsymcount = symcount; + extsymoff = 0; + } + else + { + extsymcount = symcount - hdr->sh_info; + extsymoff = hdr->sh_info; + } + + if (extsymcount == 0) + return FALSE; + + /* Read in the symbol table. */ + isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff, + NULL, NULL, NULL); + if (isymbuf == NULL) + return FALSE; + + /* Scan the symbol table looking for SYMDEF. */ + result = FALSE; + for (isym = isymbuf, isymend = isymbuf + extsymcount; isym < isymend; isym++) + { + const char *name; + + name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + isym->st_name); + if (name == (const char *) NULL) + break; + + if (strcmp (name, symdef->name) == 0) + { + result = is_global_data_symbol_definition (abfd, isym); + break; + } + } + + free (isymbuf); + + return result; +} + +/* 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. + + Fortunately, ELF archive handling is simpler than that done by + _bfd_generic_link_add_archive_symbols, which has to allow for a.out + oddities. In ELF, if we find a symbol in the archive map, and the + symbol is currently undefined, we know that we must pull in that + object file. + + Unfortunately, we do have to make multiple passes over the symbol + table until nothing further is resolved. */ + +static bfd_boolean +elf_link_add_archive_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + symindex c; + bfd_boolean *defined = NULL; + bfd_boolean *included = NULL; + carsym *symdefs; + bfd_boolean loop; + bfd_size_type amt; + + if (! bfd_has_map (abfd)) + { + /* An empty archive is a special case. */ + if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL) + return TRUE; + bfd_set_error (bfd_error_no_armap); + return FALSE; + } + + /* Keep track of all symbols we know to be already defined, and all + files we know to be already included. This is to speed up the + second and subsequent passes. */ + c = bfd_ardata (abfd)->symdef_count; + 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 == (bfd_boolean *) NULL || included == (bfd_boolean *) NULL) + goto error_return; + + symdefs = bfd_ardata (abfd)->symdefs; + + do + { + file_ptr last; + symindex i; + carsym *symdef; + carsym *symdefend; + + loop = FALSE; + last = -1; + + symdef = symdefs; + symdefend = symdef + c; + for (i = 0; symdef < symdefend; symdef++, i++) + { + struct elf_link_hash_entry *h; + bfd *element; + struct bfd_link_hash_entry *undefs_tail; + symindex mark; + + if (defined[i] || included[i]) + continue; + if (symdef->file_offset == last) + { + included[i] = TRUE; + continue; + } + + h = elf_link_hash_lookup (elf_hash_table (info), symdef->name, + FALSE, FALSE, FALSE); + + if (h == NULL) + { + char *p, *copy; + size_t len, first; + + /* If this is a default version (the name contains @@), + look up the symbol again with only one `@' as well + as without the version. The effect is that references + to the symbol with and without the version will be + matched by the default symbol in the archive. */ + + p = strchr (symdef->name, ELF_VER_CHR); + if (p == NULL || p[1] != ELF_VER_CHR) + continue; + + /* First check with only one `@'. */ + len = strlen (symdef->name); + copy = bfd_alloc (abfd, (bfd_size_type) len); + if (copy == NULL) + goto error_return; + first = p - symdef->name + 1; + memcpy (copy, symdef->name, first); + memcpy (copy + first, symdef->name + first + 1, len - first); + + h = elf_link_hash_lookup (elf_hash_table (info), copy, + FALSE, FALSE, FALSE); + + if (h == NULL) + { + /* We also need to check references to the symbol + without the version. */ + + copy[first - 1] = '\0'; + h = elf_link_hash_lookup (elf_hash_table (info), + copy, FALSE, FALSE, FALSE); + } + + bfd_release (abfd, copy); + } + + if (h == NULL) + continue; + + if (h->root.type == bfd_link_hash_common) + { + /* We currently have a common symbol. The archive map contains + a reference to this symbol, so we may want to include it. We + only want to include it however, if this archive element + contains a definition of the symbol, not just another common + declaration of it. + + Unfortunately some archivers (including GNU ar) will put + declarations of common symbols into their archive maps, as + well as real definitions, so we cannot just go by the archive + map alone. Instead we must read in the element's symbol + table and check that to see what kind of symbol definition + this is. */ + if (! elf_link_is_defined_archive_symbol (abfd, symdef)) + continue; + } + else if (h->root.type != bfd_link_hash_undefined) + { + if (h->root.type != bfd_link_hash_undefweak) + defined[i] = TRUE; + continue; + } + + /* We need to include this archive member. */ + element = _bfd_get_elt_at_filepos (abfd, symdef->file_offset); + if (element == (bfd *) NULL) + goto error_return; + + 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->add_archive_element) (info, element, + symdef->name)) + goto error_return; + if (! elf_link_add_object_symbols (element, info)) + goto error_return; + + /* If there are any new undefined symbols, we need to make + another pass through the archive in order to see whether + they can be defined. FIXME: This isn't perfect, because + common symbols wind up on undefs_tail and because an + undefined symbol which is defined later on in this pass + does not require another pass. This isn't a bug, but it + does make the code less efficient than it could be. */ + if (undefs_tail != info->hash->undefs_tail) + loop = TRUE; + + /* Look backward to mark all symbols from this object file + which we have already seen in this pass. */ + mark = i; + do + { + included[mark] = TRUE; + if (mark == 0) + break; + --mark; + } + while (symdefs[mark].file_offset == symdef->file_offset); + + /* We mark subsequent symbols from this object file as we go + on through the loop. */ + last = symdef->file_offset; + } + } + while (loop); + + free (defined); + free (included); + + return TRUE; + + error_return: + if (defined != (bfd_boolean *) NULL) + free (defined); + if (included != (bfd_boolean *) NULL) + free (included); + return FALSE; +} + +/* 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. DT_NEEDED indicates if it comes from a DT_NEEDED entry of + a shared object. */ + +static bfd_boolean +elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, skip, + override, type_change_ok, size_change_ok, dt_needed) + 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_boolean *skip; + bfd_boolean *override; + bfd_boolean *type_change_ok; + bfd_boolean *size_change_ok; + bfd_boolean dt_needed; +{ + asection *sec; + struct elf_link_hash_entry *h; + struct elf_link_hash_entry *flip; + int bind; + bfd *oldbfd; + bfd_boolean newdyn, olddyn, olddef, newdef, newdyncommon, olddyncommon; + bfd_boolean newweakdef, oldweakdef, newweakundef, oldweakundef; + + *skip = FALSE; + *override = FALSE; + + sec = *psec; + bind = ELF_ST_BIND (sym->st_info); + + if (! bfd_is_und_section (sec)) + h = elf_link_hash_lookup (elf_hash_table (info), name, TRUE, FALSE, FALSE); + else + h = ((struct elf_link_hash_entry *) + bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, FALSE, FALSE)); + if (h == NULL) + return FALSE; + *sym_hash = h; + + /* This code is for coping with dynamic objects, and is only useful + if we are doing an ELF link. */ + if (info->hash->creator != abfd->xvec) + return TRUE; + + /* For merging, we only care about real symbols. */ + + 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 we just created the symbol, mark it as being an ELF symbol. + Other than that, there is nothing to do--there is no merge issue + with a newly defined symbol--so we just return. */ + + if (h->root.type == bfd_link_hash_new) + { + h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF; + return TRUE; + } + + /* OLDBFD is a BFD associated with the existing symbol. */ + + switch (h->root.type) + { + default: + oldbfd = NULL; + 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; + break; + + case bfd_link_hash_common: + oldbfd = h->root.u.c.p->section->owner; + break; + } + + /* 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 + itself. The additional tests catch cases like + _GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a + dynamic object, which we do want to handle here. */ + if (abfd == oldbfd + && ((abfd->flags & DYNAMIC) == 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)) + return TRUE; + + /* NEWDYN and OLDDYN indicate whether the new or old symbol, + respectively, is from a dynamic object. */ + + if ((abfd->flags & DYNAMIC) != 0) + newdyn = TRUE; + else + newdyn = FALSE; + + if (oldbfd != NULL) + olddyn = (oldbfd->flags & DYNAMIC) != 0; + else + { + asection *hsec; + + /* This code handles the special SHN_MIPS_{TEXT,DATA} section + indices used by MIPS ELF. */ + switch (h->root.type) + { + default: + hsec = NULL; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + hsec = h->root.u.def.section; + break; + + case bfd_link_hash_common: + hsec = h->root.u.c.p->section; + break; + } + + if (hsec == NULL) + olddyn = FALSE; + else + olddyn = (hsec->symbol->flags & BSF_DYNAMIC) != 0; + } + + /* NEWDEF and OLDDEF indicate whether the new or old symbol, + respectively, appear to be a definition rather than reference. */ + + if (bfd_is_und_section (sec) || bfd_is_com_section (sec)) + newdef = FALSE; + else + newdef = TRUE; + + if (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_common) + olddef = FALSE; + else + olddef = TRUE; + + /* We need to rememeber if a symbol has a definition in a dynamic + object or is weak in all dynamic objects. Internal and hidden + visibility will make it unavailable to dynamic objects. */ + if (newdyn && (h->elf_link_hash_flags & ELF_LINK_DYNAMIC_DEF) == 0) + { + if (!bfd_is_und_section (sec)) + h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_DEF; + else + { + /* Check if this symbol is weak in all dynamic objects. If it + is the first time we see it in a dynamic object, we mark + if it is weak. Otherwise, we clear it. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0) + { + if (bind == STB_WEAK) + h->elf_link_hash_flags |= ELF_LINK_DYNAMIC_WEAK; + } + else if (bind != STB_WEAK) + h->elf_link_hash_flags &= ~ELF_LINK_DYNAMIC_WEAK; + } + } + + /* If the old symbol has non-default visibility, we ignore the new + definition from a dynamic object. */ + if (newdyn + && ELF_ST_VISIBILITY (h->other) + && !bfd_is_und_section (sec)) + { + *skip = TRUE; + /* Make sure this symbol is dynamic. */ + h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; + /* A protected symbol has external availability. Make sure it is + recorded as dynamic. + + FIXME: Should we check type and size for protected symbol? */ + if (ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + return _bfd_elf_link_record_dynamic_symbol (info, h); + else + return TRUE; + } + else if (!newdyn + && ELF_ST_VISIBILITY (sym->st_other) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0) + { + /* 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) + h = *sym_hash; + h->root.type = bfd_link_hash_new; + h->root.u.undef.abfd = NULL; + if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) + { + h->elf_link_hash_flags &= ~ELF_LINK_HASH_DEF_DYNAMIC; + h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_DYNAMIC_DEF); + } + /* FIXME: Should we check type and size for protected symbol? */ + h->size = 0; + h->type = 0; + return TRUE; + } + + /* We need to treat weak definiton right, depending on if there is a + definition from a dynamic object. */ + if (bind == STB_WEAK) + { + if (olddef) + { + newweakdef = TRUE; + newweakundef = FALSE; + } + else + { + newweakdef = FALSE; + newweakundef = TRUE; + } + } + else + newweakdef = newweakundef = FALSE; + + /* If the new weak definition comes from a relocatable file and the + old symbol comes from a dynamic object, we treat the new one as + strong. */ + if (newweakdef && !newdyn && olddyn) + newweakdef = FALSE; + + if (h->root.type == bfd_link_hash_defweak) + { + oldweakdef = TRUE; + oldweakundef = FALSE; + } + else if (h->root.type == bfd_link_hash_undefweak) + { + oldweakdef = FALSE; + oldweakundef = TRUE; + } + else + oldweakdef = oldweakundef = FALSE; + + /* If the old weak definition comes from a relocatable file and the + new symbol comes from a dynamic object, we treat the old one as + strong. */ + if (oldweakdef && !olddyn && newdyn) + oldweakdef = FALSE; + + /* NEWDYNCOMMON and OLDDYNCOMMON indicate whether the new or old + symbol, respectively, appears to be a common symbol in a dynamic + object. If a symbol appears in an uninitialized section, and is + not weak, and is not a function, then it may be a common symbol + which was resolved when the dynamic object was created. We want + to treat such symbols specially, because they raise special + considerations when setting the symbol size: if the symbol + appears as a common symbol in a regular object, and the size in + the regular object is larger, we must make sure that we use the + larger size. This problematic case can always be avoided in C, + but it must be handled correctly when using Fortran shared + libraries. + + Note that if NEWDYNCOMMON is set, NEWDEF will be set, and + likewise for OLDDYNCOMMON and OLDDEF. + + Note that this test is just a heuristic, and that it is quite + possible to have an uninitialized symbol in a shared object which + is really a definition, rather than a common symbol. This could + lead to some minor confusion when the symbol really is a common + symbol in some regular object. However, I think it will be + harmless. */ + + if (newdyn + && newdef + && (sec->flags & SEC_ALLOC) != 0 + && (sec->flags & SEC_LOAD) == 0 + && sym->st_size > 0 + && !newweakdef + && !newweakundef + && ELF_ST_TYPE (sym->st_info) != STT_FUNC) + newdyncommon = TRUE; + else + newdyncommon = FALSE; + + if (olddyn + && olddef + && h->root.type == bfd_link_hash_defined + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->root.u.def.section->flags & SEC_ALLOC) != 0 + && (h->root.u.def.section->flags & SEC_LOAD) == 0 + && h->size > 0 + && h->type != STT_FUNC) + olddyncommon = TRUE; + else + olddyncommon = FALSE; + + /* It's OK to change the type if either the existing symbol or the + new symbol is weak unless it comes from a DT_NEEDED entry of + a shared object, in which case, the DT_NEEDED entry may not be + required at the run time. */ + + if ((! dt_needed && oldweakdef) + || oldweakundef + || newweakdef + || newweakundef) + *type_change_ok = TRUE; + + /* It's OK to change the size if either the existing symbol or the + new symbol is weak, or if the old symbol is undefined. */ + + if (*type_change_ok + || h->root.type == bfd_link_hash_undefined) + *size_change_ok = TRUE; + + /* 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 + two. */ + + if (olddyncommon + && newdyncommon + && sym->st_size != h->size) + { + /* Since we think we have two common symbols, issue a multiple + common warning if desired. Note that we only warn if the + size is different. If the size is the same, we simply let + the old symbol override the new one as normally happens with + symbols defined in dynamic objects. */ + + if (! ((*info->callbacks->multiple_common) + (info, h->root.root.string, oldbfd, bfd_link_hash_common, + h->size, abfd, bfd_link_hash_common, sym->st_size))) + return FALSE; + + if (sym->st_size > h->size) + h->size = sym->st_size; + + *size_change_ok = TRUE; + } + + /* If we are looking at a dynamic object, and we have found a + definition, we need to see if the symbol was already defined by + some other object. If so, we want to use the existing + definition, and we do not want to report a multiple symbol + definition error; we do this by clobbering *PSEC to be + bfd_und_section_ptr. + + We treat a common symbol as a definition if the symbol in the + shared library is a function, since common symbols always + represent variables; this can cause confusion in principle, but + any such confusion would seem to indicate an erroneous program or + shared library. We also permit a common symbol in a regular + object to override a weak symbol in a shared object. + + We prefer a non-weak definition in a shared library to a weak + definition in the executable unless it comes from a DT_NEEDED + entry of a shared object, in which case, the DT_NEEDED entry + may not be required at the run time. */ + + if (newdyn + && newdef + && (olddef + || (h->root.type == bfd_link_hash_common + && (newweakdef + || newweakundef + || ELF_ST_TYPE (sym->st_info) == STT_FUNC))) + && (!oldweakdef + || dt_needed + || newweakdef + || newweakundef)) + { + *override = TRUE; + newdef = FALSE; + newdyncommon = FALSE; + + *psec = sec = bfd_und_section_ptr; + *size_change_ok = TRUE; + + /* If we get here when the old symbol is a common symbol, then + we are explicitly letting it override a weak symbol or + function in a dynamic object, and we don't want to warn about + a type change. If the old symbol is a defined symbol, a type + change warning may still be appropriate. */ + + if (h->root.type == bfd_link_hash_common) + *type_change_ok = TRUE; + } + + /* Handle the special case of an old common symbol merging with a + new symbol which looks like a common symbol in a shared object. + We change *PSEC and *PVALUE to make the new symbol look like a + common symbol, and let _bfd_generic_link_add_one_symbol will do + the right thing. */ + + if (newdyncommon + && h->root.type == bfd_link_hash_common) + { + *override = TRUE; + newdef = FALSE; + newdyncommon = FALSE; + *pvalue = sym->st_size; + *psec = sec = bfd_com_section_ptr; + *size_change_ok = TRUE; + } + + /* If the old symbol is from a dynamic object, and the new symbol is + a definition which is not from a dynamic object, then the new + symbol overrides the old symbol. Symbols from regular files + always take precedence over symbols from dynamic objects, even if + they are defined after the dynamic object in the link. + + As above, we again permit a common symbol in a regular object to + override a definition in a shared object if the shared object + symbol is a function or is weak. + + As above, we permit a non-weak definition in a shared object to + override a weak definition in a regular object. */ + + flip = NULL; + if (! newdyn + && (newdef + || (bfd_is_com_section (sec) + && (oldweakdef || h->type == STT_FUNC))) + && olddyn + && olddef + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && ((!newweakdef && !newweakundef) || oldweakdef)) + { + /* Change the hash table entry to undefined, and let + _bfd_generic_link_add_one_symbol do the right thing with the + new definition. */ + + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = h->root.u.def.section->owner; + *size_change_ok = TRUE; + + olddef = FALSE; + olddyncommon = FALSE; + + /* We again permit a type change when a common symbol may be + overriding a function. */ + + if (bfd_is_com_section (sec)) + *type_change_ok = TRUE; + + if ((*sym_hash)->root.type == bfd_link_hash_indirect) + flip = *sym_hash; + 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 + NULL, so that it is correct for a regular symbol. */ + h->verinfo.vertree = NULL; + } + + /* Handle the special case of a new common symbol merging with an + old symbol that looks like it might be a common symbol defined in + a shared object. Note that we have already handled the case in + which a new common symbol should simply override the definition + in the shared library. */ + + if (! newdyn + && bfd_is_com_section (sec) + && olddyncommon) + { + /* It would be best if we could set the hash table entry to a + common symbol, but we don't know what to use for the section + or the alignment. */ + if (! ((*info->callbacks->multiple_common) + (info, h->root.root.string, oldbfd, bfd_link_hash_common, + h->size, abfd, bfd_link_hash_common, sym->st_size))) + return FALSE; + + /* If the predumed common symbol in the dynamic object is + larger, pretend that the new symbol has its size. */ + + if (h->size > *pvalue) + *pvalue = h->size; + + /* FIXME: We no longer know the alignment required by the symbol + in the dynamic object, so we just wind up using the one from + the regular object. */ + + olddef = FALSE; + olddyncommon = FALSE; + + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = h->root.u.def.section->owner; + + *size_change_ok = TRUE; + *type_change_ok = TRUE; + + if ((*sym_hash)->root.type == bfd_link_hash_indirect) + flip = *sym_hash; + else + h->verinfo.vertree = NULL; + } + + if (flip != NULL) + { + /* Handle the case where we had a versioned symbol in a dynamic + library and now find a definition in a normal object. In this + case, we make the versioned symbol point to the normal one. */ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + flip->root.type = h->root.type; + h->root.type = bfd_link_hash_indirect; + h->root.u.i.link = (struct bfd_link_hash_entry *) flip; + (*bed->elf_backend_copy_indirect_symbol) (bed, flip, h); + flip->root.u.undef.abfd = h->root.u.undef.abfd; + if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) + { + h->elf_link_hash_flags &= ~ELF_LINK_HASH_DEF_DYNAMIC; + flip->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; + } + } + + /* Handle the special case of a weak definition in a regular object + followed by a non-weak definition in a shared object. In this + case, we prefer the definition in the shared object unless it + comes from a DT_NEEDED entry of a shared object, in which case, + the DT_NEEDED entry may not be required at the run time. */ + if (olddef + && ! dt_needed + && oldweakdef + && newdef + && newdyn + && !newweakdef + && !newweakundef) + { + /* To make this work we have to frob the flags so that the rest + of the code does not think we are using the regular + definition. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) + h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0) + h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; + h->elf_link_hash_flags &= ~ (ELF_LINK_HASH_DEF_REGULAR + | ELF_LINK_HASH_DEF_DYNAMIC); + + /* If H is the target of an indirection, we want the caller to + use H rather than the indirect symbol. Otherwise if we are + defining a new indirect symbol we will wind up attaching it + to the entry we are overriding. */ + *sym_hash = h; + } + + /* Handle the special case of a non-weak definition in a shared + object followed by a weak definition in a regular object. In + this case we prefer the definition in the shared object. To make + this work we have to tell the caller to not treat the new symbol + as a definition. */ + if (olddef + && olddyn + && !oldweakdef + && newdef + && ! newdyn + && (newweakdef || newweakundef)) + *override = TRUE; + + return TRUE; +} + +/* 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 + set DYNSYM if the new indirect symbol is dynamic. DT_NEEDED + indicates if it comes from a DT_NEEDED entry of a shared object. */ + +static bfd_boolean +elf_add_default_symbol (abfd, info, h, name, sym, psec, value, + dynsym, override, dt_needed) + bfd *abfd; + struct bfd_link_info *info; + struct elf_link_hash_entry *h; + const char *name; + Elf_Internal_Sym *sym; + asection **psec; + bfd_vma *value; + bfd_boolean *dynsym; + bfd_boolean override; + bfd_boolean dt_needed; +{ + bfd_boolean type_change_ok; + bfd_boolean size_change_ok; + bfd_boolean skip; + char *shortname; + struct elf_link_hash_entry *hi; + struct bfd_link_hash_entry *bh; + struct elf_backend_data *bed; + bfd_boolean collect; + bfd_boolean dynamic; + char *p; + size_t len, shortlen; + asection *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 + decorated name. This will cause external references which do not + specify a version to be bound to this version of the symbol. */ + p = strchr (name, ELF_VER_CHR); + if (p == NULL || p[1] != ELF_VER_CHR) + return TRUE; + + if (override) + { + /* We are overridden by an old defition. 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; + + shortlen = p - name; + shortname = bfd_hash_allocate (&info->hash->table, shortlen + 1); + if (shortname == NULL) + return FALSE; + memcpy (shortname, name, shortlen); + shortname[shortlen] = '\0'; + + /* We are going to create a new symbol. Merge it with any existing + symbol with this name. For the purposes of the merge, act as + though we were defining the symbol we just defined, although we + actually going to define an indirect symbol. */ + type_change_ok = FALSE; + size_change_ok = FALSE; + sec = *psec; + if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value, + &hi, &skip, &override, &type_change_ok, + &size_change_ok, dt_needed)) + return FALSE; + + if (skip) + goto nondefault; + + if (! override) + { + bh = &hi->root; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, shortname, BSF_INDIRECT, bfd_ind_section_ptr, + (bfd_vma) 0, name, FALSE, collect, &bh))) + return FALSE; + hi = (struct elf_link_hash_entry *) bh; + } + else + { + /* In this case the symbol named SHORTNAME is overriding the + indirect symbol we want to add. We were planning on making + SHORTNAME an indirect symbol referring to NAME. SHORTNAME + is the name without a version. NAME is the fully versioned + name, and it is the default version. + + Overriding means that we already saw a definition for the + symbol SHORTNAME in a regular object, and it is overriding + the symbol defined in the dynamic object. + + When this happens, we actually want to change NAME, the + symbol we just added, to refer to SHORTNAME. This will cause + references to NAME in the shared object to become references + to SHORTNAME in the regular object. This is what we expect + when we override a function in a shared object: that the + references in the shared object will be mapped to the + definition in the regular object. */ + + 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; + + h->root.type = bfd_link_hash_indirect; + h->root.u.i.link = (struct bfd_link_hash_entry *) hi; + if (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) + { + h->elf_link_hash_flags &=~ ELF_LINK_HASH_DEF_DYNAMIC; + hi->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; + if (hi->elf_link_hash_flags + & (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_DEF_REGULAR)) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, hi)) + return FALSE; + } + } + + /* Now set HI to H, so that the following code will set the + other fields correctly. */ + hi = h; + } + + /* If there is a duplicate definition somewhere, then HI may not + point to an indirect symbol. We will have reported an error to + the user in that case. */ + + if (hi->root.type == bfd_link_hash_indirect) + { + struct elf_link_hash_entry *ht; + + /* If the symbol became indirect, then we assume that we have + not seen a definition before. */ + BFD_ASSERT ((hi->elf_link_hash_flags + & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_DEF_REGULAR)) == 0); + + ht = (struct elf_link_hash_entry *) hi->root.u.i.link; + (*bed->elf_backend_copy_indirect_symbol) (bed, ht, hi); + + /* See if the new flags lead us to realize that the symbol must + be dynamic. */ + if (! *dynsym) + { + if (! dynamic) + { + if (info->shared + || ((hi->elf_link_hash_flags + & ELF_LINK_HASH_REF_DYNAMIC) != 0)) + *dynsym = TRUE; + } + else + { + if ((hi->elf_link_hash_flags + & ELF_LINK_HASH_REF_REGULAR) != 0) + *dynsym = TRUE; + } + } + } + + /* We also need to define an indirection from the nondefault version + of the symbol. */ + +nondefault: + len = strlen (name); + shortname = bfd_hash_allocate (&info->hash->table, len); + if (shortname == NULL) + return FALSE; + memcpy (shortname, name, shortlen); + memcpy (shortname + shortlen, p + 1, len - shortlen); + + /* Once again, merge with any existing symbol. */ + type_change_ok = FALSE; + size_change_ok = FALSE; + sec = *psec; + if (! elf_merge_symbol (abfd, info, shortname, sym, &sec, value, + &hi, &skip, &override, &type_change_ok, + &size_change_ok, dt_needed)) + return FALSE; + + if (skip) + return TRUE; + + if (override) + { + /* Here SHORTNAME is a versioned name, so we don't expect to see + the type of override we do in the case above unless it is + overridden by a versioned definiton. */ + if (hi->root.type != bfd_link_hash_defined + && hi->root.type != bfd_link_hash_defweak) + (*_bfd_error_handler) + (_("%s: warning: unexpected redefinition of indirect versioned symbol `%s'"), + bfd_archive_filename (abfd), shortname); + } + else + { + bh = &hi->root; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, shortname, BSF_INDIRECT, + bfd_ind_section_ptr, (bfd_vma) 0, name, FALSE, collect, &bh))) + return FALSE; + hi = (struct elf_link_hash_entry *) bh; + + /* If there is a duplicate definition somewhere, then HI may not + point to an indirect symbol. We will have reported an error + to the user in that case. */ + + if (hi->root.type == bfd_link_hash_indirect) + { + /* If the symbol became indirect, then we assume that we have + not seen a definition before. */ + BFD_ASSERT ((hi->elf_link_hash_flags + & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_DEF_REGULAR)) == 0); + + (*bed->elf_backend_copy_indirect_symbol) (bed, h, hi); + + /* See if the new flags lead us to realize that the symbol + must be dynamic. */ + if (! *dynsym) + { + if (! dynamic) + { + if (info->shared + || ((hi->elf_link_hash_flags + & ELF_LINK_HASH_REF_DYNAMIC) != 0)) + *dynsym = TRUE; + } + else + { + if ((hi->elf_link_hash_flags + & ELF_LINK_HASH_REF_REGULAR) != 0) + *dynsym = TRUE; + } + } + } + } + + return TRUE; +} + +/* Add symbols from an ELF object file to the linker hash table. */ + +static bfd_boolean +elf_link_add_object_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd_boolean (*add_symbol_hook) + PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Sym *, + const char **, flagword *, asection **, bfd_vma *)); + bfd_boolean (*check_relocs) + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); + bfd_boolean collect; + Elf_Internal_Shdr *hdr; + bfd_size_type symcount; + bfd_size_type extsymcount; + bfd_size_type extsymoff; + struct elf_link_hash_entry **sym_hash; + bfd_boolean dynamic; + Elf_External_Versym *extversym = NULL; + Elf_External_Versym *ever; + struct elf_link_hash_entry *weaks; + struct elf_link_hash_entry **nondeflt_vers = NULL; + bfd_size_type nondeflt_vers_cnt = 0; + Elf_Internal_Sym *isymbuf = NULL; + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + struct elf_backend_data *bed; + bfd_boolean dt_needed; + struct elf_link_hash_table * hash_table; + bfd_size_type amt; + + hash_table = elf_hash_table (info); + + bed = get_elf_backend_data (abfd); + add_symbol_hook = bed->elf_add_symbol_hook; + collect = bed->collect; + + if ((abfd->flags & DYNAMIC) == 0) + dynamic = FALSE; + else + { + dynamic = TRUE; + + /* You can't use -r against a dynamic object. Also, there's no + hope of using a dynamic object which does not exactly match + the format of the output file. */ + if (info->relocateable || info->hash->creator != abfd->xvec) + { + bfd_set_error (bfd_error_invalid_operation); + goto error_return; + } + } + + /* As a GNU extension, any input sections which are named + .gnu.warning.SYMBOL are treated as warning symbols for the given + symbol. This differs from .gnu.warning sections, which generate + warnings when they are included in an output file. */ + if (! info->shared) + { + asection *s; + + for (s = abfd->sections; s != NULL; s = s->next) + { + const char *name; + + name = bfd_get_section_name (abfd, s); + if (strncmp (name, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0) + { + 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 && abfd->xvec == info->hash->creator) + { + struct elf_link_hash_entry *h; + + h = elf_link_hash_lookup (hash_table, 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->_raw_size = 0; + continue; + } + } + + sz = bfd_section_size (abfd, s); + msg = (char *) bfd_alloc (abfd, sz + 1); + if (msg == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, s, msg, (file_ptr) 0, sz)) + goto error_return; + + msg[sz] = '\0'; + + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, BSF_WARNING, s, (bfd_vma) 0, msg, + FALSE, collect, (struct bfd_link_hash_entry **) NULL))) + goto error_return; + + if (! info->relocateable) + { + /* Clobber the section size so that the warning does + not get copied into the output file. */ + s->_raw_size = 0; + } + } + } + } + + dt_needed = FALSE; + 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 + && is_elf_hash_table (info) + && ! hash_table->dynamic_sections_created + && abfd->xvec == info->hash->creator) + { + if (! elf_link_create_dynamic_sections (abfd, info)) + goto error_return; + } + } + else if (! is_elf_hash_table (info)) + goto error_return; + else + { + asection *s; + bfd_boolean add_needed; + const char *name; + bfd_size_type oldsize; + bfd_size_type strindex; + struct bfd_link_needed_list *rpath = NULL, *runpath = NULL; + + /* ld --just-symbols and dynamic objects don't mix very well. + Test for --just-symbols by looking at info set up by + _bfd_elf_link_just_syms. */ + if ((s = abfd->sections) != NULL + && s->sec_info_type == ELF_INFO_TYPE_JUST_SYMS) + goto error_return; + + /* Find the name to use in a DT_NEEDED entry that refers to this + object. If the object has a DT_SONAME entry, we use it. + Otherwise, if the generic linker stuck something in + elf_dt_name, we use that. Otherwise, we just use the file + name. If the generic linker put a null string into + elf_dt_name, we don't make a DT_NEEDED entry at all, even if + there is a DT_SONAME entry. */ + add_needed = TRUE; + name = bfd_get_filename (abfd); + if (elf_dt_name (abfd) != NULL) + { + name = elf_dt_name (abfd); + if (*name == '\0') + { + if (elf_dt_soname (abfd) != NULL) + dt_needed = TRUE; + + add_needed = FALSE; + } + } + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s != NULL) + { + Elf_External_Dyn *dynbuf = NULL; + Elf_External_Dyn *extdyn; + Elf_External_Dyn *extdynend; + int elfsec; + unsigned long shlink; + + dynbuf = (Elf_External_Dyn *) bfd_malloc (s->_raw_size); + if (dynbuf == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, s, (PTR) dynbuf, + (file_ptr) 0, s->_raw_size)) + goto error_free_dyn; + + elfsec = _bfd_elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_free_dyn; + shlink = elf_elfsections (abfd)[elfsec]->sh_link; + + extdyn = dynbuf; + extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn); + for (; extdyn < extdynend; extdyn++) + { + Elf_Internal_Dyn dyn; + + elf_swap_dyn_in (abfd, extdyn, &dyn); + if (dyn.d_tag == DT_SONAME) + { + unsigned int tagv = dyn.d_un.d_val; + name = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (name == NULL) + goto error_free_dyn; + } + if (dyn.d_tag == DT_NEEDED) + { + struct bfd_link_needed_list *n, **pn; + char *fnm, *anm; + unsigned int tagv = dyn.d_un.d_val; + + amt = sizeof (struct bfd_link_needed_list); + n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); + fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (n == NULL || fnm == NULL) + goto error_free_dyn; + amt = strlen (fnm) + 1; + anm = bfd_alloc (abfd, amt); + if (anm == NULL) + goto error_free_dyn; + memcpy (anm, fnm, (size_t) amt); + n->name = anm; + n->by = abfd; + n->next = NULL; + for (pn = & hash_table->needed; + *pn != NULL; + pn = &(*pn)->next) + ; + *pn = n; + } + if (dyn.d_tag == DT_RUNPATH) + { + struct bfd_link_needed_list *n, **pn; + char *fnm, *anm; + unsigned int tagv = dyn.d_un.d_val; + + amt = sizeof (struct bfd_link_needed_list); + n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); + fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (n == NULL || fnm == NULL) + goto error_free_dyn; + amt = strlen (fnm) + 1; + anm = bfd_alloc (abfd, amt); + if (anm == NULL) + goto error_free_dyn; + memcpy (anm, fnm, (size_t) amt); + n->name = anm; + n->by = abfd; + n->next = NULL; + for (pn = & runpath; + *pn != NULL; + pn = &(*pn)->next) + ; + *pn = n; + } + /* Ignore DT_RPATH if we have seen DT_RUNPATH. */ + if (!runpath && dyn.d_tag == DT_RPATH) + { + struct bfd_link_needed_list *n, **pn; + char *fnm, *anm; + unsigned int tagv = dyn.d_un.d_val; + + amt = sizeof (struct bfd_link_needed_list); + n = (struct bfd_link_needed_list *) bfd_alloc (abfd, amt); + fnm = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (n == NULL || fnm == NULL) + goto error_free_dyn; + amt = strlen (fnm) + 1; + anm = bfd_alloc (abfd, amt); + if (anm == NULL) + { + error_free_dyn: + free (dynbuf); + goto error_return; + } + memcpy (anm, fnm, (size_t) amt); + n->name = anm; + n->by = abfd; + n->next = NULL; + for (pn = & rpath; + *pn != NULL; + pn = &(*pn)->next) + ; + *pn = n; + } + } + + free (dynbuf); + } + + /* DT_RUNPATH overrides DT_RPATH. Do _NOT_ bfd_release, as that + frees all more recently bfd_alloc'd blocks as well. */ + if (runpath) + rpath = runpath; + + if (rpath) + { + struct bfd_link_needed_list **pn; + for (pn = & hash_table->runpath; + *pn != NULL; + pn = &(*pn)->next) + ; + *pn = rpath; + } + + /* We do not want to include any of the sections in a dynamic + object in the output file. We hack by simply clobbering the + list of sections in the BFD. This could be handled more + cleanly by, say, a new section flag; the existing + SEC_NEVER_LOAD flag is not the one we want, because that one + still implies that the section takes up space in the output + file. */ + bfd_section_list_clear (abfd); + + /* If this is the first dynamic object found in the link, create + the special sections required for dynamic linking. */ + if (! hash_table->dynamic_sections_created) + if (! elf_link_create_dynamic_sections (abfd, info)) + goto error_return; + + if (add_needed) + { + /* Add a DT_NEEDED entry for this dynamic object. */ + oldsize = _bfd_elf_strtab_size (hash_table->dynstr); + strindex = _bfd_elf_strtab_add (hash_table->dynstr, name, FALSE); + if (strindex == (bfd_size_type) -1) + goto error_return; + + if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr)) + { + asection *sdyn; + Elf_External_Dyn *dyncon, *dynconend; + + /* The hash table size did not change, which means that + the dynamic object name was already entered. If we + have already included this dynamic object in the + link, just ignore it. There is no reason to include + a particular dynamic object more than once. */ + sdyn = bfd_get_section_by_name (hash_table->dynobj, ".dynamic"); + BFD_ASSERT (sdyn != NULL); + + dyncon = (Elf_External_Dyn *) sdyn->contents; + dynconend = (Elf_External_Dyn *) (sdyn->contents + + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + + elf_swap_dyn_in (hash_table->dynobj, dyncon, & dyn); + if (dyn.d_tag == DT_NEEDED + && dyn.d_un.d_val == strindex) + { + _bfd_elf_strtab_delref (hash_table->dynstr, strindex); + return TRUE; + } + } + } + + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_NEEDED, strindex)) + goto error_return; + } + + /* Save the SONAME, if there is one, because sometimes the + linker emulation code will need to know it. */ + if (*name == '\0') + name = basename (bfd_get_filename (abfd)); + elf_dt_name (abfd) = name; + } + + /* If this is a dynamic object, we always link against the .dynsym + symbol table, not the .symtab symbol table. The dynamic linker + will only see the .dynsym symbol table, so there is no reason to + look at .symtab for a dynamic object. */ + + if (! dynamic || elf_dynsymtab (abfd) == 0) + hdr = &elf_tdata (abfd)->symtab_hdr; + else + hdr = &elf_tdata (abfd)->dynsymtab_hdr; + + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + + /* The sh_info field of the symtab header tells us where the + external symbols start. We don't care about the local symbols at + this point. */ + if (elf_bad_symtab (abfd)) + { + extsymcount = symcount; + extsymoff = 0; + } + else + { + extsymcount = symcount - hdr->sh_info; + extsymoff = hdr->sh_info; + } + + sym_hash = NULL; + if (extsymcount != 0) + { + isymbuf = bfd_elf_get_elf_syms (abfd, hdr, extsymcount, extsymoff, + NULL, NULL, NULL); + 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; + } + + if (dynamic) + { + /* Read in any version definitions. */ + if (! _bfd_elf_slurp_version_tables (abfd)) + goto error_free_sym; + + /* Read in the symbol versions, but don't bother to convert them + to internal format. */ + if (elf_dynversym (abfd) != 0) + { + Elf_Internal_Shdr *versymhdr; + + versymhdr = &elf_tdata (abfd)->dynversym_hdr; + extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size); + if (extversym == NULL) + goto error_free_sym; + amt = versymhdr->sh_size; + if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0 + || bfd_bread ((PTR) extversym, amt, abfd) != amt) + goto error_free_vers; + } + } + + weaks = NULL; + + ever = extversym != NULL ? extversym + extsymoff : NULL; + for (isym = isymbuf, isymend = isymbuf + extsymcount; + isym < isymend; + isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL)) + { + int bind; + bfd_vma value; + asection *sec; + flagword flags; + const char *name; + struct elf_link_hash_entry *h; + bfd_boolean definition; + bfd_boolean size_change_ok; + bfd_boolean type_change_ok; + bfd_boolean new_weakdef; + bfd_boolean override; + unsigned int old_alignment; + bfd *old_bfd; + + override = FALSE; + + flags = BSF_NO_FLAGS; + sec = NULL; + value = isym->st_value; + *sym_hash = NULL; + + bind = ELF_ST_BIND (isym->st_info); + if (bind == STB_LOCAL) + { + /* This should be impossible, since ELF requires that all + global symbols follow all local symbols, and that sh_info + point to the first global symbol. Unfortunatealy, Irix 5 + screws this up. */ + continue; + } + else if (bind == STB_GLOBAL) + { + if (isym->st_shndx != SHN_UNDEF + && isym->st_shndx != SHN_COMMON) + flags = BSF_GLOBAL; + } + else if (bind == STB_WEAK) + flags = BSF_WEAK; + else + { + /* Leave it up to the processor backend. */ + } + + if (isym->st_shndx == SHN_UNDEF) + sec = bfd_und_section_ptr; + else if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE) + { + sec = section_from_elf_index (abfd, isym->st_shndx); + if (sec == NULL) + sec = bfd_abs_section_ptr; + else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) + value -= sec->vma; + } + else if (isym->st_shndx == SHN_ABS) + sec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + { + sec = bfd_com_section_ptr; + /* What ELF calls the size we call the value. What ELF + calls the value we call the alignment. */ + value = isym->st_size; + } + else + { + /* Leave it up to the processor backend. */ + } + + name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, + isym->st_name); + if (name == (const char *) NULL) + goto error_free_vers; + + if (isym->st_shndx == SHN_COMMON + && ELF_ST_TYPE (isym->st_info) == STT_TLS) + { + asection *tcomm = bfd_get_section_by_name (abfd, ".tcommon"); + + if (tcomm == NULL) + { + tcomm = bfd_make_section (abfd, ".tcommon"); + if (tcomm == NULL + || !bfd_set_section_flags (abfd, tcomm, (SEC_ALLOC + | SEC_IS_COMMON + | SEC_LINKER_CREATED + | SEC_THREAD_LOCAL))) + goto error_free_vers; + } + sec = tcomm; + } + else if (add_symbol_hook) + { + if (! (*add_symbol_hook) (abfd, info, isym, &name, &flags, &sec, + &value)) + goto error_free_vers; + + /* The hook function sets the name to NULL if this symbol + should be skipped for some reason. */ + if (name == (const char *) NULL) + continue; + } + + /* Sanity check that all possibilities were handled. */ + if (sec == (asection *) NULL) + { + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; + } + + if (bfd_is_und_section (sec) + || bfd_is_com_section (sec)) + definition = FALSE; + else + definition = TRUE; + + size_change_ok = FALSE; + type_change_ok = get_elf_backend_data (abfd)->type_change_ok; + old_alignment = 0; + old_bfd = NULL; + + if (info->hash->creator->flavour == bfd_target_elf_flavour) + { + Elf_Internal_Versym iver; + unsigned int vernum = 0; + bfd_boolean skip; + + if (ever != NULL) + { + _bfd_elf_swap_versym_in (abfd, ever, &iver); + vernum = iver.vs_vers & VERSYM_VERSION; + + /* If this is a hidden symbol, or if it is not version + 1, we append the version name to the symbol name. + However, we do not modify a non-hidden absolute + symbol, because it might be the version symbol + itself. FIXME: What if it isn't? */ + if ((iver.vs_vers & VERSYM_HIDDEN) != 0 + || (vernum > 1 && ! bfd_is_abs_section (sec))) + { + const char *verstr; + size_t namelen, verlen, newlen; + char *newname, *p; + + if (isym->st_shndx != SHN_UNDEF) + { + if (vernum > elf_tdata (abfd)->dynverdef_hdr.sh_info) + { + (*_bfd_error_handler) + (_("%s: %s: invalid version %u (max %d)"), + bfd_archive_filename (abfd), name, vernum, + elf_tdata (abfd)->dynverdef_hdr.sh_info); + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; + } + else if (vernum > 1) + verstr = + elf_tdata (abfd)->verdef[vernum - 1].vd_nodename; + else + verstr = ""; + } + else + { + /* We cannot simply test for the number of + entries in the VERNEED section since the + numbers for the needed versions do not start + at 0. */ + Elf_Internal_Verneed *t; + + verstr = NULL; + 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) + { + verstr = a->vna_nodename; + break; + } + } + if (a != NULL) + break; + } + if (verstr == NULL) + { + (*_bfd_error_handler) + (_("%s: %s: invalid needed version %d"), + bfd_archive_filename (abfd), name, vernum); + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; + } + } + + namelen = strlen (name); + verlen = strlen (verstr); + newlen = namelen + verlen + 2; + if ((iver.vs_vers & VERSYM_HIDDEN) == 0 + && isym->st_shndx != SHN_UNDEF) + ++newlen; + + newname = (char *) bfd_alloc (abfd, (bfd_size_type) newlen); + if (newname == NULL) + goto error_free_vers; + memcpy (newname, name, namelen); + p = newname + namelen; + *p++ = ELF_VER_CHR; + /* If this is a defined non-hidden version symbol, + we add another @ to the name. This indicates the + default version of the symbol. */ + if ((iver.vs_vers & VERSYM_HIDDEN) == 0 + && isym->st_shndx != SHN_UNDEF) + *p++ = ELF_VER_CHR; + memcpy (p, verstr, verlen + 1); + + name = newname; + } + } + + if (! elf_merge_symbol (abfd, info, name, isym, &sec, &value, + sym_hash, &skip, &override, + &type_change_ok, &size_change_ok, + dt_needed)) + goto error_free_vers; + + if (skip) + continue; + + if (override) + definition = FALSE; + + h = *sym_hash; + 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; + + /* 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 + && ! override + && vernum > 1 + && definition) + h->verinfo.verdef = &elf_tdata (abfd)->verdef[vernum - 1]; + } + + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, flags, sec, value, (const char *) NULL, + FALSE, collect, (struct bfd_link_hash_entry **) sym_hash))) + goto error_free_vers; + + h = *sym_hash; + 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; + *sym_hash = h; + + new_weakdef = FALSE; + if (dynamic + && definition + && (flags & BSF_WEAK) != 0 + && ELF_ST_TYPE (isym->st_info) != STT_FUNC + && info->hash->creator->flavour == bfd_target_elf_flavour + && h->weakdef == NULL) + { + /* Keep a list of all weak defined non function symbols from + a dynamic object, using the weakdef field. Later in this + function we will set the weakdef field to the correct + value. We only put non-function symbols from dynamic + objects on this list, because that happens to be the only + time we need to know the normal symbol corresponding to a + weak symbol, and the information is time consuming to + figure out. If the weakdef field is not already NULL, + then this symbol was already defined by some previous + dynamic object, and we will be using that previous + definition anyhow. */ + + h->weakdef = weaks; + weaks = h; + new_weakdef = TRUE; + } + + /* Set the alignment of a common symbol. */ + if (isym->st_shndx == SHN_COMMON + && h->root.type == bfd_link_hash_common) + { + unsigned int align; + + align = bfd_log2 (isym->st_value); + if (align > old_alignment + /* Permit an alignment power of zero if an alignment of one + is specified and no other alignments have been specified. */ + || (isym->st_value == 1 && old_alignment == 0)) + h->root.u.c.p->alignment_power = align; + else + h->root.u.c.p->alignment_power = old_alignment; + } + + if (info->hash->creator->flavour == bfd_target_elf_flavour) + { + int old_flags; + bfd_boolean dynsym; + int new_flag; + + /* Check the alignment when a common symbol is involved. This + can change when a common symbol is overriden by a normal + definition or a common symbol is ignored due to the old + normal definition. We need to make sure the maximum + alignment is maintained. */ + if ((old_alignment || isym->st_shndx == SHN_COMMON) + && h->root.type != bfd_link_hash_common) + { + unsigned int common_align; + unsigned int normal_align; + unsigned int symbol_align; + bfd *normal_bfd; + bfd *common_bfd; + + symbol_align = ffs (h->root.u.def.value) - 1; + if ((h->root.u.def.section->owner->flags & DYNAMIC) == 0) + { + normal_align = h->root.u.def.section->alignment_power; + if (normal_align > symbol_align) + normal_align = symbol_align; + } + else + normal_align = symbol_align; + + if (old_alignment) + { + common_align = old_alignment; + common_bfd = old_bfd; + normal_bfd = abfd; + } + else + { + common_align = bfd_log2 (isym->st_value); + common_bfd = abfd; + normal_bfd = old_bfd; + } + + if (normal_align < common_align) + (*_bfd_error_handler) + (_("Warning: alignment %u of symbol `%s' in %s is smaller than %u in %s"), + 1 << normal_align, + name, + bfd_archive_filename (normal_bfd), + 1 << common_align, + bfd_archive_filename (common_bfd)); + } + + /* Remember the symbol size and type. */ + if (isym->st_size != 0 + && (definition || h->size == 0)) + { + if (h->size != 0 && h->size != isym->st_size && ! size_change_ok) + (*_bfd_error_handler) + (_("Warning: size of symbol `%s' changed from %lu in %s to %lu in %s"), + name, (unsigned long) h->size, + bfd_archive_filename (old_bfd), + (unsigned long) isym->st_size, + bfd_archive_filename (abfd)); + + h->size = isym->st_size; + } + + /* If this is a common symbol, then we always want H->SIZE + 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. */ + if (h->root.type == bfd_link_hash_common) + h->size = h->root.u.c.size; + + if (ELF_ST_TYPE (isym->st_info) != STT_NOTYPE + && (definition || h->type == STT_NOTYPE)) + { + if (h->type != STT_NOTYPE + && h->type != ELF_ST_TYPE (isym->st_info) + && ! type_change_ok) + (*_bfd_error_handler) + (_("Warning: type of symbol `%s' changed from %d to %d in %s"), + name, h->type, ELF_ST_TYPE (isym->st_info), + bfd_archive_filename (abfd)); + + h->type = ELF_ST_TYPE (isym->st_info); + } + + /* 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. */ + if (isym->st_other != 0 && !dynamic) + { + unsigned char hvis, symvis, other, nvis; + + /* Take the balance of OTHER from the definition. */ + other = (definition ? isym->st_other : h->other); + 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; + + h->other = other | nvis; + } + + /* 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. */ + old_flags = h->elf_link_hash_flags; + dynsym = FALSE; + if (! dynamic) + { + if (! definition) + { + new_flag = ELF_LINK_HASH_REF_REGULAR; + if (bind != STB_WEAK) + new_flag |= ELF_LINK_HASH_REF_REGULAR_NONWEAK; + } + else + new_flag = ELF_LINK_HASH_DEF_REGULAR; + if (info->shared + || (old_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0) + dynsym = TRUE; + } + else + { + if (! definition) + new_flag = ELF_LINK_HASH_REF_DYNAMIC; + else + new_flag = ELF_LINK_HASH_DEF_DYNAMIC; + if ((old_flags & (ELF_LINK_HASH_DEF_REGULAR + | ELF_LINK_HASH_REF_REGULAR)) != 0 + || (h->weakdef != NULL + && ! new_weakdef + && h->weakdef->dynindx != -1)) + dynsym = TRUE; + } + + h->elf_link_hash_flags |= new_flag; + + /* 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 (! elf_add_default_symbol (abfd, info, h, name, isym, + &sec, &value, &dynsym, + override, dt_needed)) + goto error_free_vers; + + if (definition && !dynamic) + { + char *p = strchr (name, ELF_VER_CHR); + if (p != NULL && p[1] != ELF_VER_CHR) + { + /* Queue non-default versions so that .symver x, x@FOO + aliases can be checked. */ + if (! nondeflt_vers) + { + amt = (isymend - isym + 1) + * sizeof (struct elf_link_hash_entry *); + nondeflt_vers = bfd_malloc (amt); + } + nondeflt_vers [nondeflt_vers_cnt++] = h; + } + } + + if (dynsym && h->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h)) + goto error_free_vers; + if (h->weakdef != NULL + && ! new_weakdef + && h->weakdef->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h->weakdef)) + goto error_free_vers; + } + } + else if (dynsym && h->dynindx != -1) + /* If the symbol already has a dynamic index, but + visibility says it should not be visible, turn it into + a local symbol. */ + switch (ELF_ST_VISIBILITY (h->other)) + { + case STV_INTERNAL: + case STV_HIDDEN: + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + break; + } + + if (dt_needed && definition + && (h->elf_link_hash_flags + & ELF_LINK_HASH_REF_REGULAR) != 0) + { + bfd_size_type oldsize; + bfd_size_type strindex; + + if (! is_elf_hash_table (info)) + goto error_free_vers; + + /* The symbol from a DT_NEEDED object is referenced from + the regular object to create a dynamic executable. We + have to make sure there is a DT_NEEDED entry for it. */ + + dt_needed = FALSE; + oldsize = _bfd_elf_strtab_size (hash_table->dynstr); + strindex = _bfd_elf_strtab_add (hash_table->dynstr, + elf_dt_soname (abfd), FALSE); + if (strindex == (bfd_size_type) -1) + goto error_free_vers; + + if (oldsize == _bfd_elf_strtab_size (hash_table->dynstr)) + { + asection *sdyn; + Elf_External_Dyn *dyncon, *dynconend; + + sdyn = bfd_get_section_by_name (hash_table->dynobj, + ".dynamic"); + BFD_ASSERT (sdyn != NULL); + + dyncon = (Elf_External_Dyn *) sdyn->contents; + dynconend = (Elf_External_Dyn *) (sdyn->contents + + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + + elf_swap_dyn_in (hash_table->dynobj, + dyncon, &dyn); + BFD_ASSERT (dyn.d_tag != DT_NEEDED || + dyn.d_un.d_val != strindex); + } + } + + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_NEEDED, strindex)) + goto error_free_vers; + } + } + } + + /* Now that all the symbols from this input file are created, handle + .symver foo, foo@BAR such that any relocs against foo become foo@BAR. */ + if (nondeflt_vers != NULL) + { + bfd_size_type cnt, symidx; + + for (cnt = 0; cnt < nondeflt_vers_cnt; ++cnt) + { + struct elf_link_hash_entry *h = nondeflt_vers[cnt], *hi; + char *shortname, *p; + + p = strchr (h->root.root.string, ELF_VER_CHR); + if (p == NULL + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak)) + continue; + + amt = p - h->root.root.string; + shortname = bfd_malloc (amt + 1); + memcpy (shortname, h->root.root.string, amt); + shortname[amt] = '\0'; + + hi = (struct elf_link_hash_entry *) + bfd_link_hash_lookup (info->hash, shortname, + FALSE, FALSE, FALSE); + if (hi != NULL + && hi->root.type == h->root.type + && hi->root.u.def.value == h->root.u.def.value + && hi->root.u.def.section == h->root.u.def.section) + { + (*bed->elf_backend_hide_symbol) (info, hi, TRUE); + hi->root.type = bfd_link_hash_indirect; + hi->root.u.i.link = (struct bfd_link_hash_entry *) h; + (*bed->elf_backend_copy_indirect_symbol) (bed, h, hi); + sym_hash = elf_sym_hashes (abfd); + if (sym_hash) + for (symidx = 0; symidx < extsymcount; ++symidx) + if (sym_hash[symidx] == hi) + { + sym_hash[symidx] = h; + break; + } + } + free (shortname); + } + free (nondeflt_vers); + nondeflt_vers = NULL; + } + + if (extversym != NULL) + { + free (extversym); + extversym = NULL; + } + + if (isymbuf != NULL) + free (isymbuf); + isymbuf = NULL; + + /* Now set the weakdefs field correctly for all the weak defined + symbols we found. The only way to do this is to search all the + symbols. Since we only need the information for non functions in + dynamic objects, that's the only time we actually put anything on + the list WEAKS. We need this information so that if a regular + object refers to a symbol defined weakly in a dynamic object, the + real symbol in the dynamic object is also put in the dynamic + symbols; we also must arrange for both symbols to point to the + same memory location. We could handle the general case of symbol + aliasing, but a general symbol alias can only be generated in + assembler code, handling it correctly would be very time + consuming, and other ELF linkers don't handle general aliasing + either. */ + while (weaks != NULL) + { + struct elf_link_hash_entry *hlook; + asection *slook; + bfd_vma vlook; + struct elf_link_hash_entry **hpp; + struct elf_link_hash_entry **hppend; + + hlook = weaks; + weaks = hlook->weakdef; + hlook->weakdef = NULL; + + BFD_ASSERT (hlook->root.type == bfd_link_hash_defined + || hlook->root.type == bfd_link_hash_defweak + || hlook->root.type == bfd_link_hash_common + || hlook->root.type == bfd_link_hash_indirect); + slook = hlook->root.u.def.section; + vlook = hlook->root.u.def.value; + + hpp = elf_sym_hashes (abfd); + hppend = hpp + extsymcount; + for (; hpp < hppend; hpp++) + { + struct elf_link_hash_entry *h; + + h = *hpp; + if (h != NULL && h != hlook + && h->root.type == bfd_link_hash_defined + && h->root.u.def.section == slook + && h->root.u.def.value == vlook) + { + hlook->weakdef = h; + + /* If the weak definition is in the list of dynamic + symbols, make sure the real definition is put there + as well. */ + if (hlook->dynindx != -1 + && h->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h)) + goto error_return; + } + + /* If the real definition is in the list of dynamic + symbols, make sure the weak definition is put there + as well. If we don't do this, then the dynamic + loader might not merge the entries for the real + definition and the weak definition. */ + if (h->dynindx != -1 + && hlook->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, hlook)) + goto error_return; + } + break; + } + } + } + + /* If this object is the same format as the output object, and it is + not a shared library, then let the backend look through the + relocs. + + This is required to build global offset table entries and to + arrange for dynamic relocs. It is not required for the + particular common case of linking non PIC code, even when linking + against shared libraries, but unfortunately there is no way of + knowing whether an object file has been compiled PIC or not. + Looking through the relocs is not particularly time consuming. + The problem is that we must either (1) keep the relocs in memory, + which causes the linker to require additional runtime memory or + (2) read the relocs twice from the input file, which wastes time. + This would be a good case for using mmap. + + I have no idea how to handle linking PIC code into a file of a + different format. It probably can't be done. */ + check_relocs = get_elf_backend_data (abfd)->check_relocs; + if (! dynamic + && abfd->xvec == info->hash->creator + && check_relocs != NULL) + { + asection *o; + + for (o = abfd->sections; o != NULL; o = o->next) + { + Elf_Internal_Rela *internal_relocs; + bfd_boolean ok; + + if ((o->flags & SEC_RELOC) == 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)) + continue; + + internal_relocs = (NAME(_bfd_elf,link_read_relocs) + (abfd, o, (PTR) NULL, + (Elf_Internal_Rela *) NULL, + info->keep_memory)); + if (internal_relocs == NULL) + goto error_return; + + ok = (*check_relocs) (abfd, info, o, internal_relocs); + + if (elf_section_data (o)->relocs != internal_relocs) + free (internal_relocs); + + if (! ok) + goto error_return; + } + } + + /* If this is a non-traditional link, try to optimize the handling + of the .stab/.stabstr sections. */ + if (! dynamic + && ! info->traditional_format + && info->hash->creator->flavour == bfd_target_elf_flavour + && is_elf_hash_table (info) + && (info->strip != strip_all && info->strip != strip_debugger)) + { + asection *stab, *stabstr; + + stab = bfd_get_section_by_name (abfd, ".stab"); + if (stab != NULL + && (stab->flags & SEC_MERGE) == 0 + && !bfd_is_abs_section (stab->output_section)) + { + stabstr = bfd_get_section_by_name (abfd, ".stabstr"); + + if (stabstr != NULL) + { + struct bfd_elf_section_data *secdata; + + secdata = elf_section_data (stab); + if (! _bfd_link_section_stabs (abfd, + & hash_table->stab_info, + stab, stabstr, + &secdata->sec_info)) + goto error_return; + if (secdata->sec_info) + stab->sec_info_type = ELF_INFO_TYPE_STABS; + } + } + } + + if (! info->relocateable && ! dynamic + && is_elf_hash_table (info)) + { + asection *s; + + for (s = abfd->sections; s != NULL; s = s->next) + if ((s->flags & SEC_MERGE) != 0 + && !bfd_is_abs_section (s->output_section)) + { + struct bfd_elf_section_data *secdata; + + secdata = elf_section_data (s); + if (! _bfd_merge_section (abfd, + & hash_table->merge_info, + s, &secdata->sec_info)) + goto error_return; + else if (secdata->sec_info) + s->sec_info_type = ELF_INFO_TYPE_MERGE; + } + } + + if (is_elf_hash_table (info)) + { + /* 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))); + if (n == NULL) + goto error_return; + n->abfd = abfd; + n->next = hash_table->loaded; + hash_table->loaded = n; + } + + return TRUE; + + error_free_vers: + if (nondeflt_vers != NULL) + free (nondeflt_vers); + if (extversym != NULL) + free (extversym); + error_free_sym: + if (isymbuf != NULL) + free (isymbuf); + error_return: + return FALSE; +} + +/* Create some sections which will be filled in with dynamic linking + information. ABFD is an input file which requires dynamic sections + to be created. The dynamic sections take up virtual memory space + when the final executable is run, so we need to create them before + addresses are assigned to the output sections. We work out the + actual contents and size of these sections later. */ + +bfd_boolean +elf_link_create_dynamic_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + flagword flags; + register asection *s; + struct elf_link_hash_entry *h; + struct bfd_link_hash_entry *bh; + struct elf_backend_data *bed; + + if (! is_elf_hash_table (info)) + return FALSE; + + if (elf_hash_table (info)->dynamic_sections_created) + return TRUE; + + /* Make sure that all dynamic sections use the same input BFD. */ + if (elf_hash_table (info)->dynobj == NULL) + elf_hash_table (info)->dynobj = abfd; + else + abfd = elf_hash_table (info)->dynobj; + + /* Note that we set the SEC_IN_MEMORY flag for all of these + sections. */ + flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + + /* A dynamically linked executable has a .interp section, but a + shared library does not. */ + if (! info->shared) + { + s = bfd_make_section (abfd, ".interp"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)) + return FALSE; + } + + if (! info->traditional_format + && info->hash->creator->flavour == bfd_target_elf_flavour) + { + s = bfd_make_section (abfd, ".eh_frame_hdr"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 2)) + return FALSE; + elf_hash_table (info)->eh_info.hdr_sec = s; + } + + /* Create sections to hold version informations. These are removed + if they are not needed. */ + s = bfd_make_section (abfd, ".gnu.version_d"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return FALSE; + + s = bfd_make_section (abfd, ".gnu.version"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, 1)) + return FALSE; + + s = bfd_make_section (abfd, ".gnu.version_r"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return FALSE; + + s = bfd_make_section (abfd, ".dynsym"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return FALSE; + + s = bfd_make_section (abfd, ".dynstr"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)) + return FALSE; + + /* Create a strtab to hold the dynamic symbol names. */ + if (elf_hash_table (info)->dynstr == NULL) + { + elf_hash_table (info)->dynstr = _bfd_elf_strtab_init (); + if (elf_hash_table (info)->dynstr == NULL) + return FALSE; + } + + s = bfd_make_section (abfd, ".dynamic"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return FALSE; + + /* The special symbol _DYNAMIC is always set to the start of the + .dynamic section. This call occurs before we have processed the + symbols for any dynamic object, so we don't have to worry about + overriding a dynamic definition. We could set _DYNAMIC in a + linker script, but we only want to define it if we are, in fact, + creating a .dynamic section. We don't want to define it if there + is no .dynamic section, since on some ELF platforms the start up + code examines it to decide how to initialize the process. */ + bh = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, "_DYNAMIC", BSF_GLOBAL, s, (bfd_vma) 0, + (const char *) 0, FALSE, get_elf_backend_data (abfd)->collect, &bh))) + return FALSE; + h = (struct elf_link_hash_entry *) bh; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + + if (info->shared + && ! _bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + bed = get_elf_backend_data (abfd); + + s = bfd_make_section (abfd, ".hash"); + if (s == NULL + || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) + || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) + return FALSE; + elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry; + + /* Let the backend create the rest of the sections. This lets the + backend set the right flags. The backend will normally create + the .got and .plt sections. */ + if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info)) + return FALSE; + + elf_hash_table (info)->dynamic_sections_created = TRUE; + + return TRUE; +} + +/* Add an entry to the .dynamic table. */ + +bfd_boolean +elf_add_dynamic_entry (info, tag, val) + struct bfd_link_info *info; + bfd_vma tag; + bfd_vma val; +{ + Elf_Internal_Dyn dyn; + bfd *dynobj; + asection *s; + bfd_size_type newsize; + bfd_byte *newcontents; + + if (! is_elf_hash_table (info)) + return FALSE; + + dynobj = elf_hash_table (info)->dynobj; + + s = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (s != NULL); + + newsize = s->_raw_size + sizeof (Elf_External_Dyn); + newcontents = (bfd_byte *) bfd_realloc (s->contents, newsize); + if (newcontents == NULL) + return FALSE; + + dyn.d_tag = tag; + dyn.d_un.d_val = val; + elf_swap_dyn_out (dynobj, &dyn, + (Elf_External_Dyn *) (newcontents + s->_raw_size)); + + s->_raw_size = newsize; + s->contents = newcontents; + + return TRUE; +} + +/* Read and swap the relocs from the section indicated by SHDR. This + may be either a REL or a RELA section. The relocations are + translated into RELA relocations and stored in INTERNAL_RELOCS, + which should have already been allocated to contain enough space. + The EXTERNAL_RELOCS are a buffer where the external form of the + relocations should be stored. + + Returns FALSE if something goes wrong. */ + +static bfd_boolean +elf_link_read_relocs_from_section (abfd, shdr, external_relocs, + internal_relocs) + bfd *abfd; + Elf_Internal_Shdr *shdr; + PTR external_relocs; + Elf_Internal_Rela *internal_relocs; +{ + struct elf_backend_data *bed; + void (*swap_in) PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); + const bfd_byte *erela; + const bfd_byte *erelaend; + Elf_Internal_Rela *irela; + + /* If there aren't any relocations, that's OK. */ + if (!shdr) + return TRUE; + + /* Position ourselves at the start of the section. */ + if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0) + return FALSE; + + /* Read the relocations. */ + if (bfd_bread (external_relocs, shdr->sh_size, abfd) != shdr->sh_size) + return FALSE; + + bed = get_elf_backend_data (abfd); + + /* Convert the external relocations to the internal format. */ + if (shdr->sh_entsize == sizeof (Elf_External_Rel)) + swap_in = bed->s->swap_reloc_in; + else if (shdr->sh_entsize == sizeof (Elf_External_Rela)) + swap_in = bed->s->swap_reloca_in; + else + { + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + erela = external_relocs; + erelaend = erela + NUM_SHDR_ENTRIES (shdr) * shdr->sh_entsize; + irela = internal_relocs; + while (erela < erelaend) + { + (*swap_in) (abfd, erela, irela); + irela += bed->s->int_rels_per_ext_rel; + erela += shdr->sh_entsize; + } + + return TRUE; +} + +/* Read and swap the relocs for a section O. They may have been + cached. If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are + not NULL, they are used as buffers to read into. They are known to + be large enough. If the INTERNAL_RELOCS relocs argument is NULL, + the return value is allocated using either malloc or bfd_alloc, + according to the KEEP_MEMORY argument. If O has two relocation + sections (both REL and RELA relocations), then the REL_HDR + relocations will appear first in INTERNAL_RELOCS, followed by the + REL_HDR2 relocations. */ + +Elf_Internal_Rela * +NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs, + keep_memory) + bfd *abfd; + asection *o; + PTR external_relocs; + Elf_Internal_Rela *internal_relocs; + bfd_boolean keep_memory; +{ + Elf_Internal_Shdr *rel_hdr; + PTR alloc1 = NULL; + Elf_Internal_Rela *alloc2 = NULL; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (elf_section_data (o)->relocs != NULL) + return elf_section_data (o)->relocs; + + if (o->reloc_count == 0) + return NULL; + + rel_hdr = &elf_section_data (o)->rel_hdr; + + if (internal_relocs == NULL) + { + bfd_size_type size; + + size = o->reloc_count; + size *= bed->s->int_rels_per_ext_rel * sizeof (Elf_Internal_Rela); + if (keep_memory) + internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size); + else + internal_relocs = alloc2 = (Elf_Internal_Rela *) bfd_malloc (size); + if (internal_relocs == NULL) + goto error_return; + } + + if (external_relocs == NULL) + { + bfd_size_type size = rel_hdr->sh_size; + + if (elf_section_data (o)->rel_hdr2) + size += elf_section_data (o)->rel_hdr2->sh_size; + alloc1 = (PTR) bfd_malloc (size); + if (alloc1 == NULL) + goto error_return; + external_relocs = alloc1; + } + + if (!elf_link_read_relocs_from_section (abfd, rel_hdr, + external_relocs, + internal_relocs)) + goto error_return; + if (!elf_link_read_relocs_from_section + (abfd, + elf_section_data (o)->rel_hdr2, + ((bfd_byte *) external_relocs) + rel_hdr->sh_size, + internal_relocs + (NUM_SHDR_ENTRIES (rel_hdr) + * bed->s->int_rels_per_ext_rel))) + goto error_return; + + /* Cache the results for next time, if we can. */ + if (keep_memory) + elf_section_data (o)->relocs = internal_relocs; + + if (alloc1 != NULL) + free (alloc1); + + /* Don't free alloc2, since if it was allocated we are passing it + back (under the name of internal_relocs). */ + + return internal_relocs; + + error_return: + if (alloc1 != NULL) + free (alloc1); + if (alloc2 != NULL) + free (alloc2); + return NULL; +} + +/* Record an assignment to a symbol made by a linker script. We need + this in case some dynamic object refers to this symbol. */ + +bfd_boolean +NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide) + bfd *output_bfd ATTRIBUTE_UNUSED; + struct bfd_link_info *info; + const char *name; + bfd_boolean provide; +{ + struct elf_link_hash_entry *h; + + if (info->hash->creator->flavour != bfd_target_elf_flavour) + return TRUE; + + h = elf_link_hash_lookup (elf_hash_table (info), name, TRUE, TRUE, FALSE); + if (h == NULL) + return FALSE; + + if (h->root.type == bfd_link_hash_new) + h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF; + + /* If this symbol is being provided by the linker script, and it is + currently defined by a dynamic object, but not by a regular + object, then mark it as undefined so that the generic linker will + force the correct value. */ + if (provide + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + h->root.type = bfd_link_hash_undefined; + + /* If this symbol is not being provided by the linker script, and it is + currently defined by a dynamic object, but not by a regular object, + then clear out any version information because the symbol will not be + associated with the dynamic object any more. */ + if (!provide + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + h->verinfo.verdef = NULL; + + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + + if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC + | ELF_LINK_HASH_REF_DYNAMIC)) != 0 + || info->shared) + && h->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + /* If this is a weak defined symbol, and we know a corresponding + real symbol from the same dynamic object, make sure the real + symbol is also made into a dynamic symbol. */ + if (h->weakdef != NULL + && h->weakdef->dynindx == -1) + { + if (! _bfd_elf_link_record_dynamic_symbol (info, h->weakdef)) + return FALSE; + } + } + + return TRUE; +} + +/* This structure is used to pass information to + elf_link_assign_sym_version. */ + +struct elf_assign_sym_version_info +{ + /* Output BFD. */ + bfd *output_bfd; + /* General link information. */ + struct bfd_link_info *info; + /* Version tree. */ + struct bfd_elf_version_tree *verdefs; + /* Whether we had a failure. */ + bfd_boolean failed; +}; + +/* This structure is used to pass information to + elf_link_find_version_dependencies. */ + +struct elf_find_verdep_info +{ + /* Output BFD. */ + bfd *output_bfd; + /* General link information. */ + struct bfd_link_info *info; + /* The number of dependencies. */ + unsigned int vers; + /* Whether we had a failure. */ + bfd_boolean failed; +}; + +/* Array used to determine the number of hash table buckets to use + based on the number of symbols there are. If there are fewer than + 3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets, + fewer than 37 we use 17 buckets, and so forth. We never use more + than 32771 buckets. */ + +static const size_t elf_buckets[] = +{ + 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209, + 16411, 32771, 0 +}; + +/* Compute bucket count for hashing table. We do not use a static set + of possible tables sizes anymore. Instead we determine for all + possible reasonable sizes of the table the outcome (i.e., the + number of collisions etc) and choose the best solution. The + weighting functions are not too simple to allow the table to grow + without bounds. Instead one of the weighting factors is the size. + Therefore the result is always a good payoff between few collisions + (= short chain lengths) and table size. */ +static size_t +compute_bucket_count (info) + struct bfd_link_info *info; +{ + size_t dynsymcount = elf_hash_table (info)->dynsymcount; + size_t best_size = 0; + unsigned long int *hashcodes; + unsigned long int *hashcodesp; + unsigned long int i; + bfd_size_type amt; + + /* Compute the hash values for all exported symbols. At the same + time store the values in an array so that we could use them for + optimizations. */ + amt = dynsymcount; + amt *= sizeof (unsigned long int); + hashcodes = (unsigned long int *) bfd_malloc (amt); + if (hashcodes == NULL) + return 0; + hashcodesp = hashcodes; + + /* Put all hash values in HASHCODES. */ + elf_link_hash_traverse (elf_hash_table (info), + elf_collect_hash_codes, &hashcodesp); + + /* We have a problem here. The following code to optimize the table + size requires an integer type with more the 32 bits. If + BFD_HOST_U_64_BIT is set we know about such a type. */ +#ifdef BFD_HOST_U_64_BIT + if (info->optimize) + { + unsigned long int nsyms = hashcodesp - hashcodes; + size_t minsize; + size_t maxsize; + BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0); + unsigned long int *counts ; + + /* Possible optimization parameters: if we have NSYMS symbols we say + that the hashing table must at least have NSYMS/4 and at most + 2*NSYMS buckets. */ + minsize = nsyms / 4; + if (minsize == 0) + minsize = 1; + best_size = maxsize = nsyms * 2; + + /* Create array where we count the collisions in. We must use bfd_malloc + since the size could be large. */ + amt = maxsize; + amt *= sizeof (unsigned long int); + counts = (unsigned long int *) bfd_malloc (amt); + if (counts == NULL) + { + free (hashcodes); + return 0; + } + + /* Compute the "optimal" size for the hash table. The criteria is a + minimal chain length. The minor criteria is (of course) the size + of the table. */ + for (i = minsize; i < maxsize; ++i) + { + /* Walk through the array of hashcodes and count the collisions. */ + BFD_HOST_U_64_BIT max; + unsigned long int j; + unsigned long int fact; + + memset (counts, '\0', i * sizeof (unsigned long int)); + + /* Determine how often each hash bucket is used. */ + for (j = 0; j < nsyms; ++j) + ++counts[hashcodes[j] % i]; + + /* For the weight function we need some information about the + pagesize on the target. This is information need not be 100% + accurate. Since this information is not available (so far) we + define it here to a reasonable default value. If it is crucial + to have a better value some day simply define this value. */ +# ifndef BFD_TARGET_PAGESIZE +# define BFD_TARGET_PAGESIZE (4096) +# endif + + /* We in any case need 2 + NSYMS entries for the size values and + the chains. */ + max = (2 + nsyms) * (ARCH_SIZE / 8); + +# if 1 + /* Variant 1: optimize for short chains. We add the squares + of all the chain lengths (which favous many small chain + over a few long chains). */ + for (j = 0; j < i; ++j) + max += counts[j] * counts[j]; + + /* This adds penalties for the overall size of the table. */ + fact = i / (BFD_TARGET_PAGESIZE / (ARCH_SIZE / 8)) + 1; + max *= fact * fact; +# else + /* Variant 2: Optimize a lot more for small table. Here we + also add squares of the size but we also add penalties for + empty slots (the +1 term). */ + for (j = 0; j < i; ++j) + max += (1 + counts[j]) * (1 + counts[j]); + + /* The overall size of the table is considered, but not as + strong as in variant 1, where it is squared. */ + fact = i / (BFD_TARGET_PAGESIZE / (ARCH_SIZE / 8)) + 1; + max *= fact; +# endif + + /* Compare with current best results. */ + if (max < best_chlen) + { + best_chlen = max; + best_size = i; + } + } + + free (counts); + } + else +#endif /* defined (BFD_HOST_U_64_BIT) */ + { + /* This is the fallback solution if no 64bit type is available or if we + are not supposed to spend much time on optimizations. We select the + bucket count using a fixed set of numbers. */ + for (i = 0; elf_buckets[i] != 0; i++) + { + best_size = elf_buckets[i]; + if (dynsymcount < elf_buckets[i + 1]) + break; + } + } + + /* Free the arrays we needed. */ + free (hashcodes); + + return best_size; +} + +/* Set up the sizes and contents of the ELF dynamic sections. This is + called by the ELF linker emulation before_allocation routine. We + must set the sizes of the sections before the linker sets the + addresses of the various sections. */ + +bfd_boolean +NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, + filter_shlib, + auxiliary_filters, info, sinterpptr, + verdefs) + bfd *output_bfd; + const char *soname; + const char *rpath; + const char *filter_shlib; + const char * const *auxiliary_filters; + struct bfd_link_info *info; + asection **sinterpptr; + struct bfd_elf_version_tree *verdefs; +{ + bfd_size_type soname_indx; + bfd *dynobj; + struct elf_backend_data *bed; + struct elf_assign_sym_version_info asvinfo; + + *sinterpptr = NULL; + + soname_indx = (bfd_size_type) -1; + + if (info->hash->creator->flavour != bfd_target_elf_flavour) + return TRUE; + + if (! is_elf_hash_table (info)) + return TRUE; + + /* Any syms created from now on start with -1 in + got.refcount/offset and plt.refcount/offset. */ + elf_hash_table (info)->init_refcount = elf_hash_table (info)->init_offset; + + /* The backend may have to create some sections regardless of whether + we're dynamic or not. */ + bed = get_elf_backend_data (output_bfd); + if (bed->elf_backend_always_size_sections + && ! (*bed->elf_backend_always_size_sections) (output_bfd, info)) + return FALSE; + + dynobj = elf_hash_table (info)->dynobj; + + /* If there were no dynamic objects in the link, there is nothing to + do here. */ + if (dynobj == NULL) + return TRUE; + + if (! _bfd_elf_maybe_strip_eh_frame_hdr (info)) + return FALSE; + + if (elf_hash_table (info)->dynamic_sections_created) + { + struct elf_info_failed eif; + struct elf_link_hash_entry *h; + asection *dynstr; + struct bfd_elf_version_tree *t; + struct bfd_elf_version_expr *d; + bfd_boolean all_defined; + + *sinterpptr = bfd_get_section_by_name (dynobj, ".interp"); + BFD_ASSERT (*sinterpptr != NULL || info->shared); + + if (soname != NULL) + { + soname_indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + soname, TRUE); + if (soname_indx == (bfd_size_type) -1 + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SONAME, + soname_indx)) + return FALSE; + } + + if (info->symbolic) + { + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMBOLIC, + (bfd_vma) 0)) + return FALSE; + info->flags |= DF_SYMBOLIC; + } + + if (rpath != NULL) + { + bfd_size_type indx; + + indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, rpath, + TRUE); + if (info->new_dtags) + _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, indx); + if (indx == (bfd_size_type) -1 + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_RPATH, indx) + || (info->new_dtags + && ! elf_add_dynamic_entry (info, (bfd_vma) DT_RUNPATH, + indx))) + return FALSE; + } + + if (filter_shlib != NULL) + { + bfd_size_type indx; + + indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + filter_shlib, TRUE); + if (indx == (bfd_size_type) -1 + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_FILTER, indx)) + return FALSE; + } + + if (auxiliary_filters != NULL) + { + const char * const *p; + + for (p = auxiliary_filters; *p != NULL; p++) + { + bfd_size_type indx; + + indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + *p, TRUE); + if (indx == (bfd_size_type) -1 + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_AUXILIARY, + indx)) + return FALSE; + } + } + + eif.info = info; + eif.verdefs = verdefs; + eif.failed = FALSE; + + /* If we are supposed to export all symbols into the dynamic symbol + table (this is not the normal case), then do so. */ + if (info->export_dynamic) + { + elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol, + (PTR) &eif); + if (eif.failed) + return FALSE; + } + + /* Make all global versions with definiton. */ + for (t = verdefs; t != NULL; t = t->next) + for (d = t->globals; d != NULL; d = d->next) + if (!d->symver && strchr (d->pattern, '*') == NULL) + { + const char *verstr, *name; + size_t namelen, verlen, newlen; + char *newname, *p; + struct elf_link_hash_entry *newh; + + name = d->pattern; + namelen = strlen (name); + verstr = t->name; + verlen = strlen (verstr); + newlen = namelen + verlen + 3; + + newname = (char *) bfd_malloc ((bfd_size_type) newlen); + if (newname == NULL) + return FALSE; + memcpy (newname, name, namelen); + + /* Check the hidden versioned definition. */ + p = newname + namelen; + *p++ = ELF_VER_CHR; + memcpy (p, verstr, verlen + 1); + newh = elf_link_hash_lookup (elf_hash_table (info), + newname, FALSE, FALSE, + FALSE); + if (newh == NULL + || (newh->root.type != bfd_link_hash_defined + && newh->root.type != bfd_link_hash_defweak)) + { + /* Check the default versioned definition. */ + *p++ = ELF_VER_CHR; + memcpy (p, verstr, verlen + 1); + newh = elf_link_hash_lookup (elf_hash_table (info), + newname, FALSE, FALSE, + FALSE); + } + free (newname); + + /* Mark this version if there is a definition and it is + not defined in a shared object. */ + if (newh != NULL + && ((newh->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) == 0) + && (newh->root.type == bfd_link_hash_defined + || newh->root.type == bfd_link_hash_defweak)) + d->symver = 1; + } + + /* Attach all the symbols to their version information. */ + asvinfo.output_bfd = output_bfd; + asvinfo.info = info; + asvinfo.verdefs = verdefs; + asvinfo.failed = FALSE; + + elf_link_hash_traverse (elf_hash_table (info), + elf_link_assign_sym_version, + (PTR) &asvinfo); + if (asvinfo.failed) + return FALSE; + + if (!info->allow_undefined_version) + { + /* Check if all global versions have a definiton. */ + all_defined = TRUE; + for (t = verdefs; t != NULL; t = t->next) + for (d = t->globals; d != NULL; d = d->next) + if (!d->symver && !d->script + && strchr (d->pattern, '*') == NULL) + { + (*_bfd_error_handler) + (_("%s: undefined version: %s"), + d->pattern, t->name); + all_defined = FALSE; + } + + if (!all_defined) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + } + + /* Find all symbols which were defined in a dynamic object and make + the backend pick a reasonable value for them. */ + elf_link_hash_traverse (elf_hash_table (info), + elf_adjust_dynamic_symbol, + (PTR) &eif); + if (eif.failed) + return FALSE; + + /* Add some entries to the .dynamic section. We fill in some of the + values later, in elf_bfd_final_link, but we must add the entries + now so that we know the final size of the .dynamic section. */ + + /* If there are initialization and/or finalization functions to + call then add the corresponding DT_INIT/DT_FINI entries. */ + h = (info->init_function + ? elf_link_hash_lookup (elf_hash_table (info), + info->init_function, FALSE, + FALSE, FALSE) + : NULL); + if (h != NULL + && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_DEF_REGULAR)) != 0) + { + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_INIT, (bfd_vma) 0)) + return FALSE; + } + h = (info->fini_function + ? elf_link_hash_lookup (elf_hash_table (info), + info->fini_function, FALSE, + FALSE, FALSE) + : NULL); + if (h != NULL + && (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_DEF_REGULAR)) != 0) + { + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_FINI, (bfd_vma) 0)) + return FALSE; + } + + if (bfd_get_section_by_name (output_bfd, ".preinit_array") != NULL) + { + /* DT_PREINIT_ARRAY is not allowed in shared library. */ + if (info->shared) + { + bfd *sub; + asection *o; + + for (sub = info->input_bfds; sub != NULL; + sub = sub->link_next) + for (o = sub->sections; o != NULL; o = o->next) + if (elf_section_data (o)->this_hdr.sh_type + == SHT_PREINIT_ARRAY) + { + (*_bfd_error_handler) + (_("%s: .preinit_array section is not allowed in DSO"), + bfd_archive_filename (sub)); + break; + } + + bfd_set_error (bfd_error_nonrepresentable_section); + return FALSE; + } + + if (!elf_add_dynamic_entry (info, (bfd_vma) DT_PREINIT_ARRAY, + (bfd_vma) 0) + || !elf_add_dynamic_entry (info, (bfd_vma) DT_PREINIT_ARRAYSZ, + (bfd_vma) 0)) + return FALSE; + } + if (bfd_get_section_by_name (output_bfd, ".init_array") != NULL) + { + if (!elf_add_dynamic_entry (info, (bfd_vma) DT_INIT_ARRAY, + (bfd_vma) 0) + || !elf_add_dynamic_entry (info, (bfd_vma) DT_INIT_ARRAYSZ, + (bfd_vma) 0)) + return FALSE; + } + if (bfd_get_section_by_name (output_bfd, ".fini_array") != NULL) + { + if (!elf_add_dynamic_entry (info, (bfd_vma) DT_FINI_ARRAY, + (bfd_vma) 0) + || !elf_add_dynamic_entry (info, (bfd_vma) DT_FINI_ARRAYSZ, + (bfd_vma) 0)) + return FALSE; + } + + dynstr = bfd_get_section_by_name (dynobj, ".dynstr"); + /* If .dynstr is excluded from the link, we don't want any of + these tags. Strictly, we should be checking each section + individually; This quick check covers for the case where + someone does a /DISCARD/ : { *(*) }. */ + if (dynstr != NULL && dynstr->output_section != bfd_abs_section_ptr) + { + bfd_size_type strsize; + + strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_HASH, (bfd_vma) 0) + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_STRTAB, (bfd_vma) 0) + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMTAB, (bfd_vma) 0) + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_STRSZ, strsize) + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_SYMENT, + (bfd_vma) sizeof (Elf_External_Sym))) + return FALSE; + } + } + + /* The backend must work out the sizes of all the other dynamic + sections. */ + if (bed->elf_backend_size_dynamic_sections + && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info)) + return FALSE; + + if (elf_hash_table (info)->dynamic_sections_created) + { + bfd_size_type dynsymcount; + asection *s; + size_t bucketcount = 0; + size_t hash_entry_size; + unsigned int dtagcount; + + /* Set up the version definition section. */ + s = bfd_get_section_by_name (dynobj, ".gnu.version_d"); + BFD_ASSERT (s != NULL); + + /* We may have created additional version definitions if we are + just linking a regular application. */ + verdefs = asvinfo.verdefs; + + /* Skip anonymous version tag. */ + if (verdefs != NULL && verdefs->vernum == 0) + verdefs = verdefs->next; + + if (verdefs == NULL) + _bfd_strip_section_from_output (info, s); + else + { + unsigned int cdefs; + bfd_size_type size; + struct bfd_elf_version_tree *t; + bfd_byte *p; + Elf_Internal_Verdef def; + Elf_Internal_Verdaux defaux; + + cdefs = 0; + size = 0; + + /* Make space for the base version. */ + size += sizeof (Elf_External_Verdef); + size += sizeof (Elf_External_Verdaux); + ++cdefs; + + for (t = verdefs; t != NULL; t = t->next) + { + struct bfd_elf_version_deps *n; + + size += sizeof (Elf_External_Verdef); + size += sizeof (Elf_External_Verdaux); + ++cdefs; + + for (n = t->deps; n != NULL; n = n->next) + size += sizeof (Elf_External_Verdaux); + } + + s->_raw_size = size; + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return FALSE; + + /* Fill in the version definition section. */ + + p = s->contents; + + def.vd_version = VER_DEF_CURRENT; + def.vd_flags = VER_FLG_BASE; + def.vd_ndx = 1; + def.vd_cnt = 1; + def.vd_aux = sizeof (Elf_External_Verdef); + def.vd_next = (sizeof (Elf_External_Verdef) + + sizeof (Elf_External_Verdaux)); + + if (soname_indx != (bfd_size_type) -1) + { + _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, + soname_indx); + def.vd_hash = bfd_elf_hash (soname); + defaux.vda_name = soname_indx; + } + else + { + const char *name; + bfd_size_type indx; + + name = basename (output_bfd->filename); + def.vd_hash = bfd_elf_hash (name); + indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + name, FALSE); + if (indx == (bfd_size_type) -1) + return FALSE; + defaux.vda_name = indx; + } + defaux.vda_next = 0; + + _bfd_elf_swap_verdef_out (output_bfd, &def, + (Elf_External_Verdef *) p); + p += sizeof (Elf_External_Verdef); + _bfd_elf_swap_verdaux_out (output_bfd, &defaux, + (Elf_External_Verdaux *) p); + p += sizeof (Elf_External_Verdaux); + + for (t = verdefs; t != NULL; t = t->next) + { + unsigned int cdeps; + struct bfd_elf_version_deps *n; + struct elf_link_hash_entry *h; + struct bfd_link_hash_entry *bh; + + cdeps = 0; + for (n = t->deps; n != NULL; n = n->next) + ++cdeps; + + /* Add a symbol representing this version. */ + bh = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, dynobj, t->name, BSF_GLOBAL, bfd_abs_section_ptr, + (bfd_vma) 0, (const char *) NULL, FALSE, + get_elf_backend_data (dynobj)->collect, &bh))) + return FALSE; + h = (struct elf_link_hash_entry *) bh; + h->elf_link_hash_flags &= ~ ELF_LINK_NON_ELF; + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->type = STT_OBJECT; + h->verinfo.vertree = t; + + if (! _bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; + + def.vd_version = VER_DEF_CURRENT; + def.vd_flags = 0; + if (t->globals == NULL && t->locals == NULL && ! t->used) + def.vd_flags |= VER_FLG_WEAK; + def.vd_ndx = t->vernum + 1; + def.vd_cnt = cdeps + 1; + def.vd_hash = bfd_elf_hash (t->name); + def.vd_aux = sizeof (Elf_External_Verdef); + if (t->next != NULL) + def.vd_next = (sizeof (Elf_External_Verdef) + + (cdeps + 1) * sizeof (Elf_External_Verdaux)); + else + def.vd_next = 0; + + _bfd_elf_swap_verdef_out (output_bfd, &def, + (Elf_External_Verdef *) p); + p += sizeof (Elf_External_Verdef); + + defaux.vda_name = h->dynstr_index; + _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, + h->dynstr_index); + if (t->deps == NULL) + defaux.vda_next = 0; + else + defaux.vda_next = sizeof (Elf_External_Verdaux); + t->name_indx = defaux.vda_name; + + _bfd_elf_swap_verdaux_out (output_bfd, &defaux, + (Elf_External_Verdaux *) p); + p += sizeof (Elf_External_Verdaux); + + for (n = t->deps; n != NULL; n = n->next) + { + if (n->version_needed == NULL) + { + /* This can happen if there was an error in the + version script. */ + defaux.vda_name = 0; + } + else + { + defaux.vda_name = n->version_needed->name_indx; + _bfd_elf_strtab_addref (elf_hash_table (info)->dynstr, + defaux.vda_name); + } + if (n->next == NULL) + defaux.vda_next = 0; + else + defaux.vda_next = sizeof (Elf_External_Verdaux); + + _bfd_elf_swap_verdaux_out (output_bfd, &defaux, + (Elf_External_Verdaux *) p); + p += sizeof (Elf_External_Verdaux); + } + } + + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_VERDEF, (bfd_vma) 0) + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_VERDEFNUM, + (bfd_vma) cdefs)) + return FALSE; + + elf_tdata (output_bfd)->cverdefs = cdefs; + } + + if ((info->new_dtags && info->flags) || (info->flags & DF_STATIC_TLS)) + { + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_FLAGS, info->flags)) + return FALSE; + } + + if (info->flags_1) + { + if (! info->shared) + info->flags_1 &= ~ (DF_1_INITFIRST + | DF_1_NODELETE + | DF_1_NOOPEN); + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_FLAGS_1, + info->flags_1)) + return FALSE; + } + + /* Work out the size of the version reference section. */ + + s = bfd_get_section_by_name (dynobj, ".gnu.version_r"); + BFD_ASSERT (s != NULL); + { + struct elf_find_verdep_info sinfo; + + sinfo.output_bfd = output_bfd; + sinfo.info = info; + sinfo.vers = elf_tdata (output_bfd)->cverdefs; + if (sinfo.vers == 0) + sinfo.vers = 1; + sinfo.failed = FALSE; + + elf_link_hash_traverse (elf_hash_table (info), + elf_link_find_version_dependencies, + (PTR) &sinfo); + + if (elf_tdata (output_bfd)->verref == NULL) + _bfd_strip_section_from_output (info, s); + else + { + Elf_Internal_Verneed *t; + unsigned int size; + unsigned int crefs; + bfd_byte *p; + + /* Build the version definition section. */ + size = 0; + crefs = 0; + for (t = elf_tdata (output_bfd)->verref; + t != NULL; + t = t->vn_nextref) + { + Elf_Internal_Vernaux *a; + + size += sizeof (Elf_External_Verneed); + ++crefs; + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + size += sizeof (Elf_External_Vernaux); + } + + s->_raw_size = size; + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL) + return FALSE; + + p = s->contents; + for (t = elf_tdata (output_bfd)->verref; + t != NULL; + t = t->vn_nextref) + { + unsigned int caux; + Elf_Internal_Vernaux *a; + bfd_size_type indx; + + caux = 0; + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + ++caux; + + t->vn_version = VER_NEED_CURRENT; + t->vn_cnt = caux; + indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + elf_dt_name (t->vn_bfd) != NULL + ? elf_dt_name (t->vn_bfd) + : basename (t->vn_bfd->filename), + FALSE); + if (indx == (bfd_size_type) -1) + return FALSE; + t->vn_file = indx; + t->vn_aux = sizeof (Elf_External_Verneed); + if (t->vn_nextref == NULL) + t->vn_next = 0; + else + t->vn_next = (sizeof (Elf_External_Verneed) + + caux * sizeof (Elf_External_Vernaux)); + + _bfd_elf_swap_verneed_out (output_bfd, t, + (Elf_External_Verneed *) p); + p += sizeof (Elf_External_Verneed); + + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + { + a->vna_hash = bfd_elf_hash (a->vna_nodename); + indx = _bfd_elf_strtab_add (elf_hash_table (info)->dynstr, + a->vna_nodename, FALSE); + if (indx == (bfd_size_type) -1) + return FALSE; + a->vna_name = indx; + if (a->vna_nextptr == NULL) + a->vna_next = 0; + else + a->vna_next = sizeof (Elf_External_Vernaux); + + _bfd_elf_swap_vernaux_out (output_bfd, a, + (Elf_External_Vernaux *) p); + p += sizeof (Elf_External_Vernaux); + } + } + + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_VERNEED, + (bfd_vma) 0) + || ! elf_add_dynamic_entry (info, (bfd_vma) DT_VERNEEDNUM, + (bfd_vma) crefs)) + return FALSE; + + elf_tdata (output_bfd)->cverrefs = crefs; + } + } + + /* Assign dynsym indicies. In a shared library we generate a + section symbol for each output section, which come first. + Next come all of the back-end allocated local dynamic syms, + followed by the rest of the global symbols. */ + + dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info); + + /* Work out the size of the symbol version section. */ + s = bfd_get_section_by_name (dynobj, ".gnu.version"); + BFD_ASSERT (s != NULL); + if (dynsymcount == 0 + || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL)) + { + _bfd_strip_section_from_output (info, s); + /* The DYNSYMCOUNT might have changed if we were going to + output a dynamic symbol table entry for S. */ + dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info); + } + else + { + s->_raw_size = dynsymcount * sizeof (Elf_External_Versym); + s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->_raw_size); + if (s->contents == NULL) + return FALSE; + + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_VERSYM, (bfd_vma) 0)) + return FALSE; + } + + /* Set the size of the .dynsym and .hash sections. We counted + the number of dynamic symbols in elf_link_add_object_symbols. + We will build the contents of .dynsym and .hash when we build + the final symbol table, because until then we do not know the + correct value to give the symbols. We built the .dynstr + section as we went along in elf_link_add_object_symbols. */ + s = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (s != NULL); + s->_raw_size = dynsymcount * sizeof (Elf_External_Sym); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + return FALSE; + + if (dynsymcount != 0) + { + Elf_Internal_Sym isym; + + /* The first entry in .dynsym is a dummy symbol. */ + isym.st_value = 0; + isym.st_size = 0; + isym.st_name = 0; + isym.st_info = 0; + isym.st_other = 0; + isym.st_shndx = 0; + elf_swap_symbol_out (output_bfd, &isym, (PTR) s->contents, (PTR) 0); + } + + /* Compute the size of the hashing table. As a side effect this + computes the hash values for all the names we export. */ + bucketcount = compute_bucket_count (info); + + s = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize; + s->_raw_size = ((2 + bucketcount + dynsymcount) * hash_entry_size); + s->contents = (bfd_byte *) bfd_zalloc (output_bfd, s->_raw_size); + if (s->contents == NULL) + return FALSE; + + bfd_put (8 * hash_entry_size, output_bfd, (bfd_vma) bucketcount, + s->contents); + bfd_put (8 * hash_entry_size, output_bfd, (bfd_vma) dynsymcount, + s->contents + hash_entry_size); + + elf_hash_table (info)->bucketcount = bucketcount; + + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + + elf_finalize_dynstr (output_bfd, info); + + s->_raw_size = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); + + for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount) + if (! elf_add_dynamic_entry (info, (bfd_vma) DT_NULL, (bfd_vma) 0)) + return FALSE; + } + + return TRUE; +} + +/* This function is used to adjust offsets into .dynstr for + dynamic symbols. This is called via elf_link_hash_traverse. */ + +static bfd_boolean elf_adjust_dynstr_offsets + PARAMS ((struct elf_link_hash_entry *, PTR)); + +static bfd_boolean +elf_adjust_dynstr_offsets (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_strtab_hash *dynstr = (struct elf_strtab_hash *) data; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->dynindx != -1) + h->dynstr_index = _bfd_elf_strtab_offset (dynstr, h->dynstr_index); + return TRUE; +} + +/* Assign string offsets in .dynstr, update all structures referencing + them. */ + +static bfd_boolean +elf_finalize_dynstr (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + struct elf_link_local_dynamic_entry *entry; + struct elf_strtab_hash *dynstr = elf_hash_table (info)->dynstr; + bfd *dynobj = elf_hash_table (info)->dynobj; + asection *sdyn; + bfd_size_type size; + Elf_External_Dyn *dyncon, *dynconend; + + _bfd_elf_strtab_finalize (dynstr); + size = _bfd_elf_strtab_size (dynstr); + + /* Update all .dynamic entries referencing .dynstr strings. */ + sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (sdyn != NULL); + + dyncon = (Elf_External_Dyn *) sdyn->contents; + dynconend = (Elf_External_Dyn *) (sdyn->contents + + sdyn->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + + elf_swap_dyn_in (dynobj, dyncon, & dyn); + switch (dyn.d_tag) + { + case DT_STRSZ: + dyn.d_un.d_val = size; + elf_swap_dyn_out (dynobj, & dyn, dyncon); + break; + case DT_NEEDED: + case DT_SONAME: + case DT_RPATH: + case DT_RUNPATH: + case DT_FILTER: + case DT_AUXILIARY: + dyn.d_un.d_val = _bfd_elf_strtab_offset (dynstr, dyn.d_un.d_val); + elf_swap_dyn_out (dynobj, & dyn, dyncon); + break; + default: + break; + } + } + + /* Now update local dynamic symbols. */ + for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next) + entry->isym.st_name = _bfd_elf_strtab_offset (dynstr, + entry->isym.st_name); + + /* And the rest of dynamic symbols. */ + elf_link_hash_traverse (elf_hash_table (info), + elf_adjust_dynstr_offsets, dynstr); + + /* Adjust version definitions. */ + if (elf_tdata (output_bfd)->cverdefs) + { + asection *s; + bfd_byte *p; + bfd_size_type i; + Elf_Internal_Verdef def; + Elf_Internal_Verdaux defaux; + + s = bfd_get_section_by_name (dynobj, ".gnu.version_d"); + p = (bfd_byte *) s->contents; + do + { + _bfd_elf_swap_verdef_in (output_bfd, (Elf_External_Verdef *) p, + &def); + p += sizeof (Elf_External_Verdef); + for (i = 0; i < def.vd_cnt; ++i) + { + _bfd_elf_swap_verdaux_in (output_bfd, + (Elf_External_Verdaux *) p, &defaux); + defaux.vda_name = _bfd_elf_strtab_offset (dynstr, + defaux.vda_name); + _bfd_elf_swap_verdaux_out (output_bfd, + &defaux, (Elf_External_Verdaux *) p); + p += sizeof (Elf_External_Verdaux); + } + } + while (def.vd_next); + } + + /* Adjust version references. */ + if (elf_tdata (output_bfd)->verref) + { + asection *s; + bfd_byte *p; + bfd_size_type i; + Elf_Internal_Verneed need; + Elf_Internal_Vernaux needaux; + + s = bfd_get_section_by_name (dynobj, ".gnu.version_r"); + p = (bfd_byte *) s->contents; + do + { + _bfd_elf_swap_verneed_in (output_bfd, (Elf_External_Verneed *) p, + &need); + need.vn_file = _bfd_elf_strtab_offset (dynstr, need.vn_file); + _bfd_elf_swap_verneed_out (output_bfd, &need, + (Elf_External_Verneed *) p); + p += sizeof (Elf_External_Verneed); + for (i = 0; i < need.vn_cnt; ++i) + { + _bfd_elf_swap_vernaux_in (output_bfd, + (Elf_External_Vernaux *) p, &needaux); + needaux.vna_name = _bfd_elf_strtab_offset (dynstr, + needaux.vna_name); + _bfd_elf_swap_vernaux_out (output_bfd, + &needaux, + (Elf_External_Vernaux *) p); + p += sizeof (Elf_External_Vernaux); + } + } + while (need.vn_next); + } + + return TRUE; +} + +/* Fix up the flags for a symbol. This handles various cases which + can only be fixed after all the input files are seen. This is + currently called by both adjust_dynamic_symbol and + assign_sym_version, which is unnecessary but perhaps more robust in + the face of future changes. */ + +static bfd_boolean +elf_fix_symbol_flags (h, eif) + struct elf_link_hash_entry *h; + struct elf_info_failed *eif; +{ + /* If this symbol was mentioned in a non-ELF file, try to set + DEF_REGULAR and REF_REGULAR correctly. This is the only way to + permit a non-ELF file to correctly refer to a symbol defined in + an ELF dynamic object. */ + if ((h->elf_link_hash_flags & ELF_LINK_NON_ELF) != 0) + { + while (h->root.type == bfd_link_hash_indirect) + 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) + h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK); + else + { + if (h->root.u.def.section->owner != NULL + && (bfd_get_flavour (h->root.u.def.section->owner) + == bfd_target_elf_flavour)) + h->elf_link_hash_flags |= (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK); + else + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + } + + if (h->dynindx == -1 + && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0)) + { + if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h)) + { + eif->failed = TRUE; + return FALSE; + } + } + } + else + { + /* Unfortunately, ELF_LINK_NON_ELF is only correct if the symbol + was first seen in a non-ELF file. Fortunately, if the symbol + was first seen in an ELF file, we're probably OK unless the + symbol was defined in a non-ELF file. Catch that case here. + FIXME: We're still in trouble if the symbol was first seen in + a dynamic object, and then later in a non-ELF regular object. */ + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && (h->root.u.def.section->owner != NULL + ? (bfd_get_flavour (h->root.u.def.section->owner) + != bfd_target_elf_flavour) + : (bfd_is_abs_section (h->root.u.def.section) + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) == 0))) + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + } + + /* If this is a final link, and the symbol was defined as a common + symbol in a regular object file, and there was no definition in + any dynamic object, then the linker will have allocated space for + the symbol in a common section but the ELF_LINK_HASH_DEF_REGULAR + flag will not have been set. */ + if (h->root.type == bfd_link_hash_defined + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + && (h->root.u.def.section->owner->flags & DYNAMIC) == 0) + h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + + /* If -Bsymbolic was used (which means to bind references to global + symbols to the definition within the shared object), and this + symbol was defined in a regular object, then it actually doesn't + need a PLT entry, and we can accomplish that by forcing it local. + Likewise, if the symbol has hidden or internal visibility. + FIXME: It might be that we also do not need a PLT for other + non-hidden visibilities, but we would have to tell that to the + backend specifically; we can't just clear PLT-related data here. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0 + && eif->info->shared + && is_elf_hash_table (eif->info) + && (eif->info->symbolic + || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL + || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) + { + struct elf_backend_data *bed; + bfd_boolean force_local; + + bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj); + + force_local = (ELF_ST_VISIBILITY (h->other) == STV_INTERNAL + || ELF_ST_VISIBILITY (h->other) == STV_HIDDEN); + (*bed->elf_backend_hide_symbol) (eif->info, h, force_local); + } + + /* If this is a weak defined symbol in a dynamic object, and we know + the real definition in the dynamic object, copy interesting flags + over to the real definition. */ + if (h->weakdef != NULL) + { + struct elf_link_hash_entry *weakdef; + + weakdef = h->weakdef; + if (h->root.type == bfd_link_hash_indirect) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak); + BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined + || weakdef->root.type == bfd_link_hash_defweak); + BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC); + + /* If the real definition is defined by a regular object file, + don't do anything special. See the longer description in + elf_adjust_dynamic_symbol, below. */ + if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) + h->weakdef = NULL; + else + { + struct elf_backend_data *bed; + + bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj); + (*bed->elf_backend_copy_indirect_symbol) (bed, weakdef, h); + } + } + + return TRUE; +} + +/* Make the backend pick a good value for a dynamic symbol. This is + called via elf_link_hash_traverse, and also calls itself + recursively. */ + +static bfd_boolean +elf_adjust_dynamic_symbol (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_info_failed *eif = (struct elf_info_failed *) data; + bfd *dynobj; + struct elf_backend_data *bed; + + if (! is_elf_hash_table (eif->info)) + return FALSE; + + if (h->root.type == bfd_link_hash_warning) + { + h->plt = elf_hash_table (eif->info)->init_offset; + h->got = elf_hash_table (eif->info)->init_offset; + + /* 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; + } + + /* Ignore indirect symbols. These are added by the versioning code. */ + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + /* Fix the symbol flags. */ + if (! elf_fix_symbol_flags (h, eif)) + return FALSE; + + /* If this symbol does not require a PLT entry, and it is not + defined by a dynamic object, or is not referenced by a regular + object, ignore it. We do have to handle a weak defined symbol, + even if no regular object refers to it, if we decided to add it + to the dynamic symbol table. FIXME: Do we normally need to worry + about symbols which are defined by one dynamic object and + referenced by another one? */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0 + && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + || ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0 + && (h->weakdef == NULL || h->weakdef->dynindx == -1)))) + { + h->plt = elf_hash_table (eif->info)->init_offset; + return TRUE; + } + + /* If we've already adjusted this symbol, don't do it again. This + can happen via a recursive call. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) + return TRUE; + + /* Don't look at this symbol again. Note that we must set this + after checking the above conditions, because we may look at a + symbol once, decide not to do anything, and then get called + recursively later after REF_REGULAR is set below. */ + h->elf_link_hash_flags |= ELF_LINK_HASH_DYNAMIC_ADJUSTED; + + /* If this is a weak definition, and we know a real definition, and + the real symbol is not itself defined by a regular object file, + then get a good value for the real definition. We handle the + real symbol first, for the convenience of the backend routine. + + Note that there is a confusing case here. If the real definition + is defined by a regular object file, we don't get the real symbol + from the dynamic object, but we do get the weak symbol. If the + processor backend uses a COPY reloc, then if some routine in the + dynamic object changes the real symbol, we will not see that + change in the corresponding weak symbol. This is the way other + ELF linkers work as well, and seems to be a result of the shared + library model. + + I will clarify this issue. Most SVR4 shared libraries define the + variable _timezone and define timezone as a weak synonym. The + tzset call changes _timezone. If you write + extern int timezone; + int _timezone = 5; + int main () { tzset (); printf ("%d %d\n", timezone, _timezone); } + you might expect that, since timezone is a synonym for _timezone, + the same number will print both times. However, if the processor + backend uses a COPY reloc, then actually timezone will be copied + into your process image, and, since you define _timezone + yourself, _timezone will not. Thus timezone and _timezone will + wind up at different memory locations. The tzset call will set + _timezone, leaving timezone unchanged. */ + + if (h->weakdef != NULL) + { + /* If we get to this point, we know there is an implicit + reference by a regular object file via the weak symbol H. + FIXME: Is this really true? What if the traversal finds + H->WEAKDEF before it finds H? */ + h->weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + + if (! elf_adjust_dynamic_symbol (h->weakdef, (PTR) eif)) + return FALSE; + } + + /* If a symbol has no type and no size and does not require a PLT + entry, then we are probably about to do the wrong thing here: we + are probably going to create a COPY reloc for an empty object. + This case can arise when a shared object is built with assembly + code, and the assembly code fails to set the symbol type. */ + if (h->size == 0 + && h->type == STT_NOTYPE + && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0) + (*_bfd_error_handler) + (_("warning: type and size of dynamic symbol `%s' are not defined"), + h->root.root.string); + + dynobj = elf_hash_table (eif->info)->dynobj; + bed = get_elf_backend_data (dynobj); + if (! (*bed->elf_backend_adjust_dynamic_symbol) (eif->info, h)) + { + eif->failed = TRUE; + return FALSE; + } + + return TRUE; +} + +/* This routine is used to export all defined symbols into the dynamic + symbol table. It is called via elf_link_hash_traverse. */ + +static bfd_boolean +elf_export_symbol (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_info_failed *eif = (struct elf_info_failed *) data; + + /* Ignore indirect symbols. These are added by the versioning code. */ + if (h->root.type == bfd_link_hash_indirect) + return TRUE; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->dynindx == -1 + && (h->elf_link_hash_flags + & (ELF_LINK_HASH_DEF_REGULAR | ELF_LINK_HASH_REF_REGULAR)) != 0) + { + struct bfd_elf_version_tree *t; + struct bfd_elf_version_expr *d; + + for (t = eif->verdefs; t != NULL; t = t->next) + { + if (t->globals != NULL) + { + for (d = t->globals; d != NULL; d = d->next) + { + if ((*d->match) (d, h->root.root.string)) + goto doit; + } + } + + if (t->locals != NULL) + { + for (d = t->locals ; d != NULL; d = d->next) + { + if ((*d->match) (d, h->root.root.string)) + return TRUE; + } + } + } + + if (!eif->verdefs) + { + doit: + if (! _bfd_elf_link_record_dynamic_symbol (eif->info, h)) + { + eif->failed = TRUE; + return FALSE; + } + } + } + + return TRUE; +} + +/* Look through the symbols which are defined in other shared + libraries and referenced here. Update the list of version + dependencies. This will be put into the .gnu.version_r section. + This function is called via elf_link_hash_traverse. */ + +static bfd_boolean +elf_link_find_version_dependencies (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_find_verdep_info *rinfo = (struct elf_find_verdep_info *) data; + Elf_Internal_Verneed *t; + Elf_Internal_Vernaux *a; + bfd_size_type amt; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* We only care about symbols defined in shared objects with version + information. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + || h->dynindx == -1 + || h->verinfo.verdef == NULL) + return TRUE; + + /* See if we already know about this version. */ + for (t = elf_tdata (rinfo->output_bfd)->verref; t != NULL; t = t->vn_nextref) + { + if (t->vn_bfd != h->verinfo.verdef->vd_bfd) + continue; + + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + if (a->vna_nodename == h->verinfo.verdef->vd_nodename) + return TRUE; + + break; + } + + /* This is a new version. Add it to tree we are building. */ + + if (t == NULL) + { + amt = sizeof *t; + t = (Elf_Internal_Verneed *) bfd_zalloc (rinfo->output_bfd, amt); + if (t == NULL) + { + rinfo->failed = TRUE; + return FALSE; + } + + t->vn_bfd = h->verinfo.verdef->vd_bfd; + t->vn_nextref = elf_tdata (rinfo->output_bfd)->verref; + elf_tdata (rinfo->output_bfd)->verref = t; + } + + amt = sizeof *a; + a = (Elf_Internal_Vernaux *) bfd_zalloc (rinfo->output_bfd, amt); + + /* Note that we are copying a string pointer here, and testing it + above. If bfd_elf_string_from_elf_section is ever changed to + discard the string data when low in memory, this will have to be + fixed. */ + a->vna_nodename = h->verinfo.verdef->vd_nodename; + + a->vna_flags = h->verinfo.verdef->vd_flags; + a->vna_nextptr = t->vn_auxptr; + + h->verinfo.verdef->vd_exp_refno = rinfo->vers; + ++rinfo->vers; + + a->vna_other = h->verinfo.verdef->vd_exp_refno + 1; + + t->vn_auxptr = a; + + return TRUE; +} + +/* Figure out appropriate versions for all the symbols. We may not + have the version number script until we have read all of the input + files, so until that point we don't know which symbols should be + local. This function is called via elf_link_hash_traverse. */ + +static bfd_boolean +elf_link_assign_sym_version (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_assign_sym_version_info *sinfo; + struct bfd_link_info *info; + struct elf_backend_data *bed; + struct elf_info_failed eif; + char *p; + bfd_size_type amt; + + sinfo = (struct elf_assign_sym_version_info *) data; + info = sinfo->info; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* Fix the symbol flags. */ + eif.failed = FALSE; + eif.info = info; + if (! elf_fix_symbol_flags (h, &eif)) + { + if (eif.failed) + sinfo->failed = TRUE; + return FALSE; + } + + /* We only need version numbers for symbols defined in regular + objects. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + return TRUE; + + bed = get_elf_backend_data (sinfo->output_bfd); + p = strchr (h->root.root.string, ELF_VER_CHR); + if (p != NULL && h->verinfo.vertree == NULL) + { + struct bfd_elf_version_tree *t; + bfd_boolean hidden; + + hidden = TRUE; + + /* There are two consecutive ELF_VER_CHR characters if this is + not a hidden symbol. */ + ++p; + if (*p == ELF_VER_CHR) + { + hidden = FALSE; + ++p; + } + + /* If there is no version string, we can just return out. */ + if (*p == '\0') + { + if (hidden) + h->elf_link_hash_flags |= ELF_LINK_HIDDEN; + return TRUE; + } + + /* Look for the version. If we find it, it is no longer weak. */ + for (t = sinfo->verdefs; t != NULL; t = t->next) + { + if (strcmp (t->name, p) == 0) + { + size_t len; + char *alc; + struct bfd_elf_version_expr *d; + + len = p - h->root.root.string; + alc = bfd_malloc ((bfd_size_type) len); + if (alc == NULL) + return FALSE; + memcpy (alc, h->root.root.string, len - 1); + alc[len - 1] = '\0'; + if (alc[len - 2] == ELF_VER_CHR) + alc[len - 2] = '\0'; + + h->verinfo.vertree = t; + t->used = TRUE; + d = NULL; + + if (t->globals != NULL) + { + for (d = t->globals; d != NULL; d = d->next) + if ((*d->match) (d, alc)) + break; + } + + /* See if there is anything to force this symbol to + local scope. */ + if (d == NULL && t->locals != NULL) + { + for (d = t->locals; d != NULL; d = d->next) + { + if ((*d->match) (d, alc)) + { + if (h->dynindx != -1 + && info->shared + && ! info->export_dynamic) + { + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + } + + break; + } + } + } + + free (alc); + break; + } + } + + /* If we are building an application, we need to create a + version node for this version. */ + if (t == NULL && ! info->shared) + { + struct bfd_elf_version_tree **pp; + int version_index; + + /* If we aren't going to export this symbol, we don't need + to worry about it. */ + if (h->dynindx == -1) + return TRUE; + + amt = sizeof *t; + t = ((struct bfd_elf_version_tree *) + bfd_alloc (sinfo->output_bfd, amt)); + if (t == NULL) + { + sinfo->failed = TRUE; + return FALSE; + } + + t->next = NULL; + t->name = p; + t->globals = NULL; + t->locals = NULL; + t->deps = NULL; + t->name_indx = (unsigned int) -1; + t->used = TRUE; + + version_index = 1; + /* Don't count anonymous version tag. */ + if (sinfo->verdefs != NULL && sinfo->verdefs->vernum == 0) + version_index = 0; + for (pp = &sinfo->verdefs; *pp != NULL; pp = &(*pp)->next) + ++version_index; + t->vernum = version_index; + + *pp = t; + + h->verinfo.vertree = t; + } + else if (t == NULL) + { + /* We could not find the version for a symbol when + generating a shared archive. Return an error. */ + (*_bfd_error_handler) + (_("%s: undefined versioned symbol name %s"), + bfd_get_filename (sinfo->output_bfd), h->root.root.string); + bfd_set_error (bfd_error_bad_value); + sinfo->failed = TRUE; + return FALSE; + } + + if (hidden) + h->elf_link_hash_flags |= ELF_LINK_HIDDEN; + } + + /* If we don't have a version for this symbol, see if we can find + something. */ + if (h->verinfo.vertree == NULL && sinfo->verdefs != NULL) + { + struct bfd_elf_version_tree *t; + struct bfd_elf_version_tree *local_ver; + struct bfd_elf_version_expr *d; + + /* See if can find what version this symbol is in. If the + symbol is supposed to be local, then don't actually register + it. */ + local_ver = NULL; + for (t = sinfo->verdefs; t != NULL; t = t->next) + { + if (t->globals != NULL) + { + bfd_boolean matched; + + matched = FALSE; + for (d = t->globals; d != NULL; d = d->next) + { + if ((*d->match) (d, h->root.root.string)) + { + if (d->symver) + matched = TRUE; + else + { + /* There is a version without definition. Make + the symbol the default definition for this + version. */ + h->verinfo.vertree = t; + local_ver = NULL; + d->script = 1; + break; + } + } + } + + if (d != NULL) + break; + else if (matched) + /* There is no undefined version for this symbol. Hide the + default one. */ + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + } + + if (t->locals != NULL) + { + for (d = t->locals; d != NULL; d = d->next) + { + /* If the match is "*", keep looking for a more + explicit, perhaps even global, match. */ + if (d->pattern[0] == '*' && d->pattern[1] == '\0') + local_ver = t; + else if ((*d->match) (d, h->root.root.string)) + { + local_ver = t; + break; + } + } + + if (d != NULL) + break; + } + } + + if (local_ver != NULL) + { + h->verinfo.vertree = local_ver; + if (h->dynindx != -1 + && info->shared + && ! info->export_dynamic) + { + (*bed->elf_backend_hide_symbol) (info, h, TRUE); + } + } + } + + return TRUE; +} + +/* Final phase of ELF linker. */ + +/* A structure we use to avoid passing large numbers of arguments. */ + +struct elf_final_link_info +{ + /* General link information. */ + struct bfd_link_info *info; + /* Output BFD. */ + bfd *output_bfd; + /* Symbol string table. */ + struct bfd_strtab_hash *symstrtab; + /* .dynsym section. */ + asection *dynsym_sec; + /* .hash section. */ + asection *hash_sec; + /* symbol version section (.gnu.version). */ + asection *symver_sec; + /* first SHF_TLS section (if any). */ + asection *first_tls_sec; + /* Buffer large enough to hold contents of any section. */ + bfd_byte *contents; + /* Buffer large enough to hold external relocs of any section. */ + PTR external_relocs; + /* Buffer large enough to hold internal relocs of any section. */ + Elf_Internal_Rela *internal_relocs; + /* Buffer large enough to hold external local symbols of any input + BFD. */ + Elf_External_Sym *external_syms; + /* And a buffer for symbol section indices. */ + Elf_External_Sym_Shndx *locsym_shndx; + /* Buffer large enough to hold internal local symbols of any input + BFD. */ + Elf_Internal_Sym *internal_syms; + /* Array large enough to hold a symbol index for each local symbol + of any input BFD. */ + long *indices; + /* Array large enough to hold a section pointer for each local + symbol of any input BFD. */ + asection **sections; + /* Buffer to hold swapped out symbols. */ + Elf_External_Sym *symbuf; + /* And one for symbol section indices. */ + 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; +}; + +static bfd_boolean elf_link_output_sym + PARAMS ((struct elf_final_link_info *, const char *, + Elf_Internal_Sym *, asection *)); +static bfd_boolean elf_link_flush_output_syms + PARAMS ((struct elf_final_link_info *)); +static bfd_boolean elf_link_output_extsym + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_link_sec_merge_syms + PARAMS ((struct elf_link_hash_entry *, PTR)); +static bfd_boolean elf_link_check_versioned_symbol + PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static bfd_boolean elf_link_input_bfd + PARAMS ((struct elf_final_link_info *, bfd *)); +static bfd_boolean elf_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* This struct is used to pass information to elf_link_output_extsym. */ + +struct elf_outext_info +{ + bfd_boolean failed; + bfd_boolean localsyms; + struct elf_final_link_info *finfo; +}; + +/* Compute the size of, and allocate space for, REL_HDR which is the + section header for a section containing relocations for O. */ + +static bfd_boolean +elf_link_size_reloc_section (abfd, rel_hdr, o) + bfd *abfd; + Elf_Internal_Shdr *rel_hdr; + asection *o; +{ + bfd_size_type reloc_count; + bfd_size_type num_rel_hashes; + + /* Figure out how many relocations there will be. */ + if (rel_hdr == &elf_section_data (o)->rel_hdr) + reloc_count = elf_section_data (o)->rel_count; + else + reloc_count = elf_section_data (o)->rel_count2; + + num_rel_hashes = o->reloc_count; + if (num_rel_hashes < reloc_count) + num_rel_hashes = reloc_count; + + /* That allows us to calculate the size of the section. */ + rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count; + + /* The contents field must last into write_object_contents, so we + allocate it with bfd_alloc rather than malloc. Also since we + cannot be sure that the contents will actually be filled in, + we zero the allocated space. */ + rel_hdr->contents = (PTR) bfd_zalloc (abfd, rel_hdr->sh_size); + if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) + return FALSE; + + /* We only allocate one set of hash entries, so we only do it the + first time we are called. */ + if (elf_section_data (o)->rel_hashes == NULL + && num_rel_hashes) + { + struct elf_link_hash_entry **p; + + p = ((struct elf_link_hash_entry **) + bfd_zmalloc (num_rel_hashes + * sizeof (struct elf_link_hash_entry *))); + if (p == NULL) + return FALSE; + + elf_section_data (o)->rel_hashes = p; + } + + return TRUE; +} + +/* When performing a relocateable link, the input relocations are + preserved. But, if they reference global symbols, the indices + referenced must be updated. Update all the relocations in + REL_HDR (there are COUNT of them), using the data in REL_HASH. */ + +static void +elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash) + bfd *abfd; + Elf_Internal_Shdr *rel_hdr; + unsigned int count; + struct elf_link_hash_entry **rel_hash; +{ + unsigned int i; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_byte *erela; + void (*swap_in) PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); + void (*swap_out) PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); + + if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + swap_in = bed->s->swap_reloc_in; + swap_out = bed->s->swap_reloc_out; + } + else if (rel_hdr->sh_entsize == sizeof (Elf_External_Rela)) + { + swap_in = bed->s->swap_reloca_in; + swap_out = bed->s->swap_reloca_out; + } + else + abort (); + + if (bed->s->int_rels_per_ext_rel > MAX_INT_RELS_PER_EXT_REL) + abort (); + + erela = rel_hdr->contents; + for (i = 0; i < count; i++, rel_hash++, erela += rel_hdr->sh_entsize) + { + Elf_Internal_Rela irela[MAX_INT_RELS_PER_EXT_REL]; + unsigned int j; + + if (*rel_hash == NULL) + continue; + + BFD_ASSERT ((*rel_hash)->indx >= 0); + + (*swap_in) (abfd, erela, irela); + for (j = 0; j < bed->s->int_rels_per_ext_rel; j++) + irela[j].r_info = ELF_R_INFO ((*rel_hash)->indx, + ELF_R_TYPE (irela[j].r_info)); + (*swap_out) (abfd, irela, erela); + } +} + +struct elf_link_sort_rela +{ + bfd_vma offset; + enum elf_reloc_type_class type; + /* We use this as an array of size int_rels_per_ext_rel. */ + Elf_Internal_Rela rela[1]; +}; + +static int +elf_link_sort_cmp1 (A, B) + const PTR A; + const PTR B; +{ + struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A; + struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B; + int relativea, relativeb; + + relativea = a->type == reloc_class_relative; + relativeb = b->type == reloc_class_relative; + + if (relativea < relativeb) + return 1; + if (relativea > relativeb) + return -1; + if (ELF_R_SYM (a->rela->r_info) < ELF_R_SYM (b->rela->r_info)) + return -1; + if (ELF_R_SYM (a->rela->r_info) > ELF_R_SYM (b->rela->r_info)) + return 1; + if (a->rela->r_offset < b->rela->r_offset) + return -1; + if (a->rela->r_offset > b->rela->r_offset) + return 1; + return 0; +} + +static int +elf_link_sort_cmp2 (A, B) + const PTR A; + const PTR B; +{ + struct elf_link_sort_rela *a = (struct elf_link_sort_rela *) A; + struct elf_link_sort_rela *b = (struct elf_link_sort_rela *) B; + int copya, copyb; + + if (a->offset < b->offset) + return -1; + if (a->offset > b->offset) + 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) + return -1; + if (copya > copyb) + return 1; + if (a->rela->r_offset < b->rela->r_offset) + return -1; + if (a->rela->r_offset > b->rela->r_offset) + return 1; + return 0; +} + +static size_t +elf_link_sort_relocs (abfd, info, psec) + bfd *abfd; + struct bfd_link_info *info; + asection **psec; +{ + bfd *dynobj = elf_hash_table (info)->dynobj; + asection *reldyn, *o; + bfd_size_type count, size; + size_t i, ret, sort_elt, ext_size; + bfd_byte *sort, *s_non_relative, *p; + struct elf_link_sort_rela *sq; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + int i2e = bed->s->int_rels_per_ext_rel; + void (*swap_in) PARAMS ((bfd *, const bfd_byte *, Elf_Internal_Rela *)); + void (*swap_out) PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); + + reldyn = bfd_get_section_by_name (abfd, ".rela.dyn"); + if (reldyn == NULL || reldyn->_raw_size == 0) + { + reldyn = bfd_get_section_by_name (abfd, ".rel.dyn"); + if (reldyn == NULL || reldyn->_raw_size == 0) + return 0; + ext_size = sizeof (Elf_External_Rel); + swap_in = bed->s->swap_reloc_in; + swap_out = bed->s->swap_reloc_out; + } + else + { + ext_size = sizeof (Elf_External_Rela); + swap_in = bed->s->swap_reloca_in; + swap_out = bed->s->swap_reloca_out; + } + count = reldyn->_raw_size / ext_size; + + size = 0; + for (o = dynobj->sections; o != NULL; o = o->next) + if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) + == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) + && o->output_section == reldyn) + size += o->_raw_size; + + if (size != reldyn->_raw_size) + return 0; + + sort_elt = (sizeof (struct elf_link_sort_rela) + + (i2e - 1) * sizeof (Elf_Internal_Rela)); + sort = bfd_zmalloc (sort_elt * count); + if (sort == NULL) + { + (*info->callbacks->warning) + (info, _("Not enough memory to sort relocations"), 0, abfd, 0, + (bfd_vma) 0); + return 0; + } + + for (o = dynobj->sections; o != NULL; o = o->next) + if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) + == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) + && o->output_section == reldyn) + { + bfd_byte *erel, *erelend; + + erel = o->contents; + erelend = o->contents + o->_raw_size; + p = sort + o->output_offset / ext_size * sort_elt; + while (erel < erelend) + { + 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); + p += sort_elt; + erel += ext_size; + } + } + + qsort (sort, (size_t) count, sort_elt, elf_link_sort_cmp1); + + for (i = 0, p = sort; i < count; i++, p += sort_elt) + { + struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; + if (s->type != reloc_class_relative) + break; + } + ret = i; + s_non_relative = p; + + sq = (struct elf_link_sort_rela *) s_non_relative; + for (; i < count; i++, p += sort_elt) + { + struct elf_link_sort_rela *sp = (struct elf_link_sort_rela *) p; + if (ELF_R_SYM (sp->rela->r_info) != ELF_R_SYM (sq->rela->r_info)) + sq = sp; + sp->offset = sq->rela->r_offset; + } + + qsort (s_non_relative, (size_t) count - ret, sort_elt, elf_link_sort_cmp2); + + for (o = dynobj->sections; o != NULL; o = o->next) + if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)) + == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED) + && o->output_section == reldyn) + { + bfd_byte *erel, *erelend; + + erel = o->contents; + erelend = o->contents + o->_raw_size; + p = sort + o->output_offset / ext_size * sort_elt; + while (erel < erelend) + { + struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; + (*swap_out) (abfd, s->rela, erel); + p += sort_elt; + erel += ext_size; + } + } + + free (sort); + *psec = reldyn; + return ret; +} + +/* Do the final step of an ELF link. */ + +bfd_boolean +elf_bfd_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd_boolean dynamic; + bfd_boolean emit_relocs; + bfd *dynobj; + struct elf_final_link_info finfo; + register asection *o; + register struct bfd_link_order *p; + register bfd *sub; + bfd_size_type max_contents_size; + bfd_size_type max_external_reloc_size; + 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; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + struct elf_outext_info eoinfo; + bfd_boolean merged; + size_t relativecount = 0; + asection *reldyn = 0; + bfd_size_type amt; + + if (! is_elf_hash_table (info)) + return FALSE; + + if (info->shared) + abfd->flags |= DYNAMIC; + + dynamic = elf_hash_table (info)->dynamic_sections_created; + dynobj = elf_hash_table (info)->dynobj; + + emit_relocs = (info->relocateable + || info->emitrelocations + || bed->elf_backend_emit_relocs); + + finfo.info = info; + finfo.output_bfd = abfd; + finfo.symstrtab = elf_stringtab_init (); + if (finfo.symstrtab == NULL) + return FALSE; + + if (! dynamic) + { + finfo.dynsym_sec = NULL; + finfo.hash_sec = NULL; + finfo.symver_sec = NULL; + } + else + { + finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym"); + finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL); + finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version"); + /* Note that it is OK if symver_sec is NULL. */ + } + + finfo.contents = NULL; + finfo.external_relocs = NULL; + finfo.internal_relocs = NULL; + finfo.external_syms = NULL; + finfo.locsym_shndx = NULL; + finfo.internal_syms = NULL; + finfo.indices = NULL; + finfo.sections = NULL; + finfo.symbuf = NULL; + finfo.symshndxbuf = NULL; + finfo.symbuf_count = 0; + finfo.shndxbuf_size = 0; + finfo.first_tls_sec = NULL; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + if ((o->flags & SEC_THREAD_LOCAL) != 0 + && (o->flags & SEC_LOAD) != 0) + { + finfo.first_tls_sec = o; + break; + } + + /* Count up the number of relocations we will output for each output + section, so that we know the sizes of the reloc sections. We + also figure out some maximum sizes. */ + max_contents_size = 0; + max_external_reloc_size = 0; + max_internal_reloc_count = 0; + max_sym_count = 0; + max_sym_shndx_count = 0; + merged = FALSE; + for (o = abfd->sections; o != (asection *) NULL; o = o->next) + { + struct bfd_elf_section_data *esdo = elf_section_data (o); + o->reloc_count = 0; + + for (p = o->link_order_head; p != NULL; p = p->next) + { + unsigned int reloc_count = 0; + struct bfd_elf_section_data *esdi = NULL; + unsigned int *rel_count1; + + if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + reloc_count = 1; + else if (p->type == bfd_indirect_link_order) + { + asection *sec; + + sec = p->u.indirect.section; + esdi = elf_section_data (sec); + + /* Mark all sections which are to be included in the + link. This will normally be every section. We need + to do this so that we can identify any sections which + the linker has decided to not include. */ + sec->linker_mark = TRUE; + + if (sec->flags & SEC_MERGE) + merged = TRUE; + + if (info->relocateable || info->emitrelocations) + reloc_count = sec->reloc_count; + else if (bed->elf_backend_count_relocs) + { + Elf_Internal_Rela * relocs; + + relocs = (NAME(_bfd_elf,link_read_relocs) + (abfd, sec, (PTR) NULL, + (Elf_Internal_Rela *) NULL, info->keep_memory)); + + reloc_count = (*bed->elf_backend_count_relocs) (sec, relocs); + + if (elf_section_data (o)->relocs != relocs) + free (relocs); + } + + if (sec->_raw_size > max_contents_size) + max_contents_size = sec->_raw_size; + if (sec->_cooked_size > max_contents_size) + max_contents_size = sec->_cooked_size; + + /* We are interested in just local symbols, not all + symbols. */ + if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour + && (sec->owner->flags & DYNAMIC) == 0) + { + size_t sym_count; + + if (elf_bad_symtab (sec->owner)) + sym_count = (elf_tdata (sec->owner)->symtab_hdr.sh_size + / sizeof (Elf_External_Sym)); + else + sym_count = elf_tdata (sec->owner)->symtab_hdr.sh_info; + + if (sym_count > max_sym_count) + max_sym_count = sym_count; + + if (sym_count > max_sym_shndx_count + && elf_symtab_shndx (sec->owner) != 0) + max_sym_shndx_count = sym_count; + + if ((sec->flags & SEC_RELOC) != 0) + { + size_t ext_size; + + ext_size = elf_section_data (sec)->rel_hdr.sh_size; + if (ext_size > max_external_reloc_size) + max_external_reloc_size = ext_size; + if (sec->reloc_count > max_internal_reloc_count) + max_internal_reloc_count = sec->reloc_count; + } + } + } + + if (reloc_count == 0) + continue; + + o->reloc_count += reloc_count; + + /* MIPS may have a mix of REL and RELA relocs on sections. + To support this curious ABI we keep reloc counts in + elf_section_data too. We must be careful to add the + relocations from the input section to the right output + count. FIXME: Get rid of one count. We have + o->reloc_count == esdo->rel_count + esdo->rel_count2. */ + rel_count1 = &esdo->rel_count; + if (esdi != NULL) + { + bfd_boolean same_size; + bfd_size_type entsize1; + + entsize1 = esdi->rel_hdr.sh_entsize; + BFD_ASSERT (entsize1 == sizeof (Elf_External_Rel) + || entsize1 == sizeof (Elf_External_Rela)); + same_size = (!o->use_rela_p + == (entsize1 == sizeof (Elf_External_Rel))); + + if (!same_size) + rel_count1 = &esdo->rel_count2; + + if (esdi->rel_hdr2 != NULL) + { + bfd_size_type entsize2 = esdi->rel_hdr2->sh_entsize; + unsigned int alt_count; + unsigned int *rel_count2; + + BFD_ASSERT (entsize2 != entsize1 + && (entsize2 == sizeof (Elf_External_Rel) + || entsize2 == sizeof (Elf_External_Rela))); + + rel_count2 = &esdo->rel_count2; + if (!same_size) + rel_count2 = &esdo->rel_count; + + /* The following is probably too simplistic if the + backend counts output relocs unusually. */ + BFD_ASSERT (bed->elf_backend_count_relocs == NULL); + alt_count = NUM_SHDR_ENTRIES (esdi->rel_hdr2); + *rel_count2 += alt_count; + reloc_count -= alt_count; + } + } + *rel_count1 += reloc_count; + } + + if (o->reloc_count > 0) + o->flags |= SEC_RELOC; + else + { + /* Explicitly clear the SEC_RELOC flag. The linker tends to + set it (this is probably a bug) and if it is set + assign_section_numbers will create a reloc section. */ + o->flags &=~ SEC_RELOC; + } + + /* If the SEC_ALLOC flag is not set, force the section VMA to + zero. This is done in elf_fake_sections as well, but forcing + the VMA to 0 here will ensure that relocs against these + sections are handled correctly. */ + if ((o->flags & SEC_ALLOC) == 0 + && ! o->user_set_vma) + o->vma = 0; + } + + if (! info->relocateable && merged) + elf_link_hash_traverse (elf_hash_table (info), + elf_link_sec_merge_syms, (PTR) abfd); + + /* 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_ASSERT (! abfd->output_has_begun); + if (! _bfd_elf_compute_section_file_positions (abfd, info)) + goto error_return; + + /* That created the reloc sections. Set their sizes, and assign + them file positions, and allocate some buffers. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0) + { + if (!elf_link_size_reloc_section (abfd, + &elf_section_data (o)->rel_hdr, + o)) + goto error_return; + + if (elf_section_data (o)->rel_hdr2 + && !elf_link_size_reloc_section (abfd, + elf_section_data (o)->rel_hdr2, + o)) + goto error_return; + } + + /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them + to count upwards while actually outputting the relocations. */ + elf_section_data (o)->rel_count = 0; + elf_section_data (o)->rel_count2 = 0; + } + + _bfd_elf_assign_file_positions_for_relocs (abfd); + + /* 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. */ + bfd_get_symcount (abfd) = 0; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + /* sh_name is set in prep_headers. */ + symtab_hdr->sh_type = SHT_SYMTAB; + /* sh_flags, sh_addr and sh_size all start off zero. */ + symtab_hdr->sh_entsize = sizeof (Elf_External_Sym); + /* sh_link is set in assign_section_numbers. */ + /* sh_info is set below. */ + /* sh_offset is set just below. */ + symtab_hdr->sh_addralign = bed->s->file_align; + + off = elf_tdata (abfd)->next_file_pos; + off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE); + + /* Note that at this point elf_tdata (abfd)->next_file_pos 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) + finfo.symbuf_size = 20; + else + finfo.symbuf_size = max_sym_count; + amt = finfo.symbuf_size; + amt *= sizeof (Elf_External_Sym); + finfo.symbuf = (Elf_External_Sym *) bfd_malloc (amt); + if (finfo.symbuf == NULL) + goto error_return; + if (elf_numsections (abfd) > SHN_LORESERVE) + { + /* Wild guess at number of output symbols. realloc'd as needed. */ + amt = 2 * max_sym_count + elf_numsections (abfd) + 1000; + finfo.shndxbuf_size = amt; + amt *= sizeof (Elf_External_Sym_Shndx); + finfo.symshndxbuf = (Elf_External_Sym_Shndx *) bfd_zmalloc (amt); + if (finfo.symshndxbuf == NULL) + goto error_return; + } + + /* Start writing out the symbol table. The first symbol is always a + dummy symbol. */ + if (info->strip != strip_all + || emit_relocs) + { + elfsym.st_value = 0; + elfsym.st_size = 0; + elfsym.st_info = 0; + elfsym.st_other = 0; + elfsym.st_shndx = SHN_UNDEF; + if (! elf_link_output_sym (&finfo, (const char *) NULL, + &elfsym, bfd_und_section_ptr)) + goto error_return; + } + +#if 0 + /* Some standard ELF linkers do this, but we don't because it causes + bootstrap comparison failures. */ + /* Output a file symbol for the output file as the second symbol. + We output this even if we are discarding local symbols, although + I'm not sure if this is correct. */ + elfsym.st_value = 0; + elfsym.st_size = 0; + elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + elfsym.st_other = 0; + elfsym.st_shndx = SHN_ABS; + if (! elf_link_output_sym (&finfo, bfd_get_filename (abfd), + &elfsym, bfd_abs_section_ptr)) + goto error_return; +#endif + + /* 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) + { + elfsym.st_size = 0; + elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + elfsym.st_other = 0; + for (i = 1; i < elf_numsections (abfd); i++) + { + o = section_from_elf_index (abfd, i); + if (o != NULL) + o->target_index = bfd_get_symcount (abfd); + elfsym.st_shndx = i; + if (info->relocateable || o == NULL) + elfsym.st_value = 0; + else + elfsym.st_value = o->vma; + if (! elf_link_output_sym (&finfo, (const char *) NULL, + &elfsym, o)) + goto error_return; + if (i == SHN_LORESERVE - 1) + i += SHN_HIRESERVE + 1 - SHN_LORESERVE; + } + } + + /* Allocate some memory to hold information read in from the input + files. */ + if (max_contents_size != 0) + { + finfo.contents = (bfd_byte *) bfd_malloc (max_contents_size); + if (finfo.contents == NULL) + goto error_return; + } + + if (max_external_reloc_size != 0) + { + finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size); + if (finfo.external_relocs == NULL) + goto error_return; + } + + if (max_internal_reloc_count != 0) + { + amt = max_internal_reloc_count * bed->s->int_rels_per_ext_rel; + amt *= sizeof (Elf_Internal_Rela); + finfo.internal_relocs = (Elf_Internal_Rela *) bfd_malloc (amt); + if (finfo.internal_relocs == NULL) + goto error_return; + } + + if (max_sym_count != 0) + { + amt = max_sym_count * sizeof (Elf_External_Sym); + finfo.external_syms = (Elf_External_Sym *) bfd_malloc (amt); + if (finfo.external_syms == NULL) + goto error_return; + + amt = max_sym_count * sizeof (Elf_Internal_Sym); + finfo.internal_syms = (Elf_Internal_Sym *) bfd_malloc (amt); + if (finfo.internal_syms == NULL) + goto error_return; + + amt = max_sym_count * sizeof (long); + finfo.indices = (long *) bfd_malloc (amt); + if (finfo.indices == NULL) + goto error_return; + + amt = max_sym_count * sizeof (asection *); + finfo.sections = (asection **) bfd_malloc (amt); + if (finfo.sections == NULL) + goto error_return; + } + + if (max_sym_shndx_count != 0) + { + amt = max_sym_shndx_count * sizeof (Elf_External_Sym_Shndx); + finfo.locsym_shndx = (Elf_External_Sym_Shndx *) bfd_malloc (amt); + if (finfo.locsym_shndx == NULL) + goto error_return; + } + + if (finfo.first_tls_sec) + { + unsigned int align = 0; + bfd_vma base = finfo.first_tls_sec->vma, end = 0; + asection *sec; + + for (sec = finfo.first_tls_sec; + sec && (sec->flags & SEC_THREAD_LOCAL); + sec = sec->next) + { + bfd_vma size = sec->_raw_size; + + if (bfd_get_section_alignment (abfd, sec) > align) + align = bfd_get_section_alignment (abfd, sec); + if (sec->_raw_size == 0 && (sec->flags & SEC_HAS_CONTENTS) == 0) + { + struct bfd_link_order *o; + + size = 0; + for (o = sec->link_order_head; o != NULL; o = o->next) + if (size < o->offset + o->size) + size = o->offset + o->size; + } + end = sec->vma + size; + } + elf_hash_table (info)->tls_segment + = bfd_zalloc (abfd, sizeof (struct elf_link_tls_segment)); + if (elf_hash_table (info)->tls_segment == NULL) + goto error_return; + elf_hash_table (info)->tls_segment->start = base; + elf_hash_table (info)->tls_segment->size = end - base; + elf_hash_table (info)->tls_segment->align = align; + } + + /* 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 + would rather not keep them in memory, we handle all the + relocations for a single input file at the same time. + + Unfortunately, there is no way to know the total number of local + symbols until we have seen all of them, and the local symbol + indices precede the global symbol indices. This means that when + we are generating relocateable output, and we see a reloc against + a global symbol, we can not know the symbol index until we have + finished examining all the local symbols to see which ones we are + going to output. To deal with this, we keep the relocations in + memory, and don't output them until the end of the link. This is + an unfortunate waste of memory, but I don't see a good way around + it. Fortunately, it only happens when performing a relocateable + link, which is not the common case. FIXME: If keep_memory is set + 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) + sub->output_has_begun = FALSE; + for (o = abfd->sections; o != NULL; o = o->next) + { + for (p = o->link_order_head; p != NULL; p = p->next) + { + if (p->type == bfd_indirect_link_order + && (bfd_get_flavour ((sub = p->u.indirect.section->owner)) + == bfd_target_elf_flavour) + && elf_elfheader (sub)->e_ident[EI_CLASS] == bed->s->elfclass) + { + if (! sub->output_has_begun) + { + if (! elf_link_input_bfd (&finfo, sub)) + goto error_return; + sub->output_has_begun = TRUE; + } + } + else if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + { + if (! elf_reloc_link_order (abfd, info, o, p)) + goto error_return; + } + else + { + if (! _bfd_default_link_order (abfd, info, o, p)) + goto error_return; + } + } + } + + /* 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 + prior to any global symbols. FIXME: We should only do this if + some global symbols were, in fact, converted to become local. + FIXME: Will this work correctly with the Irix 5 linker? */ + eoinfo.failed = FALSE; + eoinfo.finfo = &finfo; + eoinfo.localsyms = TRUE; + elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, + (PTR) &eoinfo); + if (eoinfo.failed) + return FALSE; + + /* That wrote out all the local symbols. Finish up the symbol table + with the global symbols. Even if we want to strip everything we + can, we still need to deal with those global symbols that got + converted to local in a version script. */ + + /* The sh_info field records the index of the first non local symbol. */ + symtab_hdr->sh_info = bfd_get_symcount (abfd); + + if (dynamic + && finfo.dynsym_sec->output_section != bfd_abs_section_ptr) + { + Elf_Internal_Sym sym; + Elf_External_Sym *dynsym = + (Elf_External_Sym *) finfo.dynsym_sec->contents; + long last_local = 0; + + /* Write out the section symbols for the output sections. */ + if (info->shared) + { + asection *s; + + sym.st_size = 0; + sym.st_name = 0; + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + sym.st_other = 0; + + for (s = abfd->sections; s != NULL; s = s->next) + { + int indx; + Elf_External_Sym *dest; + + indx = elf_section_data (s)->this_idx; + BFD_ASSERT (indx > 0); + sym.st_shndx = indx; + sym.st_value = s->vma; + dest = dynsym + elf_section_data (s)->dynindx; + elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0); + } + + last_local = bfd_count_sections (abfd); + } + + /* Write out the local dynsyms. */ + if (elf_hash_table (info)->dynlocal) + { + struct elf_link_local_dynamic_entry *e; + for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) + { + asection *s; + Elf_External_Sym *dest; + + sym.st_size = e->isym.st_size; + sym.st_other = e->isym.st_other; + + /* Copy the internal symbol as is. + Note that we saved a word of storage and overwrote + the original st_name with the dynstr_index. */ + sym = e->isym; + + if (e->isym.st_shndx != SHN_UNDEF + && (e->isym.st_shndx < SHN_LORESERVE + || e->isym.st_shndx > SHN_HIRESERVE)) + { + s = bfd_section_from_elf_index (e->input_bfd, + e->isym.st_shndx); + + sym.st_shndx = + elf_section_data (s->output_section)->this_idx; + sym.st_value = (s->output_section->vma + + s->output_offset + + e->isym.st_value); + } + + if (last_local < e->dynindx) + last_local = e->dynindx; + + dest = dynsym + e->dynindx; + elf_swap_symbol_out (abfd, &sym, (PTR) dest, (PTR) 0); + } + } + + elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = + last_local + 1; + } + + /* We get the global symbols from the hash table. */ + eoinfo.failed = FALSE; + eoinfo.localsyms = FALSE; + eoinfo.finfo = &finfo; + elf_link_hash_traverse (elf_hash_table (info), elf_link_output_extsym, + (PTR) &eoinfo); + if (eoinfo.failed) + return FALSE; + + /* If backend needs to output some symbols not present in the hash + table, do it now. */ + if (bed->elf_backend_output_arch_syms) + { + typedef bfd_boolean (*out_sym_func) + PARAMS ((PTR, const char *, Elf_Internal_Sym *, asection *)); + + if (! ((*bed->elf_backend_output_arch_syms) + (abfd, info, (PTR) &finfo, (out_sym_func) elf_link_output_sym))) + return FALSE; + } + + /* Flush all symbols to the file. */ + if (! elf_link_flush_output_syms (&finfo)) + 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) + { + 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; + + 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 ((PTR) finfo.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 (finfo.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_tdata (abfd)->next_file_pos = off; + + if (bfd_get_symcount (abfd) > 0) + { + if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 + || ! _bfd_stringtab_emit (abfd, finfo.symstrtab)) + return FALSE; + } + + /* Adjust the relocs to have the correct symbol indices. */ + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) == 0) + continue; + + elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr, + elf_section_data (o)->rel_count, + elf_section_data (o)->rel_hashes); + if (elf_section_data (o)->rel_hdr2 != NULL) + elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2, + elf_section_data (o)->rel_count2, + (elf_section_data (o)->rel_hashes + + elf_section_data (o)->rel_count)); + + /* Set the reloc_count field to 0 to prevent write_relocs from + trying to swap the relocs out itself. */ + o->reloc_count = 0; + } + + if (dynamic && info->combreloc && dynobj != NULL) + relativecount = elf_link_sort_relocs (abfd, info, &reldyn); + + /* If we are linking against a dynamic object, or generating a + shared library, finish up the dynamic linking information. */ + if (dynamic) + { + Elf_External_Dyn *dyncon, *dynconend; + + /* Fix up .dynamic entries. */ + o = bfd_get_section_by_name (dynobj, ".dynamic"); + BFD_ASSERT (o != NULL); + + dyncon = (Elf_External_Dyn *) o->contents; + dynconend = (Elf_External_Dyn *) (o->contents + o->_raw_size); + for (; dyncon < dynconend; dyncon++) + { + Elf_Internal_Dyn dyn; + const char *name; + unsigned int type; + + elf_swap_dyn_in (dynobj, dyncon, &dyn); + + switch (dyn.d_tag) + { + default: + break; + case DT_NULL: + if (relativecount > 0 && dyncon + 1 < dynconend) + { + switch (elf_section_data (reldyn)->this_hdr.sh_type) + { + case SHT_REL: dyn.d_tag = DT_RELCOUNT; break; + case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break; + default: break; + } + if (dyn.d_tag != DT_NULL) + { + dyn.d_un.d_val = relativecount; + elf_swap_dyn_out (dynobj, &dyn, dyncon); + relativecount = 0; + } + } + break; + case DT_INIT: + name = info->init_function; + goto get_sym; + case DT_FINI: + name = info->fini_function; + get_sym: + { + struct elf_link_hash_entry *h; + + h = elf_link_hash_lookup (elf_hash_table (info), name, + FALSE, FALSE, TRUE); + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + dyn.d_un.d_val = h->root.u.def.value; + o = h->root.u.def.section; + if (o->output_section != NULL) + dyn.d_un.d_val += (o->output_section->vma + + o->output_offset); + else + { + /* The symbol is imported from another shared + library and does not apply to this one. */ + dyn.d_un.d_val = 0; + } + + elf_swap_dyn_out (dynobj, &dyn, dyncon); + } + } + break; + + case DT_PREINIT_ARRAYSZ: + name = ".preinit_array"; + goto get_size; + case DT_INIT_ARRAYSZ: + name = ".init_array"; + goto get_size; + case DT_FINI_ARRAYSZ: + name = ".fini_array"; + get_size: + o = bfd_get_section_by_name (abfd, name); + if (o == NULL) + { + (*_bfd_error_handler) + (_("%s: could not find output section %s"), + bfd_get_filename (abfd), name); + goto error_return; + } + if (o->_raw_size == 0) + (*_bfd_error_handler) + (_("warning: %s section has zero size"), name); + dyn.d_un.d_val = o->_raw_size; + elf_swap_dyn_out (dynobj, &dyn, dyncon); + break; + + case DT_PREINIT_ARRAY: + name = ".preinit_array"; + goto get_vma; + case DT_INIT_ARRAY: + name = ".init_array"; + goto get_vma; + case DT_FINI_ARRAY: + name = ".fini_array"; + goto get_vma; + + case DT_HASH: + name = ".hash"; + goto get_vma; + case DT_STRTAB: + name = ".dynstr"; + goto get_vma; + case DT_SYMTAB: + name = ".dynsym"; + goto get_vma; + case DT_VERDEF: + name = ".gnu.version_d"; + goto get_vma; + case DT_VERNEED: + name = ".gnu.version_r"; + goto get_vma; + case DT_VERSYM: + name = ".gnu.version"; + get_vma: + o = bfd_get_section_by_name (abfd, name); + if (o == NULL) + { + (*_bfd_error_handler) + (_("%s: could not find output section %s"), + bfd_get_filename (abfd), name); + goto error_return; + } + dyn.d_un.d_ptr = o->vma; + elf_swap_dyn_out (dynobj, &dyn, dyncon); + break; + + case DT_REL: + case DT_RELA: + case DT_RELSZ: + case DT_RELASZ: + if (dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ) + type = SHT_REL; + else + type = SHT_RELA; + dyn.d_un.d_val = 0; + for (i = 1; i < elf_numsections (abfd); i++) + { + Elf_Internal_Shdr *hdr; + + hdr = elf_elfsections (abfd)[i]; + if (hdr->sh_type == type + && (hdr->sh_flags & SHF_ALLOC) != 0) + { + if (dyn.d_tag == DT_RELSZ || dyn.d_tag == DT_RELASZ) + dyn.d_un.d_val += hdr->sh_size; + else + { + if (dyn.d_un.d_val == 0 + || hdr->sh_addr < dyn.d_un.d_val) + dyn.d_un.d_val = hdr->sh_addr; + } + } + } + elf_swap_dyn_out (dynobj, &dyn, dyncon); + break; + } + } + } + + /* If we have created any dynamic sections, then output them. */ + if (dynobj != NULL) + { + if (! (*bed->elf_backend_finish_dynamic_sections) (abfd, info)) + goto error_return; + + for (o = dynobj->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_HAS_CONTENTS) == 0 + || o->_raw_size == 0 + || o->output_section == bfd_abs_section_ptr) + continue; + if ((o->flags & SEC_LINKER_CREATED) == 0) + { + /* At this point, we are only interested in sections + created by elf_link_create_dynamic_sections. */ + continue; + } + if ((elf_section_data (o->output_section)->this_hdr.sh_type + != SHT_STRTAB) + || strcmp (bfd_get_section_name (abfd, o), ".dynstr") != 0) + { + if (! bfd_set_section_contents (abfd, o->output_section, + o->contents, + (file_ptr) o->output_offset, + o->_raw_size)) + goto error_return; + } + else + { + /* The contents of the .dynstr section are actually in a + stringtab. */ + off = elf_section_data (o->output_section)->this_hdr.sh_offset; + if (bfd_seek (abfd, off, SEEK_SET) != 0 + || ! _bfd_elf_strtab_emit (abfd, + elf_hash_table (info)->dynstr)) + goto error_return; + } + } + } + + if (info->relocateable) + { + bfd_boolean failed = FALSE; + + bfd_map_over_sections (abfd, bfd_elf_set_group_contents, &failed); + if (failed) + goto error_return; + } + + /* If we have optimized stabs strings, output them. */ + if (elf_hash_table (info)->stab_info != NULL) + { + if (! _bfd_write_stab_strings (abfd, &elf_hash_table (info)->stab_info)) + goto error_return; + } + + if (info->eh_frame_hdr) + { + if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info)) + goto error_return; + } + + if (finfo.symstrtab != NULL) + _bfd_stringtab_free (finfo.symstrtab); + if (finfo.contents != NULL) + free (finfo.contents); + if (finfo.external_relocs != NULL) + free (finfo.external_relocs); + if (finfo.internal_relocs != NULL) + free (finfo.internal_relocs); + if (finfo.external_syms != NULL) + free (finfo.external_syms); + if (finfo.locsym_shndx != NULL) + free (finfo.locsym_shndx); + if (finfo.internal_syms != NULL) + free (finfo.internal_syms); + if (finfo.indices != NULL) + free (finfo.indices); + if (finfo.sections != NULL) + free (finfo.sections); + if (finfo.symbuf != NULL) + free (finfo.symbuf); + if (finfo.symshndxbuf != NULL) + free (finfo.symshndxbuf); + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0 + && elf_section_data (o)->rel_hashes != NULL) + free (elf_section_data (o)->rel_hashes); + } + + elf_tdata (abfd)->linker = TRUE; + + return TRUE; + + error_return: + if (finfo.symstrtab != NULL) + _bfd_stringtab_free (finfo.symstrtab); + if (finfo.contents != NULL) + free (finfo.contents); + if (finfo.external_relocs != NULL) + free (finfo.external_relocs); + if (finfo.internal_relocs != NULL) + free (finfo.internal_relocs); + if (finfo.external_syms != NULL) + free (finfo.external_syms); + if (finfo.locsym_shndx != NULL) + free (finfo.locsym_shndx); + if (finfo.internal_syms != NULL) + free (finfo.internal_syms); + if (finfo.indices != NULL) + free (finfo.indices); + if (finfo.sections != NULL) + free (finfo.sections); + if (finfo.symbuf != NULL) + free (finfo.symbuf); + if (finfo.symshndxbuf != NULL) + free (finfo.symshndxbuf); + for (o = abfd->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_RELOC) != 0 + && elf_section_data (o)->rel_hashes != NULL) + free (elf_section_data (o)->rel_hashes); + } + + return FALSE; +} + +/* Add a symbol to the output symbol table. */ + +static bfd_boolean +elf_link_output_sym (finfo, name, elfsym, input_sec) + struct elf_final_link_info *finfo; + const char *name; + Elf_Internal_Sym *elfsym; + asection *input_sec; +{ + Elf_External_Sym *dest; + Elf_External_Sym_Shndx *destshndx; + bfd_boolean (*output_symbol_hook) + PARAMS ((bfd *, struct bfd_link_info *info, const char *, + Elf_Internal_Sym *, asection *)); + + output_symbol_hook = get_elf_backend_data (finfo->output_bfd)-> + elf_backend_link_output_symbol_hook; + if (output_symbol_hook != NULL) + { + if (! ((*output_symbol_hook) + (finfo->output_bfd, finfo->info, name, elfsym, input_sec))) + return FALSE; + } + + if (name == (const char *) NULL || *name == '\0') + elfsym->st_name = 0; + else if (input_sec->flags & SEC_EXCLUDE) + elfsym->st_name = 0; + else + { + elfsym->st_name = (unsigned long) _bfd_stringtab_add (finfo->symstrtab, + name, TRUE, FALSE); + if (elfsym->st_name == (unsigned long) -1) + return FALSE; + } + + if (finfo->symbuf_count >= finfo->symbuf_size) + { + if (! elf_link_flush_output_syms (finfo)) + return FALSE; + } + + dest = finfo->symbuf + finfo->symbuf_count; + destshndx = finfo->symshndxbuf; + if (destshndx != NULL) + { + if (bfd_get_symcount (finfo->output_bfd) >= finfo->shndxbuf_size) + { + bfd_size_type amt; + + amt = finfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx); + finfo->symshndxbuf = destshndx = bfd_realloc (destshndx, amt * 2); + if (destshndx == NULL) + return FALSE; + memset ((char *) destshndx + amt, 0, amt); + finfo->shndxbuf_size *= 2; + } + destshndx += bfd_get_symcount (finfo->output_bfd); + } + + elf_swap_symbol_out (finfo->output_bfd, elfsym, (PTR) dest, (PTR) destshndx); + finfo->symbuf_count += 1; + bfd_get_symcount (finfo->output_bfd) += 1; + + return TRUE; +} + +/* Flush the output symbols to the file. */ + +static bfd_boolean +elf_link_flush_output_syms (finfo) + struct elf_final_link_info *finfo; +{ + if (finfo->symbuf_count > 0) + { + Elf_Internal_Shdr *hdr; + file_ptr pos; + bfd_size_type amt; + + hdr = &elf_tdata (finfo->output_bfd)->symtab_hdr; + pos = hdr->sh_offset + hdr->sh_size; + amt = finfo->symbuf_count * sizeof (Elf_External_Sym); + if (bfd_seek (finfo->output_bfd, pos, SEEK_SET) != 0 + || bfd_bwrite ((PTR) finfo->symbuf, amt, finfo->output_bfd) != amt) + return FALSE; + + hdr->sh_size += amt; + finfo->symbuf_count = 0; + } + + return TRUE; +} + +/* Adjust all external symbols pointing into SEC_MERGE sections + to reflect the object merging within the sections. */ + +static bfd_boolean +elf_link_sec_merge_syms (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + asection *sec; + + if (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) + && ((sec = h->root.u.def.section)->flags & SEC_MERGE) + && sec->sec_info_type == ELF_INFO_TYPE_MERGE) + { + bfd *output_bfd = (bfd *) data; + + h->root.u.def.value = + _bfd_merged_section_offset (output_bfd, + &h->root.u.def.section, + elf_section_data (sec)->sec_info, + h->root.u.def.value, (bfd_vma) 0); + } + + return TRUE; +} + +/* For DSOs loaded in via a DT_NEEDED entry, emulate ld.so in + allowing an unsatisfied unversioned symbol in the DSO to match a + versioned symbol that would normally require an explicit version. + We also handle the case that a DSO references a hidden symbol + which may be satisfied by a versioned symbol in another DSO. */ + +static bfd_boolean +elf_link_check_versioned_symbol (info, h) + struct bfd_link_info *info; + struct elf_link_hash_entry *h; +{ + bfd *abfd; + struct elf_link_loaded_list *loaded; + + if (info->hash->creator->flavour != bfd_target_elf_flavour) + return FALSE; + + switch (h->root.type) + { + default: + abfd = NULL; + break; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + abfd = h->root.u.undef.abfd; + if ((abfd->flags & DYNAMIC) == 0 || elf_dt_soname (abfd) == NULL) + return FALSE; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + abfd = h->root.u.def.section->owner; + break; + + case bfd_link_hash_common: + abfd = h->root.u.c.p->section->owner; + break; + } + BFD_ASSERT (abfd != NULL); + + for (loaded = elf_hash_table (info)->loaded; + loaded != NULL; + loaded = loaded->next) + { + bfd *input; + Elf_Internal_Shdr *hdr; + bfd_size_type symcount; + bfd_size_type extsymcount; + bfd_size_type extsymoff; + Elf_Internal_Shdr *versymhdr; + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + Elf_Internal_Sym *isymbuf; + Elf_External_Versym *ever; + Elf_External_Versym *extversym; + + input = loaded->abfd; + + /* We check each DSO for a possible hidden versioned definition. */ + if (input == abfd + || (input->flags & DYNAMIC) == 0 + || elf_dynversym (input) == 0) + continue; + + hdr = &elf_tdata (input)->dynsymtab_hdr; + + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + if (elf_bad_symtab (input)) + { + extsymcount = symcount; + extsymoff = 0; + } + else + { + extsymcount = symcount - hdr->sh_info; + extsymoff = hdr->sh_info; + } + + if (extsymcount == 0) + continue; + + isymbuf = bfd_elf_get_elf_syms (input, hdr, extsymcount, extsymoff, + NULL, NULL, NULL); + if (isymbuf == NULL) + return FALSE; + + /* Read in any version definitions. */ + versymhdr = &elf_tdata (input)->dynversym_hdr; + extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size); + if (extversym == NULL) + goto error_ret; + + if (bfd_seek (input, versymhdr->sh_offset, SEEK_SET) != 0 + || (bfd_bread ((PTR) extversym, versymhdr->sh_size, input) + != versymhdr->sh_size)) + { + free (extversym); + error_ret: + free (isymbuf); + return FALSE; + } + + ever = extversym + extsymoff; + isymend = isymbuf + extsymcount; + for (isym = isymbuf; isym < isymend; isym++, ever++) + { + const char *name; + Elf_Internal_Versym iver; + + if (ELF_ST_BIND (isym->st_info) == STB_LOCAL + || isym->st_shndx == SHN_UNDEF) + continue; + + name = bfd_elf_string_from_elf_section (input, + hdr->sh_link, + isym->st_name); + if (strcmp (name, h->root.root.string) != 0) + continue; + + _bfd_elf_swap_versym_in (input, ever, &iver); + + if ((iver.vs_vers & VERSYM_HIDDEN) == 0) + { + /* If we have a non-hidden versioned sym, then it should + have provided a definition for the undefined sym. */ + abort (); + } + + if ((iver.vs_vers & VERSYM_VERSION) == 2) + { + /* This is the oldest (default) sym. We can use it. */ + free (extversym); + free (isymbuf); + return TRUE; + } + } + + free (extversym); + free (isymbuf); + } + + return FALSE; +} + +/* Add an external symbol to the symbol table. This is called from + the hash table traversal routine. When generating a shared object, + we go through the symbol table twice. The first time we output + anything that might have been forced to local scope in a version + script. The second time we output the symbols that are still + global symbols. */ + +static bfd_boolean +elf_link_output_extsym (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + struct elf_outext_info *eoinfo = (struct elf_outext_info *) data; + struct elf_final_link_info *finfo = eoinfo->finfo; + bfd_boolean strip; + Elf_Internal_Sym sym; + asection *input_sec; + + if (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_new) + return TRUE; + } + + /* Decide whether to output this symbol in this pass. */ + if (eoinfo->localsyms) + { + if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + return TRUE; + } + else + { + if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + return TRUE; + } + + /* If we are not creating a shared library, and this symbol is + referenced by a shared library but is not defined anywhere, then + warn that it is undefined. If we do not do this, the runtime + linker will complain that the symbol is undefined when the + program is run. We don't have to worry about symbols that are + referenced by regular files, because we will already have issued + warnings for them. */ + if (! finfo->info->relocateable + && (! finfo->info->shared || ! finfo->info->allow_shlib_undefined) + && h->root.type == bfd_link_hash_undefined + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0 + && ! elf_link_check_versioned_symbol (finfo->info, h)) + { + if (! ((*finfo->info->callbacks->undefined_symbol) + (finfo->info, h->root.root.string, h->root.u.undef.abfd, + (asection *) NULL, (bfd_vma) 0, TRUE))) + { + eoinfo->failed = TRUE; + return FALSE; + } + } + + /* We should also warn if a forced local symbol is referenced from + shared libraries. */ + if (! finfo->info->relocateable + && (! finfo->info->shared || ! finfo->info->allow_shlib_undefined) + && (h->elf_link_hash_flags + & (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_DYNAMIC_DEF | ELF_LINK_DYNAMIC_WEAK)) + == (ELF_LINK_FORCED_LOCAL | ELF_LINK_HASH_REF_DYNAMIC) + && ! elf_link_check_versioned_symbol (finfo->info, h)) + { + (*_bfd_error_handler) + (_("%s: %s symbol `%s' in %s is referenced by DSO"), + bfd_get_filename (finfo->output_bfd), + ELF_ST_VISIBILITY (h->other) == STV_INTERNAL + ? "internal" + : ELF_ST_VISIBILITY (h->other) == STV_HIDDEN + ? "hidden" : "local", + h->root.root.string, + bfd_archive_filename (h->root.u.def.section->owner)); + eoinfo->failed = TRUE; + return FALSE; + } + + /* We don't want to output symbols that have never been mentioned by + 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. */ + if (h->indx == -2) + strip = FALSE; + else if (((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + strip = TRUE; + else if (finfo->info->strip == strip_all) + strip = TRUE; + else if (finfo->info->strip == strip_some + && bfd_hash_lookup (finfo->info->keep_hash, + h->root.root.string, FALSE, FALSE) == NULL) + strip = TRUE; + else if (finfo->info->strip_discarded + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && elf_discarded_section (h->root.u.def.section)) + 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. */ + if (strip + && h->dynindx == -1 + && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + return TRUE; + + sym.st_value = 0; + sym.st_size = h->size; + sym.st_other = h->other; + if ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + sym.st_info = ELF_ST_INFO (STB_LOCAL, h->type); + else if (h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_defweak) + sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); + else + sym.st_info = ELF_ST_INFO (STB_GLOBAL, h->type); + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + case bfd_link_hash_warning: + abort (); + return FALSE; + + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + input_sec = bfd_und_section_ptr; + sym.st_shndx = SHN_UNDEF; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + { + input_sec = h->root.u.def.section; + if (input_sec->output_section != NULL) + { + sym.st_shndx = + _bfd_elf_section_from_bfd_section (finfo->output_bfd, + input_sec->output_section); + if (sym.st_shndx == SHN_BAD) + { + (*_bfd_error_handler) + (_("%s: could not find output section %s for input section %s"), + bfd_get_filename (finfo->output_bfd), + input_sec->output_section->name, + input_sec->name); + eoinfo->failed = TRUE; + return FALSE; + } + + /* ELF symbols in relocateable files are section relative, + but in nonrelocateable files they are virtual + addresses. */ + sym.st_value = h->root.u.def.value + input_sec->output_offset; + if (! finfo->info->relocateable) + { + sym.st_value += input_sec->output_section->vma; + if (h->type == STT_TLS) + { + /* STT_TLS symbols are relative to PT_TLS segment + base. */ + BFD_ASSERT (finfo->first_tls_sec != NULL); + sym.st_value -= finfo->first_tls_sec->vma; + } + } + } + else + { + BFD_ASSERT (input_sec->owner == NULL + || (input_sec->owner->flags & DYNAMIC) != 0); + sym.st_shndx = SHN_UNDEF; + input_sec = bfd_und_section_ptr; + } + } + break; + + case bfd_link_hash_common: + input_sec = h->root.u.c.p->section; + sym.st_shndx = SHN_COMMON; + sym.st_value = 1 << h->root.u.c.p->alignment_power; + break; + + case bfd_link_hash_indirect: + /* These symbols are created by symbol versioning. They point + to the decorated version of the name. For example, if the + symbol foo@@GNU_1.2 is the default, which should be used when + foo is used with no version, then we add an indirect symbol + foo which points to foo@@GNU_1.2. We ignore these symbols, + since the indirected symbol is already in the hash table. */ + return TRUE; + } + + /* Give the processor backend a chance to tweak the symbol value, + and also to finish up anything that needs to be done for this + symbol. FIXME: Not calling elf_backend_finish_dynamic_symbol for + forced local syms when non-shared is due to a historical quirk. */ + if ((h->dynindx != -1 + || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + && (finfo->info->shared + || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + && elf_hash_table (finfo->info)->dynamic_sections_created) + { + struct elf_backend_data *bed; + + bed = get_elf_backend_data (finfo->output_bfd); + if (! ((*bed->elf_backend_finish_dynamic_symbol) + (finfo->output_bfd, finfo->info, h, &sym))) + { + eoinfo->failed = TRUE; + return FALSE; + } + } + + /* If we are marking the symbol as undefined, and there are no + non-weak references to this symbol from a regular object, then + mark the symbol as weak undefined; if there are non-weak + references, mark the symbol as strong. We can't do this earlier, + because it might not be marked as undefined until the + finish_dynamic_symbol routine gets through with it. */ + if (sym.st_shndx == SHN_UNDEF + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0 + && (ELF_ST_BIND (sym.st_info) == STB_GLOBAL + || ELF_ST_BIND (sym.st_info) == STB_WEAK)) + { + int bindtype; + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0) + bindtype = STB_GLOBAL; + else + bindtype = STB_WEAK; + sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info)); + } + + /* If a non-weak symbol with non-default visibility is not defined + locally, it is a fatal error. */ + if (! finfo->info->relocateable + && ELF_ST_VISIBILITY (sym.st_other) + && ELF_ST_BIND (sym.st_info) != STB_WEAK + && h->root.type == bfd_link_hash_undefined + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + (*_bfd_error_handler) + (_("%s: %s symbol `%s' isn't defined"), + bfd_get_filename (finfo->output_bfd), + ELF_ST_VISIBILITY (sym.st_other) == STV_PROTECTED + ? "protected" + : ELF_ST_VISIBILITY (sym.st_other) == STV_INTERNAL + ? "internal" : "hidden", + h->root.root.string); + eoinfo->failed = TRUE; + return FALSE; + } + + /* If this symbol should be put in the .dynsym section, then put it + there now. We already know the symbol index. We also fill in + the entry in the .hash section. */ + if (h->dynindx != -1 + && elf_hash_table (finfo->info)->dynamic_sections_created) + { + size_t bucketcount; + size_t bucket; + size_t hash_entry_size; + bfd_byte *bucketpos; + bfd_vma chain; + Elf_External_Sym *esym; + + sym.st_name = h->dynstr_index; + esym = (Elf_External_Sym *) finfo->dynsym_sec->contents + h->dynindx; + elf_swap_symbol_out (finfo->output_bfd, &sym, (PTR) esym, (PTR) 0); + + bucketcount = elf_hash_table (finfo->info)->bucketcount; + bucket = h->elf_hash_value % bucketcount; + hash_entry_size + = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; + bucketpos = ((bfd_byte *) finfo->hash_sec->contents + + (bucket + 2) * hash_entry_size); + chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); + bfd_put (8 * hash_entry_size, finfo->output_bfd, (bfd_vma) h->dynindx, + bucketpos); + bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, + ((bfd_byte *) finfo->hash_sec->contents + + (bucketcount + 2 + h->dynindx) * hash_entry_size)); + + if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL) + { + Elf_Internal_Versym iversym; + Elf_External_Versym *eversym; + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + if (h->verinfo.verdef == NULL) + iversym.vs_vers = 0; + else + iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1; + } + else + { + if (h->verinfo.vertree == NULL) + iversym.vs_vers = 1; + else + iversym.vs_vers = h->verinfo.vertree->vernum + 1; + } + + if ((h->elf_link_hash_flags & ELF_LINK_HIDDEN) != 0) + iversym.vs_vers |= VERSYM_HIDDEN; + + eversym = (Elf_External_Versym *) finfo->symver_sec->contents; + eversym += h->dynindx; + _bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym); + } + } + + /* 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) + return TRUE; + + h->indx = bfd_get_symcount (finfo->output_bfd); + + if (! elf_link_output_sym (finfo, h->root.root.string, &sym, input_sec)) + { + eoinfo->failed = TRUE; + return FALSE; + } + + return TRUE; +} + +/* Copy the relocations indicated by the INTERNAL_RELOCS (which + originated from the section given by INPUT_REL_HDR) to the + OUTPUT_BFD. */ + +static bfd_boolean +elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, + internal_relocs) + bfd *output_bfd; + asection *input_section; + Elf_Internal_Shdr *input_rel_hdr; + Elf_Internal_Rela *internal_relocs; +{ + Elf_Internal_Rela *irela; + Elf_Internal_Rela *irelaend; + bfd_byte *erel; + Elf_Internal_Shdr *output_rel_hdr; + asection *output_section; + unsigned int *rel_countp = NULL; + struct elf_backend_data *bed; + void (*swap_out) PARAMS ((bfd *, const Elf_Internal_Rela *, bfd_byte *)); + + output_section = input_section->output_section; + output_rel_hdr = NULL; + + if (elf_section_data (output_section)->rel_hdr.sh_entsize + == input_rel_hdr->sh_entsize) + { + output_rel_hdr = &elf_section_data (output_section)->rel_hdr; + rel_countp = &elf_section_data (output_section)->rel_count; + } + else if (elf_section_data (output_section)->rel_hdr2 + && (elf_section_data (output_section)->rel_hdr2->sh_entsize + == input_rel_hdr->sh_entsize)) + { + output_rel_hdr = elf_section_data (output_section)->rel_hdr2; + rel_countp = &elf_section_data (output_section)->rel_count2; + } + else + { + (*_bfd_error_handler) + (_("%s: relocation size mismatch in %s section %s"), + bfd_get_filename (output_bfd), + bfd_archive_filename (input_section->owner), + input_section->name); + bfd_set_error (bfd_error_wrong_object_format); + return FALSE; + } + + bed = get_elf_backend_data (output_bfd); + if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + swap_out = bed->s->swap_reloc_out; + else if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rela)) + swap_out = bed->s->swap_reloca_out; + else + abort (); + + erel = output_rel_hdr->contents; + erel += *rel_countp * input_rel_hdr->sh_entsize; + irela = internal_relocs; + irelaend = irela + (NUM_SHDR_ENTRIES (input_rel_hdr) + * bed->s->int_rels_per_ext_rel); + while (irela < irelaend) + { + (*swap_out) (output_bfd, irela, erel); + irela += bed->s->int_rels_per_ext_rel; + erel += input_rel_hdr->sh_entsize; + } + + /* Bump the counter, so that we know where to add the next set of + relocations. */ + *rel_countp += NUM_SHDR_ENTRIES (input_rel_hdr); + + return TRUE; +} + +/* Link an input file into the linker output file. This function + handles all the sections and relocations of the input file at once. + This is so that we only have to read the local symbols once, and + don't have to keep them in memory. */ + +static bfd_boolean +elf_link_input_bfd (finfo, input_bfd) + struct elf_final_link_info *finfo; + bfd *input_bfd; +{ + bfd_boolean (*relocate_section) + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); + bfd *output_bfd; + Elf_Internal_Shdr *symtab_hdr; + size_t locsymcount; + size_t extsymoff; + Elf_Internal_Sym *isymbuf; + Elf_Internal_Sym *isym; + Elf_Internal_Sym *isymend; + long *pindex; + asection **ppsection; + asection *o; + struct elf_backend_data *bed; + bfd_boolean emit_relocs; + struct elf_link_hash_entry **sym_hashes; + + output_bfd = finfo->output_bfd; + bed = get_elf_backend_data (output_bfd); + relocate_section = bed->elf_backend_relocate_section; + + /* If this is a dynamic object, we don't want to do anything here: + we don't want the local symbols, and we don't want the section + contents. */ + if ((input_bfd->flags & DYNAMIC) != 0) + return TRUE; + + emit_relocs = (finfo->info->relocateable + || finfo->info->emitrelocations + || bed->elf_backend_emit_relocs); + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + if (elf_bad_symtab (input_bfd)) + { + locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym); + extsymoff = 0; + } + else + { + locsymcount = symtab_hdr->sh_info; + extsymoff = symtab_hdr->sh_info; + } + + /* Read the local symbols. */ + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isymbuf == NULL && locsymcount != 0) + { + isymbuf = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, locsymcount, 0, + finfo->internal_syms, + finfo->external_syms, + finfo->locsym_shndx); + if (isymbuf == NULL) + return FALSE; + } + + /* Find local symbol sections and adjust values of symbols in + SEC_MERGE sections. Write out those local symbols we know are + going into the output file. */ + isymend = isymbuf + locsymcount; + for (isym = isymbuf, pindex = finfo->indices, ppsection = finfo->sections; + isym < isymend; + isym++, pindex++, ppsection++) + { + asection *isec; + const char *name; + Elf_Internal_Sym osym; + + *pindex = -1; + + if (elf_bad_symtab (input_bfd)) + { + if (ELF_ST_BIND (isym->st_info) != STB_LOCAL) + { + *ppsection = NULL; + continue; + } + } + + if (isym->st_shndx == SHN_UNDEF) + isec = bfd_und_section_ptr; + else if (isym->st_shndx < SHN_LORESERVE + || isym->st_shndx > SHN_HIRESERVE) + { + isec = section_from_elf_index (input_bfd, isym->st_shndx); + if (isec + && isec->sec_info_type == ELF_INFO_TYPE_MERGE + && ELF_ST_TYPE (isym->st_info) != STT_SECTION) + isym->st_value = + _bfd_merged_section_offset (output_bfd, &isec, + elf_section_data (isec)->sec_info, + isym->st_value, (bfd_vma) 0); + } + else if (isym->st_shndx == SHN_ABS) + isec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + isec = bfd_com_section_ptr; + else + { + /* Who knows? */ + isec = NULL; + } + + *ppsection = isec; + + /* Don't output the first, undefined, symbol. */ + if (ppsection == finfo->sections) + continue; + + if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) + { + /* We never output section symbols. Instead, we use the + section symbol of the corresponding section in the output + file. */ + continue; + } + + /* If we are stripping all symbols, we don't want to output this + one. */ + if (finfo->info->strip == strip_all) + continue; + + /* If we are discarding all local symbols, we don't want to + output this one. If we are generating a relocateable output + file, then some of the local symbols may be required by + relocs; we output them below as we discover that they are + needed. */ + if (finfo->info->discard == discard_all) + continue; + + /* If this symbol is defined in a section which we are + discarding, we don't need to keep it, but note that + linker_mark is only reliable for sections that have contents. + For the benefit of the MIPS ELF linker, we check SEC_EXCLUDE + as well as linker_mark. */ + if ((isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE) + && isec != NULL + && ((! isec->linker_mark && (isec->flags & SEC_HAS_CONTENTS) != 0) + || (! finfo->info->relocateable + && (isec->flags & SEC_EXCLUDE) != 0))) + continue; + + /* Get the name of the symbol. */ + name = bfd_elf_string_from_elf_section (input_bfd, symtab_hdr->sh_link, + isym->st_name); + if (name == NULL) + return FALSE; + + /* See if we are discarding symbols with this name. */ + if ((finfo->info->strip == strip_some + && (bfd_hash_lookup (finfo->info->keep_hash, name, FALSE, FALSE) + == NULL)) + || (((finfo->info->discard == discard_sec_merge + && (isec->flags & SEC_MERGE) && ! finfo->info->relocateable) + || finfo->info->discard == discard_l) + && bfd_is_local_label_name (input_bfd, name))) + continue; + + /* If we get here, we are going to output this symbol. */ + + osym = *isym; + + /* Adjust the section index for the output file. */ + osym.st_shndx = _bfd_elf_section_from_bfd_section (output_bfd, + isec->output_section); + if (osym.st_shndx == SHN_BAD) + return FALSE; + + *pindex = bfd_get_symcount (output_bfd); + + /* ELF symbols in relocateable files are section relative, but + in executable files they are virtual addresses. Note that + this code assumes that all ELF sections have an associated + BFD section with a reasonable value for output_offset; below + we assume that they also have a reasonable value for + output_section. Any special sections must be set up to meet + these requirements. */ + osym.st_value += isec->output_offset; + if (! finfo->info->relocateable) + { + osym.st_value += isec->output_section->vma; + if (ELF_ST_TYPE (osym.st_info) == STT_TLS) + { + /* STT_TLS symbols are relative to PT_TLS segment base. */ + BFD_ASSERT (finfo->first_tls_sec != NULL); + osym.st_value -= finfo->first_tls_sec->vma; + } + } + + if (! elf_link_output_sym (finfo, name, &osym, isec)) + return FALSE; + } + + /* Relocate the contents of each section. */ + sym_hashes = elf_sym_hashes (input_bfd); + for (o = input_bfd->sections; o != NULL; o = o->next) + { + bfd_byte *contents; + + if (! o->linker_mark) + { + /* This section was omitted from the link. */ + continue; + } + + if ((o->flags & SEC_HAS_CONTENTS) == 0 + || (o->_raw_size == 0 && (o->flags & SEC_RELOC) == 0)) + continue; + + if ((o->flags & SEC_LINKER_CREATED) != 0) + { + /* Section was created by elf_link_create_dynamic_sections + or somesuch. */ + continue; + } + + /* Get the contents of the section. They have been cached by a + relaxation routine. Note that o is a section in an input + 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; + else + { + contents = finfo->contents; + if (! bfd_get_section_contents (input_bfd, o, contents, + (file_ptr) 0, o->_raw_size)) + return FALSE; + } + + if ((o->flags & SEC_RELOC) != 0) + { + Elf_Internal_Rela *internal_relocs; + + /* Get the swapped relocs. */ + internal_relocs = (NAME(_bfd_elf,link_read_relocs) + (input_bfd, o, finfo->external_relocs, + finfo->internal_relocs, FALSE)); + if (internal_relocs == NULL + && o->reloc_count > 0) + return FALSE; + + /* Run through the relocs looking for any against symbols + from discarded sections and section symbols from + removed link-once sections. Complain about relocs + against discarded sections. Zero relocs against removed + link-once sections. */ + if (!finfo->info->relocateable + && !elf_section_ignore_discarded_relocs (o)) + { + Elf_Internal_Rela *rel, *relend; + + rel = internal_relocs; + relend = rel + o->reloc_count * bed->s->int_rels_per_ext_rel; + for ( ; rel < relend; rel++) + { + unsigned long r_symndx = ELF_R_SYM (rel->r_info); + + if (r_symndx >= locsymcount + || (elf_bad_symtab (input_bfd) + && finfo->sections[r_symndx] == NULL)) + { + struct elf_link_hash_entry *h; + + h = sym_hashes[r_symndx - 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; + + /* Complain if the definition comes from a + discarded section. */ + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && elf_discarded_section (h->root.u.def.section)) + { + if ((o->flags & SEC_DEBUGGING) != 0) + { + BFD_ASSERT (r_symndx != 0); + memset (rel, 0, sizeof (*rel)); + } + else + { + if (! ((*finfo->info->callbacks->undefined_symbol) + (finfo->info, h->root.root.string, + input_bfd, o, rel->r_offset, + TRUE))) + return FALSE; + } + } + } + else + { + asection *sec = finfo->sections[r_symndx]; + + if (sec != NULL && elf_discarded_section (sec)) + { + if ((o->flags & SEC_DEBUGGING) != 0 + || (sec->flags & SEC_LINK_ONCE) != 0) + { + BFD_ASSERT (r_symndx != 0); + rel->r_info + = ELF_R_INFO (0, ELF_R_TYPE (rel->r_info)); + rel->r_addend = 0; + } + else + { + bfd_boolean ok; + const char *msg + = _("local symbols in discarded section %s"); + bfd_size_type amt + = strlen (sec->name) + strlen (msg) - 1; + char *buf = (char *) bfd_malloc (amt); + + if (buf != NULL) + sprintf (buf, msg, sec->name); + else + buf = (char *) sec->name; + ok = (*finfo->info->callbacks + ->undefined_symbol) (finfo->info, buf, + input_bfd, o, + rel->r_offset, + TRUE); + if (buf != sec->name) + free (buf); + if (!ok) + return FALSE; + } + } + } + } + } + + /* Relocate the section by invoking a back end routine. + + The back end routine is responsible for adjusting the + section contents as necessary, and (if using Rela relocs + and generating a relocateable output file) adjusting the + reloc addend as necessary. + + The back end routine does not have to worry about setting + the reloc address or the reloc symbol index. + + The back end routine is given a pointer to the swapped in + internal symbols, and can access the hash table entries + for the external symbols via elf_sym_hashes (input_bfd). + + When generating relocateable output, the back end routine + must handle STB_LOCAL/STT_SECTION symbols specially. The + output symbol is going to be a section symbol + corresponding to the output section, which will require + the addend to be adjusted. */ + + if (! (*relocate_section) (output_bfd, finfo->info, + input_bfd, o, contents, + internal_relocs, + isymbuf, + finfo->sections)) + return FALSE; + + if (emit_relocs) + { + Elf_Internal_Rela *irela; + Elf_Internal_Rela *irelaend; + bfd_vma last_offset; + struct elf_link_hash_entry **rel_hash; + Elf_Internal_Shdr *input_rel_hdr, *input_rel_hdr2; + unsigned int next_erel; + bfd_boolean (*reloc_emitter) + PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, + Elf_Internal_Rela *)); + bfd_boolean rela_normal; + + input_rel_hdr = &elf_section_data (o)->rel_hdr; + rela_normal = (bed->rela_normal + && (input_rel_hdr->sh_entsize + == sizeof (Elf_External_Rela))); + + /* Adjust the reloc addresses and symbol indices. */ + + irela = internal_relocs; + irelaend = irela + o->reloc_count * bed->s->int_rels_per_ext_rel; + rel_hash = (elf_section_data (o->output_section)->rel_hashes + + elf_section_data (o->output_section)->rel_count + + elf_section_data (o->output_section)->rel_count2); + last_offset = o->output_offset; + if (!finfo->info->relocateable) + last_offset += o->output_section->vma; + for (next_erel = 0; irela < irelaend; irela++, next_erel++) + { + unsigned long r_symndx; + asection *sec; + Elf_Internal_Sym sym; + + if (next_erel == bed->s->int_rels_per_ext_rel) + { + rel_hash++; + next_erel = 0; + } + + irela->r_offset = _bfd_elf_section_offset (output_bfd, + finfo->info, o, + irela->r_offset); + if (irela->r_offset >= (bfd_vma) -2) + { + /* This is a reloc for a deleted entry or somesuch. + Turn it into an R_*_NONE reloc, at the same + offset as the last reloc. elf_eh_frame.c and + elf_bfd_discard_info rely on reloc offsets + being ordered. */ + irela->r_offset = last_offset; + irela->r_info = 0; + irela->r_addend = 0; + continue; + } + + irela->r_offset += o->output_offset; + + /* Relocs in an executable have to be virtual addresses. */ + if (!finfo->info->relocateable) + irela->r_offset += o->output_section->vma; + + last_offset = irela->r_offset; + + r_symndx = ELF_R_SYM (irela->r_info); + if (r_symndx == STN_UNDEF) + continue; + + if (r_symndx >= locsymcount + || (elf_bad_symtab (input_bfd) + && finfo->sections[r_symndx] == NULL)) + { + struct elf_link_hash_entry *rh; + unsigned long indx; + + /* This is a reloc against a global symbol. We + have not yet output all the local symbols, so + we do not know the symbol index of any global + symbol. We set the rel_hash entry for this + reloc to point to the global hash table entry + for this symbol. The symbol index is then + set at the end of elf_bfd_final_link. */ + indx = r_symndx - extsymoff; + rh = elf_sym_hashes (input_bfd)[indx]; + while (rh->root.type == bfd_link_hash_indirect + || rh->root.type == bfd_link_hash_warning) + rh = (struct elf_link_hash_entry *) rh->root.u.i.link; + + /* Setting the index to -2 tells + elf_link_output_extsym that this symbol is + used by a reloc. */ + BFD_ASSERT (rh->indx < 0); + rh->indx = -2; + + *rel_hash = rh; + + continue; + } + + /* This is a reloc against a local symbol. */ + + *rel_hash = NULL; + sym = isymbuf[r_symndx]; + sec = finfo->sections[r_symndx]; + if (ELF_ST_TYPE (sym.st_info) == STT_SECTION) + { + /* I suppose the backend ought to fill in the + section of any STT_SECTION symbol against a + processor specific section. If we have + discarded a section, the output_section will + be the absolute section. */ + if (bfd_is_abs_section (sec) + || (sec != NULL + && bfd_is_abs_section (sec->output_section))) + r_symndx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else + { + r_symndx = sec->output_section->target_index; + BFD_ASSERT (r_symndx != 0); + } + + /* Adjust the addend according to where the + section winds up in the output section. */ + if (rela_normal) + irela->r_addend += sec->output_offset; + } + else + { + if (finfo->indices[r_symndx] == -1) + { + unsigned long shlink; + const char *name; + asection *osec; + + if (finfo->info->strip == strip_all) + { + /* You can't do ld -r -s. */ + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + /* This symbol was skipped earlier, but + since it is needed by a reloc, we + must output it now. */ + shlink = symtab_hdr->sh_link; + name = (bfd_elf_string_from_elf_section + (input_bfd, shlink, sym.st_name)); + if (name == NULL) + return FALSE; + + osec = sec->output_section; + sym.st_shndx = + _bfd_elf_section_from_bfd_section (output_bfd, + osec); + if (sym.st_shndx == SHN_BAD) + return FALSE; + + sym.st_value += sec->output_offset; + if (! finfo->info->relocateable) + { + sym.st_value += osec->vma; + if (ELF_ST_TYPE (sym.st_info) == STT_TLS) + { + /* STT_TLS symbols are relative to PT_TLS + segment base. */ + BFD_ASSERT (finfo->first_tls_sec != NULL); + sym.st_value -= finfo->first_tls_sec->vma; + } + } + + finfo->indices[r_symndx] + = bfd_get_symcount (output_bfd); + + if (! elf_link_output_sym (finfo, name, &sym, sec)) + return FALSE; + } + + r_symndx = finfo->indices[r_symndx]; + } + + irela->r_info = ELF_R_INFO (r_symndx, + ELF_R_TYPE (irela->r_info)); + } + + /* Swap out the relocs. */ + if (bed->elf_backend_emit_relocs + && !(finfo->info->relocateable + || finfo->info->emitrelocations)) + reloc_emitter = bed->elf_backend_emit_relocs; + else + reloc_emitter = elf_link_output_relocs; + + if (input_rel_hdr->sh_size != 0 + && ! (*reloc_emitter) (output_bfd, o, input_rel_hdr, + internal_relocs)) + return FALSE; + + input_rel_hdr2 = elf_section_data (o)->rel_hdr2; + if (input_rel_hdr2 && input_rel_hdr2->sh_size != 0) + { + internal_relocs += (NUM_SHDR_ENTRIES (input_rel_hdr) + * bed->s->int_rels_per_ext_rel); + if (! (*reloc_emitter) (output_bfd, o, input_rel_hdr2, + internal_relocs)) + return FALSE; + } + } + } + + /* Write out the modified section contents. */ + if (bed->elf_backend_write_section + && (*bed->elf_backend_write_section) (output_bfd, o, contents)) + { + /* Section written out. */ + } + else switch (o->sec_info_type) + { + case ELF_INFO_TYPE_STABS: + if (! (_bfd_write_section_stabs + (output_bfd, + &elf_hash_table (finfo->info)->stab_info, + o, &elf_section_data (o)->sec_info, contents))) + return FALSE; + break; + case ELF_INFO_TYPE_MERGE: + if (! _bfd_write_merged_section (output_bfd, o, + elf_section_data (o)->sec_info)) + return FALSE; + break; + case ELF_INFO_TYPE_EH_FRAME: + { + if (! _bfd_elf_write_section_eh_frame (output_bfd, finfo->info, + o, contents)) + return FALSE; + } + break; + default: + { + bfd_size_type sec_size; + + sec_size = (o->_cooked_size != 0 ? o->_cooked_size : o->_raw_size); + if (! (o->flags & SEC_EXCLUDE) + && ! bfd_set_section_contents (output_bfd, o->output_section, + contents, + (file_ptr) o->output_offset, + sec_size)) + return FALSE; + } + break; + } + } + + return TRUE; +} + +/* Generate a reloc when linking an ELF file. This is a reloc + requested by the linker, and does come from any input file. This + is used to build constructor and destructor tables when linking + with -Ur. */ + +static bfd_boolean +elf_reloc_link_order (output_bfd, info, output_section, link_order) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; +{ + reloc_howto_type *howto; + long indx; + bfd_vma offset; + bfd_vma addend; + struct elf_link_hash_entry **rel_hash_ptr; + Elf_Internal_Shdr *rel_hdr; + struct elf_backend_data *bed = get_elf_backend_data (output_bfd); + Elf_Internal_Rela irel[MAX_INT_RELS_PER_EXT_REL]; + bfd_byte *erel; + unsigned int i; + + howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc); + if (howto == NULL) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + addend = link_order->u.reloc.p->addend; + + /* Figure out the symbol index. */ + rel_hash_ptr = (elf_section_data (output_section)->rel_hashes + + elf_section_data (output_section)->rel_count + + elf_section_data (output_section)->rel_count2); + if (link_order->type == bfd_section_reloc_link_order) + { + indx = link_order->u.reloc.p->u.section->target_index; + BFD_ASSERT (indx != 0); + *rel_hash_ptr = NULL; + } + else + { + struct elf_link_hash_entry *h; + + /* Treat a reloc against a defined symbol as though it were + actually against the section. */ + h = ((struct elf_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, info, + link_order->u.reloc.p->u.name, + FALSE, FALSE, TRUE)); + if (h != NULL + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak)) + { + asection *section; + + section = h->root.u.def.section; + indx = section->output_section->target_index; + *rel_hash_ptr = NULL; + /* It seems that we ought to add the symbol value to the + addend here, but in practice it has already been added + because it was passed to constructor_callback. */ + addend += section->output_section->vma + section->output_offset; + } + else if (h != NULL) + { + /* Setting the index to -2 tells elf_link_output_extsym that + this symbol is used by a reloc. */ + h->indx = -2; + *rel_hash_ptr = h; + indx = 0; + } + else + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, (bfd *) NULL, + (asection *) NULL, (bfd_vma) 0))) + return FALSE; + indx = 0; + } + } + + /* If this is an inplace reloc, we must write the addend into the + object file. */ + if (howto->partial_inplace && addend != 0) + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + bfd_boolean ok; + const char *sym_name; + + size = bfd_get_reloc_size (howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + return FALSE; + rstat = _bfd_relocate_contents (howto, output_bfd, (bfd_vma) addend, buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + + default: + case bfd_reloc_outofrange: + abort (); + + case bfd_reloc_overflow: + if (link_order->type == bfd_section_reloc_link_order) + sym_name = bfd_section_name (output_bfd, + link_order->u.reloc.p->u.section); + else + sym_name = link_order->u.reloc.p->u.name; + if (! ((*info->callbacks->reloc_overflow) + (info, sym_name, howto->name, addend, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return FALSE; + } + break; + } + ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf, + (file_ptr) link_order->offset, size); + free (buf); + if (! ok) + return FALSE; + } + + /* The address of a reloc is relative to the section in a + relocateable file, and is a virtual address in an executable + file. */ + offset = link_order->offset; + if (! info->relocateable) + offset += output_section->vma; + + for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) + { + irel[i].r_offset = offset; + irel[i].r_info = 0; + irel[i].r_addend = 0; + } + irel[0].r_info = ELF_R_INFO (indx, howto->type); + + rel_hdr = &elf_section_data (output_section)->rel_hdr; + erel = rel_hdr->contents; + if (rel_hdr->sh_type == SHT_REL) + { + erel += (elf_section_data (output_section)->rel_count + * sizeof (Elf_External_Rel)); + (*bed->s->swap_reloc_out) (output_bfd, irel, erel); + } + else + { + irel[0].r_addend = addend; + erel += (elf_section_data (output_section)->rel_count + * sizeof (Elf_External_Rela)); + (*bed->s->swap_reloca_out) (output_bfd, irel, erel); + } + + ++elf_section_data (output_section)->rel_count; + + return TRUE; +} + +/* Allocate a pointer to live in a linker created section. */ + +bfd_boolean +elf_create_pointer_linker_section (abfd, info, lsect, h, rel) + bfd *abfd; + struct bfd_link_info *info; + elf_linker_section_t *lsect; + struct elf_link_hash_entry *h; + const Elf_Internal_Rela *rel; +{ + elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL; + elf_linker_section_pointers_t *linker_section_ptr; + unsigned long r_symndx = ELF_R_SYM (rel->r_info); + bfd_size_type amt; + + BFD_ASSERT (lsect != NULL); + + /* Is this a global symbol? */ + if (h != NULL) + { + /* Has this symbol already been allocated? If so, our work is done. */ + if (_bfd_elf_find_pointer_linker_section (h->linker_section_pointer, + rel->r_addend, + lsect->which)) + return TRUE; + + ptr_linker_section_ptr = &h->linker_section_pointer; + /* Make sure this symbol is output as a dynamic symbol. */ + if (h->dynindx == -1) + { + if (! elf_link_record_dynamic_symbol (info, h)) + return FALSE; + } + + if (lsect->rel_section) + lsect->rel_section->_raw_size += sizeof (Elf_External_Rela); + } + else + { + /* Allocation of a pointer to a local symbol. */ + elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd); + + /* Allocate a table to hold the local symbols if first time. */ + if (!ptr) + { + unsigned int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info; + register unsigned int i; + + amt = num_symbols; + amt *= sizeof (elf_linker_section_pointers_t *); + ptr = (elf_linker_section_pointers_t **) bfd_alloc (abfd, amt); + + if (!ptr) + return FALSE; + + elf_local_ptr_offsets (abfd) = ptr; + for (i = 0; i < num_symbols; i++) + ptr[i] = (elf_linker_section_pointers_t *) 0; + } + + /* Has this symbol already been allocated? If so, our work is done. */ + if (_bfd_elf_find_pointer_linker_section (ptr[r_symndx], + rel->r_addend, + lsect->which)) + return TRUE; + + ptr_linker_section_ptr = &ptr[r_symndx]; + + if (info->shared) + { + /* If we are generating a shared object, we need to + output a R__RELATIVE reloc so that the + dynamic linker can adjust this GOT entry. */ + BFD_ASSERT (lsect->rel_section != NULL); + lsect->rel_section->_raw_size += sizeof (Elf_External_Rela); + } + } + + /* Allocate space for a pointer in the linker section, and allocate + a new pointer record from internal memory. */ + BFD_ASSERT (ptr_linker_section_ptr != NULL); + amt = sizeof (elf_linker_section_pointers_t); + linker_section_ptr = (elf_linker_section_pointers_t *) bfd_alloc (abfd, amt); + + if (!linker_section_ptr) + return FALSE; + + linker_section_ptr->next = *ptr_linker_section_ptr; + linker_section_ptr->addend = rel->r_addend; + linker_section_ptr->which = lsect->which; + linker_section_ptr->written_address_p = FALSE; + *ptr_linker_section_ptr = linker_section_ptr; + +#if 0 + if (lsect->hole_size && lsect->hole_offset < lsect->max_hole_offset) + { + linker_section_ptr->offset = (lsect->section->_raw_size + - lsect->hole_size + (ARCH_SIZE / 8)); + lsect->hole_offset += ARCH_SIZE / 8; + lsect->sym_offset += ARCH_SIZE / 8; + if (lsect->sym_hash) + { + /* Bump up symbol value if needed. */ + lsect->sym_hash->root.u.def.value += ARCH_SIZE / 8; +#ifdef DEBUG + fprintf (stderr, "Bump up %s by %ld, current value = %ld\n", + lsect->sym_hash->root.root.string, + (long) ARCH_SIZE / 8, + (long) lsect->sym_hash->root.u.def.value); +#endif + } + } + else +#endif + linker_section_ptr->offset = lsect->section->_raw_size; + + lsect->section->_raw_size += ARCH_SIZE / 8; + +#ifdef DEBUG + fprintf (stderr, + "Create pointer in linker section %s, offset = %ld, section size = %ld\n", + lsect->name, (long) linker_section_ptr->offset, + (long) lsect->section->_raw_size); +#endif + + return TRUE; +} + +#if ARCH_SIZE==64 +#define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_64 (BFD, VAL, ADDR) +#endif +#if ARCH_SIZE==32 +#define bfd_put_ptr(BFD,VAL,ADDR) bfd_put_32 (BFD, VAL, ADDR) +#endif + +/* Fill in the address for a pointer generated in a linker section. */ + +bfd_vma +elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, + relocation, rel, relative_reloc) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + elf_linker_section_t *lsect; + struct elf_link_hash_entry *h; + bfd_vma relocation; + const Elf_Internal_Rela *rel; + int relative_reloc; +{ + elf_linker_section_pointers_t *linker_section_ptr; + + BFD_ASSERT (lsect != NULL); + + if (h != NULL) + { + /* Handle global symbol. */ + linker_section_ptr = (_bfd_elf_find_pointer_linker_section + (h->linker_section_pointer, + rel->r_addend, + lsect->which)); + + BFD_ASSERT (linker_section_ptr != NULL); + + if (! elf_hash_table (info)->dynamic_sections_created + || (info->shared + && info->symbolic + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + { + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally. We must initialize this entry in the + global section. + + When doing a dynamic link, we create a .rela. + relocation entry to initialize the value. This + is done in the finish_dynamic_symbol routine. */ + if (!linker_section_ptr->written_address_p) + { + linker_section_ptr->written_address_p = TRUE; + bfd_put_ptr (output_bfd, + relocation + linker_section_ptr->addend, + (lsect->section->contents + + linker_section_ptr->offset)); + } + } + } + else + { + /* Handle local symbol. */ + unsigned long r_symndx = ELF_R_SYM (rel->r_info); + BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL); + BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL); + linker_section_ptr = (_bfd_elf_find_pointer_linker_section + (elf_local_ptr_offsets (input_bfd)[r_symndx], + rel->r_addend, + lsect->which)); + + BFD_ASSERT (linker_section_ptr != NULL); + + /* Write out pointer if it hasn't been rewritten out before. */ + if (!linker_section_ptr->written_address_p) + { + linker_section_ptr->written_address_p = TRUE; + bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend, + lsect->section->contents + linker_section_ptr->offset); + + if (info->shared) + { + asection *srel = lsect->rel_section; + Elf_Internal_Rela outrel[MAX_INT_RELS_PER_EXT_REL]; + bfd_byte *erel; + struct elf_backend_data *bed = get_elf_backend_data (output_bfd); + unsigned int i; + + /* We need to generate a relative reloc for the dynamic + linker. */ + if (!srel) + { + srel = bfd_get_section_by_name (elf_hash_table (info)->dynobj, + lsect->rel_name); + lsect->rel_section = srel; + } + + BFD_ASSERT (srel != NULL); + + for (i = 0; i < bed->s->int_rels_per_ext_rel; i++) + { + outrel[i].r_offset = (lsect->section->output_section->vma + + lsect->section->output_offset + + linker_section_ptr->offset); + outrel[i].r_info = 0; + outrel[i].r_addend = 0; + } + outrel[0].r_info = ELF_R_INFO (0, relative_reloc); + erel = lsect->section->contents; + erel += (elf_section_data (lsect->section)->rel_count++ + * sizeof (Elf_External_Rela)); + elf_swap_reloca_out (output_bfd, outrel, erel); + } + } + } + + relocation = (lsect->section->output_offset + + linker_section_ptr->offset + - lsect->hole_offset + - lsect->sym_offset); + +#ifdef DEBUG + fprintf (stderr, + "Finish pointer in linker section %s, offset = %ld (0x%lx)\n", + lsect->name, (long) relocation, (long) relocation); +#endif + + /* Subtract out the addend, because it will get added back in by the normal + processing. */ + return relocation - linker_section_ptr->addend; +} + +/* Garbage collect unused sections. */ + +static bfd_boolean elf_gc_mark + PARAMS ((struct bfd_link_info *, asection *, + asection * (*) (asection *, struct bfd_link_info *, + Elf_Internal_Rela *, struct elf_link_hash_entry *, + Elf_Internal_Sym *))); + +static bfd_boolean elf_gc_sweep + PARAMS ((struct bfd_link_info *, + bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *))); + +static bfd_boolean elf_gc_sweep_symbol + PARAMS ((struct elf_link_hash_entry *, PTR)); + +static bfd_boolean elf_gc_allocate_got_offsets + PARAMS ((struct elf_link_hash_entry *, PTR)); + +static bfd_boolean elf_gc_propagate_vtable_entries_used + PARAMS ((struct elf_link_hash_entry *, PTR)); + +static bfd_boolean elf_gc_smash_unused_vtentry_relocs + PARAMS ((struct elf_link_hash_entry *, PTR)); + +/* 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. */ + +typedef asection * (*gc_mark_hook_fn) + PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *, Elf_Internal_Sym *)); + +static bfd_boolean +elf_gc_mark (info, sec, gc_mark_hook) + struct bfd_link_info *info; + asection *sec; + gc_mark_hook_fn gc_mark_hook; +{ + bfd_boolean ret; + asection *group_sec; + + sec->gc_mark = 1; + + /* Mark all the sections in the group. */ + group_sec = elf_section_data (sec)->next_in_group; + if (group_sec && !group_sec->gc_mark) + if (!elf_gc_mark (info, group_sec, gc_mark_hook)) + return FALSE; + + /* Look through the section relocs. */ + ret = TRUE; + if ((sec->flags & SEC_RELOC) != 0 && sec->reloc_count > 0) + { + Elf_Internal_Rela *relstart, *rel, *relend; + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + size_t nlocsyms; + size_t extsymoff; + bfd *input_bfd = sec->owner; + struct elf_backend_data *bed = get_elf_backend_data (input_bfd); + Elf_Internal_Sym *isym = NULL; + + symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (input_bfd); + + /* Read the local symbols. */ + if (elf_bad_symtab (input_bfd)) + { + nlocsyms = symtab_hdr->sh_size / sizeof (Elf_External_Sym); + extsymoff = 0; + } + else + extsymoff = nlocsyms = symtab_hdr->sh_info; + + isym = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isym == NULL && nlocsyms != 0) + { + isym = bfd_elf_get_elf_syms (input_bfd, symtab_hdr, nlocsyms, 0, + NULL, NULL, NULL); + if (isym == NULL) + return FALSE; + } + + /* Read the relocations. */ + relstart = (NAME(_bfd_elf,link_read_relocs) + (input_bfd, sec, NULL, (Elf_Internal_Rela *) NULL, + info->keep_memory)); + if (relstart == NULL) + { + ret = FALSE; + goto out1; + } + relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; + + for (rel = relstart; rel < relend; rel++) + { + unsigned long r_symndx; + asection *rsec; + struct elf_link_hash_entry *h; + + r_symndx = ELF_R_SYM (rel->r_info); + if (r_symndx == 0) + continue; + + if (r_symndx >= nlocsyms + || ELF_ST_BIND (isym[r_symndx].st_info) != STB_LOCAL) + { + h = sym_hashes[r_symndx - extsymoff]; + rsec = (*gc_mark_hook) (sec, info, rel, h, NULL); + } + else + { + rsec = (*gc_mark_hook) (sec, info, rel, NULL, &isym[r_symndx]); + } + + if (rsec && !rsec->gc_mark) + { + if (bfd_get_flavour (rsec->owner) != bfd_target_elf_flavour) + rsec->gc_mark = 1; + else if (!elf_gc_mark (info, rsec, gc_mark_hook)) + { + ret = FALSE; + goto out2; + } + } + } + + out2: + if (elf_section_data (sec)->relocs != relstart) + free (relstart); + out1: + if (isym != NULL && symtab_hdr->contents != (unsigned char *) isym) + { + if (! info->keep_memory) + free (isym); + else + symtab_hdr->contents = (unsigned char *) isym; + } + } + + return ret; +} + +/* The sweep phase of garbage collection. Remove all garbage sections. */ + +typedef bfd_boolean (*gc_sweep_hook_fn) + PARAMS ((bfd *, struct bfd_link_info *, asection *, + const Elf_Internal_Rela *)); + +static bfd_boolean +elf_gc_sweep (info, gc_sweep_hook) + struct bfd_link_info *info; + gc_sweep_hook_fn gc_sweep_hook; +{ + bfd *sub; + + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *o; + + if (bfd_get_flavour (sub) != bfd_target_elf_flavour) + continue; + + for (o = sub->sections; o != NULL; o = o->next) + { + /* Keep special sections. Keep .debug sections. */ + if ((o->flags & SEC_LINKER_CREATED) + || (o->flags & SEC_DEBUGGING)) + 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; + + /* But we also have to update some of the relocation + info we collected before. */ + if (gc_sweep_hook + && (o->flags & SEC_RELOC) && o->reloc_count > 0) + { + Elf_Internal_Rela *internal_relocs; + bfd_boolean r; + + internal_relocs = (NAME(_bfd_elf,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 (elf_section_data (o)->relocs != internal_relocs) + free (internal_relocs); + + if (!r) + return FALSE; + } + } + } + + /* Remove the symbols that were in the swept sections from the dynamic + symbol table. GCFIXME: Anyone know how to get them out of the + static symbol table as well? */ + { + int i = 0; + + elf_link_hash_traverse (elf_hash_table (info), + elf_gc_sweep_symbol, + (PTR) &i); + + elf_hash_table (info)->dynsymcount = i; + } + + return TRUE; +} + +/* Sweep symbols in swept sections. Called via elf_link_hash_traverse. */ + +static bfd_boolean +elf_gc_sweep_symbol (h, idxptr) + struct elf_link_hash_entry *h; + PTR idxptr; +{ + int *idx = (int *) idxptr; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->dynindx != -1 + && ((h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + || h->root.u.def.section->gc_mark)) + h->dynindx = (*idx)++; + + return TRUE; +} + +/* Propogate collected vtable information. This is called through + elf_link_hash_traverse. */ + +static bfd_boolean +elf_gc_propagate_vtable_entries_used (h, okp) + struct elf_link_hash_entry *h; + PTR okp; +{ + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* Those that are not vtables. */ + if (h->vtable_parent == NULL) + return TRUE; + + /* Those vtables that do not have parents, we cannot merge. */ + if (h->vtable_parent == (struct elf_link_hash_entry *) -1) + return TRUE; + + /* If we've already been done, exit. */ + if (h->vtable_entries_used && h->vtable_entries_used[-1]) + return TRUE; + + /* Make sure the parent's table is up to date. */ + elf_gc_propagate_vtable_entries_used (h->vtable_parent, okp); + + if (h->vtable_entries_used == NULL) + { + /* None of this table's entries were referenced. Re-use the + parent's table. */ + h->vtable_entries_used = h->vtable_parent->vtable_entries_used; + h->vtable_entries_size = h->vtable_parent->vtable_entries_size; + } + else + { + size_t n; + bfd_boolean *cu, *pu; + + /* Or the parent's entries into ours. */ + cu = h->vtable_entries_used; + cu[-1] = TRUE; + pu = h->vtable_parent->vtable_entries_used; + if (pu != NULL) + { + asection *sec = h->root.u.def.section; + struct elf_backend_data *bed = get_elf_backend_data (sec->owner); + int file_align = bed->s->file_align; + + n = h->vtable_parent->vtable_entries_size / file_align; + while (n--) + { + if (*pu) + *cu = TRUE; + pu++; + cu++; + } + } + } + + return TRUE; +} + +static bfd_boolean +elf_gc_smash_unused_vtentry_relocs (h, okp) + struct elf_link_hash_entry *h; + PTR okp; +{ + asection *sec; + bfd_vma hstart, hend; + Elf_Internal_Rela *relstart, *relend, *rel; + struct elf_backend_data *bed; + int file_align; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* Take care of both those symbols that do not describe vtables as + well as those that are not loaded. */ + if (h->vtable_parent == NULL) + return TRUE; + + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak); + + sec = h->root.u.def.section; + hstart = h->root.u.def.value; + hend = hstart + h->size; + + relstart = (NAME(_bfd_elf,link_read_relocs) + (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL, TRUE)); + if (!relstart) + return *(bfd_boolean *) okp = FALSE; + bed = get_elf_backend_data (sec->owner); + file_align = bed->s->file_align; + + relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; + + for (rel = relstart; rel < relend; ++rel) + if (rel->r_offset >= hstart && rel->r_offset < hend) + { + /* If the entry is in use, do nothing. */ + if (h->vtable_entries_used + && (rel->r_offset - hstart) < h->vtable_entries_size) + { + bfd_vma entry = (rel->r_offset - hstart) / file_align; + if (h->vtable_entries_used[entry]) + continue; + } + /* Otherwise, kill it. */ + rel->r_offset = rel->r_info = rel->r_addend = 0; + } + + return TRUE; +} + +/* Do mark and sweep of unused sections. */ + +bfd_boolean +elf_gc_sections (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd_boolean ok = TRUE; + bfd *sub; + asection * (*gc_mark_hook) + PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, + struct elf_link_hash_entry *h, Elf_Internal_Sym *)); + + if (!get_elf_backend_data (abfd)->can_gc_sections + || info->relocateable || info->emitrelocations + || elf_hash_table (info)->dynamic_sections_created) + return TRUE; + + /* Apply transitive closure to the vtable entry usage info. */ + elf_link_hash_traverse (elf_hash_table (info), + elf_gc_propagate_vtable_entries_used, + (PTR) &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, + (PTR) &ok); + if (!ok) + return FALSE; + + /* Grovel through relocs to find out who stays ... */ + + gc_mark_hook = get_elf_backend_data (abfd)->gc_mark_hook; + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *o; + + if (bfd_get_flavour (sub) != bfd_target_elf_flavour) + continue; + + for (o = sub->sections; o != NULL; o = o->next) + { + if (o->flags & SEC_KEEP) + if (!elf_gc_mark (info, o, gc_mark_hook)) + return FALSE; + } + } + + /* ... and mark SEC_EXCLUDE for those that go. */ + if (!elf_gc_sweep (info, get_elf_backend_data (abfd)->gc_sweep_hook)) + return FALSE; + + return TRUE; +} + +/* Called from check_relocs to record the existance of a VTINHERIT reloc. */ + +bfd_boolean +elf_gc_record_vtinherit (abfd, sec, h, offset) + bfd *abfd; + asection *sec; + struct elf_link_hash_entry *h; + bfd_vma offset; +{ + struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; + struct elf_link_hash_entry **search, *child; + bfd_size_type extsymcount; + + /* The sh_info field of the symtab header tells us where the + external symbols start. We don't care about the local symbols at + this point. */ + extsymcount = elf_tdata (abfd)->symtab_hdr.sh_size/sizeof (Elf_External_Sym); + if (!elf_bad_symtab (abfd)) + extsymcount -= elf_tdata (abfd)->symtab_hdr.sh_info; + + sym_hashes = elf_sym_hashes (abfd); + sym_hashes_end = sym_hashes + extsymcount; + + /* Hunt down the child symbol, which is in this section at the same + offset as the relocation. */ + for (search = sym_hashes; search != sym_hashes_end; ++search) + { + if ((child = *search) != NULL + && (child->root.type == bfd_link_hash_defined + || child->root.type == bfd_link_hash_defweak) + && child->root.u.def.section == sec + && child->root.u.def.value == offset) + goto win; + } + + (*_bfd_error_handler) ("%s: %s+%lu: No symbol found for INHERIT", + bfd_archive_filename (abfd), sec->name, + (unsigned long) offset); + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + + win: + if (!h) + { + /* This *should* only be the absolute section. It could potentially + be that someone has defined a non-global vtable though, which + would be bad. It isn't worth paging in the local symbols to be + sure though; that case should simply be handled by the assembler. */ + + child->vtable_parent = (struct elf_link_hash_entry *) -1; + } + else + child->vtable_parent = h; + + return TRUE; +} + +/* Called from check_relocs to record the existance of a VTENTRY reloc. */ + +bfd_boolean +elf_gc_record_vtentry (abfd, sec, h, addend) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec ATTRIBUTE_UNUSED; + struct elf_link_hash_entry *h; + bfd_vma addend; +{ + struct elf_backend_data *bed = get_elf_backend_data (abfd); + int file_align = bed->s->file_align; + + if (addend >= h->vtable_entries_size) + { + size_t size, bytes; + bfd_boolean *ptr = h->vtable_entries_used; + + /* While the symbol is undefined, we have to be prepared to handle + a zero size. */ + if (h->root.type == bfd_link_hash_undefined) + size = addend; + else + { + size = h->size; + if (size < addend) + { + /* Oops! We've got a reference past the defined end of + the table. This is probably a bug -- shall we warn? */ + size = addend; + } + } + + /* Allocate one extra entry for use as a "done" flag for the + consolidation pass. */ + bytes = (size / file_align + 1) * sizeof (bfd_boolean); + + if (ptr) + { + ptr = bfd_realloc (ptr - 1, (bfd_size_type) bytes); + + if (ptr != NULL) + { + size_t oldbytes; + + oldbytes = ((h->vtable_entries_size / file_align + 1) + * sizeof (bfd_boolean)); + memset (((char *) ptr) + oldbytes, 0, bytes - oldbytes); + } + } + else + ptr = bfd_zmalloc ((bfd_size_type) bytes); + + if (ptr == NULL) + return FALSE; + + /* And arrange for that done flag to be at index -1. */ + h->vtable_entries_used = ptr + 1; + h->vtable_entries_size = size; + } + + h->vtable_entries_used[addend / file_align] = TRUE; + + return TRUE; +} + +/* And an accompanying bit to work out final got entry offsets once + we're done. Should be called from final_link. */ + +bfd_boolean +elf_gc_common_finalize_got_offsets (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd *i; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_vma gotoff; + + /* The GOT offset is relative to the .got section, but the GOT header is + put into the .got.plt section, if the backend uses it. */ + if (bed->want_got_plt) + gotoff = 0; + else + gotoff = bed->got_header_size; + + /* Do the local .got entries first. */ + for (i = info->input_bfds; i; i = i->link_next) + { + bfd_signed_vma *local_got; + bfd_size_type j, locsymcount; + Elf_Internal_Shdr *symtab_hdr; + + if (bfd_get_flavour (i) != bfd_target_elf_flavour) + continue; + + local_got = elf_local_got_refcounts (i); + if (!local_got) + continue; + + symtab_hdr = &elf_tdata (i)->symtab_hdr; + if (elf_bad_symtab (i)) + locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym); + else + locsymcount = symtab_hdr->sh_info; + + for (j = 0; j < locsymcount; ++j) + { + if (local_got[j] > 0) + { + local_got[j] = gotoff; + gotoff += ARCH_SIZE / 8; + } + else + local_got[j] = (bfd_vma) -1; + } + } + + /* Then the global .got entries. .plt refcounts are handled by + adjust_dynamic_symbol */ + elf_link_hash_traverse (elf_hash_table (info), + elf_gc_allocate_got_offsets, + (PTR) &gotoff); + return TRUE; +} + +/* We need a special top-level link routine to convert got reference counts + to real got offsets. */ + +static bfd_boolean +elf_gc_allocate_got_offsets (h, offarg) + struct elf_link_hash_entry *h; + PTR offarg; +{ + bfd_vma *off = (bfd_vma *) offarg; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + if (h->got.refcount > 0) + { + h->got.offset = off[0]; + off[0] += ARCH_SIZE / 8; + } + else + h->got.offset = (bfd_vma) -1; + + return TRUE; +} + +/* Many folk need no more in the way of final link than this, once + got entry reference counting is enabled. */ + +bfd_boolean +elf_gc_common_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + if (!elf_gc_common_finalize_got_offsets (abfd, info)) + return FALSE; + + /* Invoke the regular ELF backend linker to do all the work. */ + return elf_bfd_final_link (abfd, info); +} + +/* This function will be called though elf_link_hash_traverse to store + all hash value of the exported symbols in an array. */ + +static bfd_boolean +elf_collect_hash_codes (h, data) + struct elf_link_hash_entry *h; + PTR data; +{ + unsigned long **valuep = (unsigned long **) data; + const char *name; + char *p; + unsigned long ha; + char *alc = NULL; + + if (h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + /* Ignore indirect symbols. These are added by the versioning code. */ + if (h->dynindx == -1) + return TRUE; + + name = h->root.root.string; + p = strchr (name, ELF_VER_CHR); + if (p != NULL) + { + alc = bfd_malloc ((bfd_size_type) (p - name + 1)); + memcpy (alc, name, (size_t) (p - name)); + alc[p - name] = '\0'; + name = alc; + } + + /* Compute the hash value. */ + ha = bfd_elf_hash (name); + + /* Store the found hash value in the array given as the argument. */ + *(*valuep)++ = ha; + + /* And store it in the struct so that we can put it in the hash table + later. */ + h->elf_hash_value = ha; + + if (alc != NULL) + free (alc); + + return TRUE; +} + +bfd_boolean +elf_reloc_symbol_deleted_p (offset, cookie) + bfd_vma offset; + PTR cookie; +{ + struct elf_reloc_cookie *rcookie = (struct elf_reloc_cookie *) cookie; + + if (rcookie->bad_symtab) + rcookie->rel = rcookie->rels; + + for (; rcookie->rel < rcookie->relend; rcookie->rel++) + { + unsigned long r_symndx; + + if (! rcookie->bad_symtab) + if (rcookie->rel->r_offset > offset) + return FALSE; + if (rcookie->rel->r_offset != offset) + continue; + + r_symndx = ELF_R_SYM (rcookie->rel->r_info); + if (r_symndx == SHN_UNDEF) + return TRUE; + + if (r_symndx >= rcookie->locsymcount + || ELF_ST_BIND (rcookie->locsyms[r_symndx].st_info) != STB_LOCAL) + { + struct elf_link_hash_entry *h; + + h = rcookie->sym_hashes[r_symndx - rcookie->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) + && elf_discarded_section (h->root.u.def.section)) + return TRUE; + else + return FALSE; + } + 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 = &rcookie->locsyms[r_symndx]; + if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE) + { + isec = section_from_elf_index (rcookie->abfd, isym->st_shndx); + if (isec != NULL && elf_discarded_section (isec)) + return TRUE; + } + } + return FALSE; + } + return FALSE; +} + +/* 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. */ + +bfd_boolean +elf_bfd_discard_info (output_bfd, info) + bfd *output_bfd; + struct bfd_link_info *info; +{ + struct elf_reloc_cookie cookie; + asection *stab, *eh; + Elf_Internal_Shdr *symtab_hdr; + struct elf_backend_data *bed; + bfd *abfd; + unsigned int count; + bfd_boolean ret = FALSE; + + if (info->traditional_format + || info->hash->creator->flavour != bfd_target_elf_flavour + || ! is_elf_hash_table (info)) + return FALSE; + + for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) + { + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) + continue; + + bed = get_elf_backend_data (abfd); + + if ((abfd->flags & DYNAMIC) != 0) + continue; + + eh = bfd_get_section_by_name (abfd, ".eh_frame"); + if (info->relocateable + || (eh != NULL + && (eh->_raw_size == 0 + || bfd_is_abs_section (eh->output_section)))) + eh = NULL; + + stab = bfd_get_section_by_name (abfd, ".stab"); + if (stab != NULL + && (stab->_raw_size == 0 + || bfd_is_abs_section (stab->output_section) + || stab->sec_info_type != ELF_INFO_TYPE_STABS)) + stab = NULL; + + if (stab == NULL + && eh == NULL + && bed->elf_backend_discard_info == NULL) + continue; + + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + cookie.abfd = abfd; + cookie.sym_hashes = elf_sym_hashes (abfd); + cookie.bad_symtab = elf_bad_symtab (abfd); + if (cookie.bad_symtab) + { + cookie.locsymcount = symtab_hdr->sh_size / sizeof (Elf_External_Sym); + cookie.extsymoff = 0; + } + else + { + cookie.locsymcount = symtab_hdr->sh_info; + cookie.extsymoff = symtab_hdr->sh_info; + } + + cookie.locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; + if (cookie.locsyms == NULL && cookie.locsymcount != 0) + { + cookie.locsyms = bfd_elf_get_elf_syms (abfd, symtab_hdr, + cookie.locsymcount, 0, + NULL, NULL, NULL); + if (cookie.locsyms == NULL) + return FALSE; + } + + if (stab != NULL) + { + cookie.rels = NULL; + count = stab->reloc_count; + if (count != 0) + cookie.rels = (NAME(_bfd_elf,link_read_relocs) + (abfd, stab, (PTR) NULL, (Elf_Internal_Rela *) NULL, + info->keep_memory)); + if (cookie.rels != NULL) + { + cookie.rel = cookie.rels; + cookie.relend = cookie.rels; + cookie.relend += count * bed->s->int_rels_per_ext_rel; + if (_bfd_discard_section_stabs (abfd, stab, + elf_section_data (stab)->sec_info, + elf_reloc_symbol_deleted_p, + &cookie)) + ret = TRUE; + if (elf_section_data (stab)->relocs != cookie.rels) + free (cookie.rels); + } + } + + if (eh != NULL) + { + cookie.rels = NULL; + count = eh->reloc_count; + if (count != 0) + cookie.rels = (NAME(_bfd_elf,link_read_relocs) + (abfd, eh, (PTR) NULL, (Elf_Internal_Rela *) NULL, + info->keep_memory)); + cookie.rel = cookie.rels; + cookie.relend = cookie.rels; + if (cookie.rels != NULL) + cookie.relend += count * bed->s->int_rels_per_ext_rel; + + if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, + elf_reloc_symbol_deleted_p, + &cookie)) + ret = TRUE; + + if (cookie.rels != NULL + && elf_section_data (eh)->relocs != cookie.rels) + free (cookie.rels); + } + + if (bed->elf_backend_discard_info != NULL + && (*bed->elf_backend_discard_info) (abfd, &cookie, info)) + ret = TRUE; + + if (cookie.locsyms != NULL + && symtab_hdr->contents != (unsigned char *) cookie.locsyms) + { + if (! info->keep_memory) + free (cookie.locsyms); + else + symtab_hdr->contents = (unsigned char *) cookie.locsyms; + } + } + + if (info->eh_frame_hdr + && !info->relocateable + && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info)) + ret = TRUE; + + return ret; +} + +static bfd_boolean +elf_section_ignore_discarded_relocs (sec) + asection *sec; +{ + struct elf_backend_data *bed; + + switch (sec->sec_info_type) + { + case ELF_INFO_TYPE_STABS: + case ELF_INFO_TYPE_EH_FRAME: + return TRUE; + default: + break; + } + + bed = get_elf_backend_data (sec->owner); + if (bed->elf_backend_ignore_discarded_relocs != NULL + && (*bed->elf_backend_ignore_discarded_relocs) (sec)) + return TRUE; + + return FALSE; +} diff --git a/contrib/binutils-2.14/bfd/elfxx-target.h b/contrib/binutils-2.14/bfd/elfxx-target.h new file mode 100644 index 0000000000..734d78bb75 --- /dev/null +++ b/contrib/binutils-2.14/bfd/elfxx-target.h @@ -0,0 +1,714 @@ +/* Target definitions for NN-bit ELF + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This structure contains everything that BFD knows about a target. + It includes things like its byte order, name, what routines to call + to do various operations, etc. Every BFD points to a target structure + with its "xvec" member. + + There are two such structures here: one for big-endian machines and + one for little-endian machines. */ + +#define bfd_elfNN_close_and_cleanup _bfd_elf_close_and_cleanup +#define bfd_elfNN_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#ifndef bfd_elfNN_get_section_contents +#define bfd_elfNN_get_section_contents _bfd_generic_get_section_contents +#endif + +#define bfd_elfNN_canonicalize_dynamic_symtab _bfd_elf_canonicalize_dynamic_symtab +#ifndef bfd_elfNN_canonicalize_reloc +#define bfd_elfNN_canonicalize_reloc _bfd_elf_canonicalize_reloc +#endif +#ifndef bfd_elfNN_find_nearest_line +#define bfd_elfNN_find_nearest_line _bfd_elf_find_nearest_line +#endif +#define bfd_elfNN_read_minisymbols _bfd_elf_read_minisymbols +#define bfd_elfNN_minisymbol_to_symbol _bfd_elf_minisymbol_to_symbol +#define bfd_elfNN_get_dynamic_symtab_upper_bound _bfd_elf_get_dynamic_symtab_upper_bound +#define bfd_elfNN_get_lineno _bfd_elf_get_lineno +#ifndef bfd_elfNN_get_reloc_upper_bound +#define bfd_elfNN_get_reloc_upper_bound _bfd_elf_get_reloc_upper_bound +#endif +#ifndef bfd_elfNN_get_symbol_info +#define bfd_elfNN_get_symbol_info _bfd_elf_get_symbol_info +#endif +#define bfd_elfNN_get_symtab _bfd_elf_get_symtab +#define bfd_elfNN_get_symtab_upper_bound _bfd_elf_get_symtab_upper_bound +#if 0 /* done in elf-bfd.h */ +#define bfd_elfNN_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol +#endif +#define bfd_elfNN_make_empty_symbol _bfd_elf_make_empty_symbol +#ifndef bfd_elfNN_new_section_hook +#define bfd_elfNN_new_section_hook _bfd_elf_new_section_hook +#endif +#define bfd_elfNN_set_arch_mach _bfd_elf_set_arch_mach +#ifndef bfd_elfNN_set_section_contents +#define bfd_elfNN_set_section_contents _bfd_elf_set_section_contents +#endif +#define bfd_elfNN_sizeof_headers _bfd_elf_sizeof_headers +#define bfd_elfNN_write_object_contents _bfd_elf_write_object_contents +#define bfd_elfNN_write_corefile_contents _bfd_elf_write_corefile_contents + +#define bfd_elfNN_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#ifndef elf_backend_got_symbol_offset +#define elf_backend_got_symbol_offset (bfd_vma) 0 +#endif +#ifndef elf_backend_can_refcount +#define elf_backend_can_refcount 0 +#endif +#ifndef elf_backend_want_got_plt +#define elf_backend_want_got_plt 0 +#endif +#ifndef elf_backend_plt_readonly +#define elf_backend_plt_readonly 0 +#endif +#ifndef elf_backend_want_plt_sym +#define elf_backend_want_plt_sym 0 +#endif +#ifndef elf_backend_plt_not_loaded +#define elf_backend_plt_not_loaded 0 +#endif +#ifndef elf_backend_plt_alignment +#define elf_backend_plt_alignment 2 +#endif +#ifndef elf_backend_want_dynbss +#define elf_backend_want_dynbss 1 +#endif +#ifndef elf_backend_want_p_paddr_set_to_zero +#define elf_backend_want_p_paddr_set_to_zero 0 +#endif + +#define bfd_elfNN_bfd_debug_info_start bfd_void +#define bfd_elfNN_bfd_debug_info_end bfd_void +#define bfd_elfNN_bfd_debug_info_accumulate \ + (void (*) PARAMS ((bfd*, struct sec *))) bfd_void + +#ifndef bfd_elfNN_bfd_get_relocated_section_contents +#define bfd_elfNN_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#endif + +#ifndef bfd_elfNN_bfd_relax_section +#define bfd_elfNN_bfd_relax_section bfd_generic_relax_section +#endif + +#ifndef elf_backend_can_gc_sections +#define elf_backend_can_gc_sections 0 +#endif +#ifndef elf_backend_can_refcount +#define elf_backend_can_refcount 0 +#endif +#ifndef elf_backend_want_got_sym +#define elf_backend_want_got_sym 1 +#endif +#ifndef elf_backend_gc_mark_hook +#define elf_backend_gc_mark_hook NULL +#endif +#ifndef elf_backend_gc_sweep_hook +#define elf_backend_gc_sweep_hook NULL +#endif +#ifndef bfd_elfNN_bfd_gc_sections +#define bfd_elfNN_bfd_gc_sections _bfd_elfNN_gc_sections +#endif + +#ifndef bfd_elfNN_bfd_merge_sections +#define bfd_elfNN_bfd_merge_sections \ + _bfd_elf_merge_sections +#endif + +#ifndef bfd_elfNN_bfd_discard_group +#define bfd_elfNN_bfd_discard_group bfd_elf_discard_group +#endif + +#ifndef bfd_elfNN_bfd_make_debug_symbol +#define bfd_elfNN_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr) +#endif + +#ifndef bfd_elfNN_bfd_copy_private_symbol_data +#define bfd_elfNN_bfd_copy_private_symbol_data \ + _bfd_elf_copy_private_symbol_data +#endif + +#ifndef bfd_elfNN_bfd_copy_private_section_data +#define bfd_elfNN_bfd_copy_private_section_data \ + _bfd_elf_copy_private_section_data +#endif +#ifndef bfd_elfNN_bfd_copy_private_bfd_data +#define bfd_elfNN_bfd_copy_private_bfd_data \ + _bfd_elf_copy_private_bfd_data +#endif +#ifndef bfd_elfNN_bfd_print_private_bfd_data +#define bfd_elfNN_bfd_print_private_bfd_data \ + _bfd_elf_print_private_bfd_data +#endif +#ifndef bfd_elfNN_bfd_merge_private_bfd_data +#define bfd_elfNN_bfd_merge_private_bfd_data \ + ((bfd_boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#endif +#ifndef bfd_elfNN_bfd_set_private_flags +#define bfd_elfNN_bfd_set_private_flags \ + ((bfd_boolean (*) PARAMS ((bfd *, flagword))) bfd_true) +#endif +#ifndef bfd_elfNN_bfd_is_local_label_name +#define bfd_elfNN_bfd_is_local_label_name _bfd_elf_is_local_label_name +#endif + +#ifndef bfd_elfNN_get_dynamic_reloc_upper_bound +#define bfd_elfNN_get_dynamic_reloc_upper_bound \ + _bfd_elf_get_dynamic_reloc_upper_bound +#endif +#ifndef bfd_elfNN_canonicalize_dynamic_reloc +#define bfd_elfNN_canonicalize_dynamic_reloc \ + _bfd_elf_canonicalize_dynamic_reloc +#endif + +#ifndef bfd_elfNN_bfd_link_hash_table_free +#define bfd_elfNN_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +#endif + +#ifdef elf_backend_relocate_section +#ifndef bfd_elfNN_bfd_link_hash_table_create +#define bfd_elfNN_bfd_link_hash_table_create _bfd_elf_link_hash_table_create +#endif +#else /* ! defined (elf_backend_relocate_section) */ +/* If no backend relocate_section routine, use the generic linker. + Note - this will prevent the port from being able to use some of + the other features of the ELF linker, because the generic hash structure + does not have the fields needed by the ELF linker. In particular it + means that linking directly to S-records will not work. */ +#ifndef bfd_elfNN_bfd_link_hash_table_create +#define bfd_elfNN_bfd_link_hash_table_create \ + _bfd_generic_link_hash_table_create +#endif +#ifndef bfd_elfNN_bfd_link_add_symbols +#define bfd_elfNN_bfd_link_add_symbols _bfd_generic_link_add_symbols +#endif +#ifndef bfd_elfNN_bfd_final_link +#define bfd_elfNN_bfd_final_link _bfd_generic_final_link +#endif +#endif /* ! defined (elf_backend_relocate_section) */ + +#ifndef bfd_elfNN_bfd_link_just_syms +#define bfd_elfNN_bfd_link_just_syms _bfd_elf_link_just_syms +#endif + +#ifndef bfd_elfNN_bfd_link_split_section +#define bfd_elfNN_bfd_link_split_section _bfd_generic_link_split_section +#endif + +#ifndef bfd_elfNN_archive_p +#define bfd_elfNN_archive_p bfd_generic_archive_p +#endif + +#ifndef bfd_elfNN_write_archive_contents +#define bfd_elfNN_write_archive_contents _bfd_write_archive_contents +#endif + +#ifndef bfd_elfNN_mkobject +#define bfd_elfNN_mkobject bfd_elf_mkobject +#endif + +#ifndef bfd_elfNN_mkcorefile +#define bfd_elfNN_mkcorefile bfd_elf_mkcorefile +#endif + +#ifndef bfd_elfNN_mkarchive +#define bfd_elfNN_mkarchive _bfd_generic_mkarchive +#endif + +#ifndef elf_symbol_leading_char +#define elf_symbol_leading_char 0 +#endif + +#ifndef elf_info_to_howto +#define elf_info_to_howto 0 +#endif + +#ifndef elf_info_to_howto_rel +#define elf_info_to_howto_rel 0 +#endif + +#ifndef ELF_MAXPAGESIZE + #error ELF_MAXPAGESIZE is not defined +#define ELF_MAXPAGESIZE 1 +#endif + +#ifndef elf_backend_collect +#define elf_backend_collect FALSE +#endif +#ifndef elf_backend_type_change_ok +#define elf_backend_type_change_ok FALSE +#endif + +#ifndef elf_backend_sym_is_global +#define elf_backend_sym_is_global 0 +#endif +#ifndef elf_backend_object_p +#define elf_backend_object_p 0 +#endif +#ifndef elf_backend_symbol_processing +#define elf_backend_symbol_processing 0 +#endif +#ifndef elf_backend_symbol_table_processing +#define elf_backend_symbol_table_processing 0 +#endif +#ifndef elf_backend_get_symbol_type +#define elf_backend_get_symbol_type 0 +#endif +#ifndef elf_backend_section_processing +#define elf_backend_section_processing 0 +#endif +#ifndef elf_backend_section_from_shdr +#define elf_backend_section_from_shdr 0 +#endif +#ifndef elf_backend_section_flags +#define elf_backend_section_flags 0 +#endif +#ifndef elf_backend_section_from_phdr +#define elf_backend_section_from_phdr 0 +#endif +#ifndef elf_backend_fake_sections +#define elf_backend_fake_sections 0 +#endif +#ifndef elf_backend_section_from_bfd_section +#define elf_backend_section_from_bfd_section 0 +#endif +#ifndef elf_backend_add_symbol_hook +#define elf_backend_add_symbol_hook 0 +#endif +#ifndef elf_backend_link_output_symbol_hook +#define elf_backend_link_output_symbol_hook 0 +#endif +#ifndef elf_backend_create_dynamic_sections +#define elf_backend_create_dynamic_sections 0 +#endif +#ifndef elf_backend_check_relocs +#define elf_backend_check_relocs 0 +#endif +#ifndef elf_backend_adjust_dynamic_symbol +#define elf_backend_adjust_dynamic_symbol 0 +#endif +#ifndef elf_backend_always_size_sections +#define elf_backend_always_size_sections 0 +#endif +#ifndef elf_backend_size_dynamic_sections +#define elf_backend_size_dynamic_sections 0 +#endif +#ifndef elf_backend_relocate_section +#define elf_backend_relocate_section 0 +#endif +#ifndef elf_backend_finish_dynamic_symbol +#define elf_backend_finish_dynamic_symbol 0 +#endif +#ifndef elf_backend_finish_dynamic_sections +#define elf_backend_finish_dynamic_sections 0 +#endif +#ifndef elf_backend_begin_write_processing +#define elf_backend_begin_write_processing 0 +#endif +#ifndef elf_backend_final_write_processing +#define elf_backend_final_write_processing 0 +#endif +#ifndef elf_backend_additional_program_headers +#define elf_backend_additional_program_headers 0 +#endif +#ifndef elf_backend_modify_segment_map +#define elf_backend_modify_segment_map 0 +#endif +#ifndef elf_backend_ecoff_debug_swap +#define elf_backend_ecoff_debug_swap 0 +#endif +#ifndef elf_backend_got_header_size +#define elf_backend_got_header_size 0 +#endif +#ifndef elf_backend_plt_header_size +#define elf_backend_plt_header_size 0 +#endif +#ifndef elf_backend_post_process_headers +#define elf_backend_post_process_headers NULL +#endif +#ifndef elf_backend_print_symbol_all +#define elf_backend_print_symbol_all NULL +#endif +#ifndef elf_backend_output_arch_syms +#define elf_backend_output_arch_syms NULL +#endif +#ifndef elf_backend_copy_indirect_symbol +#define elf_backend_copy_indirect_symbol _bfd_elf_link_hash_copy_indirect +#endif +#ifndef elf_backend_hide_symbol +#define elf_backend_hide_symbol _bfd_elf_link_hash_hide_symbol +#endif +#ifndef elf_backend_emit_relocs +#define elf_backend_emit_relocs NULL +#endif +#ifndef elf_backend_count_relocs +#define elf_backend_count_relocs NULL +#endif +#ifndef elf_backend_grok_prstatus +#define elf_backend_grok_prstatus NULL +#endif +#ifndef elf_backend_grok_psinfo +#define elf_backend_grok_psinfo NULL +#endif +#ifndef elf_backend_sprintf_vma +#define elf_backend_sprintf_vma _bfd_elf_sprintf_vma +#endif +#ifndef elf_backend_fprintf_vma +#define elf_backend_fprintf_vma _bfd_elf_fprintf_vma +#endif +#ifndef elf_backend_reloc_type_class +#define elf_backend_reloc_type_class _bfd_elf_reloc_type_class +#endif +#ifndef elf_backend_discard_info +#define elf_backend_discard_info NULL +#endif +#ifndef elf_backend_ignore_discarded_relocs +#define elf_backend_ignore_discarded_relocs NULL +#endif +#ifndef elf_backend_write_section +#define elf_backend_write_section NULL +#endif +#ifndef elf_backend_mips_irix_compat +#define elf_backend_mips_irix_compat NULL +#endif +#ifndef elf_backend_mips_rtype_to_howto +#define elf_backend_mips_rtype_to_howto NULL +#endif + +/* Previously, backends could only use SHT_REL or SHT_RELA relocation + sections, but not both. They defined USE_REL to indicate SHT_REL + sections, and left it undefined to indicated SHT_RELA sections. + For backwards compatibility, we still support this usage. */ +#ifndef USE_REL +#define USE_REL 0 +#endif + +/* Use these in new code. */ +#ifndef elf_backend_may_use_rel_p +#define elf_backend_may_use_rel_p USE_REL +#endif +#ifndef elf_backend_may_use_rela_p +#define elf_backend_may_use_rela_p !USE_REL +#endif +#ifndef elf_backend_default_use_rela_p +#define elf_backend_default_use_rela_p !USE_REL +#endif + +#ifndef elf_backend_rela_normal +#define elf_backend_rela_normal 0 +#endif + +#ifndef ELF_MACHINE_ALT1 +#define ELF_MACHINE_ALT1 0 +#endif + +#ifndef ELF_MACHINE_ALT2 +#define ELF_MACHINE_ALT2 0 +#endif + +#ifndef elf_backend_size_info +#define elf_backend_size_info _bfd_elfNN_size_info +#endif + +#ifndef elf_backend_sign_extend_vma +#define elf_backend_sign_extend_vma 0 +#endif + +extern const struct elf_size_info _bfd_elfNN_size_info; + +#ifndef INCLUDED_TARGET_FILE +static const struct elf_backend_data elfNN_bed = +{ + ELF_ARCH, /* arch */ + ELF_MACHINE_CODE, /* elf_machine_code */ + ELF_MAXPAGESIZE, /* maxpagesize */ + elf_info_to_howto, + elf_info_to_howto_rel, + elf_backend_sym_is_global, + elf_backend_object_p, + elf_backend_symbol_processing, + elf_backend_symbol_table_processing, + elf_backend_get_symbol_type, + elf_backend_section_processing, + elf_backend_section_from_shdr, + elf_backend_section_flags, + elf_backend_section_from_phdr, + elf_backend_fake_sections, + elf_backend_section_from_bfd_section, + elf_backend_add_symbol_hook, + elf_backend_link_output_symbol_hook, + elf_backend_create_dynamic_sections, + elf_backend_check_relocs, + elf_backend_adjust_dynamic_symbol, + elf_backend_always_size_sections, + elf_backend_size_dynamic_sections, + elf_backend_relocate_section, + elf_backend_finish_dynamic_symbol, + elf_backend_finish_dynamic_sections, + elf_backend_begin_write_processing, + elf_backend_final_write_processing, + elf_backend_additional_program_headers, + elf_backend_modify_segment_map, + elf_backend_gc_mark_hook, + elf_backend_gc_sweep_hook, + elf_backend_post_process_headers, + elf_backend_print_symbol_all, + elf_backend_output_arch_syms, + elf_backend_copy_indirect_symbol, + elf_backend_hide_symbol, + elf_backend_emit_relocs, + elf_backend_count_relocs, + elf_backend_grok_prstatus, + elf_backend_grok_psinfo, + elf_backend_sprintf_vma, + elf_backend_fprintf_vma, + elf_backend_reloc_type_class, + elf_backend_discard_info, + elf_backend_ignore_discarded_relocs, + elf_backend_write_section, + elf_backend_mips_irix_compat, + elf_backend_mips_rtype_to_howto, + elf_backend_ecoff_debug_swap, + ELF_MACHINE_ALT1, + ELF_MACHINE_ALT2, + &elf_backend_size_info, + elf_backend_got_symbol_offset, + elf_backend_got_header_size, + elf_backend_plt_header_size, + elf_backend_collect, + elf_backend_type_change_ok, + elf_backend_may_use_rel_p, + elf_backend_may_use_rela_p, + elf_backend_default_use_rela_p, + elf_backend_rela_normal, + elf_backend_sign_extend_vma, + elf_backend_want_got_plt, + elf_backend_plt_readonly, + elf_backend_want_plt_sym, + elf_backend_plt_not_loaded, + elf_backend_plt_alignment, + elf_backend_can_gc_sections, + elf_backend_can_refcount, + elf_backend_want_got_sym, + elf_backend_want_dynbss, + elf_backend_want_p_paddr_set_to_zero +}; +#endif + +/* Forward declaration for use when initialising alternative_target field. */ +#ifdef TARGET_LITTLE_SYM +extern const bfd_target TARGET_LITTLE_SYM; +#endif + +#ifdef TARGET_BIG_SYM +const bfd_target TARGET_BIG_SYM = +{ + /* name: identify kind of target */ + TARGET_BIG_NAME, + + /* flavour: general indication about file */ + bfd_target_elf_flavour, + + /* byteorder: data is big endian */ + BFD_ENDIAN_BIG, + + /* header_byteorder: header is also big endian */ + BFD_ENDIAN_BIG, + + /* object_flags: mask of all file flags */ + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS + | DYNAMIC | WP_TEXT | D_PAGED), + + /* section_flags: mask of all section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY + | SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES + | SEC_ARCH_BIT_0 | SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS | SEC_GROUP), + + /* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + elf_symbol_leading_char, + + /* ar_pad_char: pad character for filenames within an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and/or os and should be independently tunable */ + '/', + + /* ar_max_namelen: maximum number of characters in an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and should be independently tunable. The System V ABI, + Chapter 7 (Formats & Protocols), Archive section sets this as 15. */ + 15, + + /* Routines to byte-swap various sized integers from the data sections */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + /* Routines to byte-swap various sized integers from the file headers */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, + + /* bfd_check_format: check the format of a file being read */ + { _bfd_dummy_target, /* unknown format */ + bfd_elfNN_object_p, /* assembler/linker output (object file) */ + bfd_elfNN_archive_p, /* an archive */ + bfd_elfNN_core_file_p /* a core file */ + }, + + /* bfd_set_format: set the format of a file being written */ + { bfd_false, + bfd_elfNN_mkobject, + bfd_elfNN_mkarchive, + bfd_elfNN_mkcorefile + }, + + /* bfd_write_contents: write cached information into a file being written */ + { bfd_false, + bfd_elfNN_write_object_contents, + bfd_elfNN_write_archive_contents, + bfd_elfNN_write_corefile_contents, + }, + + BFD_JUMP_TABLE_GENERIC (bfd_elfNN), + BFD_JUMP_TABLE_COPY (bfd_elfNN), + BFD_JUMP_TABLE_CORE (bfd_elfNN), +#ifdef bfd_elfNN_archive_functions + BFD_JUMP_TABLE_ARCHIVE (bfd_elfNN_archive), +#else + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), +#endif + BFD_JUMP_TABLE_SYMBOLS (bfd_elfNN), + BFD_JUMP_TABLE_RELOCS (bfd_elfNN), + BFD_JUMP_TABLE_WRITE (bfd_elfNN), + BFD_JUMP_TABLE_LINK (bfd_elfNN), + BFD_JUMP_TABLE_DYNAMIC (bfd_elfNN), + + /* Alternative endian target. */ +#ifdef TARGET_LITTLE_SYM + & TARGET_LITTLE_SYM, +#else + NULL, +#endif + + /* backend_data: */ + (PTR) &elfNN_bed +}; +#endif + +#ifdef TARGET_LITTLE_SYM +const bfd_target TARGET_LITTLE_SYM = +{ + /* name: identify kind of target */ + TARGET_LITTLE_NAME, + + /* flavour: general indication about file */ + bfd_target_elf_flavour, + + /* byteorder: data is little endian */ + BFD_ENDIAN_LITTLE, + + /* header_byteorder: header is also little endian */ + BFD_ENDIAN_LITTLE, + + /* object_flags: mask of all file flags */ + (HAS_RELOC | EXEC_P | HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS + | DYNAMIC | WP_TEXT | D_PAGED), + + /* section_flags: mask of all section flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_READONLY + | SEC_CODE | SEC_DATA | SEC_DEBUGGING | SEC_EXCLUDE | SEC_SORT_ENTRIES + | SEC_ARCH_BIT_0 | SEC_SMALL_DATA | SEC_MERGE | SEC_STRINGS | SEC_GROUP), + + /* leading_symbol_char: is the first char of a user symbol + predictable, and if so what is it */ + elf_symbol_leading_char, + + /* ar_pad_char: pad character for filenames within an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and/or os and should be independently tunable */ + '/', + + /* ar_max_namelen: maximum number of characters in an archive header + FIXME: this really has nothing to do with ELF, this is a characteristic + of the archiver and should be independently tunable. The System V ABI, + Chapter 7 (Formats & Protocols), Archive section sets this as 15. */ + 15, + + /* Routines to byte-swap various sized integers from the data sections */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + /* Routines to byte-swap various sized integers from the file headers */ + bfd_getl64, bfd_getl_signed_64, bfd_putl64, + bfd_getl32, bfd_getl_signed_32, bfd_putl32, + bfd_getl16, bfd_getl_signed_16, bfd_putl16, + + /* bfd_check_format: check the format of a file being read */ + { _bfd_dummy_target, /* unknown format */ + bfd_elfNN_object_p, /* assembler/linker output (object file) */ + bfd_elfNN_archive_p, /* an archive */ + bfd_elfNN_core_file_p /* a core file */ + }, + + /* bfd_set_format: set the format of a file being written */ + { bfd_false, + bfd_elfNN_mkobject, + bfd_elfNN_mkarchive, + bfd_elfNN_mkcorefile + }, + + /* bfd_write_contents: write cached information into a file being written */ + { bfd_false, + bfd_elfNN_write_object_contents, + bfd_elfNN_write_archive_contents, + bfd_elfNN_write_corefile_contents, + }, + + BFD_JUMP_TABLE_GENERIC (bfd_elfNN), + BFD_JUMP_TABLE_COPY (bfd_elfNN), + BFD_JUMP_TABLE_CORE (bfd_elfNN), +#ifdef bfd_elfNN_archive_functions + BFD_JUMP_TABLE_ARCHIVE (bfd_elfNN_archive), +#else + BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff), +#endif + BFD_JUMP_TABLE_SYMBOLS (bfd_elfNN), + BFD_JUMP_TABLE_RELOCS (bfd_elfNN), + BFD_JUMP_TABLE_WRITE (bfd_elfNN), + BFD_JUMP_TABLE_LINK (bfd_elfNN), + BFD_JUMP_TABLE_DYNAMIC (bfd_elfNN), + + /* Alternative endian target. */ +#ifdef TARGET_BIG_SYM + & TARGET_BIG_SYM, +#else + NULL, +#endif + + /* backend_data: */ + (PTR) &elfNN_bed +}; +#endif diff --git a/contrib/binutils-2.14/bfd/format.c b/contrib/binutils-2.14/bfd/format.c new file mode 100644 index 0000000000..6415b8d57b --- /dev/null +++ b/contrib/binutils-2.14/bfd/format.c @@ -0,0 +1,444 @@ +/* Generic BFD support for file formats. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + File formats + + A format is a BFD concept of high level file contents type. The + formats supported by BFD are: + + o <> + + The BFD may contain data, symbols, relocations and debug info. + + o <> + + The BFD contains other BFDs and an optional index. + + o <> + + The BFD contains the result of an executable core dump. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* IMPORT from targets.c. */ +extern const size_t _bfd_target_vector_entries; + +/* +FUNCTION + bfd_check_format + +SYNOPSIS + bfd_boolean bfd_check_format (bfd *abfd, bfd_format format); + +DESCRIPTION + Verify if the file attached to the BFD @var{abfd} is compatible + with the format @var{format} (i.e., one of <>, + <> or <>). + + If the BFD has been set to a specific target before the + call, only the named target and format combination is + checked. If the target has not been set, or has been set to + <>, then all the known target backends is + interrogated to determine a match. If the default target + matches, it is used. If not, exactly one target must recognize + the file, or an error results. + + The function returns <> on success, otherwise <> + with one of the following error codes: + + o <> - + if <> is not one of <>, <> or + <>. + + o <> - + if an error occured during a read - even some file mismatches + can cause bfd_error_system_calls. + + o <> - + none of the backends recognised the file format. + + o <> - + more than one backend recognised the file format. +*/ + +bfd_boolean +bfd_check_format (abfd, format) + bfd *abfd; + bfd_format format; +{ + return bfd_check_format_matches (abfd, format, NULL); +} + +/* +FUNCTION + bfd_check_format_matches + +SYNOPSIS + bfd_boolean bfd_check_format_matches (bfd *abfd, bfd_format format, + char ***matching); + +DESCRIPTION + Like <>, except when it returns FALSE with + <> set to <>. In that + case, if @var{matching} is not NULL, it will be filled in with + a NULL-terminated list of the names of the formats that matched, + allocated with <>. + Then the user may choose a format and try again. + + When done with the list that @var{matching} points to, the caller + should free it. +*/ + +bfd_boolean +bfd_check_format_matches (abfd, format, matching) + bfd *abfd; + bfd_format format; + char ***matching; +{ + extern const bfd_target binary_vec; + const bfd_target * const *target; + const bfd_target **matching_vector = NULL; + const bfd_target *save_targ, *right_targ, *ar_right_targ; + int match_count; + int ar_match_index; + + if (!bfd_read_p (abfd) + || (unsigned int) abfd->format >= (unsigned int) bfd_type_end) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + if (abfd->format != bfd_unknown) + return abfd->format == format; + + /* Since the target type was defaulted, check them + all in the hope that one will be uniquely recognized. */ + save_targ = abfd->xvec; + match_count = 0; + ar_match_index = _bfd_target_vector_entries; + + if (matching) + { + bfd_size_type amt; + + *matching = NULL; + amt = sizeof (*matching_vector) * 2 * _bfd_target_vector_entries; + matching_vector = (const bfd_target **) bfd_malloc (amt); + if (!matching_vector) + return FALSE; + } + + right_targ = 0; + ar_right_targ = 0; + + /* Presume the answer is yes. */ + abfd->format = format; + + /* If the target type was explicitly specified, just check that target. */ + if (!abfd->target_defaulted) + { + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) /* rewind! */ + { + if (matching) + free ((PTR) matching_vector); + return FALSE; + } + + right_targ = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + + if (right_targ) + { + abfd->xvec = right_targ; /* Set the target as returned. */ + + if (matching) + free ((PTR) matching_vector); + + return TRUE; /* File position has moved, BTW. */ + } + + /* For a long time the code has dropped through to check all + targets if the specified target was wrong. I don't know why, + and I'm reluctant to change it. However, in the case of an + archive, it can cause problems. If the specified target does + not permit archives (e.g., the binary target), then we should + not allow some other target to recognize it as an archive, but + should instead allow the specified target to recognize it as an + object. When I first made this change, it broke the PE target, + because the specified pei-i386 target did not recognize the + actual pe-i386 archive. Since there may be other problems of + this sort, I changed this test to check only for the binary + target. */ + if (format == bfd_archive && save_targ == &binary_vec) + { + abfd->xvec = save_targ; + abfd->format = bfd_unknown; + + if (matching) + free ((PTR) matching_vector); + + bfd_set_error (bfd_error_file_not_recognized); + + return FALSE; + } + } + + for (target = bfd_target_vector; *target != NULL; target++) + { + const bfd_target *temp; + bfd_error_type err; + + if (*target == &binary_vec) + continue; + + abfd->xvec = *target; /* Change BFD's target temporarily. */ + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + { + if (matching) + free ((PTR) matching_vector); + return FALSE; + } + + /* If _bfd_check_format neglects to set bfd_error, assume + bfd_error_wrong_format. We didn't used to even pay any + attention to bfd_error, so I suspect that some + _bfd_check_format might have this problem. */ + bfd_set_error (bfd_error_wrong_format); + + temp = BFD_SEND_FMT (abfd, _bfd_check_format, (abfd)); + + if (temp) + { + /* This format checks out as ok! */ + right_targ = temp; + + /* If this is the default target, accept it, even if other + targets might match. People who want those other targets + have to set the GNUTARGET variable. */ + if (temp == bfd_default_vector[0]) + { + match_count = 1; + break; + } + + if (matching) + matching_vector[match_count] = temp; + + match_count++; + +#ifdef GNU960 + /* Big- and little-endian b.out archives look the same, but it + doesn't matter: there is no difference in their headers, and + member file byte orders will (I hope) be handled appropriately + by bfd. Ditto for big and little coff archives. And the 4 + coff/b.out object formats are unambiguous. So accept the + first match we find. */ + break; +#endif + } + else if ((err = bfd_get_error ()) == bfd_error_wrong_object_format + || err == bfd_error_file_ambiguously_recognized) + { + /* An archive with objects of the wrong type, or an + ambiguous match. We want this target to match if we get + no better matches. */ + if (ar_right_targ != bfd_default_vector[0]) + ar_right_targ = *target; + if (matching) + matching_vector[ar_match_index] = *target; + ar_match_index++; + } + else if (err != bfd_error_wrong_format) + { + abfd->xvec = save_targ; + abfd->format = bfd_unknown; + + if (matching) + free ((PTR) matching_vector); + + return FALSE; + } + } + + if (match_count == 0) + { + /* Try partial matches. */ + right_targ = ar_right_targ; + + if (right_targ == bfd_default_vector[0]) + { + match_count = 1; + } + else + { + match_count = ar_match_index - _bfd_target_vector_entries; + + if (matching && match_count > 1) + memcpy (matching_vector, + matching_vector + _bfd_target_vector_entries, + sizeof (*matching_vector) * match_count); + } + } + + if (match_count > 1 + && bfd_associated_vector != NULL + && matching) + { + const bfd_target * const *assoc = bfd_associated_vector; + + while ((right_targ = *assoc++) != NULL) + { + int i = match_count; + + while (--i >= 0) + if (matching_vector[i] == right_targ) + break; + + if (i >= 0) + { + match_count = 1; + break; + } + } + } + + if (match_count == 1) + { + abfd->xvec = right_targ; /* Change BFD's target permanently. */ + + if (matching) + free ((PTR) matching_vector); + + return TRUE; /* File position has moved, BTW. */ + } + + abfd->xvec = save_targ; /* Restore original target type. */ + abfd->format = bfd_unknown; /* Restore original format. */ + + if (match_count == 0) + { + bfd_set_error (bfd_error_file_not_recognized); + + if (matching) + free ((PTR) matching_vector); + } + else + { + bfd_set_error (bfd_error_file_ambiguously_recognized); + + if (matching) + { + *matching = (char **) matching_vector; + matching_vector[match_count] = NULL; + /* Return target names. This is a little nasty. Maybe we + should do another bfd_malloc? */ + while (--match_count >= 0) + { + const char *name = matching_vector[match_count]->name; + *(const char **) &matching_vector[match_count] = name; + } + } + } + + return FALSE; +} + +/* +FUNCTION + bfd_set_format + +SYNOPSIS + bfd_boolean bfd_set_format (bfd *abfd, bfd_format format); + +DESCRIPTION + This function sets the file format of the BFD @var{abfd} to the + format @var{format}. If the target set in the BFD does not + support the format requested, the format is invalid, or the BFD + is not open for writing, then an error occurs. +*/ + +bfd_boolean +bfd_set_format (abfd, format) + bfd *abfd; + bfd_format format; +{ + if (bfd_read_p (abfd) + || (unsigned int) abfd->format >= (unsigned int) bfd_type_end) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + if (abfd->format != bfd_unknown) + return abfd->format == format; + + /* Presume the answer is yes. */ + abfd->format = format; + + if (!BFD_SEND_FMT (abfd, _bfd_set_format, (abfd))) + { + abfd->format = bfd_unknown; + return FALSE; + } + + return TRUE; +} + +/* +FUNCTION + bfd_format_string + +SYNOPSIS + const char *bfd_format_string (bfd_format format); + +DESCRIPTION + Return a pointer to a const string + <>, <>, <>, <>, or <>, + depending upon the value of @var{format}. +*/ + +const char * +bfd_format_string (format) + bfd_format format; +{ + if (((int)format <(int) bfd_unknown) + || ((int)format >=(int) bfd_type_end)) + return "invalid"; + + switch (format) + { + case bfd_object: + return "object"; /* Linker/assember/compiler output. */ + case bfd_archive: + return "archive"; /* Object archive file. */ + case bfd_core: + return "core"; /* Core dump. */ + default: + return "unknown"; + } +} diff --git a/contrib/binutils-2.14/bfd/genlink.h b/contrib/binutils-2.14/bfd/genlink.h new file mode 100644 index 0000000000..bcdc34b156 --- /dev/null +++ b/contrib/binutils-2.14/bfd/genlink.h @@ -0,0 +1,111 @@ +/* genlink.h -- interface to the BFD generic linker + Copyright 1993, 1994, 1996, 2002 Free Software Foundation, Inc. + Written by Ian Lance Taylor, 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef GENLINK_H +#define GENLINK_H + +/* This header file is internal to BFD. It describes the internal + structures and functions used by the BFD generic linker, in case + any of the more specific linkers want to use or call them. Note + that some functions, such as _bfd_generic_link_hash_table_create, + are declared in libbfd.h, because they are expected to be widely + used. The functions and structures in this file will probably only + be used by a few files besides linker.c itself. In fact, this file + is not particularly complete; I have only put in the interfaces I + actually needed. */ + +/* The generic linker uses a hash table which is a derived class of + the standard linker hash table, just as the other backend specific + linkers do. Do not confuse the generic linker hash table with the + standard BFD linker hash table it is built upon. */ + +/* Generic linker hash table entries. */ + +struct generic_link_hash_entry +{ + struct bfd_link_hash_entry root; + /* Whether this symbol has been written out. */ + bfd_boolean written; + /* Symbol from input BFD. */ + asymbol *sym; +}; + +/* Generic linker hash table. */ + +struct generic_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Look up an entry in a generic link hash table. */ + +#define _bfd_generic_link_hash_lookup(table, string, create, copy, follow) \ + ((struct generic_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) + +/* Traverse a generic link hash table. */ + +#define _bfd_generic_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (bfd_boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the generic link hash table from the info structure. This is + just a cast. */ + +#define _bfd_generic_hash_table(p) \ + ((struct generic_link_hash_table *) ((p)->hash)) + +/* The generic linker reads in the asymbol structures for an input BFD + and keeps them in the outsymbol and symcount fields. */ + +#define _bfd_generic_link_get_symbols(abfd) ((abfd)->outsymbols) +#define _bfd_generic_link_get_symcount(abfd) ((abfd)->symcount) + +/* Add the symbols of input_bfd to the symbols being built for + output_bfd. */ +extern bfd_boolean _bfd_generic_link_output_symbols + PARAMS ((bfd *output_bfd, bfd *input_bfd, struct bfd_link_info *, + size_t *psymalloc)); + +/* This structure is used to pass information to + _bfd_generic_link_write_global_symbol, which may be called via + _bfd_generic_link_hash_traverse. */ + +struct generic_write_global_symbol_info +{ + struct bfd_link_info *info; + bfd *output_bfd; + size_t *psymalloc; +}; + +/* Write out a single global symbol. This is expected to be called + via _bfd_generic_link_hash_traverse. The second argument must + actually be a struct generic_write_global_symbol_info *. */ +extern bfd_boolean _bfd_generic_link_write_global_symbol + PARAMS ((struct generic_link_hash_entry *, PTR)); + +/* Generic link hash table entry creation routine. */ +struct bfd_hash_entry *_bfd_generic_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, + const char *)); + +#endif diff --git a/contrib/binutils-2.14/bfd/hash.c b/contrib/binutils-2.14/bfd/hash.c new file mode 100644 index 0000000000..8ae0c7a63e --- /dev/null +++ b/contrib/binutils-2.14/bfd/hash.c @@ -0,0 +1,735 @@ +/* hash.c -- hash table routines for BFD + Copyright 1993, 1994, 1995, 1997, 1999, 2001, 2002 + Free Software Foundation, Inc. + Written by Steve Chamberlain + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "objalloc.h" + +/* +SECTION + Hash Tables + +@cindex Hash tables + BFD provides a simple set of hash table functions. Routines + are provided to initialize a hash table, to free a hash table, + to look up a string in a hash table and optionally create an + entry for it, and to traverse a hash table. There is + currently no routine to delete an string from a hash table. + + The basic hash table does not permit any data to be stored + with a string. However, a hash table is designed to present a + base class from which other types of hash tables may be + derived. These derived types may store additional information + with the string. Hash tables were implemented in this way, + rather than simply providing a data pointer in a hash table + entry, because they were designed for use by the linker back + ends. The linker may create thousands of hash table entries, + and the overhead of allocating private data and storing and + following pointers becomes noticeable. + + The basic hash table code is in <>. + +@menu +@* Creating and Freeing a Hash Table:: +@* Looking Up or Entering a String:: +@* Traversing a Hash Table:: +@* Deriving a New Hash Table Type:: +@end menu + +INODE +Creating and Freeing a Hash Table, Looking Up or Entering a String, Hash Tables, Hash Tables +SUBSECTION + Creating and freeing a hash table + +@findex bfd_hash_table_init +@findex bfd_hash_table_init_n + To create a hash table, create an instance of a <> (defined in <>) and call + <> (if you know approximately how many + entries you will need, the function <>, + which takes a @var{size} argument, may be used). + <> returns <> if some sort of + error occurs. + +@findex bfd_hash_newfunc + The function <> take as an argument a + function to use to create new entries. For a basic hash + table, use the function <>. @xref{Deriving + a New Hash Table Type}, for why you would want to use a + different value for this argument. + +@findex bfd_hash_allocate + <> will create an objalloc which will be + used to allocate new entries. You may allocate memory on this + objalloc using <>. + +@findex bfd_hash_table_free + Use <> to free up all the memory that has + been allocated for a hash table. This will not free up the + <> itself, which you must provide. + +INODE +Looking Up or Entering a String, Traversing a Hash Table, Creating and Freeing a Hash Table, Hash Tables +SUBSECTION + Looking up or entering a string + +@findex bfd_hash_lookup + The function <> is used both to look up a + string in the hash table and to create a new entry. + + If the @var{create} argument is <>, <> + will look up a string. If the string is found, it will + returns a pointer to a <>. If the + string is not found in the table <> will + return <>. You should not modify any of the fields in + the returns <>. + + If the @var{create} argument is <>, the string will be + entered into the hash table if it is not already there. + Either way a pointer to a <> will be + returned, either to the existing structure or to a newly + created one. In this case, a <> return means that an + error occurred. + + If the @var{create} argument is <>, and a new entry is + created, the @var{copy} argument is used to decide whether to + copy the string onto the hash table objalloc or not. If + @var{copy} is passed as <>, you must be careful not to + deallocate or modify the string as long as the hash table + exists. + +INODE +Traversing a Hash Table, Deriving a New Hash Table Type, Looking Up or Entering a String, Hash Tables +SUBSECTION + Traversing a hash table + +@findex bfd_hash_traverse + The function <> may be used to traverse a + hash table, calling a function on each element. The traversal + is done in a random order. + + <> takes as arguments a function and a + generic <> pointer. The function is called with a + hash table entry (a <>) and the + generic pointer passed to <>. The function + must return a <> value, which indicates whether to + continue traversing the hash table. If the function returns + <>, <> will stop the traversal and + return immediately. + +INODE +Deriving a New Hash Table Type, , Traversing a Hash Table, Hash Tables +SUBSECTION + Deriving a new hash table type + + Many uses of hash tables want to store additional information + which each entry in the hash table. Some also find it + convenient to store additional information with the hash table + itself. This may be done using a derived hash table. + + Since C is not an object oriented language, creating a derived + hash table requires sticking together some boilerplate + routines with a few differences specific to the type of hash + table you want to create. + + An example of a derived hash table is the linker hash table. + The structures for this are defined in <>. The + functions are in <>. + + You may also derive a hash table from an already derived hash + table. For example, the a.out linker backend code uses a hash + table derived from the linker hash table. + +@menu +@* Define the Derived Structures:: +@* Write the Derived Creation Routine:: +@* Write Other Derived Routines:: +@end menu + +INODE +Define the Derived Structures, Write the Derived Creation Routine, Deriving a New Hash Table Type, Deriving a New Hash Table Type +SUBSUBSECTION + Define the derived structures + + You must define a structure for an entry in the hash table, + and a structure for the hash table itself. + + The first field in the structure for an entry in the hash + table must be of the type used for an entry in the hash table + you are deriving from. If you are deriving from a basic hash + table this is <>, which is defined in + <>. The first field in the structure for the hash + table itself must be of the type of the hash table you are + deriving from itself. If you are deriving from a basic hash + table, this is <>. + + For example, the linker hash table defines <> (in <>). The first field, + <>, is of type <>. Similarly, + the first field in <>, <>, + is of type <>. + +INODE +Write the Derived Creation Routine, Write Other Derived Routines, Define the Derived Structures, Deriving a New Hash Table Type +SUBSUBSECTION + Write the derived creation routine + + You must write a routine which will create and initialize an + entry in the hash table. This routine is passed as the + function argument to <>. + + In order to permit other hash tables to be derived from the + hash table you are creating, this routine must be written in a + standard way. + + The first argument to the creation routine is a pointer to a + hash table entry. This may be <>, in which case the + routine should allocate the right amount of space. Otherwise + the space has already been allocated by a hash table type + derived from this one. + + After allocating space, the creation routine must call the + creation routine of the hash table type it is derived from, + passing in a pointer to the space it just allocated. This + will initialize any fields used by the base hash table. + + Finally the creation routine must initialize any local fields + for the new hash table type. + + Here is a boilerplate example of a creation routine. + @var{function_name} is the name of the routine. + @var{entry_type} is the type of an entry in the hash table you + are creating. @var{base_newfunc} is the name of the creation + routine of the hash table type your hash table is derived + from. + +EXAMPLE + +.struct bfd_hash_entry * +.@var{function_name} (entry, table, string) +. struct bfd_hash_entry *entry; +. struct bfd_hash_table *table; +. const char *string; +.{ +. struct @var{entry_type} *ret = (@var{entry_type} *) entry; +. +. {* Allocate the structure if it has not already been allocated by a +. derived class. *} +. if (ret == (@var{entry_type} *) NULL) +. { +. ret = ((@var{entry_type} *) +. bfd_hash_allocate (table, sizeof (@var{entry_type}))); +. if (ret == (@var{entry_type} *) NULL) +. return NULL; +. } +. +. {* Call the allocation method of the base class. *} +. ret = ((@var{entry_type} *) +. @var{base_newfunc} ((struct bfd_hash_entry *) ret, table, string)); +. +. {* Initialize the local fields here. *} +. +. return (struct bfd_hash_entry *) ret; +.} + +DESCRIPTION + The creation routine for the linker hash table, which is in + <>, looks just like this example. + @var{function_name} is <<_bfd_link_hash_newfunc>>. + @var{entry_type} is <>. + @var{base_newfunc} is <>, the creation + routine for a basic hash table. + + <<_bfd_link_hash_newfunc>> also initializes the local fields + in a linker hash table entry: <>, <> and + <>. + +INODE +Write Other Derived Routines, , Write the Derived Creation Routine, Deriving a New Hash Table Type +SUBSUBSECTION + Write other derived routines + + You will want to write other routines for your new hash table, + as well. + + You will want an initialization routine which calls the + initialization routine of the hash table you are deriving from + and initializes any other local fields. For the linker hash + table, this is <<_bfd_link_hash_table_init>> in <>. + + You will want a lookup routine which calls the lookup routine + of the hash table you are deriving from and casts the result. + The linker hash table uses <> in + <> (this actually takes an additional argument which + it uses to decide how to return the looked up value). + + You may want a traversal routine. This should just call the + traversal routine of the hash table you are deriving from with + appropriate casts. The linker hash table uses + <> in <>. + + These routines may simply be defined as macros. For example, + the a.out backend linker hash table, which is derived from the + linker hash table, uses macros for the lookup and traversal + routines. These are <> and + <> in aoutx.h. +*/ + +/* The default number of entries to use when creating a hash table. */ +#define DEFAULT_SIZE (4051) + +/* Create a new hash table, given a number of entries. */ + +bfd_boolean +bfd_hash_table_init_n (table, newfunc, size) + struct bfd_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); + unsigned int size; +{ + unsigned int alloc; + + alloc = size * sizeof (struct bfd_hash_entry *); + + table->memory = (PTR) objalloc_create (); + if (table->memory == NULL) + { + bfd_set_error (bfd_error_no_memory); + return FALSE; + } + table->table = ((struct bfd_hash_entry **) + objalloc_alloc ((struct objalloc *) table->memory, alloc)); + if (table->table == NULL) + { + bfd_set_error (bfd_error_no_memory); + return FALSE; + } + memset ((PTR) table->table, 0, alloc); + table->size = size; + table->newfunc = newfunc; + return TRUE; +} + +/* Create a new hash table with the default number of entries. */ + +bfd_boolean +bfd_hash_table_init (table, newfunc) + struct bfd_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return bfd_hash_table_init_n (table, newfunc, DEFAULT_SIZE); +} + +/* Free a hash table. */ + +void +bfd_hash_table_free (table) + struct bfd_hash_table *table; +{ + objalloc_free ((struct objalloc *) table->memory); + table->memory = NULL; +} + +/* Look up a string in a hash table. */ + +struct bfd_hash_entry * +bfd_hash_lookup (table, string, create, copy) + struct bfd_hash_table *table; + const char *string; + bfd_boolean create; + bfd_boolean copy; +{ + register const unsigned char *s; + register unsigned long hash; + register unsigned int c; + struct bfd_hash_entry *hashp; + unsigned int len; + unsigned int index; + + hash = 0; + len = 0; + s = (const unsigned char *) string; + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + } + len = (s - (const unsigned char *) string) - 1; + hash += len + (len << 17); + hash ^= hash >> 2; + + index = hash % table->size; + for (hashp = table->table[index]; + hashp != (struct bfd_hash_entry *) NULL; + hashp = hashp->next) + { + if (hashp->hash == hash + && strcmp (hashp->string, string) == 0) + return hashp; + } + + if (! create) + return (struct bfd_hash_entry *) NULL; + + hashp = (*table->newfunc) ((struct bfd_hash_entry *) NULL, table, string); + if (hashp == (struct bfd_hash_entry *) NULL) + return (struct bfd_hash_entry *) NULL; + if (copy) + { + char *new; + + new = (char *) objalloc_alloc ((struct objalloc *) table->memory, + len + 1); + if (!new) + { + bfd_set_error (bfd_error_no_memory); + return (struct bfd_hash_entry *) NULL; + } + memcpy (new, string, len + 1); + string = new; + } + hashp->string = string; + hashp->hash = hash; + hashp->next = table->table[index]; + table->table[index] = hashp; + + return hashp; +} + +/* Replace an entry in a hash table. */ + +void +bfd_hash_replace (table, old, nw) + struct bfd_hash_table *table; + struct bfd_hash_entry *old; + struct bfd_hash_entry *nw; +{ + unsigned int index; + struct bfd_hash_entry **pph; + + index = old->hash % table->size; + for (pph = &table->table[index]; + (*pph) != (struct bfd_hash_entry *) NULL; + pph = &(*pph)->next) + { + if (*pph == old) + { + *pph = nw; + return; + } + } + + abort (); +} + +/* Base method for creating a new hash table entry. */ + +/*ARGSUSED*/ +struct bfd_hash_entry * +bfd_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string ATTRIBUTE_UNUSED; +{ + if (entry == (struct bfd_hash_entry *) NULL) + entry = ((struct bfd_hash_entry *) + bfd_hash_allocate (table, sizeof (struct bfd_hash_entry))); + return entry; +} + +/* Allocate space in a hash table. */ + +PTR +bfd_hash_allocate (table, size) + struct bfd_hash_table *table; + unsigned int size; +{ + PTR ret; + + ret = objalloc_alloc ((struct objalloc *) table->memory, size); + if (ret == NULL && size != 0) + bfd_set_error (bfd_error_no_memory); + return ret; +} + +/* Traverse a hash table. */ + +void +bfd_hash_traverse (table, func, info) + struct bfd_hash_table *table; + bfd_boolean (*func) PARAMS ((struct bfd_hash_entry *, PTR)); + PTR info; +{ + unsigned int i; + + for (i = 0; i < table->size; i++) + { + struct bfd_hash_entry *p; + + for (p = table->table[i]; p != NULL; p = p->next) + { + if (! (*func) (p, info)) + return; + } + } +} + +/* A few different object file formats (a.out, COFF, ELF) use a string + table. These functions support adding strings to a string table, + returning the byte offset, and writing out the table. + + Possible improvements: + + look for strings matching trailing substrings of other strings + + better data structures? balanced trees? + + look at reducing memory use elsewhere -- maybe if we didn't have + to construct the entire symbol table at once, we could get by + with smaller amounts of VM? (What effect does that have on the + string table reductions?) */ + +/* An entry in the strtab hash table. */ + +struct strtab_hash_entry +{ + struct bfd_hash_entry root; + /* Index in string table. */ + bfd_size_type index; + /* Next string in strtab. */ + struct strtab_hash_entry *next; +}; + +/* The strtab hash table. */ + +struct bfd_strtab_hash +{ + struct bfd_hash_table table; + /* Size of strtab--also next available index. */ + bfd_size_type size; + /* First string in strtab. */ + struct strtab_hash_entry *first; + /* Last string in strtab. */ + struct strtab_hash_entry *last; + /* Whether to precede strings with a two byte length, as in the + XCOFF .debug section. */ + bfd_boolean xcoff; +}; + +static struct bfd_hash_entry *strtab_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + +/* Routine to create an entry in a strtab. */ + +static struct bfd_hash_entry * +strtab_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct strtab_hash_entry *) NULL) + ret = ((struct strtab_hash_entry *) + bfd_hash_allocate (table, sizeof (struct strtab_hash_entry))); + if (ret == (struct strtab_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct strtab_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->index = (bfd_size_type) -1; + ret->next = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in an strtab. */ + +#define strtab_hash_lookup(t, string, create, copy) \ + ((struct strtab_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* Create a new strtab. */ + +struct bfd_strtab_hash * +_bfd_stringtab_init () +{ + struct bfd_strtab_hash *table; + bfd_size_type amt = sizeof (struct bfd_strtab_hash); + + table = (struct bfd_strtab_hash *) bfd_malloc (amt); + if (table == NULL) + return NULL; + + if (! bfd_hash_table_init (&table->table, strtab_hash_newfunc)) + { + free (table); + return NULL; + } + + table->size = 0; + table->first = NULL; + table->last = NULL; + table->xcoff = FALSE; + + return table; +} + +/* Create a new strtab in which the strings are output in the format + used in the XCOFF .debug section: a two byte length precedes each + string. */ + +struct bfd_strtab_hash * +_bfd_xcoff_stringtab_init () +{ + struct bfd_strtab_hash *ret; + + ret = _bfd_stringtab_init (); + if (ret != NULL) + ret->xcoff = TRUE; + return ret; +} + +/* Free a strtab. */ + +void +_bfd_stringtab_free (table) + struct bfd_strtab_hash *table; +{ + bfd_hash_table_free (&table->table); + free (table); +} + +/* Get the index of a string in a strtab, adding it if it is not + already present. If HASH is FALSE, we don't really use the hash + table, and we don't eliminate duplicate strings. */ + +bfd_size_type +_bfd_stringtab_add (tab, str, hash, copy) + struct bfd_strtab_hash *tab; + const char *str; + bfd_boolean hash; + bfd_boolean copy; +{ + register struct strtab_hash_entry *entry; + + if (hash) + { + entry = strtab_hash_lookup (tab, str, TRUE, copy); + if (entry == NULL) + return (bfd_size_type) -1; + } + else + { + entry = ((struct strtab_hash_entry *) + bfd_hash_allocate (&tab->table, + sizeof (struct strtab_hash_entry))); + if (entry == NULL) + return (bfd_size_type) -1; + if (! copy) + entry->root.string = str; + else + { + char *n; + + n = (char *) bfd_hash_allocate (&tab->table, strlen (str) + 1); + if (n == NULL) + return (bfd_size_type) -1; + entry->root.string = n; + } + entry->index = (bfd_size_type) -1; + entry->next = NULL; + } + + if (entry->index == (bfd_size_type) -1) + { + entry->index = tab->size; + tab->size += strlen (str) + 1; + if (tab->xcoff) + { + entry->index += 2; + tab->size += 2; + } + if (tab->first == NULL) + tab->first = entry; + else + tab->last->next = entry; + tab->last = entry; + } + + return entry->index; +} + +/* Get the number of bytes in a strtab. */ + +bfd_size_type +_bfd_stringtab_size (tab) + struct bfd_strtab_hash *tab; +{ + return tab->size; +} + +/* Write out a strtab. ABFD must already be at the right location in + the file. */ + +bfd_boolean +_bfd_stringtab_emit (abfd, tab) + register bfd *abfd; + struct bfd_strtab_hash *tab; +{ + register bfd_boolean xcoff; + register struct strtab_hash_entry *entry; + + xcoff = tab->xcoff; + + for (entry = tab->first; entry != NULL; entry = entry->next) + { + const char *str; + size_t len; + + str = entry->root.string; + len = strlen (str) + 1; + + if (xcoff) + { + bfd_byte buf[2]; + + /* The output length includes the null byte. */ + bfd_put_16 (abfd, (bfd_vma) len, buf); + if (bfd_bwrite ((PTR) buf, (bfd_size_type) 2, abfd) != 2) + return FALSE; + } + + if (bfd_bwrite ((PTR) str, (bfd_size_type) len, abfd) != len) + return FALSE; + } + + return TRUE; +} diff --git a/contrib/binutils-2.14/bfd/ihex.c b/contrib/binutils-2.14/bfd/ihex.c new file mode 100644 index 0000000000..2f4aa569f4 --- /dev/null +++ b/contrib/binutils-2.14/bfd/ihex.c @@ -0,0 +1,1052 @@ +/* BFD back-end for Intel Hex objects. + Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + Written by Ian Lance Taylor of 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This is what Intel Hex files look like: + +1. INTEL FORMATS + +A. Intel 1 + + 16-bit address-field format, for files 64k bytes in length or less. + + DATA RECORD + Byte 1 Header = colon(:) + 2..3 The number of data bytes in hex notation + 4..5 High byte of the record load address + 6..7 Low byte of the record load address + 8..9 Record type, must be "00" + 10..x Data bytes in hex notation: + x = (number of bytes - 1) * 2 + 11 + x+1..x+2 Checksum in hex notation + x+3..x+4 Carriage return, line feed + + END RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "00" + 4..7 Transfer-address (usually "0000") + the jump-to address, execution start address + 8..9 Record type, must be "01" + 10..11 Checksum, in hex notation + 12..13 Carriage return, line feed + +B. INTEL 2 + + MCS-86 format, using a 20-bit address for files larger than 64K bytes. + + DATA RECORD + Byte 1 Header = colon (:) + 2..3 The byte count of this record, hex notation + 4..5 High byte of the record load address + 6..7 Low byte of the record load address + 8..9 Record type, must be "00" + 10..x The data bytes in hex notation: + x = (number of data bytes - 1) * 2 + 11 + x+1..x+2 Checksum in hex notation + x+3..x+4 Carriage return, line feed + + EXTENDED ADDRESS RECORD + Byte 1 Header = colon(:) + 2..3 The byte count, must be "02" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "02" + 10..11 High byte of the offset address + 12..13 Low byte of the offset address + 14..15 Checksum in hex notation + 16..17 Carriage return, line feed + + The checksums are the two's complement of the 8-bit sum + without carry of the byte count, offset address, and the + record type. + + START ADDRESS RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "04" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "03" + 10..13 8086 CS value + 14..17 8086 IP value + 18..19 Checksum in hex notation + 20..21 Carriage return, line feed + +Another document reports these additional types: + + EXTENDED LINEAR ADDRESS RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "02" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "04" + 10..13 Upper 16 bits of address of subsequent records + 14..15 Checksum in hex notation + 16..17 Carriage return, line feed + + START LINEAR ADDRESS RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "02" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "05" + 10..13 Upper 16 bits of start address + 14..15 Checksum in hex notation + 16..17 Carriage return, line feed + +The MRI compiler uses this, which is a repeat of type 5: + + EXTENDED START RECORD + Byte 1 Header = colon (:) + 2..3 The byte count, must be "04" + 4..7 Load address, must be "0000" + 8..9 Record type, must be "05" + 10..13 Upper 16 bits of start address + 14..17 Lower 16 bits of start address + 18..19 Checksum in hex notation + 20..21 Carriage return, line feed +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libiberty.h" +#include "safe-ctype.h" + +static void ihex_init + PARAMS ((void)); +static bfd_boolean ihex_mkobject + PARAMS ((bfd *)); +static INLINE int ihex_get_byte + PARAMS ((bfd *, bfd_boolean *)); +static void ihex_bad_byte + PARAMS ((bfd *, unsigned int, int, bfd_boolean)); +static bfd_boolean ihex_scan + PARAMS ((bfd *)); +static const bfd_target *ihex_object_p + PARAMS ((bfd *)); +static bfd_boolean ihex_read_section + PARAMS ((bfd *, asection *, bfd_byte *)); +static bfd_boolean ihex_get_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static bfd_boolean ihex_set_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static bfd_boolean ihex_write_record + PARAMS ((bfd *, size_t, unsigned int, unsigned int, bfd_byte *)); +static bfd_boolean ihex_write_object_contents + PARAMS ((bfd *)); +static bfd_boolean ihex_set_arch_mach + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); +static int ihex_sizeof_headers + PARAMS ((bfd *, bfd_boolean)); + +/* The number of bytes we put on one line during output. */ + +#define CHUNK 16 + +/* Macros for converting between hex and binary. */ + +#define NIBBLE(x) (hex_value (x)) +#define HEX2(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1])) +#define HEX4(buffer) ((HEX2 (buffer) << 8) + HEX2 ((buffer) + 2)) +#define ISHEX(x) (hex_p (x)) + +/* When we write out an ihex value, the values can not be output as + they are seen. Instead, we hold them in memory in this structure. */ + +struct ihex_data_list +{ + struct ihex_data_list *next; + bfd_byte *data; + bfd_vma where; + bfd_size_type size; +}; + +/* The ihex tdata information. */ + +struct ihex_data_struct +{ + struct ihex_data_list *head; + struct ihex_data_list *tail; +}; + +/* Initialize by filling in the hex conversion array. */ + +static void +ihex_init () +{ + static bfd_boolean inited; + + if (! inited) + { + inited = TRUE; + hex_init (); + } +} + +/* Create an ihex object. */ + +static bfd_boolean +ihex_mkobject (abfd) + bfd *abfd; +{ + struct ihex_data_struct *tdata; + bfd_size_type amt = sizeof (struct ihex_data_struct); + + tdata = (struct ihex_data_struct *) bfd_alloc (abfd, amt); + if (tdata == NULL) + return FALSE; + + abfd->tdata.ihex_data = tdata; + tdata->head = NULL; + tdata->tail = NULL; + return TRUE; +} + +/* Read a byte from a BFD. Set *ERRORPTR if an error occurred. + Return EOF on error or end of file. */ + +static INLINE int +ihex_get_byte (abfd, errorptr) + bfd *abfd; + bfd_boolean *errorptr; +{ + bfd_byte c; + + if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1) + { + if (bfd_get_error () != bfd_error_file_truncated) + *errorptr = TRUE; + return EOF; + } + + return (int) (c & 0xff); +} + +/* Report a problem in an Intel Hex file. */ + +static void +ihex_bad_byte (abfd, lineno, c, error) + bfd *abfd; + unsigned int lineno; + int c; + bfd_boolean error; +{ + if (c == EOF) + { + if (! error) + bfd_set_error (bfd_error_file_truncated); + } + else + { + char buf[10]; + + if (! ISPRINT (c)) + sprintf (buf, "\\%03o", (unsigned int) c); + else + { + buf[0] = c; + buf[1] = '\0'; + } + (*_bfd_error_handler) + (_("%s:%d: unexpected character `%s' in Intel Hex file\n"), + bfd_archive_filename (abfd), lineno, buf); + bfd_set_error (bfd_error_bad_value); + } +} + +/* Read an Intel hex file and turn it into sections. We create a new + section for each contiguous set of bytes. */ + +static bfd_boolean +ihex_scan (abfd) + bfd *abfd; +{ + bfd_vma segbase; + bfd_vma extbase; + asection *sec; + unsigned int lineno; + bfd_boolean error; + bfd_byte *buf = NULL; + size_t bufsize; + int c; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + goto error_return; + + abfd->start_address = 0; + + segbase = 0; + extbase = 0; + sec = NULL; + lineno = 1; + error = FALSE; + bufsize = 0; + + while ((c = ihex_get_byte (abfd, &error)) != EOF) + { + if (c == '\r') + continue; + else if (c == '\n') + { + ++lineno; + continue; + } + else if (c != ':') + { + ihex_bad_byte (abfd, lineno, c, error); + goto error_return; + } + else + { + file_ptr pos; + char hdr[8]; + unsigned int i; + unsigned int len; + bfd_vma addr; + unsigned int type; + unsigned int chars; + unsigned int chksum; + + /* This is a data record. */ + pos = bfd_tell (abfd) - 1; + + /* Read the header bytes. */ + if (bfd_bread (hdr, (bfd_size_type) 8, abfd) != 8) + goto error_return; + + for (i = 0; i < 8; i++) + { + if (! ISHEX (hdr[i])) + { + ihex_bad_byte (abfd, lineno, hdr[i], error); + goto error_return; + } + } + + len = HEX2 (hdr); + addr = HEX4 (hdr + 2); + type = HEX2 (hdr + 6); + + /* Read the data bytes. */ + chars = len * 2 + 2; + if (chars >= bufsize) + { + buf = (bfd_byte *) bfd_realloc (buf, (bfd_size_type) chars); + if (buf == NULL) + goto error_return; + bufsize = chars; + } + + if (bfd_bread (buf, (bfd_size_type) chars, abfd) != chars) + goto error_return; + + for (i = 0; i < chars; i++) + { + if (! ISHEX (buf[i])) + { + ihex_bad_byte (abfd, lineno, hdr[i], error); + goto error_return; + } + } + + /* Check the checksum. */ + chksum = len + addr + (addr >> 8) + type; + for (i = 0; i < len; i++) + chksum += HEX2 (buf + 2 * i); + if (((- chksum) & 0xff) != (unsigned int) HEX2 (buf + 2 * i)) + { + (*_bfd_error_handler) + (_("%s:%u: bad checksum in Intel Hex file (expected %u, found %u)"), + bfd_archive_filename (abfd), lineno, + (- chksum) & 0xff, (unsigned int) HEX2 (buf + 2 * i)); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + switch (type) + { + case 0: + /* This is a data record. */ + if (sec != NULL + && sec->vma + sec->_raw_size == extbase + segbase + addr) + { + /* This data goes at the end of the section we are + currently building. */ + sec->_raw_size += len; + } + else if (len > 0) + { + char secbuf[20]; + char *secname; + bfd_size_type amt; + + sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1); + amt = strlen (secbuf) + 1; + secname = (char *) bfd_alloc (abfd, amt); + if (secname == NULL) + goto error_return; + strcpy (secname, secbuf); + sec = bfd_make_section (abfd, secname); + if (sec == NULL) + goto error_return; + sec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; + sec->vma = extbase + segbase + addr; + sec->lma = extbase + segbase + addr; + sec->_raw_size = len; + sec->filepos = pos; + } + break; + + case 1: + /* An end record. */ + if (abfd->start_address == 0) + abfd->start_address = addr; + if (buf != NULL) + free (buf); + return TRUE; + + case 2: + /* An extended address record. */ + if (len != 2) + { + (*_bfd_error_handler) + (_("%s:%u: bad extended address record length in Intel Hex file"), + bfd_archive_filename (abfd), lineno); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + segbase = HEX4 (buf) << 4; + + sec = NULL; + + break; + + case 3: + /* An extended start address record. */ + if (len != 4) + { + (*_bfd_error_handler) + (_("%s:%u: bad extended start address length in Intel Hex file"), + bfd_archive_filename (abfd), lineno); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + abfd->start_address += (HEX4 (buf) << 4) + HEX4 (buf + 4); + + sec = NULL; + + break; + + case 4: + /* An extended linear address record. */ + if (len != 2) + { + (*_bfd_error_handler) + (_("%s:%u: bad extended linear address record length in Intel Hex file"), + bfd_archive_filename (abfd), lineno); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + extbase = HEX4 (buf) << 16; + + sec = NULL; + + break; + + case 5: + /* An extended linear start address record. */ + if (len != 2 && len != 4) + { + (*_bfd_error_handler) + (_("%s:%u: bad extended linear start address length in Intel Hex file"), + bfd_archive_filename (abfd), lineno); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + if (len == 2) + abfd->start_address += HEX4 (buf) << 16; + else + abfd->start_address = (HEX4 (buf) << 16) + HEX4 (buf + 4); + + sec = NULL; + + break; + + default: + (*_bfd_error_handler) + (_("%s:%u: unrecognized ihex type %u in Intel Hex file\n"), + bfd_archive_filename (abfd), lineno, type); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + } + } + + if (error) + goto error_return; + + if (buf != NULL) + free (buf); + + return TRUE; + + error_return: + if (buf != NULL) + free (buf); + return FALSE; +} + +/* Try to recognize an Intel Hex file. */ + +static const bfd_target * +ihex_object_p (abfd) + bfd *abfd; +{ + PTR tdata_save; + bfd_byte b[9]; + unsigned int i; + unsigned int type; + + ihex_init (); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + return NULL; + if (bfd_bread (b, (bfd_size_type) 9, abfd) != 9) + { + if (bfd_get_error () == bfd_error_file_truncated) + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + if (b[0] != ':') + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + for (i = 1; i < 9; i++) + { + if (! ISHEX (b[i])) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + } + + type = HEX2 (b + 7); + if (type > 5) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + /* OK, it looks like it really is an Intel Hex file. */ + tdata_save = abfd->tdata.any; + if (! ihex_mkobject (abfd) || ! ihex_scan (abfd)) + { + if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) + bfd_release (abfd, abfd->tdata.any); + abfd->tdata.any = tdata_save; + return NULL; + } + + return abfd->xvec; +} + +/* Read the contents of a section in an Intel Hex file. */ + +static bfd_boolean +ihex_read_section (abfd, section, contents) + bfd *abfd; + asection *section; + bfd_byte *contents; +{ + int c; + bfd_byte *p; + bfd_byte *buf = NULL; + size_t bufsize; + bfd_boolean error; + + if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0) + goto error_return; + + p = contents; + bufsize = 0; + error = FALSE; + while ((c = ihex_get_byte (abfd, &error)) != EOF) + { + char hdr[8]; + unsigned int len; + bfd_vma addr; + unsigned int type; + unsigned int i; + + if (c == '\r' || c == '\n') + continue; + + /* This is called after ihex_scan has succeeded, so we ought to + know the exact format. */ + BFD_ASSERT (c == ':'); + + if (bfd_bread (hdr, (bfd_size_type) 8, abfd) != 8) + goto error_return; + + len = HEX2 (hdr); + addr = HEX4 (hdr + 2); + type = HEX2 (hdr + 6); + + /* We should only see type 0 records here. */ + if (type != 0) + { + (*_bfd_error_handler) + (_("%s: internal error in ihex_read_section"), + bfd_archive_filename (abfd)); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + if (len * 2 > bufsize) + { + buf = (bfd_byte *) bfd_realloc (buf, (bfd_size_type) len * 2); + if (buf == NULL) + goto error_return; + bufsize = len * 2; + } + + if (bfd_bread (buf, (bfd_size_type) len * 2, abfd) != len * 2) + goto error_return; + + for (i = 0; i < len; i++) + *p++ = HEX2 (buf + 2 * i); + if ((bfd_size_type) (p - contents) >= section->_raw_size) + { + /* We've read everything in the section. */ + if (buf != NULL) + free (buf); + return TRUE; + } + + /* Skip the checksum. */ + if (bfd_bread (buf, (bfd_size_type) 2, abfd) != 2) + goto error_return; + } + + if ((bfd_size_type) (p - contents) < section->_raw_size) + { + (*_bfd_error_handler) + (_("%s: bad section length in ihex_read_section"), + bfd_archive_filename (abfd)); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + + if (buf != NULL) + free (buf); + + return TRUE; + + error_return: + if (buf != NULL) + free (buf); + return FALSE; +} + +/* Get the contents of a section in an Intel Hex file. */ + +static bfd_boolean +ihex_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (section->used_by_bfd == NULL) + { + section->used_by_bfd = bfd_alloc (abfd, section->_raw_size); + if (section->used_by_bfd == NULL) + return FALSE; + if (! ihex_read_section (abfd, section, section->used_by_bfd)) + return FALSE; + } + + memcpy (location, (bfd_byte *) section->used_by_bfd + offset, + (size_t) count); + + return TRUE; +} + +/* Set the contents of a section in an Intel Hex file. */ + +static bfd_boolean +ihex_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + struct ihex_data_list *n; + bfd_byte *data; + struct ihex_data_struct *tdata; + bfd_size_type amt; + + if (count == 0 + || (section->flags & SEC_ALLOC) == 0 + || (section->flags & SEC_LOAD) == 0) + return TRUE; + + amt = sizeof (struct ihex_data_list); + n = (struct ihex_data_list *) bfd_alloc (abfd, amt); + if (n == NULL) + return FALSE; + + data = (bfd_byte *) bfd_alloc (abfd, count); + if (data == NULL) + return FALSE; + memcpy (data, location, (size_t) count); + + n->data = data; + n->where = section->lma + offset; + n->size = count; + + /* Sort the records by address. Optimize for the common case of + adding a record to the end of the list. */ + tdata = abfd->tdata.ihex_data; + if (tdata->tail != NULL + && n->where >= tdata->tail->where) + { + tdata->tail->next = n; + n->next = NULL; + tdata->tail = n; + } + else + { + register struct ihex_data_list **pp; + + for (pp = &tdata->head; + *pp != NULL && (*pp)->where < n->where; + pp = &(*pp)->next) + ; + n->next = *pp; + *pp = n; + if (n->next == NULL) + tdata->tail = n; + } + + return TRUE; +} + +/* Write a record out to an Intel Hex file. */ + +static bfd_boolean +ihex_write_record (abfd, count, addr, type, data) + bfd *abfd; + size_t count; + unsigned int addr; + unsigned int type; + bfd_byte *data; +{ + static const char digs[] = "0123456789ABCDEF"; + char buf[9 + CHUNK * 2 + 4]; + char *p; + unsigned int chksum; + unsigned int i; + size_t total; + +#define TOHEX(buf, v) \ + ((buf)[0] = digs[((v) >> 4) & 0xf], (buf)[1] = digs[(v) & 0xf]) + + buf[0] = ':'; + TOHEX (buf + 1, count); + TOHEX (buf + 3, (addr >> 8) & 0xff); + TOHEX (buf + 5, addr & 0xff); + TOHEX (buf + 7, type); + + chksum = count + addr + (addr >> 8) + type; + + for (i = 0, p = buf + 9; i < count; i++, p += 2, data++) + { + TOHEX (p, *data); + chksum += *data; + } + + TOHEX (p, (- chksum) & 0xff); + p[2] = '\r'; + p[3] = '\n'; + + total = 9 + count * 2 + 4; + if (bfd_bwrite (buf, (bfd_size_type) total, abfd) != total) + return FALSE; + + return TRUE; +} + +/* Write out an Intel Hex file. */ + +static bfd_boolean +ihex_write_object_contents (abfd) + bfd *abfd; +{ + bfd_vma segbase; + bfd_vma extbase; + struct ihex_data_list *l; + + segbase = 0; + extbase = 0; + for (l = abfd->tdata.ihex_data->head; l != NULL; l = l->next) + { + bfd_vma where; + bfd_byte *p; + bfd_size_type count; + + where = l->where; + p = l->data; + count = l->size; + while (count > 0) + { + size_t now; + unsigned int rec_addr; + + now = count; + if (count > CHUNK) + now = CHUNK; + + if (where > segbase + extbase + 0xffff) + { + bfd_byte addr[2]; + + /* We need a new base address. */ + if (where <= 0xfffff) + { + /* The addresses should be sorted. */ + BFD_ASSERT (extbase == 0); + + segbase = where & 0xf0000; + addr[0] = (bfd_byte)(segbase >> 12) & 0xff; + addr[1] = (bfd_byte)(segbase >> 4) & 0xff; + if (! ihex_write_record (abfd, 2, 0, 2, addr)) + return FALSE; + } + else + { + /* The extended address record and the extended + linear address record are combined, at least by + some readers. We need an extended linear address + record here, so if we've already written out an + extended address record, zero it out to avoid + confusion. */ + if (segbase != 0) + { + addr[0] = 0; + addr[1] = 0; + if (! ihex_write_record (abfd, 2, 0, 2, addr)) + return FALSE; + segbase = 0; + } + + extbase = where & 0xffff0000; + if (where > extbase + 0xffff) + { + char buf[20]; + + sprintf_vma (buf, where); + (*_bfd_error_handler) + (_("%s: address 0x%s out of range for Intel Hex file"), + bfd_get_filename (abfd), buf); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + addr[0] = (bfd_byte)(extbase >> 24) & 0xff; + addr[1] = (bfd_byte)(extbase >> 16) & 0xff; + if (! ihex_write_record (abfd, 2, 0, 4, addr)) + return FALSE; + } + } + + rec_addr = where - (extbase + segbase); + + /* Output records shouldn't cross 64K boundaries. */ + if (rec_addr + now > 0xffff) + now = 0x10000 - rec_addr; + + if (! ihex_write_record (abfd, now, rec_addr, 0, p)) + return FALSE; + + where += now; + p += now; + count -= now; + } + } + + if (abfd->start_address != 0) + { + bfd_vma start; + bfd_byte startbuf[4]; + + start = abfd->start_address; + + if (start <= 0xfffff) + { + startbuf[0] = (bfd_byte)((start & 0xf0000) >> 12) & 0xff; + startbuf[1] = 0; + startbuf[2] = (bfd_byte)(start >> 8) & 0xff; + startbuf[3] = (bfd_byte)start & 0xff; + if (! ihex_write_record (abfd, 4, 0, 3, startbuf)) + return FALSE; + } + else + { + startbuf[0] = (bfd_byte)(start >> 24) & 0xff; + startbuf[1] = (bfd_byte)(start >> 16) & 0xff; + startbuf[2] = (bfd_byte)(start >> 8) & 0xff; + startbuf[3] = (bfd_byte)start & 0xff; + if (! ihex_write_record (abfd, 4, 0, 5, startbuf)) + return FALSE; + } + } + + if (! ihex_write_record (abfd, 0, 0, 1, NULL)) + return FALSE; + + return TRUE; +} + +/* Set the architecture for the output file. The architecture is + irrelevant, so we ignore errors about unknown architectures. */ + +static bfd_boolean +ihex_set_arch_mach (abfd, arch, mach) + bfd *abfd; + enum bfd_architecture arch; + unsigned long mach; +{ + if (! bfd_default_set_arch_mach (abfd, arch, mach)) + { + if (arch != bfd_arch_unknown) + return FALSE; + } + return TRUE; +} + +/* Get the size of the headers, for the linker. */ + +/*ARGSUSED*/ +static int +ihex_sizeof_headers (abfd, exec) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_boolean exec ATTRIBUTE_UNUSED; +{ + return 0; +} + +/* Some random definitions for the target vector. */ + +#define ihex_close_and_cleanup _bfd_generic_close_and_cleanup +#define ihex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define ihex_new_section_hook _bfd_generic_new_section_hook +#define ihex_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#define ihex_get_symtab_upper_bound bfd_0l +#define ihex_get_symtab \ + ((long (*) PARAMS ((bfd *, asymbol **))) bfd_0l) +#define ihex_make_empty_symbol _bfd_generic_make_empty_symbol +#define ihex_print_symbol _bfd_nosymbols_print_symbol +#define ihex_get_symbol_info _bfd_nosymbols_get_symbol_info +#define ihex_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name +#define ihex_get_lineno _bfd_nosymbols_get_lineno +#define ihex_find_nearest_line _bfd_nosymbols_find_nearest_line +#define ihex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define ihex_read_minisymbols _bfd_nosymbols_read_minisymbols +#define ihex_minisymbol_to_symbol _bfd_nosymbols_minisymbol_to_symbol + +#define ihex_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) bfd_0l) +#define ihex_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l) +#define ihex_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +#define ihex_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define ihex_bfd_relax_section bfd_generic_relax_section +#define ihex_bfd_gc_sections bfd_generic_gc_sections +#define ihex_bfd_merge_sections bfd_generic_merge_sections +#define ihex_bfd_discard_group bfd_generic_discard_group +#define ihex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define ihex_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +#define ihex_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define ihex_bfd_link_just_syms _bfd_generic_link_just_syms +#define ihex_bfd_final_link _bfd_generic_final_link +#define ihex_bfd_link_split_section _bfd_generic_link_split_section + +/* The Intel Hex target vector. */ + +const bfd_target ihex_vec = +{ + "ihex", /* name */ + bfd_target_ihex_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + 0, /* object flags */ + (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + ihex_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + ihex_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + ihex_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (ihex), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (ihex), + BFD_JUMP_TABLE_RELOCS (ihex), + BFD_JUMP_TABLE_WRITE (ihex), + BFD_JUMP_TABLE_LINK (ihex), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + NULL, + + (PTR) 0 +}; diff --git a/contrib/binutils-2.14/bfd/init.c b/contrib/binutils-2.14/bfd/init.c new file mode 100644 index 0000000000..198b979e1b --- /dev/null +++ b/contrib/binutils-2.14/bfd/init.c @@ -0,0 +1,51 @@ +/* bfd initialization stuff + Copyright 1990, 1991, 1992, 1993, 1994, 1995 + Free Software Foundation, Inc. + Written by Steve Chamberlain of 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +/* +SECTION + Initialization + + 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 () +{ +} diff --git a/contrib/binutils-2.14/bfd/libaout.h b/contrib/binutils-2.14/bfd/libaout.h new file mode 100644 index 0000000000..7dc44a2672 --- /dev/null +++ b/contrib/binutils-2.14/bfd/libaout.h @@ -0,0 +1,694 @@ +/* BFD back-end data structures for a.out (and similar) files. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef LIBAOUT_H +#define LIBAOUT_H + +/* We try to encapsulate the differences in the various a.out file + variants in a few routines, and otherwise share large masses of code. + This means we only have to fix bugs in one place, most of the time. */ + +#include "bfdlink.h" + +/* Macros for accessing components in an aout header. Saves cluttering + the source with (bfd_vma) and (bfd_byte *) casts. */ + +#define H_PUT_64(abfd, val, where) \ + bfd_h_put_64 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_32(abfd, val, where) \ + bfd_h_put_32 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_16(abfd, val, where) \ + bfd_h_put_16 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_8 bfd_h_put_8 + +#define H_PUT_S64(abfd, val, where) \ + bfd_h_put_signed_64 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_S32(abfd, val, where) \ + bfd_h_put_signed_32 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_S16(abfd, val, where) \ + bfd_h_put_signed_16 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) + +#define H_PUT_S8 bfd_h_put_signed_8 + +#define H_GET_64(abfd, where) \ + bfd_h_get_64 ((abfd), (bfd_byte *) (where)) + +#define H_GET_32(abfd, where) \ + bfd_h_get_32 ((abfd), (bfd_byte *) (where)) + +#define H_GET_16(abfd, where) \ + bfd_h_get_16 ((abfd), (bfd_byte *) (where)) + +#define H_GET_8 bfd_h_get_8 + +#define H_GET_S64(abfd, where) \ + bfd_h_get_signed_64 ((abfd), (bfd_byte *) (where)) + +#define H_GET_S32(abfd, where) \ + bfd_h_get_signed_32 ((abfd), (bfd_byte *) (where)) + +#define H_GET_S16(abfd, where) \ + bfd_h_get_signed_16 ((abfd), (bfd_byte *) (where)) + +#define H_GET_S8 bfd_h_get_signed_8 + +/* Parameterize the a.out code based on whether it is being built + for a 32-bit architecture or a 64-bit architecture. */ +/* Do not "beautify" the CONCAT* macro args. Traditional C will not + remove whitespace added here, and thus will fail to concatenate + the tokens. */ +#if ARCH_SIZE==64 +#define GET_WORD H_GET_64 +#define GET_SWORD H_GET_S64 +#define GET_MAGIC H_GET_32 +#define PUT_WORD H_PUT_64 +#define PUT_MAGIC H_PUT_32 +#ifndef NAME +#define NAME(x,y) CONCAT3 (x,_64_,y) +#endif +#define JNAME(x) CONCAT2 (x,_64) +#define BYTES_IN_WORD 8 +#else +#if ARCH_SIZE==16 +#define GET_WORD H_GET_16 +#define GET_SWORD H_GET_S16 +#define GET_MAGIC H_GET_16 +#define PUT_WORD H_PUT_16 +#define PUT_MAGIC H_PUT_16 +#ifndef NAME +#define NAME(x,y) CONCAT3 (x,_16_,y) +#endif +#define JNAME(x) CONCAT2 (x,_16) +#define BYTES_IN_WORD 2 +#else /* ARCH_SIZE == 32 */ +#define GET_WORD H_GET_32 +#define GET_SWORD H_GET_S32 +#define GET_MAGIC H_GET_32 +#define PUT_WORD H_PUT_32 +#define PUT_MAGIC H_PUT_32 +#ifndef NAME +#define NAME(x,y) CONCAT3 (x,_32_,y) +#endif +#define JNAME(x) CONCAT2 (x,_32) +#define BYTES_IN_WORD 4 +#endif /* ARCH_SIZE==32 */ +#endif /* ARCH_SIZE==64 */ + +/* Declare at file level, since used in parameter lists, which have + weird scope. */ +struct external_exec; +struct external_nlist; +struct reloc_ext_external; +struct reloc_std_external; + +/* a.out backend linker hash table entries. */ + +struct aout_link_hash_entry +{ + struct bfd_link_hash_entry root; + /* Whether this symbol has been written out. */ + bfd_boolean written; + /* Symbol index in output file. */ + int indx; +}; + +/* a.out backend linker hash table. */ + +struct aout_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Look up an entry in an a.out link hash table. */ + +#define aout_link_hash_lookup(table, string, create, copy, follow) \ + ((struct aout_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) + +/* Traverse an a.out link hash table. */ + +#define aout_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (bfd_boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the a.out link hash table from the info structure. This is + just a cast. */ + +#define aout_hash_table(p) ((struct aout_link_hash_table *) ((p)->hash)) + +/* Back-end information for various a.out targets. */ +struct aout_backend_data +{ + /* Are ZMAGIC files mapped contiguously? If so, the text section may + need more padding, if the segment size (granularity for memory access + control) is larger than the page size. */ + unsigned char zmagic_mapped_contiguous; + /* If this flag is set, ZMAGIC/NMAGIC file headers get mapped in with the + text section, which starts immediately after the file header. + If not, the text section starts on the next page. */ + unsigned char text_includes_header; + + /* If this flag is set, then if the entry address is not in the + first SEGMENT_SIZE bytes of the text section, it is taken to be + the address of the start of the text section. This can be useful + for kernels. */ + unsigned char entry_is_text_address; + + /* The value to pass to N_SET_FLAGS. */ + unsigned char exec_hdr_flags; + + /* If the text section VMA isn't specified, and we need an absolute + address, use this as the default. If we're producing a relocatable + file, zero is always used. */ + /* ?? Perhaps a callback would be a better choice? Will this do anything + reasonable for a format that handles multiple CPUs with different + load addresses for each? */ + bfd_vma default_text_vma; + + /* Callback for setting the page and segment sizes, if they can't be + trivially determined from the architecture. */ + bfd_boolean (*set_sizes) + PARAMS ((bfd *)); + + /* zmagic files only. For go32, the length of the exec header contributes + to the size of the text section in the file for alignment purposes but + does *not* get counted in the length of the text section. */ + unsigned char exec_header_not_counted; + + /* Callback from the add symbols phase of the linker code to handle + a dynamic object. */ + bfd_boolean (*add_dynamic_symbols) + PARAMS ((bfd *, struct bfd_link_info *, struct external_nlist **, + bfd_size_type *, char **)); + + /* Callback from the add symbols phase of the linker code to handle + adding a single symbol to the global linker hash table. */ + bfd_boolean (*add_one_symbol) + PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, + asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, + struct bfd_link_hash_entry **)); + + /* Called to handle linking a dynamic object. */ + bfd_boolean (*link_dynamic_object) + PARAMS ((struct bfd_link_info *, bfd *)); + + /* Called for each global symbol being written out by the linker. + This should write out the dynamic symbol information. */ + bfd_boolean (*write_dynamic_symbol) + PARAMS ((bfd *, struct bfd_link_info *, struct aout_link_hash_entry *)); + + /* If this callback is not NULL, the linker calls it for each reloc. + RELOC is a pointer to the unswapped reloc. If *SKIP is set to + TRUE, the reloc will be skipped. *RELOCATION may be changed to + change the effects of the relocation. */ + bfd_boolean (*check_dynamic_reloc) + PARAMS ((struct bfd_link_info *info, bfd *input_bfd, + asection *input_section, struct aout_link_hash_entry *h, + PTR reloc, bfd_byte *contents, bfd_boolean *skip, + bfd_vma *relocation)); + + /* Called at the end of a link to finish up any dynamic linking + information. */ + bfd_boolean (*finish_dynamic_link) + PARAMS ((bfd *, struct bfd_link_info *)); +}; +#define aout_backend_info(abfd) \ + ((const struct aout_backend_data *)((abfd)->xvec->backend_data)) + +/* This is the layout in memory of a "struct exec" while we process it. + All 'lengths' are given as a number of bytes. + All 'alignments' are for relinkable files only; an alignment of + 'n' indicates the corresponding segment must begin at an + address that is a multiple of (2**n). */ + +struct internal_exec +{ + long a_info; /* Magic number and flags, packed */ + bfd_vma a_text; /* length of text, in bytes */ + bfd_vma a_data; /* length of data, in bytes */ + bfd_vma a_bss; /* length of uninitialized data area in mem */ + bfd_vma a_syms; /* length of symbol table data in file */ + bfd_vma a_entry; /* start address */ + bfd_vma a_trsize; /* length of text's relocation info, in bytes */ + bfd_vma a_drsize; /* length of data's relocation info, in bytes */ + /* Added for i960 */ + bfd_vma a_tload; /* Text runtime load address */ + bfd_vma a_dload; /* Data runtime load address */ + unsigned char a_talign; /* Alignment of text segment */ + unsigned char a_dalign; /* Alignment of data segment */ + unsigned char a_balign; /* Alignment of bss segment */ + char a_relaxable; /* Enough info for linker relax */ +}; + +/* Magic number is written +< MSB > +3130292827262524232221201918171615141312111009080706050403020100 +< FLAGS >< MACHINE TYPE >< MAGIC NUMBER > +*/ +/* Magic number for NetBSD is + +3130292827262524232221201918171615141312111009080706050403020100 +< FLAGS >< MACHINE TYPE >< MAGIC NUMBER > +*/ + +enum machine_type { + M_UNKNOWN = 0, + M_68010 = 1, + M_68020 = 2, + M_SPARC = 3, + /* Skip a bunch so we don't run into any of SUN's numbers. */ + /* Make these up for the ns32k. */ + M_NS32032 = (64), /* ns32032 running ? */ + M_NS32532 = (64 + 5), /* ns32532 running mach */ + + M_386 = 100, + M_29K = 101, /* AMD 29000 */ + M_386_DYNIX = 102, /* Sequent running dynix */ + M_ARM = 103, /* Advanced Risc Machines ARM */ + M_SPARCLET = 131, /* SPARClet = M_SPARC + 128 */ + M_386_NETBSD = 134, /* NetBSD/i386 binary */ + M_68K_NETBSD = 135, /* NetBSD/m68k binary */ + M_68K4K_NETBSD = 136, /* NetBSD/m68k4k binary */ + M_532_NETBSD = 137, /* NetBSD/ns32k binary */ + M_SPARC_NETBSD = 138, /* NetBSD/sparc binary */ + M_PMAX_NETBSD = 139, /* NetBSD/pmax (MIPS little-endian) binary */ + M_VAX_NETBSD = 140, /* NetBSD/vax binary */ + M_ALPHA_NETBSD = 141, /* NetBSD/alpha binary */ + M_ARM6_NETBSD = 143, /* NetBSD/arm32 binary */ + M_SPARCLET_1 = 147, /* 0x93, reserved */ + M_VAX4K_NETBSD = 150, /* NetBSD/vax 4K pages binary */ + M_MIPS1 = 151, /* MIPS R2000/R3000 binary */ + M_MIPS2 = 152, /* MIPS R4000/R6000 binary */ + M_SPARCLET_2 = 163, /* 0xa3, reserved */ + M_SPARCLET_3 = 179, /* 0xb3, reserved */ + M_SPARCLET_4 = 195, /* 0xc3, reserved */ + M_HP200 = 200, /* HP 200 (68010) BSD binary */ + M_HP300 = (300 % 256), /* HP 300 (68020+68881) BSD binary */ + M_HPUX = (0x20c % 256), /* HP 200/300 HPUX binary */ + M_SPARCLET_5 = 211, /* 0xd3, reserved */ + M_SPARCLET_6 = 227, /* 0xe3, reserved */ + /* M_SPARCLET_7 = 243 / * 0xf3, reserved */ + M_SPARCLITE_LE = 243, + M_CRIS = 255 /* Axis CRIS binary. */ +}; + +#define N_DYNAMIC(exec) ((exec).a_info & 0x80000000) + +#ifndef N_MAGIC +# define N_MAGIC(exec) ((exec).a_info & 0xffff) +#endif + +#ifndef N_MACHTYPE +# define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#endif + +#ifndef N_FLAGS +# define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#endif + +#ifndef N_SET_INFO +# define N_SET_INFO(exec, magic, type, flags) \ +((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#endif + +#ifndef N_SET_DYNAMIC +# define N_SET_DYNAMIC(exec, dynamic) \ +((exec).a_info = (dynamic) ? (long) ((exec).a_info | 0x80000000) : \ +((exec).a_info & 0x7fffffff)) +#endif + +#ifndef N_SET_MAGIC +# define N_SET_MAGIC(exec, magic) \ +((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) +#endif + +#ifndef N_SET_MACHTYPE +# define N_SET_MACHTYPE(exec, machtype) \ +((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) +#endif + +#ifndef N_SET_FLAGS +# define N_SET_FLAGS(exec, flags) \ +((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) +#endif + +typedef struct aout_symbol { + asymbol symbol; + short desc; + char other; + unsigned char type; +} aout_symbol_type; + +/* The `tdata' struct for all a.out-like object file formats. + Various things depend on this struct being around any time an a.out + file is being handled. An example is dbxread.c in GDB. */ + +struct aoutdata { + struct internal_exec *hdr; /* exec file header */ + aout_symbol_type *symbols; /* symtab for input bfd */ + + /* For ease, we do this. */ + asection *textsec; + asection *datasec; + asection *bsssec; + + /* We remember these offsets so that after check_file_format, we have + no dependencies on the particular format of the exec_hdr. */ + file_ptr sym_filepos; + file_ptr str_filepos; + + /* Size of a relocation entry in external form. */ + unsigned reloc_entry_size; + + /* Size of a symbol table entry in external form. */ + unsigned symbol_entry_size; + + /* Page size - needed for alignment of demand paged files. */ + unsigned long page_size; + + /* Segment size - needed for alignment of demand paged files. */ + unsigned long segment_size; + + /* Zmagic disk block size - need to align the start of the text + section in ZMAGIC binaries. Normally the same as page_size. */ + unsigned long zmagic_disk_block_size; + + unsigned exec_bytes_size; + unsigned vma_adjusted : 1; + + /* Used when a bfd supports several highly similar formats. */ + enum + { + default_format = 0, + /* Used on HP 9000/300 running HP/UX. See hp300hpux.c. */ + gnu_encap_format, + /* Used on Linux, 386BSD, etc. See include/aout/aout64.h. */ + q_magic_format + } subformat; + + enum + { + undecided_magic = 0, + z_magic, + o_magic, + n_magic + } magic; + + /* A buffer for find_nearest_line. */ + char *line_buf; + + /* The external symbol information. */ + struct external_nlist *external_syms; + bfd_size_type external_sym_count; + bfd_window sym_window; + char *external_strings; + bfd_size_type external_string_size; + bfd_window string_window; + struct aout_link_hash_entry **sym_hashes; + + /* A pointer for shared library information. */ + PTR dynamic_info; + + /* A mapping from local symbols to offsets into the global offset + table, used when linking on SunOS. This is indexed by the symbol + index. */ + bfd_vma *local_got_offsets; +}; + +struct aout_data_struct { + struct aoutdata a; + struct internal_exec e; +}; + +#define adata(bfd) ((bfd)->tdata.aout_data->a) +#define exec_hdr(bfd) (adata(bfd).hdr) +#define obj_aout_symbols(bfd) (adata(bfd).symbols) +#define obj_textsec(bfd) (adata(bfd).textsec) +#define obj_datasec(bfd) (adata(bfd).datasec) +#define obj_bsssec(bfd) (adata(bfd).bsssec) +#define obj_sym_filepos(bfd) (adata(bfd).sym_filepos) +#define obj_str_filepos(bfd) (adata(bfd).str_filepos) +#define obj_reloc_entry_size(bfd) (adata(bfd).reloc_entry_size) +#define obj_symbol_entry_size(bfd) (adata(bfd).symbol_entry_size) +#define obj_aout_subformat(bfd) (adata(bfd).subformat) +#define obj_aout_external_syms(bfd) (adata(bfd).external_syms) +#define obj_aout_external_sym_count(bfd) (adata(bfd).external_sym_count) +#define obj_aout_sym_window(bfd) (adata(bfd).sym_window) +#define obj_aout_external_strings(bfd) (adata(bfd).external_strings) +#define obj_aout_external_string_size(bfd) (adata(bfd).external_string_size) +#define obj_aout_string_window(bfd) (adata(bfd).string_window) +#define obj_aout_sym_hashes(bfd) (adata(bfd).sym_hashes) +#define obj_aout_dynamic_info(bfd) (adata(bfd).dynamic_info) + +/* We take the address of the first element of an asymbol to ensure that the + macro is only ever applied to an asymbol. */ +#define aout_symbol(asymbol) ((aout_symbol_type *)(&(asymbol)->the_bfd)) + +/* Information we keep for each a.out section. This is currently only + used by the a.out backend linker. */ + +struct aout_section_data_struct +{ + /* The unswapped relocation entries for this section. */ + PTR relocs; +}; + +#define aout_section_data(s) \ + ((struct aout_section_data_struct *) (s)->used_by_bfd) + +#define set_aout_section_data(s,v) \ + ((s)->used_by_bfd = (PTR)&(v)->relocs) + +/* Prototype declarations for functions defined in aoutx.h. */ + +extern bfd_boolean NAME(aout,squirt_out_relocs) + PARAMS ((bfd *, asection *)); + +extern bfd_boolean NAME(aout,make_sections) + PARAMS ((bfd *)); + +extern const bfd_target * NAME(aout,some_aout_object_p) + PARAMS ((bfd *, struct internal_exec *, const bfd_target *(*) (bfd *))); + +extern bfd_boolean NAME(aout,mkobject) + PARAMS ((bfd *)); + +extern enum machine_type NAME(aout,machine_type) + PARAMS ((enum bfd_architecture, unsigned long, bfd_boolean *)); + +extern bfd_boolean NAME(aout,set_arch_mach) + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); + +extern bfd_boolean NAME(aout,new_section_hook) + PARAMS ((bfd *, asection *)); + +extern bfd_boolean NAME(aout,set_section_contents) + PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); + +extern asymbol * NAME(aout,make_empty_symbol) + PARAMS ((bfd *)); + +extern bfd_boolean NAME(aout,translate_symbol_table) + PARAMS ((bfd *, aout_symbol_type *, struct external_nlist *, bfd_size_type, + char *, bfd_size_type, bfd_boolean)); + +extern bfd_boolean NAME(aout,slurp_symbol_table) + PARAMS ((bfd *)); + +extern bfd_boolean NAME(aout,write_syms) + PARAMS ((bfd *)); + +extern void NAME(aout,reclaim_symbol_table) + PARAMS ((bfd *)); + +extern long NAME(aout,get_symtab_upper_bound) + PARAMS ((bfd *)); + +extern long NAME(aout,get_symtab) + PARAMS ((bfd *, asymbol **)); + +extern void NAME(aout,swap_ext_reloc_in) + PARAMS ((bfd *, struct reloc_ext_external *, arelent *, asymbol **, + bfd_size_type)); +extern void NAME(aout,swap_std_reloc_in) + PARAMS ((bfd *, struct reloc_std_external *, arelent *, asymbol **, + bfd_size_type)); + +extern reloc_howto_type * NAME(aout,reloc_type_lookup) + PARAMS ((bfd *, bfd_reloc_code_real_type)); + +extern bfd_boolean NAME(aout,slurp_reloc_table) + PARAMS ((bfd *, sec_ptr, asymbol **)); + +extern long NAME(aout,canonicalize_reloc) + PARAMS ((bfd *, sec_ptr, arelent **, asymbol **)); + +extern long NAME(aout,get_reloc_upper_bound) + PARAMS ((bfd *, sec_ptr)); + +extern void NAME(aout,reclaim_reloc) + PARAMS ((bfd *, sec_ptr)); + +extern alent * NAME(aout,get_lineno) + PARAMS ((bfd *, asymbol *)); + +extern void NAME(aout,print_symbol) + PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type)); + +extern void NAME(aout,get_symbol_info) + PARAMS ((bfd *, asymbol *, symbol_info *)); + +extern bfd_boolean NAME(aout,find_nearest_line) + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *)); + +extern long NAME(aout,read_minisymbols) + PARAMS ((bfd *, bfd_boolean, PTR *, unsigned int *)); + +extern asymbol * NAME(aout,minisymbol_to_symbol) + PARAMS ((bfd *, bfd_boolean, const PTR, asymbol *)); + +extern int NAME(aout,sizeof_headers) + PARAMS ((bfd *, bfd_boolean)); + +extern bfd_boolean NAME(aout,adjust_sizes_and_vmas) + PARAMS ((bfd *, bfd_size_type *, file_ptr *)); + +extern void NAME(aout,swap_exec_header_in) + PARAMS ((bfd *, struct external_exec *, struct internal_exec *)); + +extern void NAME(aout,swap_exec_header_out) + PARAMS ((bfd *, struct internal_exec *, struct external_exec *)); + +extern struct bfd_hash_entry * NAME(aout,link_hash_newfunc) + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + +extern bfd_boolean NAME(aout,link_hash_table_init) + PARAMS ((struct aout_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +extern struct bfd_link_hash_table * NAME(aout,link_hash_table_create) + PARAMS ((bfd *)); + +extern bfd_boolean NAME(aout,link_add_symbols) + PARAMS ((bfd *, struct bfd_link_info *)); + +extern bfd_boolean NAME(aout,final_link) + PARAMS ((bfd *, struct bfd_link_info *, + void (*) (bfd *, file_ptr *, file_ptr *, file_ptr *))); + +extern bfd_boolean NAME(aout,bfd_free_cached_info) + PARAMS ((bfd *)); + +/* A.out uses the generic versions of these routines... */ + +#define aout_16_get_section_contents _bfd_generic_get_section_contents + +#define aout_32_get_section_contents _bfd_generic_get_section_contents + +#define aout_64_get_section_contents _bfd_generic_get_section_contents +#ifndef NO_WRITE_HEADER_KLUDGE +#define NO_WRITE_HEADER_KLUDGE 0 +#endif + +#ifndef aout_32_bfd_is_local_label_name +#define aout_32_bfd_is_local_label_name bfd_generic_is_local_label_name +#endif + +#ifndef WRITE_HEADERS +#define WRITE_HEADERS(abfd, execp) \ + { \ + bfd_size_type text_size; /* dummy vars */ \ + file_ptr text_end; \ + if (adata(abfd).magic == undecided_magic) \ + NAME(aout,adjust_sizes_and_vmas) (abfd, &text_size, &text_end); \ + \ + execp->a_syms = bfd_get_symcount (abfd) * EXTERNAL_NLIST_SIZE; \ + execp->a_entry = bfd_get_start_address (abfd); \ + \ + execp->a_trsize = ((obj_textsec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + execp->a_drsize = ((obj_datasec (abfd)->reloc_count) * \ + obj_reloc_entry_size (abfd)); \ + NAME(aout,swap_exec_header_out) (abfd, execp, &exec_bytes); \ + \ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 \ + || bfd_bwrite ((PTR) &exec_bytes, (bfd_size_type) EXEC_BYTES_SIZE, \ + abfd) != EXEC_BYTES_SIZE) \ + return FALSE; \ + /* Now write out reloc info, followed by syms and strings. */ \ + \ + if (bfd_get_outsymbols (abfd) != (asymbol **) NULL \ + && bfd_get_symcount (abfd) != 0) \ + { \ + if (bfd_seek (abfd, (file_ptr) (N_SYMOFF(*execp)), SEEK_SET) != 0)\ + return FALSE; \ + \ + if (! NAME(aout,write_syms) (abfd)) \ + return FALSE; \ + } \ + \ + if (bfd_seek (abfd, (file_ptr) (N_TRELOFF(*execp)), SEEK_SET) != 0) \ + return FALSE; \ + if (!NAME(aout,squirt_out_relocs) (abfd, obj_textsec (abfd))) \ + return FALSE; \ + \ + if (bfd_seek (abfd, (file_ptr) (N_DRELOFF(*execp)), SEEK_SET) != 0) \ + return FALSE; \ + if (!NAME(aout,squirt_out_relocs) (abfd, obj_datasec (abfd))) \ + return FALSE; \ + } +#endif + +/* Test if a read-only section can be merged with .text. This is + possible if: + + 1. Section has file contents and is read-only. + 2. The VMA of the section is after the end of .text and before + the start of .data. + 3. The image is demand-pageable (otherwise, a_text in the header + will not reflect the gap between .text and .data). */ + +#define aout_section_merge_with_text_p(abfd, sec) \ + (((sec)->flags & (SEC_HAS_CONTENTS | SEC_READONLY)) == \ + (SEC_HAS_CONTENTS | SEC_READONLY) \ + && obj_textsec (abfd) != NULL \ + && obj_datasec (abfd) != NULL \ + && (sec)->vma >= (obj_textsec (abfd)->vma + \ + obj_textsec (abfd)->_cooked_size) \ + && ((sec)->vma + (sec)->_cooked_size) <= obj_datasec (abfd)->vma \ + && ((abfd)->flags & D_PAGED) != 0) + +#endif /* ! defined (LIBAOUT_H) */ diff --git a/contrib/binutils-2.14/bfd/libbfd.c b/contrib/binutils-2.14/bfd/libbfd.c new file mode 100644 index 0000000000..da93831e6d --- /dev/null +++ b/contrib/binutils-2.14/bfd/libbfd.c @@ -0,0 +1,924 @@ +/* Assorted BFD support routines, only used internally. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" + +#ifndef HAVE_GETPAGESIZE +#define getpagesize() 2048 +#endif + +/* +SECTION + Internal functions + +DESCRIPTION + These routines are used within BFD. + They are not intended for export, but are documented here for + completeness. +*/ + +/* A routine which is used in target vectors for unsupported + operations. */ + +bfd_boolean +bfd_false (ignore) + bfd *ignore ATTRIBUTE_UNUSED; +{ + bfd_set_error (bfd_error_invalid_operation); + return FALSE; +} + +/* A routine which is used in target vectors for supported operations + which do not actually do anything. */ + +bfd_boolean +bfd_true (ignore) + bfd *ignore ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +/* A routine which is used in target vectors for unsupported + operations which return a pointer value. */ + +PTR +bfd_nullvoidptr (ignore) + bfd *ignore ATTRIBUTE_UNUSED; +{ + bfd_set_error (bfd_error_invalid_operation); + return NULL; +} + +int +bfd_0 (ignore) + bfd *ignore ATTRIBUTE_UNUSED; +{ + return 0; +} + +unsigned int +bfd_0u (ignore) + bfd *ignore ATTRIBUTE_UNUSED; +{ + return 0; +} + +long +bfd_0l (ignore) + bfd *ignore ATTRIBUTE_UNUSED; +{ + return 0; +} + +/* A routine which is used in target vectors for unsupported + operations which return -1 on error. */ + +long +_bfd_n1 (ignore_abfd) + bfd *ignore_abfd ATTRIBUTE_UNUSED; +{ + bfd_set_error (bfd_error_invalid_operation); + return -1; +} + +void +bfd_void (ignore) + bfd *ignore ATTRIBUTE_UNUSED; +{ +} + +bfd_boolean +_bfd_nocore_core_file_matches_executable_p (ignore_core_bfd, ignore_exec_bfd) + bfd *ignore_core_bfd ATTRIBUTE_UNUSED; + bfd *ignore_exec_bfd ATTRIBUTE_UNUSED; +{ + bfd_set_error (bfd_error_invalid_operation); + return FALSE; +} + +/* Routine to handle core_file_failing_command entry point for targets + without core file support. */ + +char * +_bfd_nocore_core_file_failing_command (ignore_abfd) + bfd *ignore_abfd ATTRIBUTE_UNUSED; +{ + bfd_set_error (bfd_error_invalid_operation); + return (char *)NULL; +} + +/* Routine to handle core_file_failing_signal entry point for targets + without core file support. */ + +int +_bfd_nocore_core_file_failing_signal (ignore_abfd) + bfd *ignore_abfd ATTRIBUTE_UNUSED; +{ + bfd_set_error (bfd_error_invalid_operation); + return 0; +} + +const bfd_target * +_bfd_dummy_target (ignore_abfd) + bfd *ignore_abfd ATTRIBUTE_UNUSED; +{ + bfd_set_error (bfd_error_wrong_format); + return 0; +} + +/* Allocate memory using malloc. */ + +PTR +bfd_malloc (size) + bfd_size_type size; +{ + PTR ptr; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + ptr = (PTR) malloc ((size_t) size); + if (ptr == NULL && (size_t) size != 0) + bfd_set_error (bfd_error_no_memory); + + return ptr; +} + +/* Reallocate memory using realloc. */ + +PTR +bfd_realloc (ptr, size) + PTR ptr; + bfd_size_type size; +{ + PTR ret; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + if (ptr == NULL) + ret = (PTR) malloc ((size_t) size); + else + ret = (PTR) realloc (ptr, (size_t) size); + + if (ret == NULL && (size_t) size != 0) + bfd_set_error (bfd_error_no_memory); + + return ret; +} + +/* Allocate memory using malloc and clear it. */ + +PTR +bfd_zmalloc (size) + bfd_size_type size; +{ + PTR ptr; + + if (size != (size_t) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + ptr = (PTR) malloc ((size_t) size); + + if ((size_t) size != 0) + { + if (ptr == NULL) + bfd_set_error (bfd_error_no_memory); + else + memset (ptr, 0, (size_t) size); + } + + return ptr; +} +/* +INTERNAL_FUNCTION + bfd_write_bigendian_4byte_int + +SYNOPSIS + bfd_boolean bfd_write_bigendian_4byte_int (bfd *, unsigned int); + +DESCRIPTION + Write a 4 byte integer @var{i} to the output BFD @var{abfd}, in big + endian order regardless of what else is going on. This is useful in + archives. + +*/ +bfd_boolean +bfd_write_bigendian_4byte_int (abfd, i) + bfd *abfd; + unsigned int i; +{ + bfd_byte buffer[4]; + bfd_putb32 ((bfd_vma) i, buffer); + return bfd_bwrite ((PTR) buffer, (bfd_size_type) 4, abfd) == 4; +} + + +/** The do-it-yourself (byte) sex-change kit */ + +/* The middle letter e.g. getshort indicates Big or Little endian + target machine. It doesn't matter what the byte order of the host + machine is; these routines work for either. */ + +/* FIXME: Should these take a count argument? + Answer (gnu@cygnus.com): No, but perhaps they should be inline + functions in swap.h #ifdef __GNUC__. + Gprof them later and find out. */ + +/* +FUNCTION + bfd_put_size +FUNCTION + bfd_get_size + +DESCRIPTION + These macros as used for reading and writing raw data in + sections; each access (except for bytes) is vectored through + the target format of the BFD and mangled accordingly. The + mangling performs any necessary endian translations and + removes alignment restrictions. Note that types accepted and + returned by these macros are identical so they can be swapped + around in macros---for example, @file{libaout.h} defines <> + to either <> or <>. + + In the put routines, @var{val} must be a <>. If we are on a + system without prototypes, the caller is responsible for making + sure that is true, with a cast if necessary. We don't cast + them in the macro definitions because that would prevent <> + or <> from detecting sins such as passing a pointer. + To detect calling these with less than a <>, use + <> on a host with 64 bit <>'s. + +. +.{* Byte swapping macros for user section data. *} +. +.#define bfd_put_8(abfd, val, ptr) \ +. ((void) (*((unsigned char *) (ptr)) = (unsigned char) (val))) +.#define bfd_put_signed_8 \ +. bfd_put_8 +.#define bfd_get_8(abfd, ptr) \ +. (*(unsigned char *) (ptr) & 0xff) +.#define bfd_get_signed_8(abfd, ptr) \ +. (((*(unsigned char *) (ptr) & 0xff) ^ 0x80) - 0x80) +. +.#define bfd_put_16(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx16, ((val),(ptr))) +.#define bfd_put_signed_16 \ +. bfd_put_16 +.#define bfd_get_16(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx16, (ptr)) +.#define bfd_get_signed_16(abfd, ptr) \ +. BFD_SEND (abfd, bfd_getx_signed_16, (ptr)) +. +.#define bfd_put_32(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx32, ((val),(ptr))) +.#define bfd_put_signed_32 \ +. bfd_put_32 +.#define bfd_get_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx32, (ptr)) +.#define bfd_get_signed_32(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_32, (ptr)) +. +.#define bfd_put_64(abfd, val, ptr) \ +. BFD_SEND(abfd, bfd_putx64, ((val), (ptr))) +.#define bfd_put_signed_64 \ +. bfd_put_64 +.#define bfd_get_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx64, (ptr)) +.#define bfd_get_signed_64(abfd, ptr) \ +. BFD_SEND(abfd, bfd_getx_signed_64, (ptr)) +. +.#define bfd_get(bits, abfd, ptr) \ +. ( (bits) == 8 ? (bfd_vma) bfd_get_8 (abfd, ptr) \ +. : (bits) == 16 ? bfd_get_16 (abfd, ptr) \ +. : (bits) == 32 ? bfd_get_32 (abfd, ptr) \ +. : (bits) == 64 ? bfd_get_64 (abfd, ptr) \ +. : (abort (), (bfd_vma) - 1)) +. +.#define bfd_put(bits, abfd, val, ptr) \ +. ( (bits) == 8 ? bfd_put_8 (abfd, val, ptr) \ +. : (bits) == 16 ? bfd_put_16 (abfd, val, ptr) \ +. : (bits) == 32 ? bfd_put_32 (abfd, val, ptr) \ +. : (bits) == 64 ? bfd_put_64 (abfd, val, ptr) \ +. : (abort (), (void) 0)) +. +*/ + +/* +FUNCTION + bfd_h_put_size + bfd_h_get_size + +DESCRIPTION + These macros have the same function as their <> + brethren, except that they are used for removing information + for the header records of object files. Believe it or not, + some object files keep their header records in big endian + order and their data in little endian order. +. +.{* Byte swapping macros for file header data. *} +. +.#define bfd_h_put_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_put_signed_8(abfd, val, ptr) \ +. bfd_put_8 (abfd, val, ptr) +.#define bfd_h_get_8(abfd, ptr) \ +. bfd_get_8 (abfd, ptr) +.#define bfd_h_get_signed_8(abfd, ptr) \ +. bfd_get_signed_8 (abfd, ptr) +. +.#define bfd_h_put_16(abfd, val, ptr) \ +. BFD_SEND (abfd, bfd_h_putx16, (val, ptr)) +.#define bfd_h_put_signed_16 \ +. bfd_h_put_16 +.#define bfd_h_get_16(abfd, ptr) \ +. BFD_SEND (abfd, bfd_h_getx16, (ptr)) +.#define bfd_h_get_signed_16(abfd, ptr) \ +. BFD_SEND (abfd, bfd_h_getx_signed_16, (ptr)) +. +.#define bfd_h_put_32(abfd, val, ptr) \ +. BFD_SEND (abfd, bfd_h_putx32, (val, ptr)) +.#define bfd_h_put_signed_32 \ +. bfd_h_put_32 +.#define bfd_h_get_32(abfd, ptr) \ +. BFD_SEND (abfd, bfd_h_getx32, (ptr)) +.#define bfd_h_get_signed_32(abfd, ptr) \ +. BFD_SEND (abfd, bfd_h_getx_signed_32, (ptr)) +. +.#define bfd_h_put_64(abfd, val, ptr) \ +. BFD_SEND (abfd, bfd_h_putx64, (val, ptr)) +.#define bfd_h_put_signed_64 \ +. bfd_h_put_64 +.#define bfd_h_get_64(abfd, ptr) \ +. BFD_SEND (abfd, bfd_h_getx64, (ptr)) +.#define bfd_h_get_signed_64(abfd, ptr) \ +. BFD_SEND (abfd, bfd_h_getx_signed_64, (ptr)) +. +.{* Refinements on the above, which should eventually go away. Save +. cluttering the source with (bfd_vma) and (bfd_byte *) casts. *} +. +.#define H_PUT_64(abfd, val, where) \ +. bfd_h_put_64 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) +. +.#define H_PUT_32(abfd, val, where) \ +. bfd_h_put_32 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) +. +.#define H_PUT_16(abfd, val, where) \ +. bfd_h_put_16 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) +. +.#define H_PUT_8 bfd_h_put_8 +. +.#define H_PUT_S64(abfd, val, where) \ +. bfd_h_put_signed_64 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) +. +.#define H_PUT_S32(abfd, val, where) \ +. bfd_h_put_signed_32 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) +. +.#define H_PUT_S16(abfd, val, where) \ +. bfd_h_put_signed_16 ((abfd), (bfd_vma) (val), (bfd_byte *) (where)) +. +.#define H_PUT_S8 bfd_h_put_signed_8 +. +.#define H_GET_64(abfd, where) \ +. bfd_h_get_64 ((abfd), (bfd_byte *) (where)) +. +.#define H_GET_32(abfd, where) \ +. bfd_h_get_32 ((abfd), (bfd_byte *) (where)) +. +.#define H_GET_16(abfd, where) \ +. bfd_h_get_16 ((abfd), (bfd_byte *) (where)) +. +.#define H_GET_8 bfd_h_get_8 +. +.#define H_GET_S64(abfd, where) \ +. bfd_h_get_signed_64 ((abfd), (bfd_byte *) (where)) +. +.#define H_GET_S32(abfd, where) \ +. bfd_h_get_signed_32 ((abfd), (bfd_byte *) (where)) +. +.#define H_GET_S16(abfd, where) \ +. bfd_h_get_signed_16 ((abfd), (bfd_byte *) (where)) +. +.#define H_GET_S8 bfd_h_get_signed_8 +. +.*/ + +/* Sign extension to bfd_signed_vma. */ +#define COERCE16(x) (((bfd_signed_vma) (x) ^ 0x8000) - 0x8000) +#define COERCE32(x) \ + ((bfd_signed_vma) (long) (((unsigned long) (x) ^ 0x80000000) - 0x80000000)) +#define EIGHT_GAZILLION (((BFD_HOST_64_BIT)0x80000000) << 32) +#define COERCE64(x) \ + (((bfd_signed_vma) (x) ^ EIGHT_GAZILLION) - EIGHT_GAZILLION) + +bfd_vma +bfd_getb16 (addr) + register const bfd_byte *addr; +{ + return (addr[0] << 8) | addr[1]; +} + +bfd_vma +bfd_getl16 (addr) + register const bfd_byte *addr; +{ + return (addr[1] << 8) | addr[0]; +} + +bfd_signed_vma +bfd_getb_signed_16 (addr) + register const bfd_byte *addr; +{ + return COERCE16((addr[0] << 8) | addr[1]); +} + +bfd_signed_vma +bfd_getl_signed_16 (addr) + register const bfd_byte *addr; +{ + return COERCE16((addr[1] << 8) | addr[0]); +} + +void +bfd_putb16 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte) (data >> 8); + addr[1] = (bfd_byte) data; +} + +void +bfd_putl16 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte) data; + addr[1] = (bfd_byte) (data >> 8); +} + +bfd_vma +bfd_getb32 (addr) + register const bfd_byte *addr; +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + v |= (unsigned long) addr[2] << 8; + v |= (unsigned long) addr[3]; + return (bfd_vma) v; +} + +bfd_vma +bfd_getl32 (addr) + register const bfd_byte *addr; +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + return (bfd_vma) v; +} + +bfd_signed_vma +bfd_getb_signed_32 (addr) + register const bfd_byte *addr; +{ + unsigned long v; + + v = (unsigned long) addr[0] << 24; + v |= (unsigned long) addr[1] << 16; + v |= (unsigned long) addr[2] << 8; + v |= (unsigned long) addr[3]; + return COERCE32 (v); +} + +bfd_signed_vma +bfd_getl_signed_32 (addr) + register const bfd_byte *addr; +{ + unsigned long v; + + v = (unsigned long) addr[0]; + v |= (unsigned long) addr[1] << 8; + v |= (unsigned long) addr[2] << 16; + v |= (unsigned long) addr[3] << 24; + return COERCE32 (v); +} + +bfd_vma +bfd_getb64 (addr) + register const bfd_byte *addr ATTRIBUTE_UNUSED; +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return high << 32 | low; +#else + BFD_FAIL(); + return 0; +#endif +} + +bfd_vma +bfd_getl64 (addr) + register const bfd_byte *addr ATTRIBUTE_UNUSED; +{ +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return high << 32 | low; +#else + BFD_FAIL(); + return 0; +#endif + +} + +bfd_signed_vma +bfd_getb_signed_64 (addr) + register const bfd_byte *addr ATTRIBUTE_UNUSED; +{ +#ifdef BFD64 + bfd_vma low, high; + + high= ((((((((addr[0]) << 8) | + addr[1]) << 8) | + addr[2]) << 8) | + addr[3]) ); + + low = (((((((((bfd_vma)addr[4]) << 8) | + addr[5]) << 8) | + addr[6]) << 8) | + addr[7])); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif +} + +bfd_signed_vma +bfd_getl_signed_64 (addr) + register const bfd_byte *addr ATTRIBUTE_UNUSED; +{ +#ifdef BFD64 + bfd_vma low, high; + high= (((((((addr[7] << 8) | + addr[6]) << 8) | + addr[5]) << 8) | + addr[4])); + + low = ((((((((bfd_vma)addr[3] << 8) | + addr[2]) << 8) | + addr[1]) << 8) | + addr[0]) ); + + return COERCE64(high << 32 | low); +#else + BFD_FAIL(); + return 0; +#endif +} + +void +bfd_putb32 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte) (data >> 24); + addr[1] = (bfd_byte) (data >> 16); + addr[2] = (bfd_byte) (data >> 8); + addr[3] = (bfd_byte) data; +} + +void +bfd_putl32 (data, addr) + bfd_vma data; + register bfd_byte *addr; +{ + addr[0] = (bfd_byte) data; + addr[1] = (bfd_byte) (data >> 8); + addr[2] = (bfd_byte) (data >> 16); + addr[3] = (bfd_byte) (data >> 24); +} + +void +bfd_putb64 (data, addr) + bfd_vma data ATTRIBUTE_UNUSED; + register bfd_byte *addr ATTRIBUTE_UNUSED; +{ +#ifdef BFD64 + addr[0] = (bfd_byte) (data >> (7*8)); + addr[1] = (bfd_byte) (data >> (6*8)); + addr[2] = (bfd_byte) (data >> (5*8)); + addr[3] = (bfd_byte) (data >> (4*8)); + addr[4] = (bfd_byte) (data >> (3*8)); + addr[5] = (bfd_byte) (data >> (2*8)); + addr[6] = (bfd_byte) (data >> (1*8)); + addr[7] = (bfd_byte) (data >> (0*8)); +#else + BFD_FAIL(); +#endif +} + +void +bfd_putl64 (data, addr) + bfd_vma data ATTRIBUTE_UNUSED; + register bfd_byte *addr ATTRIBUTE_UNUSED; +{ +#ifdef BFD64 + addr[7] = (bfd_byte) (data >> (7*8)); + addr[6] = (bfd_byte) (data >> (6*8)); + addr[5] = (bfd_byte) (data >> (5*8)); + addr[4] = (bfd_byte) (data >> (4*8)); + addr[3] = (bfd_byte) (data >> (3*8)); + addr[2] = (bfd_byte) (data >> (2*8)); + addr[1] = (bfd_byte) (data >> (1*8)); + addr[0] = (bfd_byte) (data >> (0*8)); +#else + BFD_FAIL(); +#endif +} + +void +bfd_put_bits (data, addr, bits, big_p) + bfd_vma data; + bfd_byte *addr; + int bits; + bfd_boolean big_p; +{ + int i; + int bytes; + + if (bits % 8 != 0) + abort (); + + bytes = bits / 8; + for (i = 0; i < bytes; i++) + { + int index = big_p ? bytes - i - 1 : i; + + addr[index] = (bfd_byte) data; + data >>= 8; + } +} + +bfd_vma +bfd_get_bits (addr, bits, big_p) + bfd_byte *addr; + int bits; + bfd_boolean big_p; +{ + bfd_vma data; + int i; + int bytes; + + if (bits % 8 != 0) + abort (); + + data = 0; + bytes = bits / 8; + for (i = 0; i < bytes; i++) + { + int index = big_p ? i : bytes - i - 1; + + data = (data << 8) | addr[index]; + } + + return data; +} + +/* Default implementation */ + +bfd_boolean +_bfd_generic_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (count == 0) + return TRUE; + + if (offset + count > section->_raw_size) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 + || bfd_bread (location, count, abfd) != count) + return FALSE; + + return TRUE; +} + +bfd_boolean +_bfd_generic_get_section_contents_in_window (abfd, section, w, offset, count) + bfd *abfd ATTRIBUTE_UNUSED; + sec_ptr section ATTRIBUTE_UNUSED; + bfd_window *w ATTRIBUTE_UNUSED; + file_ptr offset ATTRIBUTE_UNUSED; + bfd_size_type count ATTRIBUTE_UNUSED; +{ +#ifdef USE_MMAP + if (count == 0) + return TRUE; + if (abfd->xvec->_bfd_get_section_contents != _bfd_generic_get_section_contents) + { + /* We don't know what changes the bfd's get_section_contents + method may have to make. So punt trying to map the file + window, and let get_section_contents do its thing. */ + /* @@ FIXME : If the internal window has a refcount of 1 and was + allocated with malloc instead of mmap, just reuse it. */ + bfd_free_window (w); + w->i = ((bfd_window_internal *) + bfd_zmalloc ((bfd_size_type) sizeof (bfd_window_internal))); + if (w->i == NULL) + return FALSE; + w->i->data = (PTR) bfd_malloc (count); + if (w->i->data == NULL) + { + free (w->i); + w->i = NULL; + return FALSE; + } + w->i->mapped = 0; + w->i->refcount = 1; + w->size = w->i->size = count; + w->data = w->i->data; + return bfd_get_section_contents (abfd, section, w->data, offset, count); + } + if (offset + count > section->_raw_size + || ! bfd_get_file_window (abfd, section->filepos + offset, count, w, + TRUE)) + return FALSE; + return TRUE; +#else + abort (); +#endif +} + +/* This generic function can only be used in implementations where creating + NEW sections is disallowed. It is useful in patching existing sections + in read-write files, though. See other set_section_contents functions + to see why it doesn't work for new sections. */ +bfd_boolean +_bfd_generic_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (count == 0) + return TRUE; + + if (bfd_seek (abfd, section->filepos + offset, SEEK_SET) != 0 + || bfd_bwrite (location, count, abfd) != count) + return FALSE; + + return TRUE; +} + +/* +INTERNAL_FUNCTION + bfd_log2 + +SYNOPSIS + unsigned int bfd_log2 (bfd_vma x); + +DESCRIPTION + Return the log base 2 of the value supplied, rounded up. E.g., an + @var{x} of 1025 returns 11. A @var{x} of 0 returns 0. +*/ + +unsigned int +bfd_log2 (x) + bfd_vma x; +{ + unsigned int result = 0; + + while ((x = (x >> 1)) != 0) + ++result; + return result; +} + +bfd_boolean +bfd_generic_is_local_label_name (abfd, name) + bfd *abfd; + const char *name; +{ + char locals_prefix = (bfd_get_symbol_leading_char (abfd) == '_') ? 'L' : '.'; + + return name[0] == locals_prefix; +} + +/* Can be used from / for bfd_merge_private_bfd_data to check that + endianness matches between input and output file. Returns + TRUE for a match, otherwise returns FALSE and emits an error. */ +bfd_boolean +_bfd_generic_verify_endian_match (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + if (ibfd->xvec->byteorder != obfd->xvec->byteorder + && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN + && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) + { + const char *msg; + + if (bfd_big_endian (ibfd)) + msg = _("%s: compiled for a big endian system and target is little endian"); + else + msg = _("%s: compiled for a little endian system and target is big endian"); + + (*_bfd_error_handler) (msg, bfd_archive_filename (ibfd)); + + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + return TRUE; +} + +/* Give a warning at runtime if someone compiles code which calls + old routines. */ + +void +warn_deprecated (what, file, line, func) + const char *what; + const char *file; + int line; + const char *func; +{ + /* Poor man's tracking of functions we've already warned about. */ + static size_t mask = 0; + + if (~(size_t) func & ~mask) + { + /* Note: separate sentences in order to allow + for translation into other languages. */ + if (func) + fprintf (stderr, _("Deprecated %s called at %s line %d in %s\n"), + what, file, line, func); + else + fprintf (stderr, _("Deprecated %s called\n"), what); + mask |= ~(size_t) func; + } +} diff --git a/contrib/binutils-2.14/bfd/libbfd.h b/contrib/binutils-2.14/bfd/libbfd.h new file mode 100644 index 0000000000..9bbdebd218 --- /dev/null +++ b/contrib/binutils-2.14/bfd/libbfd.h @@ -0,0 +1,1532 @@ +/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically + generated from "libbfd-in.h", "init.c", "libbfd.c", "bfdio.c", + "bfdwin.c", "cache.c", "reloc.c", "archures.c" and "elf.c". + Run "make headers" in your build bfd/ to regenerate. */ + +/* libbfd.h -- Declarations used by bfd library *implementation*. + (This include file is not for users of the library.) + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Align an address upward to a boundary, expressed as a number of bytes. + E.g. align to an 8-byte boundary with argument of 8. Take care never + to wrap around if the address is within boundary-1 of the end of the + address space. */ +#define BFD_ALIGN(this, boundary) \ + ((((bfd_vma) (this) + (boundary) - 1) >= (bfd_vma) (this)) \ + ? (((bfd_vma) (this) + ((boundary) - 1)) & ~ (bfd_vma) ((boundary)-1)) \ + : ~ (bfd_vma) 0) + +/* If you want to read and write large blocks, you might want to do it + in quanta of this amount */ +#define DEFAULT_BUFFERSIZE 8192 + +/* Set a tdata field. Can't use the other macros for this, since they + do casts, and casting to the left of assignment isn't portable. */ +#define set_tdata(bfd, v) ((bfd)->tdata.any = (PTR) (v)) + +/* If BFD_IN_MEMORY is set for a BFD, then the iostream fields points + to an instance of this structure. */ + +struct bfd_in_memory +{ + /* Size of buffer. */ + bfd_size_type size; + /* Buffer holding contents of BFD. */ + bfd_byte *buffer; +}; + +/* tdata for an archive. For an input archive, cache + needs to be free()'d. For an output archive, symdefs do. */ + +struct artdata { + file_ptr first_file_filepos; + /* Speed up searching the armap */ + struct ar_cache *cache; + bfd *archive_head; /* Only interesting in output routines */ + carsym *symdefs; /* the symdef entries */ + symindex symdef_count; /* how many there are */ + char *extended_names; /* clever intel extension */ + /* when more compilers are standard C, this can be a time_t */ + long armap_timestamp; /* Timestamp value written into armap. + This is used for BSD archives to check + that the timestamp is recent enough + for the BSD linker to not complain, + just before we finish writing an + archive. */ + file_ptr armap_datepos; /* Position within archive to seek to + rewrite the date field. */ + PTR tdata; /* Backend specific information. */ +}; + +#define bfd_ardata(bfd) ((bfd)->tdata.aout_ar_data) + +/* Goes in bfd's arelt_data slot */ +struct areltdata { + char * arch_header; /* it's actually a string */ + unsigned int parsed_size; /* octets of filesize not including ar_hdr */ + char *filename; /* null-terminated */ +}; + +#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size) + +extern PTR bfd_malloc + PARAMS ((bfd_size_type)); +extern PTR bfd_realloc + PARAMS ((PTR, bfd_size_type)); +extern PTR bfd_zmalloc + PARAMS ((bfd_size_type)); + +extern bfd_error_handler_type _bfd_error_handler; + +/* These routines allocate and free things on the BFD's objalloc. */ + +extern PTR bfd_alloc + PARAMS ((bfd *, bfd_size_type)); +extern PTR bfd_zalloc + PARAMS ((bfd *, bfd_size_type)); +extern void bfd_release + PARAMS ((bfd *, PTR)); + +bfd * _bfd_create_empty_archive_element_shell + PARAMS ((bfd *obfd)); +bfd * _bfd_look_for_bfd_in_cache + PARAMS ((bfd *, file_ptr)); +bfd_boolean _bfd_add_bfd_to_archive_cache + PARAMS ((bfd *, file_ptr, bfd *)); +bfd_boolean _bfd_generic_mkarchive + PARAMS ((bfd *abfd)); +const bfd_target *bfd_generic_archive_p + PARAMS ((bfd *abfd)); +bfd_boolean bfd_slurp_armap + PARAMS ((bfd *abfd)); +bfd_boolean bfd_slurp_bsd_armap_f2 + PARAMS ((bfd *abfd)); +#define bfd_slurp_bsd_armap bfd_slurp_armap +#define bfd_slurp_coff_armap bfd_slurp_armap +bfd_boolean _bfd_slurp_extended_name_table + PARAMS ((bfd *abfd)); +extern bfd_boolean _bfd_construct_extended_name_table + PARAMS ((bfd *, bfd_boolean, char **, bfd_size_type *)); +bfd_boolean _bfd_write_archive_contents + PARAMS ((bfd *abfd)); +bfd_boolean _bfd_compute_and_write_armap + PARAMS ((bfd *, unsigned int elength)); +bfd *_bfd_get_elt_at_filepos + PARAMS ((bfd *archive, file_ptr filepos)); +extern bfd *_bfd_generic_get_elt_at_index + PARAMS ((bfd *, symindex)); +bfd * _bfd_new_bfd + PARAMS ((void)); +void _bfd_delete_bfd + PARAMS ((bfd *)); + +bfd_boolean bfd_false + PARAMS ((bfd *ignore)); +bfd_boolean bfd_true + PARAMS ((bfd *ignore)); +PTR bfd_nullvoidptr + PARAMS ((bfd *ignore)); +int bfd_0 + PARAMS ((bfd *ignore)); +unsigned int bfd_0u + PARAMS ((bfd *ignore)); +long bfd_0l + PARAMS ((bfd *ignore)); +long _bfd_n1 + PARAMS ((bfd *ignore)); +void bfd_void + PARAMS ((bfd *ignore)); + +bfd *_bfd_new_bfd_contained_in + PARAMS ((bfd *)); +const bfd_target *_bfd_dummy_target + PARAMS ((bfd *abfd)); + +void bfd_dont_truncate_arname + PARAMS ((bfd *abfd, const char *filename, char *hdr)); +void bfd_bsd_truncate_arname + PARAMS ((bfd *abfd, const char *filename, char *hdr)); +void bfd_gnu_truncate_arname + PARAMS ((bfd *abfd, const char *filename, char *hdr)); + +bfd_boolean bsd_write_armap + PARAMS ((bfd *arch, unsigned int elength, struct orl *map, + unsigned int orl_count, int stridx)); + +bfd_boolean coff_write_armap + PARAMS ((bfd *arch, unsigned int elength, struct orl *map, + unsigned int orl_count, int stridx)); + +extern PTR _bfd_generic_read_ar_hdr + PARAMS ((bfd *)); + +extern PTR _bfd_generic_read_ar_hdr_mag + PARAMS ((bfd *, const char *)); + +bfd * bfd_generic_openr_next_archived_file + PARAMS ((bfd *archive, bfd *last_file)); + +int bfd_generic_stat_arch_elt + PARAMS ((bfd *, struct stat *)); + +#define _bfd_read_ar_hdr(abfd) \ + BFD_SEND (abfd, _bfd_read_ar_hdr_fn, (abfd)) + +/* Generic routines to use for BFD_JUMP_TABLE_GENERIC. Use + BFD_JUMP_TABLE_GENERIC (_bfd_generic). */ + +#define _bfd_generic_close_and_cleanup bfd_true +#define _bfd_generic_bfd_free_cached_info bfd_true +#define _bfd_generic_new_section_hook \ + ((bfd_boolean (*) PARAMS ((bfd *, asection *))) bfd_true) +extern bfd_boolean _bfd_generic_get_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +extern bfd_boolean _bfd_generic_get_section_contents_in_window + PARAMS ((bfd *, asection *, bfd_window *, file_ptr, bfd_size_type)); + +/* Generic routines to use for BFD_JUMP_TABLE_COPY. Use + BFD_JUMP_TABLE_COPY (_bfd_generic). */ + +#define _bfd_generic_bfd_copy_private_bfd_data \ + ((bfd_boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#define _bfd_generic_bfd_merge_private_bfd_data \ + ((bfd_boolean (*) PARAMS ((bfd *, bfd *))) bfd_true) +#define _bfd_generic_bfd_set_private_flags \ + ((bfd_boolean (*) PARAMS ((bfd *, flagword))) bfd_true) +#define _bfd_generic_bfd_copy_private_section_data \ + ((bfd_boolean (*) PARAMS ((bfd *, asection *, bfd *, asection *))) bfd_true) +#define _bfd_generic_bfd_copy_private_symbol_data \ + ((bfd_boolean (*) PARAMS ((bfd *, asymbol *, bfd *, asymbol *))) bfd_true) +#define _bfd_generic_bfd_print_private_bfd_data \ + ((bfd_boolean (*) PARAMS ((bfd *, PTR))) bfd_true) + +/* Routines to use for BFD_JUMP_TABLE_CORE when there is no core file + support. Use BFD_JUMP_TABLE_CORE (_bfd_nocore). */ + +extern char *_bfd_nocore_core_file_failing_command + PARAMS ((bfd *)); +extern int _bfd_nocore_core_file_failing_signal + PARAMS ((bfd *)); +extern bfd_boolean _bfd_nocore_core_file_matches_executable_p + PARAMS ((bfd *, bfd *)); + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE when there is no archive + file support. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive). */ + +#define _bfd_noarchive_slurp_armap bfd_false +#define _bfd_noarchive_slurp_extended_name_table bfd_false +#define _bfd_noarchive_construct_extended_name_table \ + ((bfd_boolean (*) \ + PARAMS ((bfd *, char **, bfd_size_type *, const char **))) \ + bfd_false) +#define _bfd_noarchive_truncate_arname \ + ((void (*) PARAMS ((bfd *, const char *, char *))) bfd_void) +#define _bfd_noarchive_write_armap \ + ((bfd_boolean (*) \ + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int))) \ + bfd_false) +#define _bfd_noarchive_read_ar_hdr bfd_nullvoidptr +#define _bfd_noarchive_openr_next_archived_file \ + ((bfd *(*) PARAMS ((bfd *, bfd *))) bfd_nullvoidptr) +#define _bfd_noarchive_get_elt_at_index \ + ((bfd *(*) PARAMS ((bfd *, symindex))) bfd_nullvoidptr) +#define _bfd_noarchive_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define _bfd_noarchive_update_armap_timestamp bfd_false + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get BSD style + archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_bsd). */ + +#define _bfd_archive_bsd_slurp_armap bfd_slurp_bsd_armap +#define _bfd_archive_bsd_slurp_extended_name_table \ + _bfd_slurp_extended_name_table +extern bfd_boolean _bfd_archive_bsd_construct_extended_name_table + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); +#define _bfd_archive_bsd_truncate_arname bfd_bsd_truncate_arname +#define _bfd_archive_bsd_write_armap bsd_write_armap +#define _bfd_archive_bsd_read_ar_hdr _bfd_generic_read_ar_hdr +#define _bfd_archive_bsd_openr_next_archived_file \ + bfd_generic_openr_next_archived_file +#define _bfd_archive_bsd_get_elt_at_index _bfd_generic_get_elt_at_index +#define _bfd_archive_bsd_generic_stat_arch_elt \ + bfd_generic_stat_arch_elt +extern bfd_boolean _bfd_archive_bsd_update_armap_timestamp + PARAMS ((bfd *)); + +/* Routines to use for BFD_JUMP_TABLE_ARCHIVE to get COFF style + archives. Use BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff). */ + +#define _bfd_archive_coff_slurp_armap bfd_slurp_coff_armap +#define _bfd_archive_coff_slurp_extended_name_table \ + _bfd_slurp_extended_name_table +extern bfd_boolean _bfd_archive_coff_construct_extended_name_table + PARAMS ((bfd *, char **, bfd_size_type *, const char **)); +#define _bfd_archive_coff_truncate_arname bfd_dont_truncate_arname +#define _bfd_archive_coff_write_armap coff_write_armap +#define _bfd_archive_coff_read_ar_hdr _bfd_generic_read_ar_hdr +#define _bfd_archive_coff_openr_next_archived_file \ + bfd_generic_openr_next_archived_file +#define _bfd_archive_coff_get_elt_at_index _bfd_generic_get_elt_at_index +#define _bfd_archive_coff_generic_stat_arch_elt \ + bfd_generic_stat_arch_elt +#define _bfd_archive_coff_update_armap_timestamp bfd_true + +/* Routines to use for BFD_JUMP_TABLE_SYMBOLS where there is no symbol + support. Use BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols). */ + +#define _bfd_nosymbols_get_symtab_upper_bound _bfd_n1 +#define _bfd_nosymbols_get_symtab \ + ((long (*) PARAMS ((bfd *, asymbol **))) _bfd_n1) +#define _bfd_nosymbols_make_empty_symbol _bfd_generic_make_empty_symbol +#define _bfd_nosymbols_print_symbol \ + ((void (*) PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type))) bfd_void) +#define _bfd_nosymbols_get_symbol_info \ + ((void (*) PARAMS ((bfd *, asymbol *, symbol_info *))) bfd_void) +#define _bfd_nosymbols_bfd_is_local_label_name \ + ((bfd_boolean (*) PARAMS ((bfd *, const char *))) bfd_false) +#define _bfd_nosymbols_get_lineno \ + ((alent *(*) PARAMS ((bfd *, asymbol *))) bfd_nullvoidptr) +#define _bfd_nosymbols_find_nearest_line \ + ((bfd_boolean (*) \ + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, \ + const char **, unsigned int *))) \ + bfd_false) +#define _bfd_nosymbols_bfd_make_debug_symbol \ + ((asymbol *(*) PARAMS ((bfd *, PTR, unsigned long))) bfd_nullvoidptr) +#define _bfd_nosymbols_read_minisymbols \ + ((long (*) PARAMS ((bfd *, bfd_boolean, PTR *, unsigned int *))) _bfd_n1) +#define _bfd_nosymbols_minisymbol_to_symbol \ + ((asymbol *(*) PARAMS ((bfd *, bfd_boolean, const PTR, asymbol *))) \ + bfd_nullvoidptr) + +/* Routines to use for BFD_JUMP_TABLE_RELOCS when there is no reloc + support. Use BFD_JUMP_TABLE_RELOCS (_bfd_norelocs). */ + +#define _bfd_norelocs_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) _bfd_n1) +#define _bfd_norelocs_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) _bfd_n1) +#define _bfd_norelocs_bfd_reloc_type_lookup \ + ((reloc_howto_type *(*) PARAMS ((bfd *, bfd_reloc_code_real_type))) \ + bfd_nullvoidptr) + +/* Routines to use for BFD_JUMP_TABLE_WRITE for targets which may not + be written. Use BFD_JUMP_TABLE_WRITE (_bfd_nowrite). */ + +#define _bfd_nowrite_set_arch_mach \ + ((bfd_boolean (*) PARAMS ((bfd *, enum bfd_architecture, unsigned long))) \ + bfd_false) +#define _bfd_nowrite_set_section_contents \ + ((bfd_boolean (*) \ + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type))) \ + bfd_false) + +/* Generic routines to use for BFD_JUMP_TABLE_WRITE. Use + BFD_JUMP_TABLE_WRITE (_bfd_generic). */ + +#define _bfd_generic_set_arch_mach bfd_default_set_arch_mach +extern bfd_boolean _bfd_generic_set_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); + +/* Routines to use for BFD_JUMP_TABLE_LINK for targets which do not + support linking. Use BFD_JUMP_TABLE_LINK (_bfd_nolink). */ + +#define _bfd_nolink_sizeof_headers ((int (*) PARAMS ((bfd *, bfd_boolean))) bfd_0) +#define _bfd_nolink_bfd_get_relocated_section_contents \ + ((bfd_byte *(*) \ + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, \ + bfd_byte *, bfd_boolean, asymbol **))) \ + bfd_nullvoidptr) +#define _bfd_nolink_bfd_relax_section \ + ((bfd_boolean (*) \ + PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *))) \ + bfd_false) +#define _bfd_nolink_bfd_gc_sections \ + ((bfd_boolean (*) \ + PARAMS ((bfd *, struct bfd_link_info *))) \ + bfd_false) +#define _bfd_nolink_bfd_merge_sections \ + ((bfd_boolean (*) \ + PARAMS ((bfd *, struct bfd_link_info *))) \ + bfd_false) +#define _bfd_nolink_bfd_discard_group \ + ((bfd_boolean (*) \ + PARAMS ((bfd *, struct sec *))) \ + bfd_false) +#define _bfd_nolink_bfd_link_hash_table_create \ + ((struct bfd_link_hash_table *(*) PARAMS ((bfd *))) bfd_nullvoidptr) +#define _bfd_nolink_bfd_link_hash_table_free \ + ((void (*) PARAMS ((struct bfd_link_hash_table *))) bfd_void) +#define _bfd_nolink_bfd_link_add_symbols \ + ((bfd_boolean (*) PARAMS ((bfd *, struct bfd_link_info *))) bfd_false) +#define _bfd_nolink_bfd_link_just_syms \ + ((void (*) PARAMS ((asection *, struct bfd_link_info *))) bfd_void) +#define _bfd_nolink_bfd_final_link \ + ((bfd_boolean (*) PARAMS ((bfd *, struct bfd_link_info *))) bfd_false) +#define _bfd_nolink_bfd_link_split_section \ + ((bfd_boolean (*) PARAMS ((bfd *, struct sec *))) bfd_false) + +/* Routines to use for BFD_JUMP_TABLE_DYNAMIC for targets which do not + have dynamic symbols or relocs. Use BFD_JUMP_TABLE_DYNAMIC + (_bfd_nodynamic). */ + +#define _bfd_nodynamic_get_dynamic_symtab_upper_bound _bfd_n1 +#define _bfd_nodynamic_canonicalize_dynamic_symtab \ + ((long (*) PARAMS ((bfd *, asymbol **))) _bfd_n1) +#define _bfd_nodynamic_get_dynamic_reloc_upper_bound _bfd_n1 +#define _bfd_nodynamic_canonicalize_dynamic_reloc \ + ((long (*) PARAMS ((bfd *, arelent **, asymbol **))) _bfd_n1) + +/* Generic routine to determine of the given symbol is a local + label. */ +extern bfd_boolean bfd_generic_is_local_label_name + PARAMS ((bfd *, const char *)); + +/* Generic minisymbol routines. */ +extern long _bfd_generic_read_minisymbols + PARAMS ((bfd *, bfd_boolean, PTR *, unsigned int *)); +extern asymbol *_bfd_generic_minisymbol_to_symbol + PARAMS ((bfd *, bfd_boolean, const PTR, asymbol *)); + +/* Find the nearest line using .stab/.stabstr sections. */ +extern bfd_boolean _bfd_stab_section_find_nearest_line + PARAMS ((bfd *, asymbol **, asection *, bfd_vma, bfd_boolean *, + const char **, const char **, unsigned int *, PTR *)); + +/* Find the neaderst line using DWARF 1 debugging information. */ +extern bfd_boolean _bfd_dwarf1_find_nearest_line + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *)); + +/* Find the nearest line using DWARF 2 debugging information. */ +extern bfd_boolean _bfd_dwarf2_find_nearest_line + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *, unsigned int, + PTR *)); + +/* Create a new section entry. */ +extern struct bfd_hash_entry *bfd_section_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + +/* A routine to create entries for a bfd_link_hash_table. */ +extern struct bfd_hash_entry *_bfd_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string)); + +/* Initialize a bfd_link_hash_table. */ +extern bfd_boolean _bfd_link_hash_table_init + PARAMS ((struct bfd_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Generic link hash table creation routine. */ +extern struct bfd_link_hash_table *_bfd_generic_link_hash_table_create + PARAMS ((bfd *)); + +/* Generic link hash table destruction routine. */ +extern void _bfd_generic_link_hash_table_free + PARAMS ((struct bfd_link_hash_table *)); + +/* Generic add symbol routine. */ +extern bfd_boolean _bfd_generic_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Generic add symbol routine. This version is used by targets for + which the linker must collect constructors and destructors by name, + as the collect2 program does. */ +extern bfd_boolean _bfd_generic_link_add_symbols_collect + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Generic archive add symbol routine. */ +extern bfd_boolean _bfd_generic_link_add_archive_symbols + PARAMS ((bfd *, struct bfd_link_info *, + bfd_boolean (*) (bfd *, struct bfd_link_info *, bfd_boolean *))); + +/* Forward declaration to avoid prototype errors. */ +typedef struct bfd_link_hash_entry _bfd_link_hash_entry; + +/* Generic routine to add a single symbol. */ +extern bfd_boolean _bfd_generic_link_add_one_symbol + PARAMS ((struct bfd_link_info *, bfd *, const char *name, flagword, + asection *, bfd_vma, const char *, bfd_boolean copy, + bfd_boolean constructor, struct bfd_link_hash_entry **)); + +/* Generic routine to mark section as supplying symbols only. */ +extern void _bfd_generic_link_just_syms + PARAMS ((asection *, struct bfd_link_info *)); + +/* Generic link routine. */ +extern bfd_boolean _bfd_generic_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern bfd_boolean _bfd_generic_link_split_section + PARAMS ((bfd *, struct sec *)); + +/* Generic reloc_link_order processing routine. */ +extern bfd_boolean _bfd_generic_reloc_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Default link order processing routine. */ +extern bfd_boolean _bfd_default_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); + +/* Count the number of reloc entries in a link order list. */ +extern unsigned int _bfd_count_link_order_relocs + PARAMS ((struct bfd_link_order *)); + +/* Final link relocation routine. */ +extern bfd_reloc_status_type _bfd_final_link_relocate + PARAMS ((reloc_howto_type *, bfd *, asection *, bfd_byte *, + bfd_vma, bfd_vma, bfd_vma)); + +/* Relocate a particular location by a howto and a value. */ +extern bfd_reloc_status_type _bfd_relocate_contents + PARAMS ((reloc_howto_type *, bfd *, bfd_vma, bfd_byte *)); + +/* Link stabs in sections in the first pass. */ + +extern bfd_boolean _bfd_link_section_stabs + PARAMS ((bfd *, PTR *, asection *, asection *, PTR *)); + +/* Eliminate stabs for discarded functions and symbols. */ +extern bfd_boolean _bfd_discard_section_stabs + PARAMS ((bfd *, asection *, PTR, + bfd_boolean (*) (bfd_vma, PTR), PTR)); + +/* Write out the .stab section when linking stabs in sections. */ + +extern bfd_boolean _bfd_write_section_stabs + PARAMS ((bfd *, PTR *, asection *, PTR *, bfd_byte *)); + +/* Write out the .stabstr string table when linking stabs in sections. */ + +extern bfd_boolean _bfd_write_stab_strings + PARAMS ((bfd *, PTR *)); + +/* Find an offset within a .stab section when linking stabs in + sections. */ + +extern bfd_vma _bfd_stab_section_offset + PARAMS ((bfd *, PTR *, asection *, PTR *, bfd_vma)); + +/* Attempt to merge a SEC_MERGE section. */ + +extern bfd_boolean _bfd_merge_section + PARAMS ((bfd *, PTR *, asection *, PTR *)); + +/* Attempt to merge SEC_MERGE sections. */ + +extern bfd_boolean _bfd_merge_sections + PARAMS ((bfd *, PTR, void (*)(bfd *, asection *))); + +/* Write out a merged section. */ + +extern bfd_boolean _bfd_write_merged_section + PARAMS ((bfd *, asection *, PTR)); + +/* Find an offset within a modified SEC_MERGE section. */ + +extern bfd_vma _bfd_merged_section_offset + PARAMS ((bfd *, asection **, PTR, bfd_vma, bfd_vma)); + +/* Create a string table. */ +extern struct bfd_strtab_hash *_bfd_stringtab_init + PARAMS ((void)); + +/* Create an XCOFF .debug section style string table. */ +extern struct bfd_strtab_hash *_bfd_xcoff_stringtab_init + PARAMS ((void)); + +/* Free a string table. */ +extern void _bfd_stringtab_free + PARAMS ((struct bfd_strtab_hash *)); + +/* Get the size of a string table. */ +extern bfd_size_type _bfd_stringtab_size + PARAMS ((struct bfd_strtab_hash *)); + +/* Add a string to a string table. */ +extern bfd_size_type _bfd_stringtab_add + PARAMS ((struct bfd_strtab_hash *, const char *, bfd_boolean hash, + bfd_boolean copy)); + +/* Write out a string table. */ +extern bfd_boolean _bfd_stringtab_emit + PARAMS ((bfd *, struct bfd_strtab_hash *)); + +/* Check that endianness of input and output file match. */ +extern bfd_boolean _bfd_generic_verify_endian_match + PARAMS ((bfd *, bfd *)); + +/* Macros to tell if bfds are read or write enabled. + + Note that bfds open for read may be scribbled into if the fd passed + to bfd_fdopenr is actually open both for read and write + simultaneously. However an output bfd will never be open for + read. Therefore sometimes you want to check bfd_read_p or + !bfd_read_p, and only sometimes bfd_write_p. +*/ + +#define bfd_read_p(abfd) ((abfd)->direction == read_direction || (abfd)->direction == both_direction) +#define bfd_write_p(abfd) ((abfd)->direction == write_direction || (abfd)->direction == both_direction) + +void bfd_assert + PARAMS ((const char*,int)); + +#define BFD_ASSERT(x) \ +{ if (!(x)) bfd_assert(__FILE__,__LINE__); } + +#define BFD_FAIL() \ +{ bfd_assert(__FILE__,__LINE__); } + +extern void _bfd_abort + PARAMS ((const char *, int, const char *)) ATTRIBUTE_NORETURN; + +/* if gcc >= 2.6, we can give a function name, too */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) +#define __PRETTY_FUNCTION__ ((char *) NULL) +#endif + +#undef abort +#define abort() _bfd_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__) + +FILE * bfd_cache_lookup_worker + PARAMS ((bfd *)); + +extern bfd *bfd_last_cache; + +/* List of supported target vectors, and the default vector (if + bfd_default_vector[0] is NULL, there is no default). */ +extern const bfd_target * const *bfd_target_vector; +extern const bfd_target *bfd_default_vector[]; + +/* List of associated target vectors. */ +extern const bfd_target * const *bfd_associated_vector; + +/* Functions shared by the ECOFF and MIPS ELF backends, which have no + other common header files. */ + +#if defined(__STDC__) || defined(ALMOST_STDC) +struct ecoff_find_line; +#endif + +extern bfd_boolean _bfd_ecoff_locate_line + PARAMS ((bfd *, asection *, bfd_vma, struct ecoff_debug_info * const, + const struct ecoff_debug_swap * const, struct ecoff_find_line *, + const char **, const char **, unsigned int *)); +extern bfd_boolean _bfd_ecoff_get_accumulated_pdr + PARAMS ((PTR, bfd_byte *)); +extern bfd_boolean _bfd_ecoff_get_accumulated_sym + PARAMS ((PTR, bfd_byte *)); +extern bfd_boolean _bfd_ecoff_get_accumulated_ss + PARAMS ((PTR, bfd_byte *)); + +extern bfd_vma _bfd_get_gp_value + PARAMS ((bfd *)); +extern void _bfd_set_gp_value + PARAMS ((bfd *, bfd_vma)); + +/* Function shared by the COFF and ELF SH backends, which have no + other common header files. */ + +extern bfd_boolean _bfd_sh_align_load_span + PARAMS ((bfd *, asection *, bfd_byte *, + bfd_boolean (*) (bfd *, asection *, PTR, bfd_byte *, bfd_vma), + PTR, bfd_vma **, bfd_vma *, bfd_vma, bfd_vma, bfd_boolean *)); + +/* Extracted from init.c. */ +/* Extracted from libbfd.c. */ +bfd_boolean +bfd_write_bigendian_4byte_int PARAMS ((bfd *, unsigned int)); + +unsigned int +bfd_log2 PARAMS ((bfd_vma x)); + +/* Extracted from bfdio.c. */ +/* Extracted from bfdwin.c. */ +struct _bfd_window_internal { + struct _bfd_window_internal *next; + PTR data; + bfd_size_type size; + int refcount : 31; /* should be enough... */ + unsigned mapped : 1; /* 1 = mmap, 0 = malloc */ +}; +/* Extracted from cache.c. */ +#define BFD_CACHE_MAX_OPEN 10 +extern bfd *bfd_last_cache; + +#define bfd_cache_lookup(x) \ + ((x)==bfd_last_cache? \ + (FILE*) (bfd_last_cache->iostream): \ + bfd_cache_lookup_worker(x)) +bfd_boolean +bfd_cache_init PARAMS ((bfd *abfd)); + +bfd_boolean +bfd_cache_close PARAMS ((bfd *abfd)); + +FILE* +bfd_open_file PARAMS ((bfd *abfd)); + +FILE * +bfd_cache_lookup_worker PARAMS ((bfd *abfd)); + +/* Extracted from reloc.c. */ +#ifdef _BFD_MAKE_TABLE_bfd_reloc_code_real + +static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", + + "BFD_RELOC_64", + "BFD_RELOC_32", + "BFD_RELOC_26", + "BFD_RELOC_24", + "BFD_RELOC_16", + "BFD_RELOC_14", + "BFD_RELOC_8", + "BFD_RELOC_64_PCREL", + "BFD_RELOC_32_PCREL", + "BFD_RELOC_24_PCREL", + "BFD_RELOC_16_PCREL", + "BFD_RELOC_12_PCREL", + "BFD_RELOC_8_PCREL", + "BFD_RELOC_32_GOT_PCREL", + "BFD_RELOC_16_GOT_PCREL", + "BFD_RELOC_8_GOT_PCREL", + "BFD_RELOC_32_GOTOFF", + "BFD_RELOC_16_GOTOFF", + "BFD_RELOC_LO16_GOTOFF", + "BFD_RELOC_HI16_GOTOFF", + "BFD_RELOC_HI16_S_GOTOFF", + "BFD_RELOC_8_GOTOFF", + "BFD_RELOC_64_PLT_PCREL", + "BFD_RELOC_32_PLT_PCREL", + "BFD_RELOC_24_PLT_PCREL", + "BFD_RELOC_16_PLT_PCREL", + "BFD_RELOC_8_PLT_PCREL", + "BFD_RELOC_64_PLTOFF", + "BFD_RELOC_32_PLTOFF", + "BFD_RELOC_16_PLTOFF", + "BFD_RELOC_LO16_PLTOFF", + "BFD_RELOC_HI16_PLTOFF", + "BFD_RELOC_HI16_S_PLTOFF", + "BFD_RELOC_8_PLTOFF", + "BFD_RELOC_68K_GLOB_DAT", + "BFD_RELOC_68K_JMP_SLOT", + "BFD_RELOC_68K_RELATIVE", + "BFD_RELOC_32_BASEREL", + "BFD_RELOC_16_BASEREL", + "BFD_RELOC_LO16_BASEREL", + "BFD_RELOC_HI16_BASEREL", + "BFD_RELOC_HI16_S_BASEREL", + "BFD_RELOC_8_BASEREL", + "BFD_RELOC_RVA", + "BFD_RELOC_8_FFnn", + "BFD_RELOC_32_PCREL_S2", + "BFD_RELOC_16_PCREL_S2", + "BFD_RELOC_23_PCREL_S2", + "BFD_RELOC_HI22", + "BFD_RELOC_LO10", + "BFD_RELOC_GPREL16", + "BFD_RELOC_GPREL32", + "BFD_RELOC_I960_CALLJ", + "BFD_RELOC_NONE", + "BFD_RELOC_SPARC_WDISP22", + "BFD_RELOC_SPARC22", + "BFD_RELOC_SPARC13", + "BFD_RELOC_SPARC_GOT10", + "BFD_RELOC_SPARC_GOT13", + "BFD_RELOC_SPARC_GOT22", + "BFD_RELOC_SPARC_PC10", + "BFD_RELOC_SPARC_PC22", + "BFD_RELOC_SPARC_WPLT30", + "BFD_RELOC_SPARC_COPY", + "BFD_RELOC_SPARC_GLOB_DAT", + "BFD_RELOC_SPARC_JMP_SLOT", + "BFD_RELOC_SPARC_RELATIVE", + "BFD_RELOC_SPARC_UA16", + "BFD_RELOC_SPARC_UA32", + "BFD_RELOC_SPARC_UA64", + "BFD_RELOC_SPARC_BASE13", + "BFD_RELOC_SPARC_BASE22", + "BFD_RELOC_SPARC_10", + "BFD_RELOC_SPARC_11", + "BFD_RELOC_SPARC_OLO10", + "BFD_RELOC_SPARC_HH22", + "BFD_RELOC_SPARC_HM10", + "BFD_RELOC_SPARC_LM22", + "BFD_RELOC_SPARC_PC_HH22", + "BFD_RELOC_SPARC_PC_HM10", + "BFD_RELOC_SPARC_PC_LM22", + "BFD_RELOC_SPARC_WDISP16", + "BFD_RELOC_SPARC_WDISP19", + "BFD_RELOC_SPARC_7", + "BFD_RELOC_SPARC_6", + "BFD_RELOC_SPARC_5", + "BFD_RELOC_SPARC_PLT32", + "BFD_RELOC_SPARC_PLT64", + "BFD_RELOC_SPARC_HIX22", + "BFD_RELOC_SPARC_LOX10", + "BFD_RELOC_SPARC_H44", + "BFD_RELOC_SPARC_M44", + "BFD_RELOC_SPARC_L44", + "BFD_RELOC_SPARC_REGISTER", + "BFD_RELOC_SPARC_REV32", + "BFD_RELOC_SPARC_TLS_GD_HI22", + "BFD_RELOC_SPARC_TLS_GD_LO10", + "BFD_RELOC_SPARC_TLS_GD_ADD", + "BFD_RELOC_SPARC_TLS_GD_CALL", + "BFD_RELOC_SPARC_TLS_LDM_HI22", + "BFD_RELOC_SPARC_TLS_LDM_LO10", + "BFD_RELOC_SPARC_TLS_LDM_ADD", + "BFD_RELOC_SPARC_TLS_LDM_CALL", + "BFD_RELOC_SPARC_TLS_LDO_HIX22", + "BFD_RELOC_SPARC_TLS_LDO_LOX10", + "BFD_RELOC_SPARC_TLS_LDO_ADD", + "BFD_RELOC_SPARC_TLS_IE_HI22", + "BFD_RELOC_SPARC_TLS_IE_LO10", + "BFD_RELOC_SPARC_TLS_IE_LD", + "BFD_RELOC_SPARC_TLS_IE_LDX", + "BFD_RELOC_SPARC_TLS_IE_ADD", + "BFD_RELOC_SPARC_TLS_LE_HIX22", + "BFD_RELOC_SPARC_TLS_LE_LOX10", + "BFD_RELOC_SPARC_TLS_DTPMOD32", + "BFD_RELOC_SPARC_TLS_DTPMOD64", + "BFD_RELOC_SPARC_TLS_DTPOFF32", + "BFD_RELOC_SPARC_TLS_DTPOFF64", + "BFD_RELOC_SPARC_TLS_TPOFF32", + "BFD_RELOC_SPARC_TLS_TPOFF64", + "BFD_RELOC_ALPHA_GPDISP_HI16", + "BFD_RELOC_ALPHA_GPDISP_LO16", + "BFD_RELOC_ALPHA_GPDISP", + "BFD_RELOC_ALPHA_LITERAL", + "BFD_RELOC_ALPHA_ELF_LITERAL", + "BFD_RELOC_ALPHA_LITUSE", + "BFD_RELOC_ALPHA_HINT", + "BFD_RELOC_ALPHA_LINKAGE", + "BFD_RELOC_ALPHA_CODEADDR", + "BFD_RELOC_ALPHA_GPREL_HI16", + "BFD_RELOC_ALPHA_GPREL_LO16", + "BFD_RELOC_ALPHA_BRSGP", + "BFD_RELOC_ALPHA_TLSGD", + "BFD_RELOC_ALPHA_TLSLDM", + "BFD_RELOC_ALPHA_DTPMOD64", + "BFD_RELOC_ALPHA_GOTDTPREL16", + "BFD_RELOC_ALPHA_DTPREL64", + "BFD_RELOC_ALPHA_DTPREL_HI16", + "BFD_RELOC_ALPHA_DTPREL_LO16", + "BFD_RELOC_ALPHA_DTPREL16", + "BFD_RELOC_ALPHA_GOTTPREL16", + "BFD_RELOC_ALPHA_TPREL64", + "BFD_RELOC_ALPHA_TPREL_HI16", + "BFD_RELOC_ALPHA_TPREL_LO16", + "BFD_RELOC_ALPHA_TPREL16", + "BFD_RELOC_MIPS_JMP", + "BFD_RELOC_MIPS16_JMP", + "BFD_RELOC_MIPS16_GPREL", + "BFD_RELOC_HI16", + "BFD_RELOC_HI16_S", + "BFD_RELOC_LO16", + "BFD_RELOC_PCREL_HI16_S", + "BFD_RELOC_PCREL_LO16", + "BFD_RELOC_MIPS_LITERAL", + "BFD_RELOC_MIPS_GOT16", + "BFD_RELOC_MIPS_CALL16", + "BFD_RELOC_MIPS_GOT_HI16", + "BFD_RELOC_MIPS_GOT_LO16", + "BFD_RELOC_MIPS_CALL_HI16", + "BFD_RELOC_MIPS_CALL_LO16", + "BFD_RELOC_MIPS_SUB", + "BFD_RELOC_MIPS_GOT_PAGE", + "BFD_RELOC_MIPS_GOT_OFST", + "BFD_RELOC_MIPS_GOT_DISP", + "BFD_RELOC_MIPS_SHIFT5", + "BFD_RELOC_MIPS_SHIFT6", + "BFD_RELOC_MIPS_INSERT_A", + "BFD_RELOC_MIPS_INSERT_B", + "BFD_RELOC_MIPS_DELETE", + "BFD_RELOC_MIPS_HIGHEST", + "BFD_RELOC_MIPS_HIGHER", + "BFD_RELOC_MIPS_SCN_DISP", + "BFD_RELOC_MIPS_REL16", + "BFD_RELOC_MIPS_RELGOT", + "BFD_RELOC_MIPS_JALR", + "BFD_RELOC_FRV_LABEL16", + "BFD_RELOC_FRV_LABEL24", + "BFD_RELOC_FRV_LO16", + "BFD_RELOC_FRV_HI16", + "BFD_RELOC_FRV_GPREL12", + "BFD_RELOC_FRV_GPRELU12", + "BFD_RELOC_FRV_GPREL32", + "BFD_RELOC_FRV_GPRELHI", + "BFD_RELOC_FRV_GPRELLO", + + "BFD_RELOC_386_GOT32", + "BFD_RELOC_386_PLT32", + "BFD_RELOC_386_COPY", + "BFD_RELOC_386_GLOB_DAT", + "BFD_RELOC_386_JUMP_SLOT", + "BFD_RELOC_386_RELATIVE", + "BFD_RELOC_386_GOTOFF", + "BFD_RELOC_386_GOTPC", + "BFD_RELOC_386_TLS_TPOFF", + "BFD_RELOC_386_TLS_IE", + "BFD_RELOC_386_TLS_GOTIE", + "BFD_RELOC_386_TLS_LE", + "BFD_RELOC_386_TLS_GD", + "BFD_RELOC_386_TLS_LDM", + "BFD_RELOC_386_TLS_LDO_32", + "BFD_RELOC_386_TLS_IE_32", + "BFD_RELOC_386_TLS_LE_32", + "BFD_RELOC_386_TLS_DTPMOD32", + "BFD_RELOC_386_TLS_DTPOFF32", + "BFD_RELOC_386_TLS_TPOFF32", + "BFD_RELOC_X86_64_GOT32", + "BFD_RELOC_X86_64_PLT32", + "BFD_RELOC_X86_64_COPY", + "BFD_RELOC_X86_64_GLOB_DAT", + "BFD_RELOC_X86_64_JUMP_SLOT", + "BFD_RELOC_X86_64_RELATIVE", + "BFD_RELOC_X86_64_GOTPCREL", + "BFD_RELOC_X86_64_32S", + "BFD_RELOC_X86_64_DTPMOD64", + "BFD_RELOC_X86_64_DTPOFF64", + "BFD_RELOC_X86_64_TPOFF64", + "BFD_RELOC_X86_64_TLSGD", + "BFD_RELOC_X86_64_TLSLD", + "BFD_RELOC_X86_64_DTPOFF32", + "BFD_RELOC_X86_64_GOTTPOFF", + "BFD_RELOC_X86_64_TPOFF32", + "BFD_RELOC_NS32K_IMM_8", + "BFD_RELOC_NS32K_IMM_16", + "BFD_RELOC_NS32K_IMM_32", + "BFD_RELOC_NS32K_IMM_8_PCREL", + "BFD_RELOC_NS32K_IMM_16_PCREL", + "BFD_RELOC_NS32K_IMM_32_PCREL", + "BFD_RELOC_NS32K_DISP_8", + "BFD_RELOC_NS32K_DISP_16", + "BFD_RELOC_NS32K_DISP_32", + "BFD_RELOC_NS32K_DISP_8_PCREL", + "BFD_RELOC_NS32K_DISP_16_PCREL", + "BFD_RELOC_NS32K_DISP_32_PCREL", + "BFD_RELOC_PDP11_DISP_8_PCREL", + "BFD_RELOC_PDP11_DISP_6_PCREL", + "BFD_RELOC_PJ_CODE_HI16", + "BFD_RELOC_PJ_CODE_LO16", + "BFD_RELOC_PJ_CODE_DIR16", + "BFD_RELOC_PJ_CODE_DIR32", + "BFD_RELOC_PJ_CODE_REL16", + "BFD_RELOC_PJ_CODE_REL32", + "BFD_RELOC_PPC_B26", + "BFD_RELOC_PPC_BA26", + "BFD_RELOC_PPC_TOC16", + "BFD_RELOC_PPC_B16", + "BFD_RELOC_PPC_B16_BRTAKEN", + "BFD_RELOC_PPC_B16_BRNTAKEN", + "BFD_RELOC_PPC_BA16", + "BFD_RELOC_PPC_BA16_BRTAKEN", + "BFD_RELOC_PPC_BA16_BRNTAKEN", + "BFD_RELOC_PPC_COPY", + "BFD_RELOC_PPC_GLOB_DAT", + "BFD_RELOC_PPC_JMP_SLOT", + "BFD_RELOC_PPC_RELATIVE", + "BFD_RELOC_PPC_LOCAL24PC", + "BFD_RELOC_PPC_EMB_NADDR32", + "BFD_RELOC_PPC_EMB_NADDR16", + "BFD_RELOC_PPC_EMB_NADDR16_LO", + "BFD_RELOC_PPC_EMB_NADDR16_HI", + "BFD_RELOC_PPC_EMB_NADDR16_HA", + "BFD_RELOC_PPC_EMB_SDAI16", + "BFD_RELOC_PPC_EMB_SDA2I16", + "BFD_RELOC_PPC_EMB_SDA2REL", + "BFD_RELOC_PPC_EMB_SDA21", + "BFD_RELOC_PPC_EMB_MRKREF", + "BFD_RELOC_PPC_EMB_RELSEC16", + "BFD_RELOC_PPC_EMB_RELST_LO", + "BFD_RELOC_PPC_EMB_RELST_HI", + "BFD_RELOC_PPC_EMB_RELST_HA", + "BFD_RELOC_PPC_EMB_BIT_FLD", + "BFD_RELOC_PPC_EMB_RELSDA", + "BFD_RELOC_PPC64_HIGHER", + "BFD_RELOC_PPC64_HIGHER_S", + "BFD_RELOC_PPC64_HIGHEST", + "BFD_RELOC_PPC64_HIGHEST_S", + "BFD_RELOC_PPC64_TOC16_LO", + "BFD_RELOC_PPC64_TOC16_HI", + "BFD_RELOC_PPC64_TOC16_HA", + "BFD_RELOC_PPC64_TOC", + "BFD_RELOC_PPC64_PLTGOT16", + "BFD_RELOC_PPC64_PLTGOT16_LO", + "BFD_RELOC_PPC64_PLTGOT16_HI", + "BFD_RELOC_PPC64_PLTGOT16_HA", + "BFD_RELOC_PPC64_ADDR16_DS", + "BFD_RELOC_PPC64_ADDR16_LO_DS", + "BFD_RELOC_PPC64_GOT16_DS", + "BFD_RELOC_PPC64_GOT16_LO_DS", + "BFD_RELOC_PPC64_PLT16_LO_DS", + "BFD_RELOC_PPC64_SECTOFF_DS", + "BFD_RELOC_PPC64_SECTOFF_LO_DS", + "BFD_RELOC_PPC64_TOC16_DS", + "BFD_RELOC_PPC64_TOC16_LO_DS", + "BFD_RELOC_PPC64_PLTGOT16_DS", + "BFD_RELOC_PPC64_PLTGOT16_LO_DS", + "BFD_RELOC_PPC_TLS", + "BFD_RELOC_PPC_DTPMOD", + "BFD_RELOC_PPC_TPREL16", + "BFD_RELOC_PPC_TPREL16_LO", + "BFD_RELOC_PPC_TPREL16_HI", + "BFD_RELOC_PPC_TPREL16_HA", + "BFD_RELOC_PPC_TPREL", + "BFD_RELOC_PPC_DTPREL16", + "BFD_RELOC_PPC_DTPREL16_LO", + "BFD_RELOC_PPC_DTPREL16_HI", + "BFD_RELOC_PPC_DTPREL16_HA", + "BFD_RELOC_PPC_DTPREL", + "BFD_RELOC_PPC_GOT_TLSGD16", + "BFD_RELOC_PPC_GOT_TLSGD16_LO", + "BFD_RELOC_PPC_GOT_TLSGD16_HI", + "BFD_RELOC_PPC_GOT_TLSGD16_HA", + "BFD_RELOC_PPC_GOT_TLSLD16", + "BFD_RELOC_PPC_GOT_TLSLD16_LO", + "BFD_RELOC_PPC_GOT_TLSLD16_HI", + "BFD_RELOC_PPC_GOT_TLSLD16_HA", + "BFD_RELOC_PPC_GOT_TPREL16", + "BFD_RELOC_PPC_GOT_TPREL16_LO", + "BFD_RELOC_PPC_GOT_TPREL16_HI", + "BFD_RELOC_PPC_GOT_TPREL16_HA", + "BFD_RELOC_PPC_GOT_DTPREL16", + "BFD_RELOC_PPC_GOT_DTPREL16_LO", + "BFD_RELOC_PPC_GOT_DTPREL16_HI", + "BFD_RELOC_PPC_GOT_DTPREL16_HA", + "BFD_RELOC_PPC64_TPREL16_DS", + "BFD_RELOC_PPC64_TPREL16_LO_DS", + "BFD_RELOC_PPC64_TPREL16_HIGHER", + "BFD_RELOC_PPC64_TPREL16_HIGHERA", + "BFD_RELOC_PPC64_TPREL16_HIGHEST", + "BFD_RELOC_PPC64_TPREL16_HIGHESTA", + "BFD_RELOC_PPC64_DTPREL16_DS", + "BFD_RELOC_PPC64_DTPREL16_LO_DS", + "BFD_RELOC_PPC64_DTPREL16_HIGHER", + "BFD_RELOC_PPC64_DTPREL16_HIGHERA", + "BFD_RELOC_PPC64_DTPREL16_HIGHEST", + "BFD_RELOC_PPC64_DTPREL16_HIGHESTA", + "BFD_RELOC_I370_D12", + "BFD_RELOC_CTOR", + "BFD_RELOC_ARM_PCREL_BRANCH", + "BFD_RELOC_ARM_PCREL_BLX", + "BFD_RELOC_THUMB_PCREL_BLX", + "BFD_RELOC_ARM_IMMEDIATE", + "BFD_RELOC_ARM_ADRL_IMMEDIATE", + "BFD_RELOC_ARM_OFFSET_IMM", + "BFD_RELOC_ARM_SHIFT_IMM", + "BFD_RELOC_ARM_SWI", + "BFD_RELOC_ARM_MULTI", + "BFD_RELOC_ARM_CP_OFF_IMM", + "BFD_RELOC_ARM_CP_OFF_IMM_S2", + "BFD_RELOC_ARM_ADR_IMM", + "BFD_RELOC_ARM_LDR_IMM", + "BFD_RELOC_ARM_LITERAL", + "BFD_RELOC_ARM_IN_POOL", + "BFD_RELOC_ARM_OFFSET_IMM8", + "BFD_RELOC_ARM_HWLITERAL", + "BFD_RELOC_ARM_THUMB_ADD", + "BFD_RELOC_ARM_THUMB_IMM", + "BFD_RELOC_ARM_THUMB_SHIFT", + "BFD_RELOC_ARM_THUMB_OFFSET", + "BFD_RELOC_ARM_GOT12", + "BFD_RELOC_ARM_GOT32", + "BFD_RELOC_ARM_JUMP_SLOT", + "BFD_RELOC_ARM_COPY", + "BFD_RELOC_ARM_GLOB_DAT", + "BFD_RELOC_ARM_PLT32", + "BFD_RELOC_ARM_RELATIVE", + "BFD_RELOC_ARM_GOTOFF", + "BFD_RELOC_ARM_GOTPC", + "BFD_RELOC_SH_PCDISP8BY2", + "BFD_RELOC_SH_PCDISP12BY2", + "BFD_RELOC_SH_IMM4", + "BFD_RELOC_SH_IMM4BY2", + "BFD_RELOC_SH_IMM4BY4", + "BFD_RELOC_SH_IMM8", + "BFD_RELOC_SH_IMM8BY2", + "BFD_RELOC_SH_IMM8BY4", + "BFD_RELOC_SH_PCRELIMM8BY2", + "BFD_RELOC_SH_PCRELIMM8BY4", + "BFD_RELOC_SH_SWITCH16", + "BFD_RELOC_SH_SWITCH32", + "BFD_RELOC_SH_USES", + "BFD_RELOC_SH_COUNT", + "BFD_RELOC_SH_ALIGN", + "BFD_RELOC_SH_CODE", + "BFD_RELOC_SH_DATA", + "BFD_RELOC_SH_LABEL", + "BFD_RELOC_SH_LOOP_START", + "BFD_RELOC_SH_LOOP_END", + "BFD_RELOC_SH_COPY", + "BFD_RELOC_SH_GLOB_DAT", + "BFD_RELOC_SH_JMP_SLOT", + "BFD_RELOC_SH_RELATIVE", + "BFD_RELOC_SH_GOTPC", + "BFD_RELOC_SH_GOT_LOW16", + "BFD_RELOC_SH_GOT_MEDLOW16", + "BFD_RELOC_SH_GOT_MEDHI16", + "BFD_RELOC_SH_GOT_HI16", + "BFD_RELOC_SH_GOTPLT_LOW16", + "BFD_RELOC_SH_GOTPLT_MEDLOW16", + "BFD_RELOC_SH_GOTPLT_MEDHI16", + "BFD_RELOC_SH_GOTPLT_HI16", + "BFD_RELOC_SH_PLT_LOW16", + "BFD_RELOC_SH_PLT_MEDLOW16", + "BFD_RELOC_SH_PLT_MEDHI16", + "BFD_RELOC_SH_PLT_HI16", + "BFD_RELOC_SH_GOTOFF_LOW16", + "BFD_RELOC_SH_GOTOFF_MEDLOW16", + "BFD_RELOC_SH_GOTOFF_MEDHI16", + "BFD_RELOC_SH_GOTOFF_HI16", + "BFD_RELOC_SH_GOTPC_LOW16", + "BFD_RELOC_SH_GOTPC_MEDLOW16", + "BFD_RELOC_SH_GOTPC_MEDHI16", + "BFD_RELOC_SH_GOTPC_HI16", + "BFD_RELOC_SH_COPY64", + "BFD_RELOC_SH_GLOB_DAT64", + "BFD_RELOC_SH_JMP_SLOT64", + "BFD_RELOC_SH_RELATIVE64", + "BFD_RELOC_SH_GOT10BY4", + "BFD_RELOC_SH_GOT10BY8", + "BFD_RELOC_SH_GOTPLT10BY4", + "BFD_RELOC_SH_GOTPLT10BY8", + "BFD_RELOC_SH_GOTPLT32", + "BFD_RELOC_SH_SHMEDIA_CODE", + "BFD_RELOC_SH_IMMU5", + "BFD_RELOC_SH_IMMS6", + "BFD_RELOC_SH_IMMS6BY32", + "BFD_RELOC_SH_IMMU6", + "BFD_RELOC_SH_IMMS10", + "BFD_RELOC_SH_IMMS10BY2", + "BFD_RELOC_SH_IMMS10BY4", + "BFD_RELOC_SH_IMMS10BY8", + "BFD_RELOC_SH_IMMS16", + "BFD_RELOC_SH_IMMU16", + "BFD_RELOC_SH_IMM_LOW16", + "BFD_RELOC_SH_IMM_LOW16_PCREL", + "BFD_RELOC_SH_IMM_MEDLOW16", + "BFD_RELOC_SH_IMM_MEDLOW16_PCREL", + "BFD_RELOC_SH_IMM_MEDHI16", + "BFD_RELOC_SH_IMM_MEDHI16_PCREL", + "BFD_RELOC_SH_IMM_HI16", + "BFD_RELOC_SH_IMM_HI16_PCREL", + "BFD_RELOC_SH_PT_16", + "BFD_RELOC_SH_TLS_GD_32", + "BFD_RELOC_SH_TLS_LD_32", + "BFD_RELOC_SH_TLS_LDO_32", + "BFD_RELOC_SH_TLS_IE_32", + "BFD_RELOC_SH_TLS_LE_32", + "BFD_RELOC_SH_TLS_DTPMOD32", + "BFD_RELOC_SH_TLS_DTPOFF32", + "BFD_RELOC_SH_TLS_TPOFF32", + "BFD_RELOC_THUMB_PCREL_BRANCH9", + "BFD_RELOC_THUMB_PCREL_BRANCH12", + "BFD_RELOC_THUMB_PCREL_BRANCH23", + "BFD_RELOC_ARC_B22_PCREL", + "BFD_RELOC_ARC_B26", + "BFD_RELOC_D10V_10_PCREL_R", + "BFD_RELOC_D10V_10_PCREL_L", + "BFD_RELOC_D10V_18", + "BFD_RELOC_D10V_18_PCREL", + "BFD_RELOC_D30V_6", + "BFD_RELOC_D30V_9_PCREL", + "BFD_RELOC_D30V_9_PCREL_R", + "BFD_RELOC_D30V_15", + "BFD_RELOC_D30V_15_PCREL", + "BFD_RELOC_D30V_15_PCREL_R", + "BFD_RELOC_D30V_21", + "BFD_RELOC_D30V_21_PCREL", + "BFD_RELOC_D30V_21_PCREL_R", + "BFD_RELOC_D30V_32", + "BFD_RELOC_D30V_32_PCREL", + "BFD_RELOC_DLX_HI16_S", + "BFD_RELOC_DLX_LO16", + "BFD_RELOC_DLX_JMP26", + "BFD_RELOC_M32R_24", + "BFD_RELOC_M32R_10_PCREL", + "BFD_RELOC_M32R_18_PCREL", + "BFD_RELOC_M32R_26_PCREL", + "BFD_RELOC_M32R_HI16_ULO", + "BFD_RELOC_M32R_HI16_SLO", + "BFD_RELOC_M32R_LO16", + "BFD_RELOC_M32R_SDA16", + "BFD_RELOC_V850_9_PCREL", + "BFD_RELOC_V850_22_PCREL", + "BFD_RELOC_V850_SDA_16_16_OFFSET", + "BFD_RELOC_V850_SDA_15_16_OFFSET", + "BFD_RELOC_V850_ZDA_16_16_OFFSET", + "BFD_RELOC_V850_ZDA_15_16_OFFSET", + "BFD_RELOC_V850_TDA_6_8_OFFSET", + "BFD_RELOC_V850_TDA_7_8_OFFSET", + "BFD_RELOC_V850_TDA_7_7_OFFSET", + "BFD_RELOC_V850_TDA_16_16_OFFSET", + "BFD_RELOC_V850_TDA_4_5_OFFSET", + "BFD_RELOC_V850_TDA_4_4_OFFSET", + "BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET", + "BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET", + "BFD_RELOC_V850_CALLT_6_7_OFFSET", + "BFD_RELOC_V850_CALLT_16_16_OFFSET", + "BFD_RELOC_V850_LONGCALL", + "BFD_RELOC_V850_LONGJUMP", + "BFD_RELOC_V850_ALIGN", + "BFD_RELOC_MN10300_32_PCREL", + "BFD_RELOC_MN10300_16_PCREL", + "BFD_RELOC_TIC30_LDP", + "BFD_RELOC_TIC54X_PARTLS7", + "BFD_RELOC_TIC54X_PARTMS9", + "BFD_RELOC_TIC54X_23", + "BFD_RELOC_TIC54X_16_OF_23", + "BFD_RELOC_TIC54X_MS7_OF_23", + "BFD_RELOC_FR30_48", + "BFD_RELOC_FR30_20", + "BFD_RELOC_FR30_6_IN_4", + "BFD_RELOC_FR30_8_IN_8", + "BFD_RELOC_FR30_9_IN_8", + "BFD_RELOC_FR30_10_IN_8", + "BFD_RELOC_FR30_9_PCREL", + "BFD_RELOC_FR30_12_PCREL", + "BFD_RELOC_MCORE_PCREL_IMM8BY4", + "BFD_RELOC_MCORE_PCREL_IMM11BY2", + "BFD_RELOC_MCORE_PCREL_IMM4BY2", + "BFD_RELOC_MCORE_PCREL_32", + "BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2", + "BFD_RELOC_MCORE_RVA", + "BFD_RELOC_MMIX_GETA", + "BFD_RELOC_MMIX_GETA_1", + "BFD_RELOC_MMIX_GETA_2", + "BFD_RELOC_MMIX_GETA_3", + "BFD_RELOC_MMIX_CBRANCH", + "BFD_RELOC_MMIX_CBRANCH_J", + "BFD_RELOC_MMIX_CBRANCH_1", + "BFD_RELOC_MMIX_CBRANCH_2", + "BFD_RELOC_MMIX_CBRANCH_3", + "BFD_RELOC_MMIX_PUSHJ", + "BFD_RELOC_MMIX_PUSHJ_1", + "BFD_RELOC_MMIX_PUSHJ_2", + "BFD_RELOC_MMIX_PUSHJ_3", + "BFD_RELOC_MMIX_JMP", + "BFD_RELOC_MMIX_JMP_1", + "BFD_RELOC_MMIX_JMP_2", + "BFD_RELOC_MMIX_JMP_3", + "BFD_RELOC_MMIX_ADDR19", + "BFD_RELOC_MMIX_ADDR27", + "BFD_RELOC_MMIX_REG_OR_BYTE", + "BFD_RELOC_MMIX_REG", + "BFD_RELOC_MMIX_BASE_PLUS_OFFSET", + "BFD_RELOC_MMIX_LOCAL", + "BFD_RELOC_AVR_7_PCREL", + "BFD_RELOC_AVR_13_PCREL", + "BFD_RELOC_AVR_16_PM", + "BFD_RELOC_AVR_LO8_LDI", + "BFD_RELOC_AVR_HI8_LDI", + "BFD_RELOC_AVR_HH8_LDI", + "BFD_RELOC_AVR_LO8_LDI_NEG", + "BFD_RELOC_AVR_HI8_LDI_NEG", + "BFD_RELOC_AVR_HH8_LDI_NEG", + "BFD_RELOC_AVR_LO8_LDI_PM", + "BFD_RELOC_AVR_HI8_LDI_PM", + "BFD_RELOC_AVR_HH8_LDI_PM", + "BFD_RELOC_AVR_LO8_LDI_PM_NEG", + "BFD_RELOC_AVR_HI8_LDI_PM_NEG", + "BFD_RELOC_AVR_HH8_LDI_PM_NEG", + "BFD_RELOC_AVR_CALL", + "BFD_RELOC_390_12", + "BFD_RELOC_390_GOT12", + "BFD_RELOC_390_PLT32", + "BFD_RELOC_390_COPY", + "BFD_RELOC_390_GLOB_DAT", + "BFD_RELOC_390_JMP_SLOT", + "BFD_RELOC_390_RELATIVE", + "BFD_RELOC_390_GOTPC", + "BFD_RELOC_390_GOT16", + "BFD_RELOC_390_PC16DBL", + "BFD_RELOC_390_PLT16DBL", + "BFD_RELOC_390_PC32DBL", + "BFD_RELOC_390_PLT32DBL", + "BFD_RELOC_390_GOTPCDBL", + "BFD_RELOC_390_GOT64", + "BFD_RELOC_390_PLT64", + "BFD_RELOC_390_GOTENT", + "BFD_RELOC_390_GOTOFF64", + "BFD_RELOC_390_GOTPLT12", + "BFD_RELOC_390_GOTPLT16", + "BFD_RELOC_390_GOTPLT32", + "BFD_RELOC_390_GOTPLT64", + "BFD_RELOC_390_GOTPLTENT", + "BFD_RELOC_390_PLTOFF16", + "BFD_RELOC_390_PLTOFF32", + "BFD_RELOC_390_PLTOFF64", + "BFD_RELOC_390_TLS_LOAD", + "BFD_RELOC_390_TLS_GDCALL", + "BFD_RELOC_390_TLS_LDCALL", + "BFD_RELOC_390_TLS_GD32", + "BFD_RELOC_390_TLS_GD64", + "BFD_RELOC_390_TLS_GOTIE12", + "BFD_RELOC_390_TLS_GOTIE32", + "BFD_RELOC_390_TLS_GOTIE64", + "BFD_RELOC_390_TLS_LDM32", + "BFD_RELOC_390_TLS_LDM64", + "BFD_RELOC_390_TLS_IE32", + "BFD_RELOC_390_TLS_IE64", + "BFD_RELOC_390_TLS_IEENT", + "BFD_RELOC_390_TLS_LE32", + "BFD_RELOC_390_TLS_LE64", + "BFD_RELOC_390_TLS_LDO32", + "BFD_RELOC_390_TLS_LDO64", + "BFD_RELOC_390_TLS_DTPMOD", + "BFD_RELOC_390_TLS_DTPOFF", + "BFD_RELOC_390_TLS_TPOFF", + "BFD_RELOC_IP2K_FR9", + "BFD_RELOC_IP2K_BANK", + "BFD_RELOC_IP2K_ADDR16CJP", + "BFD_RELOC_IP2K_PAGE3", + "BFD_RELOC_IP2K_LO8DATA", + "BFD_RELOC_IP2K_HI8DATA", + "BFD_RELOC_IP2K_EX8DATA", + "BFD_RELOC_IP2K_LO8INSN", + "BFD_RELOC_IP2K_HI8INSN", + "BFD_RELOC_IP2K_PC_SKIP", + "BFD_RELOC_IP2K_TEXT", + "BFD_RELOC_IP2K_FR_OFFSET", + "BFD_RELOC_VPE4KMATH_DATA", + "BFD_RELOC_VPE4KMATH_INSN", + "BFD_RELOC_VTABLE_INHERIT", + "BFD_RELOC_VTABLE_ENTRY", + "BFD_RELOC_IA64_IMM14", + "BFD_RELOC_IA64_IMM22", + "BFD_RELOC_IA64_IMM64", + "BFD_RELOC_IA64_DIR32MSB", + "BFD_RELOC_IA64_DIR32LSB", + "BFD_RELOC_IA64_DIR64MSB", + "BFD_RELOC_IA64_DIR64LSB", + "BFD_RELOC_IA64_GPREL22", + "BFD_RELOC_IA64_GPREL64I", + "BFD_RELOC_IA64_GPREL32MSB", + "BFD_RELOC_IA64_GPREL32LSB", + "BFD_RELOC_IA64_GPREL64MSB", + "BFD_RELOC_IA64_GPREL64LSB", + "BFD_RELOC_IA64_LTOFF22", + "BFD_RELOC_IA64_LTOFF64I", + "BFD_RELOC_IA64_PLTOFF22", + "BFD_RELOC_IA64_PLTOFF64I", + "BFD_RELOC_IA64_PLTOFF64MSB", + "BFD_RELOC_IA64_PLTOFF64LSB", + "BFD_RELOC_IA64_FPTR64I", + "BFD_RELOC_IA64_FPTR32MSB", + "BFD_RELOC_IA64_FPTR32LSB", + "BFD_RELOC_IA64_FPTR64MSB", + "BFD_RELOC_IA64_FPTR64LSB", + "BFD_RELOC_IA64_PCREL21B", + "BFD_RELOC_IA64_PCREL21BI", + "BFD_RELOC_IA64_PCREL21M", + "BFD_RELOC_IA64_PCREL21F", + "BFD_RELOC_IA64_PCREL22", + "BFD_RELOC_IA64_PCREL60B", + "BFD_RELOC_IA64_PCREL64I", + "BFD_RELOC_IA64_PCREL32MSB", + "BFD_RELOC_IA64_PCREL32LSB", + "BFD_RELOC_IA64_PCREL64MSB", + "BFD_RELOC_IA64_PCREL64LSB", + "BFD_RELOC_IA64_LTOFF_FPTR22", + "BFD_RELOC_IA64_LTOFF_FPTR64I", + "BFD_RELOC_IA64_LTOFF_FPTR32MSB", + "BFD_RELOC_IA64_LTOFF_FPTR32LSB", + "BFD_RELOC_IA64_LTOFF_FPTR64MSB", + "BFD_RELOC_IA64_LTOFF_FPTR64LSB", + "BFD_RELOC_IA64_SEGREL32MSB", + "BFD_RELOC_IA64_SEGREL32LSB", + "BFD_RELOC_IA64_SEGREL64MSB", + "BFD_RELOC_IA64_SEGREL64LSB", + "BFD_RELOC_IA64_SECREL32MSB", + "BFD_RELOC_IA64_SECREL32LSB", + "BFD_RELOC_IA64_SECREL64MSB", + "BFD_RELOC_IA64_SECREL64LSB", + "BFD_RELOC_IA64_REL32MSB", + "BFD_RELOC_IA64_REL32LSB", + "BFD_RELOC_IA64_REL64MSB", + "BFD_RELOC_IA64_REL64LSB", + "BFD_RELOC_IA64_LTV32MSB", + "BFD_RELOC_IA64_LTV32LSB", + "BFD_RELOC_IA64_LTV64MSB", + "BFD_RELOC_IA64_LTV64LSB", + "BFD_RELOC_IA64_IPLTMSB", + "BFD_RELOC_IA64_IPLTLSB", + "BFD_RELOC_IA64_COPY", + "BFD_RELOC_IA64_LTOFF22X", + "BFD_RELOC_IA64_LDXMOV", + "BFD_RELOC_IA64_TPREL14", + "BFD_RELOC_IA64_TPREL22", + "BFD_RELOC_IA64_TPREL64I", + "BFD_RELOC_IA64_TPREL64MSB", + "BFD_RELOC_IA64_TPREL64LSB", + "BFD_RELOC_IA64_LTOFF_TPREL22", + "BFD_RELOC_IA64_DTPMOD64MSB", + "BFD_RELOC_IA64_DTPMOD64LSB", + "BFD_RELOC_IA64_LTOFF_DTPMOD22", + "BFD_RELOC_IA64_DTPREL14", + "BFD_RELOC_IA64_DTPREL22", + "BFD_RELOC_IA64_DTPREL64I", + "BFD_RELOC_IA64_DTPREL32MSB", + "BFD_RELOC_IA64_DTPREL32LSB", + "BFD_RELOC_IA64_DTPREL64MSB", + "BFD_RELOC_IA64_DTPREL64LSB", + "BFD_RELOC_IA64_LTOFF_DTPREL22", + "BFD_RELOC_M68HC11_HI8", + "BFD_RELOC_M68HC11_LO8", + "BFD_RELOC_M68HC11_3B", + "BFD_RELOC_M68HC11_RL_JUMP", + "BFD_RELOC_M68HC11_RL_GROUP", + "BFD_RELOC_M68HC11_LO16", + "BFD_RELOC_M68HC11_PAGE", + "BFD_RELOC_M68HC11_24", + "BFD_RELOC_CRIS_BDISP8", + "BFD_RELOC_CRIS_UNSIGNED_5", + "BFD_RELOC_CRIS_SIGNED_6", + "BFD_RELOC_CRIS_UNSIGNED_6", + "BFD_RELOC_CRIS_UNSIGNED_4", + "BFD_RELOC_CRIS_COPY", + "BFD_RELOC_CRIS_GLOB_DAT", + "BFD_RELOC_CRIS_JUMP_SLOT", + "BFD_RELOC_CRIS_RELATIVE", + "BFD_RELOC_CRIS_32_GOT", + "BFD_RELOC_CRIS_16_GOT", + "BFD_RELOC_CRIS_32_GOTPLT", + "BFD_RELOC_CRIS_16_GOTPLT", + "BFD_RELOC_CRIS_32_GOTREL", + "BFD_RELOC_CRIS_32_PLT_GOTREL", + "BFD_RELOC_CRIS_32_PLT_PCREL", + "BFD_RELOC_860_COPY", + "BFD_RELOC_860_GLOB_DAT", + "BFD_RELOC_860_JUMP_SLOT", + "BFD_RELOC_860_RELATIVE", + "BFD_RELOC_860_PC26", + "BFD_RELOC_860_PLT26", + "BFD_RELOC_860_PC16", + "BFD_RELOC_860_LOW0", + "BFD_RELOC_860_SPLIT0", + "BFD_RELOC_860_LOW1", + "BFD_RELOC_860_SPLIT1", + "BFD_RELOC_860_LOW2", + "BFD_RELOC_860_SPLIT2", + "BFD_RELOC_860_LOW3", + "BFD_RELOC_860_LOGOT0", + "BFD_RELOC_860_SPGOT0", + "BFD_RELOC_860_LOGOT1", + "BFD_RELOC_860_SPGOT1", + "BFD_RELOC_860_LOGOTOFF0", + "BFD_RELOC_860_SPGOTOFF0", + "BFD_RELOC_860_LOGOTOFF1", + "BFD_RELOC_860_SPGOTOFF1", + "BFD_RELOC_860_LOGOTOFF2", + "BFD_RELOC_860_LOGOTOFF3", + "BFD_RELOC_860_LOPC", + "BFD_RELOC_860_HIGHADJ", + "BFD_RELOC_860_HAGOT", + "BFD_RELOC_860_HAGOTOFF", + "BFD_RELOC_860_HAPC", + "BFD_RELOC_860_HIGH", + "BFD_RELOC_860_HIGOT", + "BFD_RELOC_860_HIGOTOFF", + "BFD_RELOC_OPENRISC_ABS_26", + "BFD_RELOC_OPENRISC_REL_26", + "BFD_RELOC_H8_DIR16A8", + "BFD_RELOC_H8_DIR16R8", + "BFD_RELOC_H8_DIR24A8", + "BFD_RELOC_H8_DIR24R8", + "BFD_RELOC_H8_DIR32A16", + "BFD_RELOC_XSTORMY16_REL_12", + "BFD_RELOC_XSTORMY16_12", + "BFD_RELOC_XSTORMY16_24", + "BFD_RELOC_XSTORMY16_FPTR16", + "BFD_RELOC_VAX_GLOB_DAT", + "BFD_RELOC_VAX_JMP_SLOT", + "BFD_RELOC_VAX_RELATIVE", + "BFD_RELOC_MSP430_10_PCREL", + "BFD_RELOC_MSP430_16_PCREL", + "BFD_RELOC_MSP430_16", + "BFD_RELOC_MSP430_16_PCREL_BYTE", + "BFD_RELOC_MSP430_16_BYTE", + "BFD_RELOC_IQ2000_OFFSET_16", + "BFD_RELOC_IQ2000_OFFSET_21", + "BFD_RELOC_IQ2000_UHI16", + "BFD_RELOC_XTENSA_RTLD", + "BFD_RELOC_XTENSA_GLOB_DAT", + "BFD_RELOC_XTENSA_JMP_SLOT", + "BFD_RELOC_XTENSA_RELATIVE", + "BFD_RELOC_XTENSA_PLT", + "BFD_RELOC_XTENSA_OP0", + "BFD_RELOC_XTENSA_OP1", + "BFD_RELOC_XTENSA_OP2", + "BFD_RELOC_XTENSA_ASM_EXPAND", + "BFD_RELOC_XTENSA_ASM_SIMPLIFY", + "@@overflow: BFD_RELOC_UNUSED@@", +}; +#endif + +reloc_howto_type * +bfd_default_reloc_type_lookup PARAMS ((bfd *abfd, bfd_reloc_code_real_type code)); + +bfd_boolean +bfd_generic_relax_section PARAMS ((bfd *abfd, + asection *section, + struct bfd_link_info *, + bfd_boolean *)); + +bfd_boolean +bfd_generic_gc_sections PARAMS ((bfd *, struct bfd_link_info *)); + +bfd_boolean +bfd_generic_merge_sections PARAMS ((bfd *, struct bfd_link_info *)); + +bfd_byte * +bfd_generic_get_relocated_section_contents PARAMS ((bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocateable, + asymbol **symbols)); + +/* Extracted from archures.c. */ +extern const bfd_arch_info_type bfd_default_arch_struct; +bfd_boolean +bfd_default_set_arch_mach PARAMS ((bfd *abfd, + enum bfd_architecture arch, + unsigned long mach)); + +const bfd_arch_info_type * +bfd_default_compatible PARAMS ((const bfd_arch_info_type *a, + const bfd_arch_info_type *b)); + +bfd_boolean +bfd_default_scan PARAMS ((const struct bfd_arch_info *info, const char *string)); + +/* Extracted from elf.c. */ +struct elf_internal_shdr * +bfd_elf_find_section PARAMS ((bfd *abfd, char *name)); + diff --git a/contrib/binutils-2.14/bfd/libcoff.h b/contrib/binutils-2.14/bfd/libcoff.h new file mode 100644 index 0000000000..1beec22af0 --- /dev/null +++ b/contrib/binutils-2.14/bfd/libcoff.h @@ -0,0 +1,933 @@ +/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically + generated from "libcoff-in.h" and "coffcode.h". + Run "make headers" in your build bfd/ to regenerate. */ + +/* BFD COFF object file private structure. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfdlink.h" + +/* Object file tdata; access macros */ + +#define coff_data(bfd) ((bfd)->tdata.coff_obj_data) +#define exec_hdr(bfd) (coff_data(bfd)->hdr) +#define obj_pe(bfd) (coff_data(bfd)->pe) +#define obj_symbols(bfd) (coff_data(bfd)->symbols) +#define obj_sym_filepos(bfd) (coff_data(bfd)->sym_filepos) + +#define obj_relocbase(bfd) (coff_data(bfd)->relocbase) +#define obj_raw_syments(bfd) (coff_data(bfd)->raw_syments) +#define obj_raw_syment_count(bfd) (coff_data(bfd)->raw_syment_count) +#define obj_convert(bfd) (coff_data(bfd)->conversion_table) +#define obj_conv_table_size(bfd) (coff_data(bfd)->conv_table_size) + +#define obj_coff_external_syms(bfd) (coff_data (bfd)->external_syms) +#define obj_coff_keep_syms(bfd) (coff_data (bfd)->keep_syms) +#define obj_coff_strings(bfd) (coff_data (bfd)->strings) +#define obj_coff_keep_strings(bfd) (coff_data (bfd)->keep_strings) +#define obj_coff_sym_hashes(bfd) (coff_data (bfd)->sym_hashes) +#define obj_coff_strings_written(bfd) (coff_data (bfd)->strings_written) + +#define obj_coff_local_toc_table(bfd) (coff_data(bfd)->local_toc_sym_map) + +/* `Tdata' information kept for COFF files. */ + +typedef struct coff_tdata +{ + struct coff_symbol_struct *symbols; /* symtab for input bfd */ + unsigned int *conversion_table; + int conv_table_size; + file_ptr sym_filepos; + + struct coff_ptr_struct *raw_syments; + unsigned long raw_syment_count; + + /* These are only valid once writing has begun */ + long int relocbase; + + /* These members communicate important constants about the symbol table + to GDB's symbol-reading code. These `constants' unfortunately vary + from coff implementation to implementation... */ + unsigned local_n_btmask; + unsigned local_n_btshft; + unsigned local_n_tmask; + unsigned local_n_tshift; + unsigned local_symesz; + unsigned local_auxesz; + unsigned local_linesz; + + /* The unswapped external symbols. May be NULL. Read by + _bfd_coff_get_external_symbols. */ + PTR external_syms; + /* If this is TRUE, the external_syms may not be freed. */ + bfd_boolean keep_syms; + + /* The string table. May be NULL. Read by + _bfd_coff_read_string_table. */ + char *strings; + /* If this is TRUE, the strings may not be freed. */ + bfd_boolean keep_strings; + /* If this is TRUE, the strings have been written out already. */ + bfd_boolean strings_written; + + /* is this a PE format coff file */ + int pe; + /* Used by the COFF backend linker. */ + struct coff_link_hash_entry **sym_hashes; + + /* used by the pe linker for PowerPC */ + int *local_toc_sym_map; + + struct bfd_link_info *link_info; + + /* Used by coff_find_nearest_line. */ + PTR line_info; + + /* A place to stash dwarf2 info for this bfd. */ + PTR dwarf2_find_line_info; + + /* The timestamp from the COFF file header. */ + long timestamp; + + /* Copy of some of the f_flags bits in the COFF filehdr structure, + used by ARM code. */ + flagword flags; + +} coff_data_type; + +/* Tdata for pe image files. */ +typedef struct pe_tdata +{ + coff_data_type coff; + struct internal_extra_pe_aouthdr pe_opthdr; + int dll; + int has_reloc_section; + bfd_boolean (*in_reloc_p) PARAMS((bfd *, reloc_howto_type *)); + flagword real_flags; + int target_subsystem; + bfd_boolean force_minimum_alignment; +} pe_data_type; + +#define pe_data(bfd) ((bfd)->tdata.pe_obj_data) + +/* Tdata for XCOFF files. */ + +struct xcoff_tdata +{ + /* Basic COFF information. */ + coff_data_type coff; + + /* TRUE if this is an XCOFF64 file. */ + bfd_boolean xcoff64; + + /* TRUE if a large a.out header should be generated. */ + bfd_boolean full_aouthdr; + + /* TOC value. */ + bfd_vma toc; + + /* Index of section holding TOC. */ + int sntoc; + + /* Index of section holding entry point. */ + int snentry; + + /* .text alignment from optional header. */ + int text_align_power; + + /* .data alignment from optional header. */ + int data_align_power; + + /* modtype from optional header. */ + short modtype; + + /* cputype from optional header. */ + short cputype; + + /* maxdata from optional header. */ + bfd_vma maxdata; + + /* maxstack from optional header. */ + bfd_vma maxstack; + + /* Used by the XCOFF backend linker. */ + asection **csects; + unsigned long *debug_indices; + unsigned int import_file_id; +}; + +#define xcoff_data(abfd) ((abfd)->tdata.xcoff_obj_data) + +/* We take the address of the first element of an asymbol to ensure that the + * macro is only ever applied to an asymbol. */ +#define coffsymbol(asymbol) ((coff_symbol_type *)(&((asymbol)->the_bfd))) + +/* 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; + int line_base; + /* A pointer used for .stab linking optimizations. */ + PTR stab_info; + /* Available for individual backends. */ + PTR tdata; +}; + +/* An accessor macro for the coff_section_tdata structure. */ +#define coff_section_data(abfd, sec) \ + ((struct coff_section_tdata *) (sec)->used_by_bfd) + +/* Tdata for sections in XCOFF files. This is used by the linker. */ + +struct xcoff_section_tdata +{ + /* Used for XCOFF csects created by the linker; points to the real + XCOFF section which contains this csect. */ + asection *enclosing; + /* The lineno_count field for the enclosing section, because we are + going to clobber it there. */ + unsigned int lineno_count; + /* The first and one past the last symbol indices for symbols used + by this csect. */ + unsigned long first_symndx; + unsigned long last_symndx; +}; + +/* An accessor macro the xcoff_section_tdata structure. */ +#define xcoff_section_data(abfd, sec) \ + ((struct xcoff_section_tdata *) coff_section_data ((abfd), (sec))->tdata) + +/* Tdata for sections in PE files. */ + +struct pei_section_tdata +{ + /* The virtual size of the section. */ + bfd_size_type virt_size; + /* The PE section flags. */ + long pe_flags; +}; + +/* An accessor macro for the pei_section_tdata structure. */ +#define pei_section_data(abfd, sec) \ + ((struct pei_section_tdata *) coff_section_data ((abfd), (sec))->tdata) + +/* COFF linker hash table entries. */ + +struct coff_link_hash_entry +{ + struct bfd_link_hash_entry root; + + /* Symbol index in output file. Set to -1 initially. Set to -2 if + there is a reloc against this symbol. */ + long indx; + + /* Symbol type. */ + unsigned short type; + + /* Symbol class. */ + unsigned char class; + + /* Number of auxiliary entries. */ + char numaux; + + /* BFD to take auxiliary entries from. */ + bfd *auxbfd; + + /* Pointer to array of auxiliary entries, if any. */ + union internal_auxent *aux; + + /* Flag word; legal values follow. */ + unsigned short coff_link_hash_flags; + /* Symbol is a PE section symbol. */ +#define COFF_LINK_HASH_PE_SECTION_SYMBOL (01) +}; + +/* COFF linker hash table. */ + +struct coff_link_hash_table +{ + struct bfd_link_hash_table root; + /* A pointer to information used to link stabs in sections. */ + PTR stab_info; +}; + +/* Look up an entry in a COFF linker hash table. */ + +#define coff_link_hash_lookup(table, string, create, copy, follow) \ + ((struct coff_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +/* Traverse a COFF linker hash table. */ + +#define coff_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (bfd_boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the COFF linker hash table from a link_info structure. */ + +#define coff_hash_table(p) ((struct coff_link_hash_table *) ((p)->hash)) + +/* Functions in coffgen.c. */ +extern const bfd_target *coff_object_p + PARAMS ((bfd *)); +extern struct sec *coff_section_from_bfd_index + PARAMS ((bfd *, int)); +extern long coff_get_symtab_upper_bound + PARAMS ((bfd *)); +extern long coff_get_symtab + PARAMS ((bfd *, asymbol **)); +extern int coff_count_linenumbers + PARAMS ((bfd *)); +extern struct coff_symbol_struct *coff_symbol_from + PARAMS ((bfd *, asymbol *)); +extern bfd_boolean coff_renumber_symbols + PARAMS ((bfd *, int *)); +extern void coff_mangle_symbols + PARAMS ((bfd *)); +extern bfd_boolean coff_write_symbols + PARAMS ((bfd *)); +extern bfd_boolean coff_write_linenumbers + PARAMS ((bfd *)); +extern alent *coff_get_lineno + PARAMS ((bfd *, asymbol *)); +extern asymbol *coff_section_symbol + PARAMS ((bfd *, char *)); +extern bfd_boolean _bfd_coff_get_external_symbols + PARAMS ((bfd *)); +extern const char *_bfd_coff_read_string_table + PARAMS ((bfd *)); +extern bfd_boolean _bfd_coff_free_symbols + PARAMS ((bfd *)); +extern struct coff_ptr_struct *coff_get_normalized_symtab + PARAMS ((bfd *)); +extern long coff_get_reloc_upper_bound + PARAMS ((bfd *, sec_ptr)); +extern asymbol *coff_make_empty_symbol + PARAMS ((bfd *)); +extern void coff_print_symbol + PARAMS ((bfd *, PTR filep, asymbol *, bfd_print_symbol_type)); +extern void coff_get_symbol_info + PARAMS ((bfd *, asymbol *, symbol_info *ret)); +extern bfd_boolean _bfd_coff_is_local_label_name + PARAMS ((bfd *, const char *)); +extern asymbol *coff_bfd_make_debug_symbol + PARAMS ((bfd *, PTR, unsigned long)); +extern bfd_boolean coff_find_nearest_line + PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **, + const char **, unsigned int *)); +extern int coff_sizeof_headers + PARAMS ((bfd *, bfd_boolean)); +extern bfd_boolean bfd_coff_reloc16_relax_section + PARAMS ((bfd *, asection *, struct bfd_link_info *, bfd_boolean *)); +extern bfd_byte *bfd_coff_reloc16_get_relocated_section_contents + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, + bfd_byte *, bfd_boolean, asymbol **)); +extern bfd_vma bfd_coff_reloc16_get_value + PARAMS ((arelent *, struct bfd_link_info *, asection *)); +extern void bfd_perform_slip + PARAMS ((bfd *, unsigned int, asection *, bfd_vma)); + +/* Functions and types in cofflink.c. */ + +#define STRING_SIZE_SIZE (4) + +/* We use a hash table to merge identical enum, struct, and union + definitions in the linker. */ + +/* Information we keep for a single element (an enum value, a + structure or union field) in the debug merge hash table. */ + +struct coff_debug_merge_element +{ + /* Next element. */ + struct coff_debug_merge_element *next; + + /* Name. */ + const char *name; + + /* Type. */ + unsigned int type; + + /* Symbol index for complex type. */ + long tagndx; +}; + +/* A linked list of debug merge entries for a given name. */ + +struct coff_debug_merge_type +{ + /* Next type with the same name. */ + struct coff_debug_merge_type *next; + + /* Class of type. */ + int class; + + /* Symbol index where this type is defined. */ + long indx; + + /* List of elements. */ + struct coff_debug_merge_element *elements; +}; + +/* Information we store in the debug merge hash table. */ + +struct coff_debug_merge_hash_entry +{ + struct bfd_hash_entry root; + + /* A list of types with this name. */ + struct coff_debug_merge_type *types; +}; + +/* The debug merge hash table. */ + +struct coff_debug_merge_hash_table +{ + struct bfd_hash_table root; +}; + +/* Initialize a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_table_init(table) \ + (bfd_hash_table_init (&(table)->root, _bfd_coff_debug_merge_hash_newfunc)) + +/* Free a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_table_free(table) \ + (bfd_hash_table_free (&(table)->root)) + +/* Look up an entry in a COFF debug merge hash table. */ + +#define coff_debug_merge_hash_lookup(table, string, create, copy) \ + ((struct coff_debug_merge_hash_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +/* Information we keep for each section in the output file when doing + a relocateable link. */ + +struct coff_link_section_info +{ + /* The relocs to be output. */ + struct internal_reloc *relocs; + /* For each reloc against a global symbol whose index was not known + when the reloc was handled, the global hash table entry. */ + struct coff_link_hash_entry **rel_hashes; +}; + +/* Information that we pass around while doing the final link step. */ + +struct coff_final_link_info +{ + /* General link information. */ + struct bfd_link_info *info; + /* Output BFD. */ + bfd *output_bfd; + /* Used to indicate failure in traversal routine. */ + bfd_boolean failed; + /* If doing "task linking" set only during the time when we want the + global symbol writer to convert the storage class of defined global + symbols from global to static. */ + bfd_boolean global_to_static; + /* Hash table for long symbol names. */ + struct bfd_strtab_hash *strtab; + /* When doing a relocateable link, an array of information kept for + each output section, indexed by the target_index field. */ + struct coff_link_section_info *section_info; + /* Symbol index of last C_FILE symbol (-1 if none). */ + long last_file_index; + /* Contents of last C_FILE symbol. */ + struct internal_syment last_file; + /* Symbol index of first aux entry of last .bf symbol with an empty + endndx field (-1 if none). */ + long last_bf_index; + /* Contents of last_bf_index aux entry. */ + union internal_auxent last_bf; + /* Hash table used to merge debug information. */ + struct coff_debug_merge_hash_table debug_merge; + /* Buffer large enough to hold swapped symbols of any input file. */ + struct internal_syment *internal_syms; + /* Buffer large enough to hold sections of symbols of any input file. */ + asection **sec_ptrs; + /* Buffer large enough to hold output indices of symbols of any + input file. */ + long *sym_indices; + /* Buffer large enough to hold output symbols for any input file. */ + bfd_byte *outsyms; + /* Buffer large enough to hold external line numbers for any input + section. */ + bfd_byte *linenos; + /* Buffer large enough to hold any input section. */ + bfd_byte *contents; + /* Buffer large enough to hold external relocs of any input section. */ + bfd_byte *external_relocs; + /* Buffer large enough to hold swapped relocs of any input section. */ + struct internal_reloc *internal_relocs; +}; + +/* Most COFF variants have no way to record the alignment of a + section. This struct is used to set a specific alignment based on + the name of the section. */ + +struct coff_section_alignment_entry +{ + /* The section name. */ + const char *name; + + /* This is either (unsigned int) -1, indicating that the section + name must match exactly, or it is the number of letters which + must match at the start of the name. */ + unsigned int comparison_length; + + /* These macros may be used to fill in the first two fields in a + structure initialization. */ +#define COFF_SECTION_NAME_EXACT_MATCH(name) (name), ((unsigned int) -1) +#define COFF_SECTION_NAME_PARTIAL_MATCH(name) (name), (sizeof (name) - 1) + + /* Only use this entry if the default section alignment for this + target is at least that much (as a power of two). If this field + is COFF_ALIGNMENT_FIELD_EMPTY, it should be ignored. */ + unsigned int default_alignment_min; + + /* Only use this entry if the default section alignment for this + target is no greater than this (as a power of two). If this + field is COFF_ALIGNMENT_FIELD_EMPTY, it should be ignored. */ + unsigned int default_alignment_max; + +#define COFF_ALIGNMENT_FIELD_EMPTY ((unsigned int) -1) + + /* The desired alignment for this section (as a power of two). */ + unsigned int alignment_power; +}; + +extern struct bfd_hash_entry *_bfd_coff_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern bfd_boolean _bfd_coff_link_hash_table_init + PARAMS ((struct coff_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); +extern struct bfd_link_hash_table *_bfd_coff_link_hash_table_create + PARAMS ((bfd *)); +extern const char *_bfd_coff_internal_syment_name + PARAMS ((bfd *, const struct internal_syment *, char *)); +extern bfd_boolean _bfd_coff_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_coff_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +extern struct internal_reloc *_bfd_coff_read_internal_relocs + PARAMS ((bfd *, asection *, bfd_boolean, bfd_byte *, bfd_boolean, + struct internal_reloc *)); +extern bfd_boolean _bfd_coff_generic_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); + +extern struct bfd_hash_entry *_bfd_coff_debug_merge_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern bfd_boolean _bfd_coff_write_global_sym + PARAMS ((struct coff_link_hash_entry *, PTR)); +extern bfd_boolean _bfd_coff_write_task_globals + PARAMS ((struct coff_link_hash_entry *, PTR)); +extern bfd_boolean _bfd_coff_link_input_bfd + PARAMS ((struct coff_final_link_info *, bfd *)); +extern bfd_boolean _bfd_coff_reloc_link_order + PARAMS ((bfd *, struct coff_final_link_info *, asection *, + struct bfd_link_order *)); + + +#define coff_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +/* Functions in xcofflink.c. */ + +extern long _bfd_xcoff_get_dynamic_symtab_upper_bound + PARAMS ((bfd *)); +extern long _bfd_xcoff_canonicalize_dynamic_symtab + PARAMS ((bfd *, asymbol **)); +extern long _bfd_xcoff_get_dynamic_reloc_upper_bound + PARAMS ((bfd *)); +extern long _bfd_xcoff_canonicalize_dynamic_reloc + PARAMS ((bfd *, arelent **, asymbol **)); +extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create + PARAMS ((bfd *)); +extern void _bfd_xcoff_bfd_link_hash_table_free + PARAMS ((struct bfd_link_hash_table *)); +extern bfd_boolean _bfd_xcoff_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_xcoff_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_ppc_xcoff_relocate_section + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); + +/* Functions in coff-ppc.c. FIXME: These are called be pe.em in the + linker, and so should start with bfd and be declared in bfd.h. */ + +extern bfd_boolean ppc_allocate_toc_section + PARAMS ((struct bfd_link_info *)); +extern bfd_boolean ppc_process_before_allocation + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Extracted from coffcode.h. */ +typedef struct coff_ptr_struct +{ + /* Remembers the offset from the first symbol in the file for + this symbol. Generated by coff_renumber_symbols. */ + unsigned int offset; + + /* Should the value of this symbol be renumbered. Used for + XCOFF C_BSTAT symbols. Set by coff_slurp_symbol_table. */ + unsigned int fix_value : 1; + + /* Should the tag field of this symbol be renumbered. + Created by coff_pointerize_aux. */ + unsigned int fix_tag : 1; + + /* Should the endidx field of this symbol be renumbered. + Created by coff_pointerize_aux. */ + unsigned int fix_end : 1; + + /* Should the x_csect.x_scnlen field be renumbered. + Created by coff_pointerize_aux. */ + unsigned int fix_scnlen : 1; + + /* Fix up an XCOFF C_BINCL/C_EINCL symbol. The value is the + index into the line number entries. Set by coff_slurp_symbol_table. */ + unsigned int fix_line : 1; + + /* The container for the symbol structure as read and translated + from the file. */ + union + { + union internal_auxent auxent; + struct internal_syment syment; + } u; +} combined_entry_type; + + +/* Each canonical asymbol really looks like this: */ + +typedef struct coff_symbol_struct +{ + /* The actual symbol which the rest of BFD works with */ + asymbol symbol; + + /* A pointer to the hidden information for this symbol */ + combined_entry_type *native; + + /* A pointer to the linenumber information for this symbol */ + struct lineno_cache_entry *lineno; + + /* Have the line numbers been relocated yet ? */ + bfd_boolean done_lineno; +} coff_symbol_type; +/* COFF symbol classifications. */ + +enum coff_symbol_classification +{ + /* Global symbol. */ + COFF_SYMBOL_GLOBAL, + /* Common symbol. */ + COFF_SYMBOL_COMMON, + /* Undefined symbol. */ + COFF_SYMBOL_UNDEFINED, + /* Local symbol. */ + COFF_SYMBOL_LOCAL, + /* PE section symbol. */ + COFF_SYMBOL_PE_SECTION +}; + +typedef struct +{ + void (*_bfd_coff_swap_aux_in) + PARAMS ((bfd *, PTR, int, int, int, int, PTR)); + + void (*_bfd_coff_swap_sym_in) + PARAMS ((bfd *, PTR, PTR)); + + void (*_bfd_coff_swap_lineno_in) + PARAMS ((bfd *, PTR, PTR)); + + unsigned int (*_bfd_coff_swap_aux_out) + PARAMS ((bfd *, PTR, int, int, int, int, PTR)); + + unsigned int (*_bfd_coff_swap_sym_out) + PARAMS ((bfd *, PTR, PTR)); + + unsigned int (*_bfd_coff_swap_lineno_out) + PARAMS ((bfd *, PTR, PTR)); + + unsigned int (*_bfd_coff_swap_reloc_out) + PARAMS ((bfd *, PTR, PTR)); + + unsigned int (*_bfd_coff_swap_filehdr_out) + PARAMS ((bfd *, PTR, PTR)); + + unsigned int (*_bfd_coff_swap_aouthdr_out) + PARAMS ((bfd *, PTR, PTR)); + + unsigned int (*_bfd_coff_swap_scnhdr_out) + PARAMS ((bfd *, PTR, PTR)); + + unsigned int _bfd_filhsz; + unsigned int _bfd_aoutsz; + unsigned int _bfd_scnhsz; + unsigned int _bfd_symesz; + unsigned int _bfd_auxesz; + unsigned int _bfd_relsz; + unsigned int _bfd_linesz; + unsigned int _bfd_filnmlen; + bfd_boolean _bfd_coff_long_filenames; + bfd_boolean _bfd_coff_long_section_names; + unsigned int _bfd_coff_default_section_alignment_power; + bfd_boolean _bfd_coff_force_symnames_in_strings; + unsigned int _bfd_coff_debug_string_prefix_length; + + void (*_bfd_coff_swap_filehdr_in) + PARAMS ((bfd *, PTR, PTR)); + + void (*_bfd_coff_swap_aouthdr_in) + PARAMS ((bfd *, PTR, PTR)); + + void (*_bfd_coff_swap_scnhdr_in) + PARAMS ((bfd *, PTR, PTR)); + + void (*_bfd_coff_swap_reloc_in) + PARAMS ((bfd *abfd, PTR, PTR)); + + bfd_boolean (*_bfd_coff_bad_format_hook) + PARAMS ((bfd *, PTR)); + + bfd_boolean (*_bfd_coff_set_arch_mach_hook) + PARAMS ((bfd *, PTR)); + + PTR (*_bfd_coff_mkobject_hook) + PARAMS ((bfd *, PTR, PTR)); + + bfd_boolean (*_bfd_styp_to_sec_flags_hook) + PARAMS ((bfd *, PTR, const char *, asection *, flagword *)); + + void (*_bfd_set_alignment_hook) + PARAMS ((bfd *, asection *, PTR)); + + bfd_boolean (*_bfd_coff_slurp_symbol_table) + PARAMS ((bfd *)); + + bfd_boolean (*_bfd_coff_symname_in_debug) + PARAMS ((bfd *, struct internal_syment *)); + + bfd_boolean (*_bfd_coff_pointerize_aux_hook) + PARAMS ((bfd *, combined_entry_type *, combined_entry_type *, + unsigned int, combined_entry_type *)); + + bfd_boolean (*_bfd_coff_print_aux) + PARAMS ((bfd *, FILE *, combined_entry_type *, combined_entry_type *, + combined_entry_type *, unsigned int)); + + void (*_bfd_coff_reloc16_extra_cases) + PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, arelent *, + bfd_byte *, unsigned int *, unsigned int *)); + + int (*_bfd_coff_reloc16_estimate) + PARAMS ((bfd *, asection *, arelent *, unsigned int, + struct bfd_link_info *)); + + enum coff_symbol_classification (*_bfd_coff_classify_symbol) + PARAMS ((bfd *, struct internal_syment *)); + + bfd_boolean (*_bfd_coff_compute_section_file_positions) + PARAMS ((bfd *)); + + bfd_boolean (*_bfd_coff_start_final_link) + PARAMS ((bfd *, struct bfd_link_info *)); + + bfd_boolean (*_bfd_coff_relocate_section) + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, + struct internal_reloc *, struct internal_syment *, asection **)); + + reloc_howto_type *(*_bfd_coff_rtype_to_howto) + PARAMS ((bfd *, asection *, struct internal_reloc *, + struct coff_link_hash_entry *, struct internal_syment *, + bfd_vma *)); + + bfd_boolean (*_bfd_coff_adjust_symndx) + PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, + struct internal_reloc *, bfd_boolean *)); + + bfd_boolean (*_bfd_coff_link_add_one_symbol) + PARAMS ((struct bfd_link_info *, bfd *, const char *, flagword, + asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, + struct bfd_link_hash_entry **)); + + bfd_boolean (*_bfd_coff_link_output_has_begun) + PARAMS ((bfd *, struct coff_final_link_info *)); + + bfd_boolean (*_bfd_coff_final_link_postscript) + PARAMS ((bfd *, struct coff_final_link_info *)); + +} bfd_coff_backend_data; + +#define coff_backend_info(abfd) \ + ((bfd_coff_backend_data *) (abfd)->xvec->backend_data) + +#define bfd_coff_swap_aux_in(a,e,t,c,ind,num,i) \ + ((coff_backend_info (a)->_bfd_coff_swap_aux_in) (a,e,t,c,ind,num,i)) + +#define bfd_coff_swap_sym_in(a,e,i) \ + ((coff_backend_info (a)->_bfd_coff_swap_sym_in) (a,e,i)) + +#define bfd_coff_swap_lineno_in(a,e,i) \ + ((coff_backend_info ( a)->_bfd_coff_swap_lineno_in) (a,e,i)) + +#define bfd_coff_swap_reloc_out(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_out) (abfd, i, o)) + +#define bfd_coff_swap_lineno_out(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_lineno_out) (abfd, i, o)) + +#define bfd_coff_swap_aux_out(a,i,t,c,ind,num,o) \ + ((coff_backend_info (a)->_bfd_coff_swap_aux_out) (a,i,t,c,ind,num,o)) + +#define bfd_coff_swap_sym_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_sym_out) (abfd, i, o)) + +#define bfd_coff_swap_scnhdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_out) (abfd, i, o)) + +#define bfd_coff_swap_filehdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_out) (abfd, i, o)) + +#define bfd_coff_swap_aouthdr_out(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_out) (abfd, i, o)) + +#define bfd_coff_filhsz(abfd) (coff_backend_info (abfd)->_bfd_filhsz) +#define bfd_coff_aoutsz(abfd) (coff_backend_info (abfd)->_bfd_aoutsz) +#define bfd_coff_scnhsz(abfd) (coff_backend_info (abfd)->_bfd_scnhsz) +#define bfd_coff_symesz(abfd) (coff_backend_info (abfd)->_bfd_symesz) +#define bfd_coff_auxesz(abfd) (coff_backend_info (abfd)->_bfd_auxesz) +#define bfd_coff_relsz(abfd) (coff_backend_info (abfd)->_bfd_relsz) +#define bfd_coff_linesz(abfd) (coff_backend_info (abfd)->_bfd_linesz) +#define bfd_coff_filnmlen(abfd) (coff_backend_info (abfd)->_bfd_filnmlen) +#define bfd_coff_long_filenames(abfd) \ + (coff_backend_info (abfd)->_bfd_coff_long_filenames) +#define bfd_coff_long_section_names(abfd) \ + (coff_backend_info (abfd)->_bfd_coff_long_section_names) +#define bfd_coff_default_section_alignment_power(abfd) \ + (coff_backend_info (abfd)->_bfd_coff_default_section_alignment_power) +#define bfd_coff_swap_filehdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_filehdr_in) (abfd, i, o)) + +#define bfd_coff_swap_aouthdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_aouthdr_in) (abfd, i, o)) + +#define bfd_coff_swap_scnhdr_in(abfd, i,o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_scnhdr_in) (abfd, i, o)) + +#define bfd_coff_swap_reloc_in(abfd, i, o) \ + ((coff_backend_info (abfd)->_bfd_coff_swap_reloc_in) (abfd, i, o)) + +#define bfd_coff_bad_format_hook(abfd, filehdr) \ + ((coff_backend_info (abfd)->_bfd_coff_bad_format_hook) (abfd, filehdr)) + +#define bfd_coff_set_arch_mach_hook(abfd, filehdr)\ + ((coff_backend_info (abfd)->_bfd_coff_set_arch_mach_hook) (abfd, filehdr)) +#define bfd_coff_mkobject_hook(abfd, filehdr, aouthdr)\ + ((coff_backend_info (abfd)->_bfd_coff_mkobject_hook)\ + (abfd, filehdr, aouthdr)) + +#define bfd_coff_styp_to_sec_flags_hook(abfd, scnhdr, name, section, flags_ptr)\ + ((coff_backend_info (abfd)->_bfd_styp_to_sec_flags_hook)\ + (abfd, scnhdr, name, section, flags_ptr)) + +#define bfd_coff_set_alignment_hook(abfd, sec, scnhdr)\ + ((coff_backend_info (abfd)->_bfd_set_alignment_hook) (abfd, sec, scnhdr)) + +#define bfd_coff_slurp_symbol_table(abfd)\ + ((coff_backend_info (abfd)->_bfd_coff_slurp_symbol_table) (abfd)) + +#define bfd_coff_symname_in_debug(abfd, sym)\ + ((coff_backend_info (abfd)->_bfd_coff_symname_in_debug) (abfd, sym)) + +#define bfd_coff_force_symnames_in_strings(abfd)\ + (coff_backend_info (abfd)->_bfd_coff_force_symnames_in_strings) + +#define bfd_coff_debug_string_prefix_length(abfd)\ + (coff_backend_info (abfd)->_bfd_coff_debug_string_prefix_length) + +#define bfd_coff_print_aux(abfd, file, base, symbol, aux, indaux)\ + ((coff_backend_info (abfd)->_bfd_coff_print_aux)\ + (abfd, file, base, symbol, aux, indaux)) + +#define bfd_coff_reloc16_extra_cases(abfd, link_info, link_order,\ + reloc, data, src_ptr, dst_ptr)\ + ((coff_backend_info (abfd)->_bfd_coff_reloc16_extra_cases)\ + (abfd, link_info, link_order, reloc, data, src_ptr, dst_ptr)) + +#define bfd_coff_reloc16_estimate(abfd, section, reloc, shrink, link_info)\ + ((coff_backend_info (abfd)->_bfd_coff_reloc16_estimate)\ + (abfd, section, reloc, shrink, link_info)) + +#define bfd_coff_classify_symbol(abfd, sym)\ + ((coff_backend_info (abfd)->_bfd_coff_classify_symbol)\ + (abfd, sym)) + +#define bfd_coff_compute_section_file_positions(abfd)\ + ((coff_backend_info (abfd)->_bfd_coff_compute_section_file_positions)\ + (abfd)) + +#define bfd_coff_start_final_link(obfd, info)\ + ((coff_backend_info (obfd)->_bfd_coff_start_final_link)\ + (obfd, info)) +#define bfd_coff_relocate_section(obfd,info,ibfd,o,con,rel,isyms,secs)\ + ((coff_backend_info (ibfd)->_bfd_coff_relocate_section)\ + (obfd, info, ibfd, o, con, rel, isyms, secs)) +#define bfd_coff_rtype_to_howto(abfd, sec, rel, h, sym, addendp)\ + ((coff_backend_info (abfd)->_bfd_coff_rtype_to_howto)\ + (abfd, sec, rel, h, sym, addendp)) +#define bfd_coff_adjust_symndx(obfd, info, ibfd, sec, rel, adjustedp)\ + ((coff_backend_info (abfd)->_bfd_coff_adjust_symndx)\ + (obfd, info, ibfd, sec, rel, adjustedp)) +#define bfd_coff_link_add_one_symbol(info, abfd, name, flags, section,\ + value, string, cp, coll, hashp)\ + ((coff_backend_info (abfd)->_bfd_coff_link_add_one_symbol)\ + (info, abfd, name, flags, section, value, string, cp, coll, hashp)) + +#define bfd_coff_link_output_has_begun(a,p) \ + ((coff_backend_info (a)->_bfd_coff_link_output_has_begun) (a,p)) +#define bfd_coff_final_link_postscript(a,p) \ + ((coff_backend_info (a)->_bfd_coff_final_link_postscript) (a,p)) + diff --git a/contrib/binutils-2.14/bfd/libecoff.h b/contrib/binutils-2.14/bfd/libecoff.h new file mode 100644 index 0000000000..7fa50698b1 --- /dev/null +++ b/contrib/binutils-2.14/bfd/libecoff.h @@ -0,0 +1,362 @@ +/* BFD ECOFF object file private structure. + Copyright 1993, 1994, 1995, 1996, 1999, 2001, 2002 + Free Software Foundation, Inc. + Written by Ian Lance Taylor, 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfdlink.h" + +#ifndef ECOFF_H +#include "coff/ecoff.h" +#endif + +/* This is the backend information kept for ECOFF files. This + structure is constant for a particular backend. The first element + is the COFF backend data structure, so that ECOFF targets can use + the generic COFF code. */ + +#define ecoff_backend(abfd) \ + ((struct ecoff_backend_data *) (abfd)->xvec->backend_data) + +struct ecoff_backend_data +{ + /* COFF backend information. This must be the first field. */ + bfd_coff_backend_data coff; + /* Supported architecture. */ + enum bfd_architecture arch; + /* Initial portion of armap string. */ + const char *armap_start; + /* The page boundary used to align sections in a demand-paged + executable file. E.g., 0x1000. */ + bfd_vma round; + /* TRUE if the .rdata section is part of the text segment, as on the + Alpha. FALSE if .rdata is part of the data segment, as on the + MIPS. */ + bfd_boolean rdata_in_text; + /* Bitsize of constructor entries. */ + unsigned int constructor_bitsize; + /* Reloc to use for constructor entries. */ + reloc_howto_type *constructor_reloc; + /* How to swap debugging information. */ + struct ecoff_debug_swap debug_swap; + /* External reloc size. */ + bfd_size_type external_reloc_size; + /* Reloc swapping functions. */ + void (*swap_reloc_in) PARAMS ((bfd *, PTR, struct internal_reloc *)); + void (*swap_reloc_out) PARAMS ((bfd *, const struct internal_reloc *, PTR)); + /* Backend reloc tweaking. */ + void (*adjust_reloc_in) + PARAMS ((bfd *, const struct internal_reloc *, arelent *)); + void (*adjust_reloc_out) + PARAMS ((bfd *, const arelent *, struct internal_reloc *)); + /* Relocate section contents while linking. */ + bfd_boolean (*relocate_section) + PARAMS ((bfd *output_bfd, struct bfd_link_info *, bfd *input_bfd, + asection *input_section, bfd_byte *contents, + PTR external_relocs)); + /* Do final adjustments to filehdr and aouthdr. */ + bfd_boolean (*adjust_headers) + PARAMS ((bfd *, struct internal_filehdr *, struct internal_aouthdr *)); + /* Read an element from an archive at a given file position. This + is needed because OSF/1 3.2 uses a weird archive format. */ + bfd *(*get_elt_at_filepos) PARAMS ((bfd *, file_ptr)); +}; + +/* This is the target specific information kept for ECOFF files. */ + +#define ecoff_data(abfd) ((abfd)->tdata.ecoff_obj_data) + +typedef struct ecoff_tdata +{ + /* The reloc file position, set by + ecoff_compute_section_file_positions. */ + file_ptr reloc_filepos; + + /* The symbol table file position, set by _bfd_ecoff_mkobject_hook. */ + file_ptr sym_filepos; + + /* The start and end of the text segment. Only valid for an + existing file, not for one we are creating. */ + unsigned long text_start; + unsigned long text_end; + + /* The cached gp value. This is used when relocating. */ + bfd_vma gp; + + /* The maximum size of objects to optimize using gp. This is + typically set by the -G option to the compiler, assembler or + linker. */ + unsigned int gp_size; + + /* The register masks. When linking, all the masks found in the + input files are combined into the masks of the output file. + These are not all used for all targets, but that's OK, because + the relevant ones are the only ones swapped in and out. */ + unsigned long gprmask; + unsigned long fprmask; + unsigned long cprmask[4]; + + /* The ECOFF symbolic debugging information. */ + struct ecoff_debug_info debug_info; + + /* The unswapped ECOFF symbolic information. */ + PTR raw_syments; + + /* The canonical BFD symbols. */ + struct ecoff_symbol_struct *canonical_symbols; + + /* A mapping from external symbol numbers to entries in the linker + hash table, used when linking. */ + struct ecoff_link_hash_entry **sym_hashes; + + /* A mapping from reloc symbol indices to sections, used when + linking. */ + asection **symndx_to_section; + + /* TRUE if this BFD was written by the backend linker. */ + bfd_boolean linker; + + /* TRUE if a warning that multiple global pointer values are + needed in the output binary was issued already. */ + bfd_boolean issued_multiple_gp_warning; + + /* Used by find_nearest_line entry point. The structure could be + included directly in this one, but there's no point to wasting + the memory just for the infrequently called find_nearest_line. */ + struct ecoff_find_line *find_line_info; + + /* Whether the .rdata section is in the text segment for this + particular ECOFF file. This is not valid until + ecoff_compute_section_file_positions is called. */ + bfd_boolean rdata_in_text; + +} ecoff_data_type; + +/* Each canonical asymbol really looks like this. */ + +typedef struct ecoff_symbol_struct +{ + /* The actual symbol which the rest of BFD works with */ + asymbol symbol; + + /* The fdr for this symbol. */ + FDR *fdr; + + /* TRUE if this is a local symbol rather than an external one. */ + bfd_boolean local; + + /* A pointer to the unswapped hidden information for this symbol. + This is either a struct sym_ext or a struct ext_ext, depending on + the value of the local field above. */ + PTR native; +} ecoff_symbol_type; + +/* We take the address of the first element of an asymbol to ensure that the + macro is only ever applied to an asymbol. */ +#define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd))) + +/* We need to save the index of an external symbol when we write it + out so that can set the symbol index correctly when we write out + the relocs. */ +#define ecoff_get_sym_index(symbol) ((symbol)->udata.i) +#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata.i = (idx)) + +/* When generating MIPS embedded PIC code, the linker relaxes the code + to turn PC relative branches into longer code sequences when the PC + relative branch is out of range. This involves reading the relocs + in bfd_relax_section as well as in bfd_final_link, and requires the + code to keep track of which relocs have been expanded. A pointer + to this structure is put in the used_by_bfd pointer of a section to + keep track of this information. The user_by_bfd pointer will be + NULL if the information was not needed. */ + +struct ecoff_section_tdata +{ + /* The unswapped relocs for this section. These are stored in + memory so the input file does not have to be read twice. */ + PTR external_relocs; + + /* The contents of the section. These bytes may or may not be saved + in memory, but if it is this is a pointer to them. */ + bfd_byte *contents; + + /* Offset adjustments for PC relative branches. A number other than + 1 is an addend for a PC relative branch, or a switch table entry + which is the difference of two .text locations; this addend + arises because the branch or difference crosses one or more + branches which were expanded into a larger code sequence. A 1 + means that this branch was itself expanded into a larger code + sequence. 1 is not a possible offset, since all offsets must be + multiples of the instruction size, which is 4; also, the only + relocs with non-zero offsets will be PC relative branches or + switch table entries within the same object file. If this field + is NULL, no branches were expanded and no offsets are required. + Otherwise there are as many entries as there are relocs in the + section, and the entry for any reloc that is not PC relative is + zero. */ + long *offsets; + + /* When producing an executable (i.e., final, non-relocatable link) + on the Alpha, we may need to use multiple global pointer values + to span the entire .lita section. In essence, we allow each + input .lita section to have its own gp value. To support this, + we need to keep track of the gp values that we picked for each + input .lita section . */ + bfd_vma gp; +}; + +/* An accessor macro for the ecoff_section_tdata structure. */ +#define ecoff_section_data(abfd, sec) \ + ((struct ecoff_section_tdata *) (sec)->used_by_bfd) + +/* ECOFF linker hash table entries. */ + +struct ecoff_link_hash_entry +{ + struct bfd_link_hash_entry root; + /* Symbol index in output file. */ + long indx; + /* BFD that ext field value came from. */ + bfd *abfd; + /* ECOFF external symbol information. */ + EXTR esym; + /* Nonzero if this symbol has been written out. */ + char written; + /* Nonzero if this symbol was referred to as small undefined. */ + char small; +}; + +/* ECOFF linker hash table. */ + +struct ecoff_link_hash_table +{ + struct bfd_link_hash_table root; +}; + +/* Make an ECOFF object. */ +extern bfd_boolean _bfd_ecoff_mkobject PARAMS ((bfd *)); + +/* Read in the ECOFF symbolic debugging information. */ +extern bfd_boolean _bfd_ecoff_slurp_symbolic_info + PARAMS ((bfd *, asection *, struct ecoff_debug_info *)); + +/* Generic ECOFF BFD backend vectors. */ + +extern bfd_boolean _bfd_ecoff_write_object_contents PARAMS ((bfd *abfd)); +extern const bfd_target *_bfd_ecoff_archive_p PARAMS ((bfd *abfd)); + +#define _bfd_ecoff_close_and_cleanup _bfd_generic_close_and_cleanup +#define _bfd_ecoff_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +extern bfd_boolean _bfd_ecoff_new_section_hook + PARAMS ((bfd *, asection *)); +extern bfd_boolean _bfd_ecoff_get_section_contents + PARAMS ((bfd *, asection *, PTR location, file_ptr, bfd_size_type)); + +#define _bfd_ecoff_bfd_link_split_section _bfd_generic_link_split_section + +extern bfd_boolean _bfd_ecoff_bfd_copy_private_bfd_data + PARAMS ((bfd *, bfd *)); +#define _bfd_ecoff_bfd_copy_private_section_data \ + _bfd_generic_bfd_copy_private_section_data + +#define _bfd_ecoff_bfd_copy_private_symbol_data \ + _bfd_generic_bfd_copy_private_symbol_data + +#define _bfd_ecoff_bfd_print_private_bfd_data \ + _bfd_generic_bfd_print_private_bfd_data + +#define _bfd_ecoff_bfd_merge_private_bfd_data \ + _bfd_generic_bfd_merge_private_bfd_data + +#define _bfd_ecoff_bfd_set_private_flags _bfd_generic_bfd_set_private_flags +extern bfd_boolean _bfd_ecoff_slurp_armap PARAMS ((bfd *abfd)); +#define _bfd_ecoff_slurp_extended_name_table _bfd_slurp_extended_name_table +#define _bfd_ecoff_construct_extended_name_table \ + _bfd_archive_bsd_construct_extended_name_table +#define _bfd_ecoff_truncate_arname bfd_dont_truncate_arname +extern bfd_boolean _bfd_ecoff_write_armap + PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int)); +#define _bfd_ecoff_read_ar_hdr _bfd_generic_read_ar_hdr +#define _bfd_ecoff_openr_next_archived_file \ + bfd_generic_openr_next_archived_file +#define _bfd_ecoff_get_elt_at_index _bfd_generic_get_elt_at_index +#define _bfd_ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt +#define _bfd_ecoff_update_armap_timestamp bfd_true + +extern long _bfd_ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd)); +extern long _bfd_ecoff_get_symtab PARAMS ((bfd *abfd, asymbol **alocation)); +extern asymbol *_bfd_ecoff_make_empty_symbol PARAMS ((bfd *abfd)); +extern void _bfd_ecoff_print_symbol + PARAMS ((bfd *, PTR filep, asymbol *, bfd_print_symbol_type)); +extern void _bfd_ecoff_get_symbol_info + PARAMS ((bfd *, asymbol *, symbol_info *)); +extern bfd_boolean _bfd_ecoff_bfd_is_local_label_name + PARAMS ((bfd *, const char *)); +#define _bfd_ecoff_get_lineno _bfd_nosymbols_get_lineno +extern bfd_boolean _bfd_ecoff_find_nearest_line + PARAMS ((bfd *, asection *, asymbol **, bfd_vma offset, + const char **filename_ptr, const char **fnname_ptr, + unsigned int *retline_ptr)); +#define _bfd_ecoff_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define _bfd_ecoff_read_minisymbols _bfd_generic_read_minisymbols +#define _bfd_ecoff_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define _bfd_ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound +extern long _bfd_ecoff_canonicalize_reloc + PARAMS ((bfd *, asection *, arelent **, asymbol **symbols)); +/* ecoff_bfd_reloc_type_lookup defined by backend. */ + +extern bfd_boolean _bfd_ecoff_set_arch_mach + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); +extern bfd_boolean _bfd_ecoff_set_section_contents + PARAMS ((bfd *, asection *, PTR location, file_ptr, bfd_size_type)); + +extern int _bfd_ecoff_sizeof_headers PARAMS ((bfd *abfd, bfd_boolean reloc)); +/* ecoff_bfd_get_relocated_section_contents defined by backend. */ +/* ecoff_bfd_relax_section defined by backend. */ +extern struct bfd_link_hash_table *_bfd_ecoff_bfd_link_hash_table_create + PARAMS ((bfd *)); +#define _bfd_ecoff_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +extern bfd_boolean _bfd_ecoff_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +#define _bfd_ecoff_bfd_link_just_syms _bfd_generic_link_just_syms +extern bfd_boolean _bfd_ecoff_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +/* Hook functions for the generic COFF section reading code. */ + +extern PTR _bfd_ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr)); +#define _bfd_ecoff_set_alignment_hook \ + ((void (*) PARAMS ((bfd *, asection *, PTR))) bfd_void) +extern bfd_boolean _bfd_ecoff_set_arch_mach_hook + PARAMS ((bfd *abfd, PTR filehdr)); +extern bfd_boolean _bfd_ecoff_styp_to_sec_flags + PARAMS ((bfd *, PTR, const char *, asection *, flagword *)); +extern bfd_boolean _bfd_ecoff_slurp_symbol_table PARAMS ((bfd *abfd)); + +/* ECOFF auxiliary information swapping routines. These are the same + for all ECOFF targets, so they are defined in ecofflink.c. */ + +extern void _bfd_ecoff_swap_tir_in + PARAMS ((int, const struct tir_ext *, TIR *)); +extern void _bfd_ecoff_swap_tir_out + PARAMS ((int, const TIR *, struct tir_ext *)); +extern void _bfd_ecoff_swap_rndx_in + PARAMS ((int, const struct rndx_ext *, RNDXR *)); +extern void _bfd_ecoff_swap_rndx_out + PARAMS ((int, const RNDXR *, struct rndx_ext *)); diff --git a/contrib/binutils-2.14/bfd/linker.c b/contrib/binutils-2.14/bfd/linker.c new file mode 100644 index 0000000000..c0e3236f85 --- /dev/null +++ b/contrib/binutils-2.14/bfd/linker.c @@ -0,0 +1,2910 @@ +/* linker.c -- BFD linker routines + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Written by Steve Chamberlain and Ian Lance Taylor, 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" +#include "genlink.h" + +/* +SECTION + Linker Functions + +@cindex Linker + The linker uses three special entry points in the BFD target + vector. It is not necessary to write special routines for + these entry points when creating a new BFD back end, since + generic versions are provided. However, writing them can + speed up linking and make it use significantly less runtime + memory. + + The first routine creates a hash table used by the other + routines. The second routine adds the symbols from an object + file to the hash table. The third routine takes all the + object files and links them together to create the output + file. These routines are designed so that the linker proper + does not need to know anything about the symbols in the object + files that it is linking. The linker merely arranges the + sections as directed by the linker script and lets BFD handle + the details of symbols and relocs. + + The second routine and third routines are passed a pointer to + a <> structure (defined in + <>) which holds information relevant to the link, + including the linker hash table (which was created by the + first routine) and a set of callback functions to the linker + proper. + + The generic linker routines are in <>, and use the + header file <>. As of this writing, the only back + ends which have implemented versions of these routines are + a.out (in <>) and ECOFF (in <>). The a.out + routines are used as examples throughout this section. + +@menu +@* Creating a Linker Hash Table:: +@* Adding Symbols to the Hash Table:: +@* Performing the Final Link:: +@end menu + +INODE +Creating a Linker Hash Table, Adding Symbols to the Hash Table, Linker Functions, Linker Functions +SUBSECTION + Creating a linker hash table + +@cindex _bfd_link_hash_table_create in target vector +@cindex target vector (_bfd_link_hash_table_create) + The linker routines must create a hash table, which must be + derived from <> described in + <>. @xref{Hash Tables}, for information on how to + create a derived hash table. This entry point is called using + the target vector of the linker output file. + + The <<_bfd_link_hash_table_create>> entry point must allocate + and initialize an instance of the desired hash table. If the + back end does not require any additional information to be + stored with the entries in the hash table, the entry point may + simply create a <>. Most likely, + however, some additional information will be needed. + + For example, with each entry in the hash table the a.out + linker keeps the index the symbol has in the final output file + (this index number is used so that when doing a relocateable + link the symbol index used in the output file can be quickly + filled in when copying over a reloc). The a.out linker code + defines the required structures and functions for a hash table + derived from <>. The a.out linker + hash table is created by the function + <>; it simply allocates + space for the hash table, initializes it, and returns a + pointer to it. + + When writing the linker routines for a new back end, you will + generally not know exactly which fields will be required until + you have finished. You should simply create a new hash table + which defines no additional fields, and then simply add fields + as they become necessary. + +INODE +Adding Symbols to the Hash Table, Performing the Final Link, Creating a Linker Hash Table, Linker Functions +SUBSECTION + Adding symbols to the hash table + +@cindex _bfd_link_add_symbols in target vector +@cindex target vector (_bfd_link_add_symbols) + The linker proper will call the <<_bfd_link_add_symbols>> + entry point for each object file or archive which is to be + linked (typically these are the files named on the command + line, but some may also come from the linker script). The + entry point is responsible for examining the file. For an + object file, BFD must add any relevant symbol information to + the hash table. For an archive, BFD must determine which + elements of the archive should be used and adding them to the + link. + + The a.out version of this entry point is + <>. + +@menu +@* Differing file formats:: +@* Adding symbols from an object file:: +@* Adding symbols from an archive:: +@end menu + +INODE +Differing file formats, Adding symbols from an object file, Adding Symbols to the Hash Table, Adding Symbols to the Hash Table +SUBSUBSECTION + Differing file formats + + Normally all the files involved in a link will be of the same + format, but it is also possible to link together different + format object files, and the back end must support that. The + <<_bfd_link_add_symbols>> entry point is called via the target + vector of the file to be added. This has an important + consequence: the function may not assume that the hash table + is the type created by the corresponding + <<_bfd_link_hash_table_create>> vector. All the + <<_bfd_link_add_symbols>> function can assume about the hash + table is that it is derived from <>. + + Sometimes the <<_bfd_link_add_symbols>> function must store + some information in the hash table entry to be used by the + <<_bfd_final_link>> function. In such a case the <> + field of the hash table must be checked to make sure that the + hash table was created by an object file of the same format. + + The <<_bfd_final_link>> routine must be prepared to handle a + hash entry without any extra information added by the + <<_bfd_link_add_symbols>> function. A hash entry without + extra information will also occur when the linker script + directs the linker to create a symbol. Note that, regardless + of how a hash table entry is added, all the fields will be + initialized to some sort of null value by the hash table entry + initialization function. + + See <> for an example of how to + check the <> field before saving information (in this + case, the ECOFF external symbol debugging information) in a + hash table entry. + +INODE +Adding symbols from an object file, Adding symbols from an archive, Differing file formats, Adding Symbols to the Hash Table +SUBSUBSECTION + Adding symbols from an object file + + When the <<_bfd_link_add_symbols>> routine is passed an object + file, it must add all externally visible symbols in that + object file to the hash table. The actual work of adding the + symbol to the hash table is normally handled by the function + <<_bfd_generic_link_add_one_symbol>>. The + <<_bfd_link_add_symbols>> routine is responsible for reading + all the symbols from the object file and passing the correct + information to <<_bfd_generic_link_add_one_symbol>>. + + The <<_bfd_link_add_symbols>> routine should not use + <> to read the symbols. The point of + providing this routine is to avoid the overhead of converting + the symbols into generic <> structures. + +@findex _bfd_generic_link_add_one_symbol + <<_bfd_generic_link_add_one_symbol>> handles the details of + combining common symbols, warning about multiple definitions, + and so forth. It takes arguments which describe the symbol to + add, notably symbol flags, a section, and an offset. The + symbol flags include such things as <> or + <>. The section is a section in the object + file, or something like <> for an undefined + symbol or <> for a common symbol. + + If the <<_bfd_final_link>> routine is also going to need to + read the symbol information, the <<_bfd_link_add_symbols>> + routine should save it somewhere attached to the object file + BFD. However, the information should only be saved if the + <> field of the <> argument is TRUE, so + that the <<-no-keep-memory>> linker switch is effective. + + The a.out function which adds symbols from an object file is + <>, and most of the interesting + work is in <>. The latter saves + pointers to the hash tables entries created by + <<_bfd_generic_link_add_one_symbol>> indexed by symbol number, + so that the <<_bfd_final_link>> routine does not have to call + the hash table lookup routine to locate the entry. + +INODE +Adding symbols from an archive, , Adding symbols from an object file, Adding Symbols to the Hash Table +SUBSUBSECTION + Adding symbols from an archive + + When the <<_bfd_link_add_symbols>> routine is passed an + archive, it must look through the symbols defined by the + archive and decide which elements of the archive should be + included in the link. For each such element it must call the + <> linker callback, and it must add the + symbols from the object file to the linker hash table. + +@findex _bfd_generic_link_add_archive_symbols + In most cases the work of looking through the symbols in the + archive should be done by the + <<_bfd_generic_link_add_archive_symbols>> function. This + function builds a hash table from the archive symbol table and + looks through the list of undefined symbols to see which + elements should be included. + <<_bfd_generic_link_add_archive_symbols>> is passed a function + to call to make the final decision about adding an archive + element to the link and to do the actual work of adding the + symbols to the linker hash table. + + The function passed to + <<_bfd_generic_link_add_archive_symbols>> must read the + symbols of the archive element and decide whether the archive + element should be included in the link. If the element is to + be included, the <> linker callback + routine must be called with the element as an argument, and + the elements symbols must be added to the linker hash table + just as though the element had itself been passed to the + <<_bfd_link_add_symbols>> function. + + When the a.out <<_bfd_link_add_symbols>> function receives an + archive, it calls <<_bfd_generic_link_add_archive_symbols>> + passing <> as the function + argument. <> calls + <>. If the latter decides to add + the element (an element is only added if it provides a real, + non-common, definition for a previously undefined or common + symbol) it calls the <> callback and then + <> calls + <> to actually add the symbols to the + linker hash table. + + The ECOFF back end is unusual in that it does not normally + call <<_bfd_generic_link_add_archive_symbols>>, because ECOFF + archives already contain a hash table of symbols. The ECOFF + back end searches the archive itself to avoid the overhead of + creating a new hash table. + +INODE +Performing the Final Link, , Adding Symbols to the Hash Table, Linker Functions +SUBSECTION + Performing the final link + +@cindex _bfd_link_final_link in target vector +@cindex target vector (_bfd_final_link) + When all the input files have been processed, the linker calls + the <<_bfd_final_link>> entry point of the output BFD. This + routine is responsible for producing the final output file, + which has several aspects. It must relocate the contents of + the input sections and copy the data into the output sections. + It must build an output symbol table including any local + symbols from the input files and the global symbols from the + hash table. When producing relocateable output, it must + modify the input relocs and write them into the output file. + There may also be object format dependent work to be done. + + The linker will also call the <> entry + point when the BFD is closed. The two entry points must work + together in order to produce the correct output file. + + The details of how this works are inevitably dependent upon + the specific object file format. The a.out + <<_bfd_final_link>> routine is <>. + +@menu +@* Information provided by the linker:: +@* Relocating the section contents:: +@* Writing the symbol table:: +@end menu + +INODE +Information provided by the linker, Relocating the section contents, Performing the Final Link, Performing the Final Link +SUBSUBSECTION + Information provided by the linker + + Before the linker calls the <<_bfd_final_link>> entry point, + it sets up some data structures for the function to use. + + The <> field of the <> structure + will point to a list of all the input files included in the + link. These files are linked through the <> field + of the <> structure. + + Each section in the output file will have a list of + <> structures attached to the <> + field (the <> structure is defined in + <>). These structures describe how to create the + contents of the output section in terms of the contents of + various input sections, fill constants, and, eventually, other + types of information. They also describe relocs that must be + created by the BFD backend, but do not correspond to any input + file; this is used to support -Ur, which builds constructors + while generating a relocateable object file. + +INODE +Relocating the section contents, Writing the symbol table, Information provided by the linker, Performing the Final Link +SUBSUBSECTION + Relocating the section contents + + The <<_bfd_final_link>> function should look through the + <> structures attached to each section of the + output file. Each <> structure should either be + handled specially, or it should be passed to the function + <<_bfd_default_link_order>> which will do the right thing + (<<_bfd_default_link_order>> is defined in <>). + + For efficiency, a <> of type + <> whose associated section belongs + to a BFD of the same format as the output BFD must be handled + specially. This type of <> describes part of an + output section in terms of a section belonging to one of the + input files. The <<_bfd_final_link>> function should read the + contents of the section and any associated relocs, apply the + relocs to the section contents, and write out the modified + section contents. If performing a relocateable link, the + relocs themselves must also be modified and written out. + +@findex _bfd_relocate_contents +@findex _bfd_final_link_relocate + The functions <<_bfd_relocate_contents>> and + <<_bfd_final_link_relocate>> provide some general support for + performing the actual relocations, notably overflow checking. + Their arguments include information about the symbol the + relocation is against and a <> argument + which describes the relocation to perform. These functions + are defined in <>. + + The a.out function which handles reading, relocating, and + writing section contents is <>. The + actual relocation is done in <> + and <>. + +INODE +Writing the symbol table, , Relocating the section contents, Performing the Final Link +SUBSUBSECTION + Writing the symbol table + + The <<_bfd_final_link>> function must gather all the symbols + in the input files and write them out. It must also write out + all the symbols in the global hash table. This must be + controlled by the <> and <> fields of the + <> structure. + + The local symbols of the input files will not have been + entered into the linker hash table. The <<_bfd_final_link>> + routine must consider each input file and include the symbols + in the output file. It may be convenient to do this when + looking through the <> structures, or it may be + done by stepping through the <> list. + + The <<_bfd_final_link>> routine must also traverse the global + hash table to gather all the externally visible symbols. It + is possible that most of the externally visible symbols may be + written out when considering the symbols of each input file, + but it is still necessary to traverse the hash table since the + linker script may have defined some symbols that are not in + any of the input files. + + The <> field of the <> structure + controls which symbols are written out. The possible values + are listed in <>. If the value is <>, + then the <> field of the <> + structure is a hash table of symbols to keep; each symbol + should be looked up in this hash table, and only symbols which + are present should be included in the output file. + + If the <> field of the <> structure + permits local symbols to be written out, the <> field + is used to further controls which local symbols are included + in the output file. If the value is <>, then all + local symbols which begin with a certain prefix are discarded; + this is controlled by the <> entry point. + + The a.out backend handles symbols by calling + <> on each input BFD and then + traversing the global hash table with the function + <>. It builds a string table + while writing out the symbols, which is written to the output + file at the end of <>. +*/ + +static bfd_boolean generic_link_read_symbols + PARAMS ((bfd *)); +static bfd_boolean generic_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean collect)); +static bfd_boolean generic_link_add_object_symbols + PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean collect)); +static bfd_boolean generic_link_check_archive_element_no_collect + PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded)); +static bfd_boolean generic_link_check_archive_element_collect + PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded)); +static bfd_boolean generic_link_check_archive_element + PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded, + bfd_boolean collect)); +static bfd_boolean generic_link_add_symbol_list + PARAMS ((bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **, + bfd_boolean collect)); +static bfd *hash_entry_bfd + PARAMS ((struct bfd_link_hash_entry *)); +static void set_symbol_from_hash + PARAMS ((asymbol *, struct bfd_link_hash_entry *)); +static bfd_boolean generic_add_output_symbol + PARAMS ((bfd *, size_t *psymalloc, asymbol *)); +static bfd_boolean default_data_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *)); +static bfd_boolean default_indirect_link_order + PARAMS ((bfd *, struct bfd_link_info *, asection *, + struct bfd_link_order *, bfd_boolean)); + +/* The link hash table structure is defined in bfdlink.h. It provides + a base hash table which the backend specific hash tables are built + upon. */ + +/* Routine to create an entry in the link hash table. */ + +struct bfd_hash_entry * +_bfd_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + /* 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 (struct bfd_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = bfd_hash_newfunc (entry, table, string); + if (entry) + { + struct bfd_link_hash_entry *h = (struct bfd_link_hash_entry *) entry; + + /* Initialize the local fields. */ + h->type = bfd_link_hash_new; + h->next = NULL; + } + + return entry; +} + +/* Initialize a link hash table. The BFD argument is the one + responsible for creating this table. */ + +bfd_boolean +_bfd_link_hash_table_init (table, abfd, newfunc) + struct bfd_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + table->creator = abfd->xvec; + table->undefs = NULL; + table->undefs_tail = NULL; + table->type = bfd_link_generic_hash_table; + + return bfd_hash_table_init (&table->table, newfunc); +} + +/* Look up a symbol in a link hash table. If follow is TRUE, we + follow bfd_link_hash_indirect and bfd_link_hash_warning links to + the real symbol. */ + +struct bfd_link_hash_entry * +bfd_link_hash_lookup (table, string, create, copy, follow) + struct bfd_link_hash_table *table; + const char *string; + bfd_boolean create; + bfd_boolean copy; + bfd_boolean follow; +{ + struct bfd_link_hash_entry *ret; + + ret = ((struct bfd_link_hash_entry *) + bfd_hash_lookup (&table->table, string, create, copy)); + + if (follow && ret != (struct bfd_link_hash_entry *) NULL) + { + while (ret->type == bfd_link_hash_indirect + || ret->type == bfd_link_hash_warning) + ret = ret->u.i.link; + } + + return ret; +} + +/* Look up a symbol in the main linker hash table if the symbol might + be wrapped. This should only be used for references to an + undefined symbol, not for definitions of a symbol. */ + +struct bfd_link_hash_entry * +bfd_wrapped_link_hash_lookup (abfd, info, string, create, copy, follow) + bfd *abfd; + struct bfd_link_info *info; + const char *string; + bfd_boolean create; + bfd_boolean copy; + bfd_boolean follow; +{ + bfd_size_type amt; + + if (info->wrap_hash != NULL) + { + const char *l; + + l = string; + if (*l == bfd_get_symbol_leading_char (abfd)) + ++l; + +#undef WRAP +#define WRAP "__wrap_" + + if (bfd_hash_lookup (info->wrap_hash, l, FALSE, FALSE) != NULL) + { + char *n; + struct bfd_link_hash_entry *h; + + /* This symbol is being wrapped. We want to replace all + references to SYM with references to __wrap_SYM. */ + + amt = strlen (l) + sizeof WRAP + 1; + n = (char *) bfd_malloc (amt); + if (n == NULL) + return NULL; + + /* Note that symbol_leading_char may be '\0'. */ + n[0] = bfd_get_symbol_leading_char (abfd); + n[1] = '\0'; + strcat (n, WRAP); + strcat (n, l); + h = bfd_link_hash_lookup (info->hash, n, create, TRUE, follow); + free (n); + return h; + } + +#undef WRAP + +#undef REAL +#define REAL "__real_" + + if (*l == '_' + && strncmp (l, REAL, sizeof REAL - 1) == 0 + && bfd_hash_lookup (info->wrap_hash, l + sizeof REAL - 1, + FALSE, FALSE) != NULL) + { + char *n; + struct bfd_link_hash_entry *h; + + /* This is a reference to __real_SYM, where SYM is being + wrapped. We want to replace all references to __real_SYM + with references to SYM. */ + + amt = strlen (l + sizeof REAL - 1) + 2; + n = (char *) bfd_malloc (amt); + if (n == NULL) + return NULL; + + /* Note that symbol_leading_char may be '\0'. */ + n[0] = bfd_get_symbol_leading_char (abfd); + n[1] = '\0'; + strcat (n, l + sizeof REAL - 1); + h = bfd_link_hash_lookup (info->hash, n, create, TRUE, follow); + free (n); + return h; + } + +#undef REAL + } + + return bfd_link_hash_lookup (info->hash, string, create, copy, follow); +} + +/* Traverse a generic link hash table. The only reason this is not a + macro is to do better type checking. This code presumes that an + argument passed as a struct bfd_hash_entry * may be caught as a + struct bfd_link_hash_entry * with no explicit cast required on the + call. */ + +void +bfd_link_hash_traverse (table, func, info) + struct bfd_link_hash_table *table; + bfd_boolean (*func) PARAMS ((struct bfd_link_hash_entry *, PTR)); + PTR info; +{ + bfd_hash_traverse (&table->table, + ((bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) + func), + info); +} + +/* Add a symbol to the linker hash table undefs list. */ + +INLINE void +bfd_link_add_undef (table, h) + struct bfd_link_hash_table *table; + struct bfd_link_hash_entry *h; +{ + BFD_ASSERT (h->next == NULL); + if (table->undefs_tail != (struct bfd_link_hash_entry *) NULL) + table->undefs_tail->next = h; + if (table->undefs == (struct bfd_link_hash_entry *) NULL) + table->undefs = h; + table->undefs_tail = h; +} + +/* Routine to create an entry in a generic link hash table. */ + +struct bfd_hash_entry * +_bfd_generic_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + /* 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 (struct generic_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = _bfd_link_hash_newfunc (entry, table, string); + if (entry) + { + struct generic_link_hash_entry *ret; + + /* Set local fields. */ + ret = (struct generic_link_hash_entry *) entry; + ret->written = FALSE; + ret->sym = NULL; + } + + return entry; +} + +/* Create a generic link hash table. */ + +struct bfd_link_hash_table * +_bfd_generic_link_hash_table_create (abfd) + bfd *abfd; +{ + struct generic_link_hash_table *ret; + bfd_size_type amt = sizeof (struct generic_link_hash_table); + + ret = (struct generic_link_hash_table *) bfd_malloc (amt); + if (ret == NULL) + return (struct bfd_link_hash_table *) NULL; + if (! _bfd_link_hash_table_init (&ret->root, abfd, + _bfd_generic_link_hash_newfunc)) + { + free (ret); + return (struct bfd_link_hash_table *) NULL; + } + return &ret->root; +} + +void +_bfd_generic_link_hash_table_free (hash) + struct bfd_link_hash_table *hash; +{ + struct generic_link_hash_table *ret + = (struct generic_link_hash_table *) hash; + + bfd_hash_table_free (&ret->root.table); + free (ret); +} + +/* Grab the symbols for an object file when doing a generic link. We + store the symbols in the outsymbols field. We need to keep them + around for the entire link to ensure that we only read them once. + If we read them multiple times, we might wind up with relocs and + the hash table pointing to different instances of the symbol + structure. */ + +static bfd_boolean +generic_link_read_symbols (abfd) + bfd *abfd; +{ + if (bfd_get_outsymbols (abfd) == (asymbol **) NULL) + { + long symsize; + long symcount; + + symsize = bfd_get_symtab_upper_bound (abfd); + if (symsize < 0) + return FALSE; + bfd_get_outsymbols (abfd) = + (asymbol **) bfd_alloc (abfd, (bfd_size_type) symsize); + if (bfd_get_outsymbols (abfd) == NULL && symsize != 0) + return FALSE; + symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd)); + if (symcount < 0) + return FALSE; + bfd_get_symcount (abfd) = symcount; + } + + return TRUE; +} + +/* Generic function to add symbols to from an object file to the + global hash table. This version does not automatically collect + constructors by name. */ + +bfd_boolean +_bfd_generic_link_add_symbols (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + return generic_link_add_symbols (abfd, info, FALSE); +} + +/* Generic function to add symbols from an object file to the global + hash table. This version automatically collects constructors by + name, as the collect2 program does. It should be used for any + target which does not provide some other mechanism for setting up + constructors and destructors; these are approximately those targets + for which gcc uses collect2 and do not support stabs. */ + +bfd_boolean +_bfd_generic_link_add_symbols_collect (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + return generic_link_add_symbols (abfd, info, TRUE); +} + +/* Indicate that we are only retrieving symbol values from this + section. We want the symbols to act as though the values in the + file are absolute. */ + +void +_bfd_generic_link_just_syms (sec, info) + asection *sec; + struct bfd_link_info *info ATTRIBUTE_UNUSED; +{ + sec->output_section = bfd_abs_section_ptr; + sec->output_offset = sec->vma; +} + +/* Add symbols from an object file to the global hash table. */ + +static bfd_boolean +generic_link_add_symbols (abfd, info, collect) + bfd *abfd; + struct bfd_link_info *info; + bfd_boolean collect; +{ + bfd_boolean ret; + + switch (bfd_get_format (abfd)) + { + case bfd_object: + ret = generic_link_add_object_symbols (abfd, info, collect); + break; + case bfd_archive: + ret = (_bfd_generic_link_add_archive_symbols + (abfd, info, + (collect + ? generic_link_check_archive_element_collect + : generic_link_check_archive_element_no_collect))); + break; + default: + bfd_set_error (bfd_error_wrong_format); + ret = FALSE; + } + + return ret; +} + +/* Add symbols from an object file to the global hash table. */ + +static bfd_boolean +generic_link_add_object_symbols (abfd, info, collect) + bfd *abfd; + struct bfd_link_info *info; + bfd_boolean collect; +{ + bfd_size_type symcount; + struct symbol_cache_entry **outsyms; + + if (! generic_link_read_symbols (abfd)) + return FALSE; + symcount = _bfd_generic_link_get_symcount (abfd); + outsyms = _bfd_generic_link_get_symbols (abfd); + return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect); +} + +/* We build a hash table of all symbols defined in an archive. */ + +/* An archive symbol may be defined by multiple archive elements. + This linked list is used to hold the elements. */ + +struct archive_list +{ + struct archive_list *next; + unsigned int indx; +}; + +/* An entry in an archive hash table. */ + +struct archive_hash_entry +{ + struct bfd_hash_entry root; + /* Where the symbol is defined. */ + struct archive_list *defs; +}; + +/* An archive hash table itself. */ + +struct archive_hash_table +{ + struct bfd_hash_table table; +}; + +static struct bfd_hash_entry *archive_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static bfd_boolean archive_hash_table_init + PARAMS ((struct archive_hash_table *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +/* Create a new entry for an archive hash table. */ + +static struct bfd_hash_entry * +archive_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct archive_hash_entry *ret = (struct archive_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct archive_hash_entry *) NULL) + ret = ((struct archive_hash_entry *) + bfd_hash_allocate (table, sizeof (struct archive_hash_entry))); + if (ret == (struct archive_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct archive_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->defs = (struct archive_list *) NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Initialize an archive hash table. */ + +static bfd_boolean +archive_hash_table_init (table, newfunc) + struct archive_hash_table *table; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return bfd_hash_table_init (&table->table, newfunc); +} + +/* Look up an entry in an archive hash table. */ + +#define archive_hash_lookup(t, string, create, copy) \ + ((struct archive_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* Allocate space in an archive hash table. */ + +#define archive_hash_allocate(t, size) bfd_hash_allocate (&(t)->table, (size)) + +/* Free an archive hash table. */ + +#define archive_hash_table_free(t) bfd_hash_table_free (&(t)->table) + +/* Generic function to add symbols from an archive file to the global + hash file. This function presumes that the archive symbol table + has already been read in (this is normally done by the + bfd_check_format entry point). It looks through the undefined and + common symbols and searches the archive symbol table for them. If + it finds an entry, it includes the associated object file in the + link. + + The old linker looked through the archive symbol table for + undefined symbols. We do it the other way around, looking through + undefined symbols for symbols defined in the archive. The + advantage of the newer scheme is that we only have to look through + the list of undefined symbols once, whereas the old method had to + re-search the symbol table each time a new object file was added. + + The CHECKFN argument is used to see if an object file should be + included. CHECKFN should set *PNEEDED to TRUE if the object file + should be included, and must also call the bfd_link_info + add_archive_element callback function and handle adding the symbols + to the global hash table. CHECKFN should only return FALSE if some + sort of error occurs. + + For some formats, such as a.out, it is possible to look through an + object file but not actually include it in the link. The + archive_pass field in a BFD is used to avoid checking the symbols + of an object files too many times. When an object is included in + the link, archive_pass is set to -1. If an object is scanned but + not included, archive_pass is set to the pass number. The pass + number is incremented each time a new object file is included. The + pass number is used because when a new object file is included it + may create new undefined symbols which cause a previously examined + object file to be included. */ + +bfd_boolean +_bfd_generic_link_add_archive_symbols (abfd, info, checkfn) + bfd *abfd; + struct bfd_link_info *info; + bfd_boolean (*checkfn) + PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean *pneeded)); +{ + carsym *arsyms; + carsym *arsym_end; + register carsym *arsym; + int pass; + struct archive_hash_table arsym_hash; + unsigned int indx; + struct bfd_link_hash_entry **pundef; + + if (! bfd_has_map (abfd)) + { + /* An empty archive is a special case. */ + if (bfd_openr_next_archived_file (abfd, (bfd *) NULL) == NULL) + return TRUE; + bfd_set_error (bfd_error_no_armap); + return FALSE; + } + + arsyms = bfd_ardata (abfd)->symdefs; + arsym_end = arsyms + bfd_ardata (abfd)->symdef_count; + + /* In order to quickly determine whether an symbol is defined in + this archive, we build a hash table of the symbols. */ + if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc)) + return FALSE; + for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++) + { + struct archive_hash_entry *arh; + struct archive_list *l, **pp; + + arh = archive_hash_lookup (&arsym_hash, arsym->name, TRUE, FALSE); + if (arh == (struct archive_hash_entry *) NULL) + goto error_return; + l = ((struct archive_list *) + archive_hash_allocate (&arsym_hash, sizeof (struct archive_list))); + if (l == NULL) + goto error_return; + l->indx = indx; + for (pp = &arh->defs; + *pp != (struct archive_list *) NULL; + pp = &(*pp)->next) + ; + *pp = l; + l->next = NULL; + } + + /* The archive_pass field in the archive itself is used to + initialize PASS, sine we may search the same archive multiple + times. */ + pass = abfd->archive_pass + 1; + + /* New undefined symbols are added to the end of the list, so we + only need to look through it once. */ + pundef = &info->hash->undefs; + while (*pundef != (struct bfd_link_hash_entry *) NULL) + { + struct bfd_link_hash_entry *h; + struct archive_hash_entry *arh; + struct archive_list *l; + + h = *pundef; + + /* When a symbol is defined, it is not necessarily removed from + the list. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Remove this entry from the list, for general cleanliness + and because we are going to look through the list again + if we search any more libraries. We can't remove the + entry if it is the tail, because that would lose any + entries we add to the list later on (it would also cause + us to lose track of whether the symbol has been + referenced). */ + if (*pundef != info->hash->undefs_tail) + *pundef = (*pundef)->next; + else + pundef = &(*pundef)->next; + continue; + } + + /* Look for this symbol in the archive symbol map. */ + arh = archive_hash_lookup (&arsym_hash, h->root.string, FALSE, FALSE); + if (arh == (struct archive_hash_entry *) NULL) + { + /* If we haven't found the exact symbol we're looking for, + let's look for its import thunk */ + if (info->pei386_auto_import) + { + bfd_size_type amt = strlen (h->root.string) + 10; + char *buf = (char *) bfd_malloc (amt); + if (buf == NULL) + return FALSE; + + sprintf (buf, "__imp_%s", h->root.string); + arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE); + free(buf); + } + if (arh == (struct archive_hash_entry *) NULL) + { + pundef = &(*pundef)->next; + continue; + } + } + /* Look at all the objects which define this symbol. */ + for (l = arh->defs; l != (struct archive_list *) NULL; l = l->next) + { + bfd *element; + bfd_boolean needed; + + /* If the symbol has gotten defined along the way, quit. */ + if (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + break; + + element = bfd_get_elt_at_index (abfd, l->indx); + if (element == (bfd *) NULL) + goto error_return; + + /* If we've already included this element, or if we've + already checked it on this pass, continue. */ + if (element->archive_pass == -1 + || element->archive_pass == pass) + continue; + + /* If we can't figure this element out, just ignore it. */ + if (! bfd_check_format (element, bfd_object)) + { + element->archive_pass = -1; + continue; + } + + /* CHECKFN will see if this element should be included, and + go ahead and include it if appropriate. */ + if (! (*checkfn) (element, info, &needed)) + goto error_return; + + if (! needed) + element->archive_pass = pass; + else + { + element->archive_pass = -1; + + /* Increment the pass count to show that we may need to + recheck object files which were already checked. */ + ++pass; + } + } + + pundef = &(*pundef)->next; + } + + archive_hash_table_free (&arsym_hash); + + /* Save PASS in case we are called again. */ + abfd->archive_pass = pass; + + return TRUE; + + error_return: + archive_hash_table_free (&arsym_hash); + return FALSE; +} + +/* See if we should include an archive element. This version is used + when we do not want to automatically collect constructors based on + the symbol name, presumably because we have some other mechanism + for finding them. */ + +static bfd_boolean +generic_link_check_archive_element_no_collect (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + bfd_boolean *pneeded; +{ + return generic_link_check_archive_element (abfd, info, pneeded, FALSE); +} + +/* See if we should include an archive element. This version is used + when we want to automatically collect constructors based on the + symbol name, as collect2 does. */ + +static bfd_boolean +generic_link_check_archive_element_collect (abfd, info, pneeded) + bfd *abfd; + struct bfd_link_info *info; + bfd_boolean *pneeded; +{ + return generic_link_check_archive_element (abfd, info, pneeded, TRUE); +} + +/* See if we should include an archive element. Optionally collect + constructors. */ + +static bfd_boolean +generic_link_check_archive_element (abfd, info, pneeded, collect) + bfd *abfd; + struct bfd_link_info *info; + bfd_boolean *pneeded; + bfd_boolean collect; +{ + asymbol **pp, **ppend; + + *pneeded = FALSE; + + if (! generic_link_read_symbols (abfd)) + return FALSE; + + pp = _bfd_generic_link_get_symbols (abfd); + ppend = pp + _bfd_generic_link_get_symcount (abfd); + for (; pp < ppend; pp++) + { + asymbol *p; + struct bfd_link_hash_entry *h; + + p = *pp; + + /* We are only interested in globally visible symbols. */ + if (! bfd_is_com_section (p->section) + && (p->flags & (BSF_GLOBAL | BSF_INDIRECT | BSF_WEAK)) == 0) + continue; + + /* We are only interested if we know something about this + symbol, and it is undefined or common. An undefined weak + symbol (type bfd_link_hash_undefweak) is not considered to be + a reference when pulling files out of an archive. See the + SVR4 ABI, p. 4-27. */ + h = bfd_link_hash_lookup (info->hash, bfd_asymbol_name (p), FALSE, + FALSE, TRUE); + if (h == (struct bfd_link_hash_entry *) NULL + || (h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common)) + continue; + + /* P is a symbol we are looking for. */ + + if (! bfd_is_com_section (p->section)) + { + bfd_size_type symcount; + asymbol **symbols; + + /* This object file defines this symbol, so pull it in. */ + if (! (*info->callbacks->add_archive_element) (info, abfd, + bfd_asymbol_name (p))) + return FALSE; + symcount = _bfd_generic_link_get_symcount (abfd); + symbols = _bfd_generic_link_get_symbols (abfd); + if (! generic_link_add_symbol_list (abfd, info, symcount, + symbols, collect)) + return FALSE; + *pneeded = TRUE; + return TRUE; + } + + /* P is a common symbol. */ + + if (h->type == bfd_link_hash_undefined) + { + bfd *symbfd; + bfd_vma size; + unsigned int power; + + symbfd = h->u.undef.abfd; + if (symbfd == (bfd *) NULL) + { + /* This symbol was created as undefined from outside + BFD. We assume that we should link in the object + file. This is for the -u option in the linker. */ + if (! (*info->callbacks->add_archive_element) + (info, abfd, bfd_asymbol_name (p))) + return FALSE; + *pneeded = TRUE; + return TRUE; + } + + /* Turn the symbol into a common symbol but do not link in + the object file. This is how a.out works. Object + formats that require different semantics must implement + this function differently. This symbol is already on the + undefs list. We add the section to a common section + attached to symbfd to ensure that it is in a BFD which + will be linked in. */ + h->type = bfd_link_hash_common; + h->u.c.p = + ((struct bfd_link_hash_common_entry *) + bfd_hash_allocate (&info->hash->table, + sizeof (struct bfd_link_hash_common_entry))); + if (h->u.c.p == NULL) + return FALSE; + + size = bfd_asymbol_value (p); + h->u.c.size = size; + + power = bfd_log2 (size); + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + + if (p->section == bfd_com_section_ptr) + h->u.c.p->section = bfd_make_section_old_way (symbfd, "COMMON"); + else + h->u.c.p->section = bfd_make_section_old_way (symbfd, + p->section->name); + h->u.c.p->section->flags = SEC_ALLOC; + } + else + { + /* Adjust the size of the common symbol if necessary. This + is how a.out works. Object formats that require + different semantics must implement this function + differently. */ + if (bfd_asymbol_value (p) > h->u.c.size) + h->u.c.size = bfd_asymbol_value (p); + } + } + + /* This archive element is not needed. */ + return TRUE; +} + +/* Add the symbols from an object file to the global hash table. ABFD + is the object file. INFO is the linker information. SYMBOL_COUNT + is the number of symbols. SYMBOLS is the list of symbols. COLLECT + is TRUE if constructors should be automatically collected by name + as is done by collect2. */ + +static bfd_boolean +generic_link_add_symbol_list (abfd, info, symbol_count, symbols, collect) + bfd *abfd; + struct bfd_link_info *info; + bfd_size_type symbol_count; + asymbol **symbols; + bfd_boolean collect; +{ + asymbol **pp, **ppend; + + pp = symbols; + ppend = symbols + symbol_count; + for (; pp < ppend; pp++) + { + asymbol *p; + + p = *pp; + + if ((p->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (p)) + || bfd_is_com_section (bfd_get_section (p)) + || bfd_is_ind_section (bfd_get_section (p))) + { + const char *name; + const char *string; + struct generic_link_hash_entry *h; + struct bfd_link_hash_entry *bh; + + name = bfd_asymbol_name (p); + if (((p->flags & BSF_INDIRECT) != 0 + || bfd_is_ind_section (p->section)) + && pp + 1 < ppend) + { + pp++; + string = bfd_asymbol_name (*pp); + } + else if ((p->flags & BSF_WARNING) != 0 + && pp + 1 < ppend) + { + /* The name of P is actually the warning string, and the + next symbol is the one to warn about. */ + string = name; + pp++; + name = bfd_asymbol_name (*pp); + } + else + string = NULL; + + bh = NULL; + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, name, p->flags, bfd_get_section (p), + p->value, string, FALSE, collect, &bh))) + return FALSE; + h = (struct generic_link_hash_entry *) bh; + + /* If this is a constructor symbol, and the linker didn't do + anything with it, then we want to just pass the symbol + through to the output file. This will happen when + linking with -r. */ + if ((p->flags & BSF_CONSTRUCTOR) != 0 + && (h == NULL || h->root.type == bfd_link_hash_new)) + { + p->udata.p = NULL; + continue; + } + + /* Save the BFD symbol so that we don't lose any backend + specific information that may be attached to it. We only + want this one if it gives more information than the + existing one; we don't want to replace a defined symbol + with an undefined one. This routine may be called with a + hash table other than the generic hash table, so we only + do this if we are certain that the hash table is a + generic one. */ + if (info->hash->creator == abfd->xvec) + { + if (h->sym == (asymbol *) NULL + || (! bfd_is_und_section (bfd_get_section (p)) + && (! bfd_is_com_section (bfd_get_section (p)) + || bfd_is_und_section (bfd_get_section (h->sym))))) + { + h->sym = p; + /* BSF_OLD_COMMON is a hack to support COFF reloc + reading, and it should go away when the COFF + linker is switched to the new version. */ + if (bfd_is_com_section (bfd_get_section (p))) + p->flags |= BSF_OLD_COMMON; + } + } + + /* Store a back pointer from the symbol to the hash + table entry for the benefit of relaxation code until + it gets rewritten to not use asymbol structures. + Setting this is also used to check whether these + symbols were set up by the generic linker. */ + p->udata.p = (PTR) h; + } + } + + return TRUE; +} + +/* We use a state table to deal with adding symbols from an object + file. The first index into the state table describes the symbol + from the object file. The second index into the state table is the + type of the symbol in the hash table. */ + +/* The symbol from the object file is turned into one of these row + values. */ + +enum link_row +{ + UNDEF_ROW, /* Undefined. */ + UNDEFW_ROW, /* Weak undefined. */ + DEF_ROW, /* Defined. */ + DEFW_ROW, /* Weak defined. */ + COMMON_ROW, /* Common. */ + INDR_ROW, /* Indirect. */ + WARN_ROW, /* Warning. */ + SET_ROW /* Member of set. */ +}; + +/* apparently needed for Hitachi 3050R(HI-UX/WE2)? */ +#undef FAIL + +/* The actions to take in the state table. */ + +enum link_action +{ + FAIL, /* Abort. */ + UND, /* Mark symbol undefined. */ + WEAK, /* Mark symbol weak undefined. */ + DEF, /* Mark symbol defined. */ + DEFW, /* Mark symbol weak defined. */ + COM, /* Mark symbol common. */ + REF, /* Mark defined symbol referenced. */ + CREF, /* Possibly warn about common reference to defined symbol. */ + CDEF, /* Define existing common symbol. */ + NOACT, /* No action. */ + BIG, /* Mark symbol common using largest size. */ + MDEF, /* Multiple definition error. */ + MIND, /* Multiple indirect symbols. */ + IND, /* Make indirect symbol. */ + CIND, /* Make indirect symbol from existing common symbol. */ + SET, /* Add value to set. */ + MWARN, /* Make warning symbol. */ + WARN, /* Issue warning. */ + CWARN, /* Warn if referenced, else MWARN. */ + CYCLE, /* Repeat with symbol pointed to. */ + REFC, /* Mark indirect symbol referenced and then CYCLE. */ + WARNC /* Issue warning and then CYCLE. */ +}; + +/* The state table itself. The first index is a link_row and the + second index is a bfd_link_hash_type. */ + +static const enum link_action link_action[8][8] = +{ + /* current\prev new undef undefw def defw com indr warn */ + /* UNDEF_ROW */ {UND, NOACT, UND, REF, REF, NOACT, REFC, WARNC }, + /* UNDEFW_ROW */ {WEAK, NOACT, NOACT, REF, REF, NOACT, REFC, WARNC }, + /* DEF_ROW */ {DEF, DEF, DEF, MDEF, DEF, CDEF, MDEF, CYCLE }, + /* DEFW_ROW */ {DEFW, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT, CYCLE }, + /* COMMON_ROW */ {COM, COM, COM, CREF, COM, BIG, REFC, WARNC }, + /* INDR_ROW */ {IND, IND, IND, MDEF, IND, CIND, MIND, CYCLE }, + /* WARN_ROW */ {MWARN, WARN, WARN, CWARN, CWARN, WARN, CWARN, NOACT }, + /* SET_ROW */ {SET, SET, SET, SET, SET, SET, CYCLE, CYCLE } +}; + +/* Most of the entries in the LINK_ACTION table are straightforward, + but a few are somewhat subtle. + + A reference to an indirect symbol (UNDEF_ROW/indr or + UNDEFW_ROW/indr) is counted as a reference both to the indirect + symbol and to the symbol the indirect symbol points to. + + A reference to a warning symbol (UNDEF_ROW/warn or UNDEFW_ROW/warn) + causes the warning to be issued. + + A common definition of an indirect symbol (COMMON_ROW/indr) is + treated as a multiple definition error. Likewise for an indirect + definition of a common symbol (INDR_ROW/com). + + An indirect definition of a warning (INDR_ROW/warn) does not cause + the warning to be issued. + + If a warning is created for an indirect symbol (WARN_ROW/indr) no + warning is created for the symbol the indirect symbol points to. + + Adding an entry to a set does not count as a reference to a set, + and no warning is issued (SET_ROW/warn). */ + +/* Return the BFD in which a hash entry has been defined, if known. */ + +static bfd * +hash_entry_bfd (h) + struct bfd_link_hash_entry *h; +{ + while (h->type == bfd_link_hash_warning) + h = h->u.i.link; + switch (h->type) + { + default: + return NULL; + case bfd_link_hash_undefined: + case bfd_link_hash_undefweak: + return h->u.undef.abfd; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->u.def.section->owner; + case bfd_link_hash_common: + return h->u.c.p->section->owner; + } + /*NOTREACHED*/ +} + +/* Add a symbol to the global hash table. + ABFD is the BFD the symbol comes from. + NAME is the name of the symbol. + FLAGS is the BSF_* bits associated with the symbol. + SECTION is the section in which the symbol is defined; this may be + bfd_und_section_ptr or bfd_com_section_ptr. + VALUE is the value of the symbol, relative to the section. + STRING is used for either an indirect symbol, in which case it is + the name of the symbol to indirect to, or a warning symbol, in + which case it is the warning string. + COPY is TRUE if NAME or STRING must be copied into locally + allocated memory if they need to be saved. + COLLECT is TRUE if we should automatically collect gcc constructor + or destructor names as collect2 does. + HASHP, if not NULL, is a place to store the created hash table + entry; if *HASHP is not NULL, the caller has already looked up + the hash table entry, and stored it in *HASHP. */ + +bfd_boolean +_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value, + string, copy, collect, hashp) + struct bfd_link_info *info; + bfd *abfd; + const char *name; + flagword flags; + asection *section; + bfd_vma value; + const char *string; + bfd_boolean copy; + bfd_boolean collect; + struct bfd_link_hash_entry **hashp; +{ + enum link_row row; + struct bfd_link_hash_entry *h; + bfd_boolean cycle; + + if (bfd_is_ind_section (section) + || (flags & BSF_INDIRECT) != 0) + row = INDR_ROW; + else if ((flags & BSF_WARNING) != 0) + row = WARN_ROW; + else if ((flags & BSF_CONSTRUCTOR) != 0) + row = SET_ROW; + else if (bfd_is_und_section (section)) + { + if ((flags & BSF_WEAK) != 0) + row = UNDEFW_ROW; + else + row = UNDEF_ROW; + } + else if ((flags & BSF_WEAK) != 0) + row = DEFW_ROW; + else if (bfd_is_com_section (section)) + row = COMMON_ROW; + else + row = DEF_ROW; + + if (hashp != NULL && *hashp != NULL) + h = *hashp; + else + { + if (row == UNDEF_ROW || row == UNDEFW_ROW) + h = bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, copy, FALSE); + else + h = bfd_link_hash_lookup (info->hash, name, TRUE, copy, FALSE); + if (h == NULL) + { + if (hashp != NULL) + *hashp = NULL; + return FALSE; + } + } + + if (info->notice_all + || (info->notice_hash != (struct bfd_hash_table *) NULL + && (bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) + != (struct bfd_hash_entry *) NULL))) + { + if (! (*info->callbacks->notice) (info, h->root.string, abfd, section, + value)) + return FALSE; + } + + if (hashp != (struct bfd_link_hash_entry **) NULL) + *hashp = h; + + do + { + enum link_action action; + + cycle = FALSE; + action = link_action[(int) row][(int) h->type]; + switch (action) + { + case FAIL: + abort (); + + case NOACT: + /* Do nothing. */ + break; + + case UND: + /* Make a new undefined symbol. */ + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = abfd; + bfd_link_add_undef (info->hash, h); + break; + + case WEAK: + /* Make a new weak undefined symbol. */ + h->type = bfd_link_hash_undefweak; + h->u.undef.abfd = abfd; + break; + + case CDEF: + /* We have found a definition for a symbol which was + previously common. */ + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, h->root.string, + h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_defined, (bfd_vma) 0))) + return FALSE; + /* Fall through. */ + case DEF: + case DEFW: + { + enum bfd_link_hash_type oldtype; + + /* Define a symbol. */ + oldtype = h->type; + if (action == DEFW) + h->type = bfd_link_hash_defweak; + else + h->type = bfd_link_hash_defined; + h->u.def.section = section; + h->u.def.value = value; + + /* If we have been asked to, we act like collect2 and + identify all functions that might be global + constructors and destructors and pass them up in a + callback. We only do this for certain object file + types, since many object file types can handle this + automatically. */ + if (collect && name[0] == '_') + { + const char *s; + + /* A constructor or destructor name starts like this: + _+GLOBAL_[_.$][ID][_.$] where the first [_.$] and + the second are the same character (we accept any + character there, in case a new object file format + comes along with even worse naming restrictions). */ + +#define CONS_PREFIX "GLOBAL_" +#define CONS_PREFIX_LEN (sizeof CONS_PREFIX - 1) + + s = name + 1; + while (*s == '_') + ++s; + if (s[0] == 'G' + && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0) + { + char c; + + c = s[CONS_PREFIX_LEN + 1]; + if ((c == 'I' || c == 'D') + && s[CONS_PREFIX_LEN] == s[CONS_PREFIX_LEN + 2]) + { + /* If this is a definition of a symbol which + was previously weakly defined, we are in + trouble. We have already added a + constructor entry for the weak defined + symbol, and now we are trying to add one + for the new symbol. Fortunately, this case + should never arise in practice. */ + if (oldtype == bfd_link_hash_defweak) + abort (); + + if (! ((*info->callbacks->constructor) + (info, c == 'I', + h->root.string, abfd, section, value))) + return FALSE; + } + } + } + } + + break; + + case COM: + /* We have found a common definition for a symbol. */ + if (h->type == bfd_link_hash_new) + bfd_link_add_undef (info->hash, h); + h->type = bfd_link_hash_common; + h->u.c.p = + ((struct bfd_link_hash_common_entry *) + bfd_hash_allocate (&info->hash->table, + sizeof (struct bfd_link_hash_common_entry))); + if (h->u.c.p == NULL) + return FALSE; + + h->u.c.size = value; + + /* Select a default alignment based on the size. This may + be overridden by the caller. */ + { + unsigned int power; + + power = bfd_log2 (value); + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + } + + /* The section of a common symbol is only used if the common + symbol is actually allocated. It basically provides a + hook for the linker script to decide which output section + the common symbols should be put in. In most cases, the + section of a common symbol will be bfd_com_section_ptr, + the code here will choose a common symbol section named + "COMMON", and the linker script will contain *(COMMON) in + the appropriate place. A few targets use separate common + sections for small symbols, and they require special + handling. */ + if (section == bfd_com_section_ptr) + { + h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON"); + h->u.c.p->section->flags = SEC_ALLOC; + } + else if (section->owner != abfd) + { + h->u.c.p->section = bfd_make_section_old_way (abfd, + section->name); + h->u.c.p->section->flags = SEC_ALLOC; + } + else + h->u.c.p->section = section; + break; + + case REF: + /* A reference to a defined symbol. */ + if (h->next == NULL && info->hash->undefs_tail != h) + h->next = h; + break; + + case BIG: + /* We have found a common definition for a symbol which + already had a common definition. Use the maximum of the + two sizes, and use the section required by the larger symbol. */ + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, h->root.string, + h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_common, value))) + return FALSE; + if (value > h->u.c.size) + { + unsigned int power; + + h->u.c.size = value; + + /* Select a default alignment based on the size. This may + be overridden by the caller. */ + power = bfd_log2 (value); + if (power > 4) + power = 4; + h->u.c.p->alignment_power = power; + + /* Some systems have special treatment for small commons, + hence we want to select the section used by the larger + symbol. This makes sure the symbol does not go in a + small common section if it is now too large. */ + if (section == bfd_com_section_ptr) + { + h->u.c.p->section + = bfd_make_section_old_way (abfd, "COMMON"); + h->u.c.p->section->flags = SEC_ALLOC; + } + else if (section->owner != abfd) + { + h->u.c.p->section + = bfd_make_section_old_way (abfd, section->name); + h->u.c.p->section->flags = SEC_ALLOC; + } + else + h->u.c.p->section = section; + } + break; + + case CREF: + { + bfd *obfd; + + /* We have found a common definition for a symbol which + was already defined. FIXME: It would nice if we could + report the BFD which defined an indirect symbol, but we + don't have anywhere to store the information. */ + if (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak) + obfd = h->u.def.section->owner; + else + obfd = NULL; + if (! ((*info->callbacks->multiple_common) + (info, h->root.string, obfd, h->type, (bfd_vma) 0, + abfd, bfd_link_hash_common, value))) + return FALSE; + } + break; + + case MIND: + /* Multiple indirect symbols. This is OK if they both point + to the same symbol. */ + if (strcmp (h->u.i.link->root.string, string) == 0) + break; + /* Fall through. */ + case MDEF: + /* Handle a multiple definition. */ + if (!info->allow_multiple_definition) + { + asection *msec = NULL; + bfd_vma mval = 0; + + switch (h->type) + { + case bfd_link_hash_defined: + msec = h->u.def.section; + mval = h->u.def.value; + break; + case bfd_link_hash_indirect: + msec = bfd_ind_section_ptr; + mval = 0; + break; + default: + abort (); + } + + /* Ignore a redefinition of an absolute symbol to the + same value; it's harmless. */ + if (h->type == bfd_link_hash_defined + && bfd_is_abs_section (msec) + && bfd_is_abs_section (section) + && value == mval) + break; + + if (! ((*info->callbacks->multiple_definition) + (info, h->root.string, msec->owner, msec, mval, + abfd, section, value))) + return FALSE; + } + break; + + case CIND: + /* Create an indirect symbol from an existing common symbol. */ + BFD_ASSERT (h->type == bfd_link_hash_common); + if (! ((*info->callbacks->multiple_common) + (info, h->root.string, + h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, + abfd, bfd_link_hash_indirect, (bfd_vma) 0))) + return FALSE; + /* Fall through. */ + case IND: + /* Create an indirect symbol. */ + { + struct bfd_link_hash_entry *inh; + + /* STRING is the name of the symbol we want to indirect + to. */ + inh = bfd_wrapped_link_hash_lookup (abfd, info, string, TRUE, + copy, FALSE); + if (inh == (struct bfd_link_hash_entry *) NULL) + return FALSE; + if (inh->type == bfd_link_hash_indirect + && inh->u.i.link == h) + { + (*_bfd_error_handler) + (_("%s: indirect symbol `%s' to `%s' is a loop"), + bfd_archive_filename (abfd), name, string); + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + if (inh->type == bfd_link_hash_new) + { + inh->type = bfd_link_hash_undefined; + inh->u.undef.abfd = abfd; + bfd_link_add_undef (info->hash, inh); + } + + /* If the indirect symbol has been referenced, we need to + push the reference down to the symbol we are + referencing. */ + if (h->type != bfd_link_hash_new) + { + row = UNDEF_ROW; + cycle = TRUE; + } + + h->type = bfd_link_hash_indirect; + h->u.i.link = inh; + } + break; + + case SET: + /* Add an entry to a set. */ + if (! (*info->callbacks->add_to_set) (info, h, BFD_RELOC_CTOR, + abfd, section, value)) + return FALSE; + break; + + case WARNC: + /* Issue a warning and cycle. */ + if (h->u.i.warning != NULL) + { + if (! (*info->callbacks->warning) (info, h->u.i.warning, + h->root.string, abfd, + (asection *) NULL, + (bfd_vma) 0)) + return FALSE; + /* Only issue a warning once. */ + h->u.i.warning = NULL; + } + /* Fall through. */ + case CYCLE: + /* Try again with the referenced symbol. */ + h = h->u.i.link; + cycle = TRUE; + break; + + case REFC: + /* A reference to an indirect symbol. */ + if (h->next == NULL && info->hash->undefs_tail != h) + h->next = h; + h = h->u.i.link; + cycle = TRUE; + break; + + case WARN: + /* Issue a warning. */ + if (! (*info->callbacks->warning) (info, string, h->root.string, + hash_entry_bfd (h), + (asection *) NULL, (bfd_vma) 0)) + return FALSE; + break; + + case CWARN: + /* Warn if this symbol has been referenced already, + otherwise add a warning. A symbol has been referenced if + the next field is not NULL, or it is the tail of the + undefined symbol list. The REF case above helps to + ensure this. */ + if (h->next != NULL || info->hash->undefs_tail == h) + { + if (! (*info->callbacks->warning) (info, string, h->root.string, + hash_entry_bfd (h), + (asection *) NULL, + (bfd_vma) 0)) + return FALSE; + break; + } + /* Fall through. */ + case MWARN: + /* Make a warning symbol. */ + { + struct bfd_link_hash_entry *sub; + + /* STRING is the warning to give. */ + sub = ((struct bfd_link_hash_entry *) + ((*info->hash->table.newfunc) + ((struct bfd_hash_entry *) NULL, &info->hash->table, + h->root.string))); + if (sub == NULL) + return FALSE; + *sub = *h; + sub->type = bfd_link_hash_warning; + sub->u.i.link = h; + if (! copy) + sub->u.i.warning = string; + else + { + char *w; + size_t len = strlen (string) + 1; + + w = bfd_hash_allocate (&info->hash->table, len); + if (w == NULL) + return FALSE; + memcpy (w, string, len); + sub->u.i.warning = w; + } + + bfd_hash_replace (&info->hash->table, + (struct bfd_hash_entry *) h, + (struct bfd_hash_entry *) sub); + if (hashp != NULL) + *hashp = sub; + } + break; + } + } + while (cycle); + + return TRUE; +} + +/* Generic final link routine. */ + +bfd_boolean +_bfd_generic_final_link (abfd, info) + bfd *abfd; + struct bfd_link_info *info; +{ + bfd *sub; + asection *o; + struct bfd_link_order *p; + size_t outsymalloc; + struct generic_write_global_symbol_info wginfo; + + bfd_get_outsymbols (abfd) = (asymbol **) NULL; + bfd_get_symcount (abfd) = 0; + outsymalloc = 0; + + /* Mark all sections which will be included in the output file. */ + for (o = abfd->sections; o != NULL; o = o->next) + for (p = o->link_order_head; p != NULL; p = p->next) + if (p->type == bfd_indirect_link_order) + p->u.indirect.section->linker_mark = TRUE; + + /* Build the output symbol table. */ + for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next) + if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc)) + return FALSE; + + /* Accumulate the global symbols. */ + wginfo.info = info; + wginfo.output_bfd = abfd; + wginfo.psymalloc = &outsymalloc; + _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info), + _bfd_generic_link_write_global_symbol, + (PTR) &wginfo); + + /* Make sure we have a trailing NULL pointer on OUTSYMBOLS. We + shouldn't really need one, since we have SYMCOUNT, but some old + code still expects one. */ + if (! generic_add_output_symbol (abfd, &outsymalloc, NULL)) + return FALSE; + + if (info->relocateable) + { + /* Allocate space for the output relocs for each section. */ + for (o = abfd->sections; + o != (asection *) NULL; + o = o->next) + { + o->reloc_count = 0; + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + if (p->type == bfd_section_reloc_link_order + || p->type == bfd_symbol_reloc_link_order) + ++o->reloc_count; + else if (p->type == bfd_indirect_link_order) + { + asection *input_section; + bfd *input_bfd; + long relsize; + arelent **relocs; + asymbol **symbols; + long reloc_count; + + input_section = p->u.indirect.section; + input_bfd = input_section->owner; + relsize = bfd_get_reloc_upper_bound (input_bfd, + input_section); + if (relsize < 0) + return FALSE; + relocs = (arelent **) bfd_malloc ((bfd_size_type) relsize); + if (!relocs && relsize != 0) + return FALSE; + symbols = _bfd_generic_link_get_symbols (input_bfd); + reloc_count = bfd_canonicalize_reloc (input_bfd, + input_section, + relocs, + symbols); + free (relocs); + if (reloc_count < 0) + return FALSE; + BFD_ASSERT ((unsigned long) reloc_count + == input_section->reloc_count); + o->reloc_count += reloc_count; + } + } + if (o->reloc_count > 0) + { + bfd_size_type amt; + + amt = o->reloc_count; + amt *= sizeof (arelent *); + o->orelocation = (arelent **) bfd_alloc (abfd, amt); + if (!o->orelocation) + return FALSE; + o->flags |= SEC_RELOC; + /* Reset the count so that it can be used as an index + when putting in the output relocs. */ + o->reloc_count = 0; + } + } + } + + /* Handle all the link order information for the sections. */ + for (o = abfd->sections; + o != (asection *) NULL; + o = o->next) + { + for (p = o->link_order_head; + p != (struct bfd_link_order *) NULL; + p = p->next) + { + switch (p->type) + { + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + if (! _bfd_generic_reloc_link_order (abfd, info, o, p)) + return FALSE; + break; + case bfd_indirect_link_order: + if (! default_indirect_link_order (abfd, info, o, p, TRUE)) + return FALSE; + break; + default: + if (! _bfd_default_link_order (abfd, info, o, p)) + return FALSE; + break; + } + } + } + + return TRUE; +} + +/* Add an output symbol to the output BFD. */ + +static bfd_boolean +generic_add_output_symbol (output_bfd, psymalloc, sym) + bfd *output_bfd; + size_t *psymalloc; + asymbol *sym; +{ + if (bfd_get_symcount (output_bfd) >= *psymalloc) + { + asymbol **newsyms; + bfd_size_type amt; + + if (*psymalloc == 0) + *psymalloc = 124; + else + *psymalloc *= 2; + amt = *psymalloc; + amt *= sizeof (asymbol *); + newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt); + if (newsyms == (asymbol **) NULL) + return FALSE; + bfd_get_outsymbols (output_bfd) = newsyms; + } + + bfd_get_outsymbols (output_bfd) [bfd_get_symcount (output_bfd)] = sym; + if (sym != NULL) + ++ bfd_get_symcount (output_bfd); + + return TRUE; +} + +/* Handle the symbols for an input BFD. */ + +bfd_boolean +_bfd_generic_link_output_symbols (output_bfd, input_bfd, info, psymalloc) + bfd *output_bfd; + bfd *input_bfd; + struct bfd_link_info *info; + size_t *psymalloc; +{ + asymbol **sym_ptr; + asymbol **sym_end; + + if (! generic_link_read_symbols (input_bfd)) + return FALSE; + + /* Create a filename symbol if we are supposed to. */ + if (info->create_object_symbols_section != (asection *) NULL) + { + asection *sec; + + for (sec = input_bfd->sections; + sec != (asection *) NULL; + sec = sec->next) + { + if (sec->output_section == info->create_object_symbols_section) + { + asymbol *newsym; + + newsym = bfd_make_empty_symbol (input_bfd); + if (!newsym) + return FALSE; + newsym->name = input_bfd->filename; + newsym->value = 0; + newsym->flags = BSF_LOCAL | BSF_FILE; + newsym->section = sec; + + if (! generic_add_output_symbol (output_bfd, psymalloc, + newsym)) + return FALSE; + + break; + } + } + } + + /* Adjust the values of the globally visible symbols, and write out + local symbols. */ + sym_ptr = _bfd_generic_link_get_symbols (input_bfd); + sym_end = sym_ptr + _bfd_generic_link_get_symcount (input_bfd); + for (; sym_ptr < sym_end; sym_ptr++) + { + asymbol *sym; + struct generic_link_hash_entry *h; + bfd_boolean output; + + h = (struct generic_link_hash_entry *) NULL; + sym = *sym_ptr; + if ((sym->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym)) + || bfd_is_ind_section (bfd_get_section (sym))) + { + if (sym->udata.p != NULL) + h = (struct generic_link_hash_entry *) sym->udata.p; + else if ((sym->flags & BSF_CONSTRUCTOR) != 0) + { + /* This case normally means that the main linker code + deliberately ignored this constructor symbol. We + should just pass it through. This will screw up if + the constructor symbol is from a different, + non-generic, object file format, but the case will + only arise when linking with -r, which will probably + fail anyhow, since there will be no way to represent + the relocs in the output format being used. */ + h = NULL; + } + else if (bfd_is_und_section (bfd_get_section (sym))) + h = ((struct generic_link_hash_entry *) + bfd_wrapped_link_hash_lookup (output_bfd, info, + bfd_asymbol_name (sym), + FALSE, FALSE, TRUE)); + else + h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info), + bfd_asymbol_name (sym), + FALSE, FALSE, TRUE); + + if (h != (struct generic_link_hash_entry *) NULL) + { + /* Force all references to this symbol to point to + the same area in memory. It is possible that + this routine will be called with a hash table + other than a generic hash table, so we double + check that. */ + if (info->hash->creator == input_bfd->xvec) + { + if (h->sym != (asymbol *) NULL) + *sym_ptr = sym = h->sym; + } + + switch (h->root.type) + { + default: + case bfd_link_hash_new: + abort (); + case bfd_link_hash_undefined: + break; + case bfd_link_hash_undefweak: + sym->flags |= BSF_WEAK; + break; + case bfd_link_hash_indirect: + h = (struct generic_link_hash_entry *) h->root.u.i.link; + /* fall through */ + case bfd_link_hash_defined: + sym->flags |= BSF_GLOBAL; + sym->flags &=~ BSF_CONSTRUCTOR; + sym->value = h->root.u.def.value; + sym->section = h->root.u.def.section; + break; + case bfd_link_hash_defweak: + sym->flags |= BSF_WEAK; + sym->flags &=~ BSF_CONSTRUCTOR; + sym->value = h->root.u.def.value; + sym->section = h->root.u.def.section; + break; + case bfd_link_hash_common: + sym->value = h->root.u.c.size; + sym->flags |= BSF_GLOBAL; + if (! bfd_is_com_section (sym->section)) + { + BFD_ASSERT (bfd_is_und_section (sym->section)); + sym->section = bfd_com_section_ptr; + } + /* We do not set the section of the symbol to + h->root.u.c.p->section. That value was saved so + that we would know where to allocate the symbol + if it was defined. In this case the type is + still bfd_link_hash_common, so we did not define + it, so we do not want to use that section. */ + break; + } + } + } + + /* This switch is straight from the old code in + write_file_locals in ldsym.c. */ + if (info->strip == strip_all + || (info->strip == strip_some + && (bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym), + FALSE, FALSE) + == (struct bfd_hash_entry *) NULL))) + output = FALSE; + else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0) + { + /* If this symbol is marked as occurring now, rather + than at the end, output it now. This is used for + COFF C_EXT FCN symbols. FIXME: There must be a + better way. */ + if (bfd_asymbol_bfd (sym) == input_bfd + && (sym->flags & BSF_NOT_AT_END) != 0) + output = TRUE; + else + output = FALSE; + } + else if (bfd_is_ind_section (sym->section)) + output = FALSE; + else if ((sym->flags & BSF_DEBUGGING) != 0) + { + if (info->strip == strip_none) + output = TRUE; + else + output = FALSE; + } + else if (bfd_is_und_section (sym->section) + || bfd_is_com_section (sym->section)) + output = FALSE; + else if ((sym->flags & BSF_LOCAL) != 0) + { + if ((sym->flags & BSF_WARNING) != 0) + output = FALSE; + else + { + switch (info->discard) + { + default: + case discard_all: + output = FALSE; + break; + case discard_sec_merge: + output = TRUE; + if (info->relocateable + || ! (sym->section->flags & SEC_MERGE)) + break; + /* FALLTHROUGH */ + case discard_l: + if (bfd_is_local_label (input_bfd, sym)) + output = FALSE; + else + output = TRUE; + break; + case discard_none: + output = TRUE; + break; + } + } + } + else if ((sym->flags & BSF_CONSTRUCTOR)) + { + if (info->strip != strip_all) + output = TRUE; + else + output = FALSE; + } + else + abort (); + + /* If this symbol is in a section which is not being included + in the output file, then we don't want to output the symbol. + + Gross. .bss and similar sections won't have the linker_mark + field set. */ + if ((sym->section->flags & SEC_HAS_CONTENTS) != 0 + && ! sym->section->linker_mark) + output = FALSE; + + if (output) + { + if (! generic_add_output_symbol (output_bfd, psymalloc, sym)) + return FALSE; + if (h != (struct generic_link_hash_entry *) NULL) + h->written = TRUE; + } + } + + return TRUE; +} + +/* Set the section and value of a generic BFD symbol based on a linker + hash table entry. */ + +static void +set_symbol_from_hash (sym, h) + asymbol *sym; + struct bfd_link_hash_entry *h; +{ + switch (h->type) + { + default: + abort (); + break; + case bfd_link_hash_new: + /* This can happen when a constructor symbol is seen but we are + not building constructors. */ + if (sym->section != NULL) + { + BFD_ASSERT ((sym->flags & BSF_CONSTRUCTOR) != 0); + } + else + { + sym->flags |= BSF_CONSTRUCTOR; + sym->section = bfd_abs_section_ptr; + sym->value = 0; + } + break; + case bfd_link_hash_undefined: + sym->section = bfd_und_section_ptr; + sym->value = 0; + break; + case bfd_link_hash_undefweak: + sym->section = bfd_und_section_ptr; + sym->value = 0; + sym->flags |= BSF_WEAK; + break; + case bfd_link_hash_defined: + sym->section = h->u.def.section; + sym->value = h->u.def.value; + break; + case bfd_link_hash_defweak: + sym->flags |= BSF_WEAK; + sym->section = h->u.def.section; + sym->value = h->u.def.value; + break; + case bfd_link_hash_common: + sym->value = h->u.c.size; + if (sym->section == NULL) + sym->section = bfd_com_section_ptr; + else if (! bfd_is_com_section (sym->section)) + { + BFD_ASSERT (bfd_is_und_section (sym->section)); + sym->section = bfd_com_section_ptr; + } + /* Do not set the section; see _bfd_generic_link_output_symbols. */ + break; + case bfd_link_hash_indirect: + case bfd_link_hash_warning: + /* FIXME: What should we do here? */ + break; + } +} + +/* Write out a global symbol, if it hasn't already been written out. + This is called for each symbol in the hash table. */ + +bfd_boolean +_bfd_generic_link_write_global_symbol (h, data) + struct generic_link_hash_entry *h; + PTR data; +{ + struct generic_write_global_symbol_info *wginfo = + (struct generic_write_global_symbol_info *) data; + asymbol *sym; + + if (h->root.type == bfd_link_hash_warning) + h = (struct generic_link_hash_entry *) h->root.u.i.link; + + if (h->written) + return TRUE; + + h->written = TRUE; + + if (wginfo->info->strip == strip_all + || (wginfo->info->strip == strip_some + && bfd_hash_lookup (wginfo->info->keep_hash, h->root.root.string, + FALSE, FALSE) == NULL)) + return TRUE; + + if (h->sym != (asymbol *) NULL) + sym = h->sym; + else + { + sym = bfd_make_empty_symbol (wginfo->output_bfd); + if (!sym) + return FALSE; + sym->name = h->root.root.string; + sym->flags = 0; + } + + set_symbol_from_hash (sym, &h->root); + + sym->flags |= BSF_GLOBAL; + + if (! generic_add_output_symbol (wginfo->output_bfd, wginfo->psymalloc, + sym)) + { + /* FIXME: No way to return failure. */ + abort (); + } + + return TRUE; +} + +/* Create a relocation. */ + +bfd_boolean +_bfd_generic_reloc_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + arelent *r; + + if (! info->relocateable) + abort (); + if (sec->orelocation == (arelent **) NULL) + abort (); + + r = (arelent *) bfd_alloc (abfd, (bfd_size_type) sizeof (arelent)); + if (r == (arelent *) NULL) + return FALSE; + + r->address = link_order->offset; + r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc); + if (r->howto == 0) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + /* Get the symbol to use for the relocation. */ + if (link_order->type == bfd_section_reloc_link_order) + r->sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr; + else + { + struct generic_link_hash_entry *h; + + h = ((struct generic_link_hash_entry *) + bfd_wrapped_link_hash_lookup (abfd, info, + link_order->u.reloc.p->u.name, + FALSE, FALSE, TRUE)); + if (h == (struct generic_link_hash_entry *) NULL + || ! h->written) + { + if (! ((*info->callbacks->unattached_reloc) + (info, link_order->u.reloc.p->u.name, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + return FALSE; + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + r->sym_ptr_ptr = &h->sym; + } + + /* If this is an inplace reloc, write the addend to the object file. + Otherwise, store it in the reloc addend. */ + if (! r->howto->partial_inplace) + r->addend = link_order->u.reloc.p->addend; + else + { + bfd_size_type size; + bfd_reloc_status_type rstat; + bfd_byte *buf; + bfd_boolean ok; + file_ptr loc; + + size = bfd_get_reloc_size (r->howto); + buf = (bfd_byte *) bfd_zmalloc (size); + if (buf == (bfd_byte *) NULL) + return FALSE; + rstat = _bfd_relocate_contents (r->howto, abfd, + (bfd_vma) link_order->u.reloc.p->addend, + buf); + switch (rstat) + { + case bfd_reloc_ok: + break; + default: + case bfd_reloc_outofrange: + abort (); + case bfd_reloc_overflow: + if (! ((*info->callbacks->reloc_overflow) + (info, + (link_order->type == bfd_section_reloc_link_order + ? bfd_section_name (abfd, link_order->u.reloc.p->u.section) + : link_order->u.reloc.p->u.name), + r->howto->name, link_order->u.reloc.p->addend, + (bfd *) NULL, (asection *) NULL, (bfd_vma) 0))) + { + free (buf); + return FALSE; + } + break; + } + loc = link_order->offset * bfd_octets_per_byte (abfd); + ok = bfd_set_section_contents (abfd, sec, (PTR) buf, loc, + (bfd_size_type) size); + free (buf); + if (! ok) + return FALSE; + + r->addend = 0; + } + + sec->orelocation[sec->reloc_count] = r; + ++sec->reloc_count; + + return TRUE; +} + +/* Allocate a new link_order for a section. */ + +struct bfd_link_order * +bfd_new_link_order (abfd, section) + bfd *abfd; + asection *section; +{ + bfd_size_type amt = sizeof (struct bfd_link_order); + struct bfd_link_order *new; + + new = (struct bfd_link_order *) bfd_zalloc (abfd, amt); + if (!new) + return NULL; + + new->type = bfd_undefined_link_order; + + if (section->link_order_tail != (struct bfd_link_order *) NULL) + section->link_order_tail->next = new; + else + section->link_order_head = new; + section->link_order_tail = new; + + return new; +} + +/* Default link order processing routine. Note that we can not handle + the reloc_link_order types here, since they depend upon the details + of how the particular backends generates relocs. */ + +bfd_boolean +_bfd_default_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + struct bfd_link_order *link_order; +{ + switch (link_order->type) + { + case bfd_undefined_link_order: + case bfd_section_reloc_link_order: + case bfd_symbol_reloc_link_order: + default: + abort (); + case bfd_indirect_link_order: + return default_indirect_link_order (abfd, info, sec, link_order, + FALSE); + case bfd_data_link_order: + return default_data_link_order (abfd, info, sec, link_order); + } +} + +/* Default routine to handle a bfd_data_link_order. */ + +static bfd_boolean +default_data_link_order (abfd, info, sec, link_order) + bfd *abfd; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + asection *sec; + struct bfd_link_order *link_order; +{ + bfd_size_type size; + size_t fill_size; + bfd_byte *fill; + file_ptr loc; + bfd_boolean result; + + BFD_ASSERT ((sec->flags & SEC_HAS_CONTENTS) != 0); + + size = link_order->size; + if (size == 0) + return TRUE; + + fill = link_order->u.data.contents; + fill_size = link_order->u.data.size; + if (fill_size != 0 && fill_size < size) + { + bfd_byte *p; + fill = (bfd_byte *) bfd_malloc (size); + if (fill == NULL) + return FALSE; + p = fill; + if (fill_size == 1) + memset (p, (int) link_order->u.data.contents[0], (size_t) size); + else + { + do + { + memcpy (p, link_order->u.data.contents, fill_size); + p += fill_size; + size -= fill_size; + } + while (size >= fill_size); + if (size != 0) + memcpy (p, link_order->u.data.contents, (size_t) size); + size = link_order->size; + } + } + + loc = link_order->offset * bfd_octets_per_byte (abfd); + result = bfd_set_section_contents (abfd, sec, fill, loc, size); + + if (fill != link_order->u.data.contents) + free (fill); + return result; +} + +/* Default routine to handle a bfd_indirect_link_order. */ + +static bfd_boolean +default_indirect_link_order (output_bfd, info, output_section, link_order, + generic_linker) + bfd *output_bfd; + struct bfd_link_info *info; + asection *output_section; + struct bfd_link_order *link_order; + bfd_boolean generic_linker; +{ + asection *input_section; + bfd *input_bfd; + bfd_byte *contents = NULL; + bfd_byte *new_contents; + bfd_size_type sec_size; + file_ptr loc; + + BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); + + if (link_order->size == 0) + return TRUE; + + input_section = link_order->u.indirect.section; + input_bfd = input_section->owner; + + BFD_ASSERT (input_section->output_section == output_section); + BFD_ASSERT (input_section->output_offset == link_order->offset); + BFD_ASSERT (input_section->_cooked_size == link_order->size); + + if (info->relocateable + && input_section->reloc_count > 0 + && output_section->orelocation == (arelent **) NULL) + { + /* Space has not been allocated for the output relocations. + This can happen when we are called by a specific backend + because somebody is attempting to link together different + types of object files. Handling this case correctly is + difficult, and sometimes impossible. */ + (*_bfd_error_handler) + (_("Attempt to do relocateable link with %s input and %s output"), + bfd_get_target (input_bfd), bfd_get_target (output_bfd)); + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + if (! generic_linker) + { + asymbol **sympp; + asymbol **symppend; + + /* Get the canonical symbols. The generic linker will always + have retrieved them by this point, but we are being called by + a specific linker, presumably because we are linking + different types of object files together. */ + if (! generic_link_read_symbols (input_bfd)) + return FALSE; + + /* Since we have been called by a specific linker, rather than + the generic linker, the values of the symbols will not be + right. They will be the values as seen in the input file, + not the values of the final link. We need to fix them up + before we can relocate the section. */ + sympp = _bfd_generic_link_get_symbols (input_bfd); + symppend = sympp + _bfd_generic_link_get_symcount (input_bfd); + for (; sympp < symppend; sympp++) + { + asymbol *sym; + struct bfd_link_hash_entry *h; + + sym = *sympp; + + if ((sym->flags & (BSF_INDIRECT + | BSF_WARNING + | BSF_GLOBAL + | BSF_CONSTRUCTOR + | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym)) + || bfd_is_ind_section (bfd_get_section (sym))) + { + /* sym->udata may have been set by + generic_link_add_symbol_list. */ + if (sym->udata.p != NULL) + h = (struct bfd_link_hash_entry *) sym->udata.p; + else if (bfd_is_und_section (bfd_get_section (sym))) + h = bfd_wrapped_link_hash_lookup (output_bfd, info, + bfd_asymbol_name (sym), + FALSE, FALSE, TRUE); + else + h = bfd_link_hash_lookup (info->hash, + bfd_asymbol_name (sym), + FALSE, FALSE, TRUE); + if (h != NULL) + set_symbol_from_hash (sym, h); + } + } + } + + /* Get and relocate the section contents. */ + sec_size = bfd_section_size (input_bfd, input_section); + contents = ((bfd_byte *) bfd_malloc (sec_size)); + if (contents == NULL && sec_size != 0) + goto error_return; + new_contents = (bfd_get_relocated_section_contents + (output_bfd, info, link_order, contents, info->relocateable, + _bfd_generic_link_get_symbols (input_bfd))); + if (!new_contents) + goto error_return; + + /* Output the section contents. */ + loc = link_order->offset * bfd_octets_per_byte (output_bfd); + if (! bfd_set_section_contents (output_bfd, output_section, + (PTR) new_contents, loc, link_order->size)) + goto error_return; + + if (contents != NULL) + free (contents); + return TRUE; + + error_return: + if (contents != NULL) + free (contents); + return FALSE; +} + +/* A little routine to count the number of relocs in a link_order + list. */ + +unsigned int +_bfd_count_link_order_relocs (link_order) + struct bfd_link_order *link_order; +{ + register unsigned int c; + register struct bfd_link_order *l; + + c = 0; + for (l = link_order; l != (struct bfd_link_order *) NULL; l = l->next) + { + if (l->type == bfd_section_reloc_link_order + || l->type == bfd_symbol_reloc_link_order) + ++c; + } + + return c; +} + +/* +FUNCTION + bfd_link_split_section + +SYNOPSIS + bfd_boolean bfd_link_split_section(bfd *abfd, asection *sec); + +DESCRIPTION + Return nonzero if @var{sec} should be split during a + reloceatable or final link. + +.#define bfd_link_split_section(abfd, sec) \ +. BFD_SEND (abfd, _bfd_link_split_section, (abfd, sec)) +. + +*/ + +bfd_boolean +_bfd_generic_link_split_section (abfd, sec) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec ATTRIBUTE_UNUSED; +{ + return FALSE; +} diff --git a/contrib/binutils-2.14/bfd/merge.c b/contrib/binutils-2.14/bfd/merge.c new file mode 100644 index 0000000000..ec75a7be7e --- /dev/null +++ b/contrib/binutils-2.14/bfd/merge.c @@ -0,0 +1,954 @@ +/* SEC_MERGE support. + Copyright 2001, 2002 Free Software Foundation, Inc. + Written by Jakub Jelinek . + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file contains support for merging duplicate entities within sections, + as used in ELF SHF_MERGE. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "hashtab.h" +#include "libiberty.h" + +struct sec_merge_sec_info; + +/* An entry in the section merge hash table. */ + +struct sec_merge_hash_entry +{ + struct bfd_hash_entry root; + /* Length of this entry. */ + unsigned int len; + /* Start of this string needs to be aligned to + alignment octets (not 1 << align). */ + unsigned int alignment; + union + { + /* Index within the merged section. */ + bfd_size_type index; + /* Entity size (if present in suffix hash tables). */ + unsigned int entsize; + /* Entry this is a suffix of (if alignment is 0). */ + struct sec_merge_hash_entry *suffix; + } u; + /* Which section is it in. */ + struct sec_merge_sec_info *secinfo; + /* Next entity in the hash table. */ + struct sec_merge_hash_entry *next; +}; + +/* The section merge hash table. */ + +struct sec_merge_hash +{ + struct bfd_hash_table table; + /* Next available index. */ + bfd_size_type size; + /* First entity in the SEC_MERGE sections of this type. */ + struct sec_merge_hash_entry *first; + /* Last entity in the SEC_MERGE sections of this type. */ + struct sec_merge_hash_entry *last; + /* Entity size. */ + unsigned int entsize; + /* Are entries fixed size or zero terminated strings? */ + bfd_boolean strings; +}; + +struct sec_merge_info +{ + /* Chain of sec_merge_infos. */ + struct sec_merge_info *next; + /* Chain of sec_merge_sec_infos. */ + struct sec_merge_sec_info *chain; + /* A hash table used to hold section content. */ + struct sec_merge_hash *htab; +}; + +struct sec_merge_sec_info +{ + /* Chain of sec_merge_sec_infos. */ + struct sec_merge_sec_info *next; + /* The corresponding section. */ + asection *sec; + /* Pointer to merge_info pointing to us. */ + PTR *psecinfo; + /* A hash table used to hold section content. */ + struct sec_merge_hash *htab; + /* First string in this section. */ + struct sec_merge_hash_entry *first; + /* Original section content. */ + unsigned char contents[1]; +}; + +static struct bfd_hash_entry *sec_merge_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static struct sec_merge_hash_entry *sec_merge_hash_lookup + PARAMS ((struct sec_merge_hash *, const char *, unsigned int, bfd_boolean)); +static struct sec_merge_hash *sec_merge_init + PARAMS ((unsigned int, bfd_boolean)); +static struct sec_merge_hash_entry *sec_merge_add + PARAMS ((struct sec_merge_hash *, const char *, unsigned int, + struct sec_merge_sec_info *)); +static bfd_boolean sec_merge_emit + PARAMS ((bfd *, struct sec_merge_hash_entry *)); +static int cmplengthentry + PARAMS ((const PTR, const PTR)); +static int last4_eq + PARAMS ((const PTR, const PTR)); +static int last_eq + PARAMS ((const PTR, const PTR)); +static bfd_boolean record_section + PARAMS ((struct sec_merge_info *, struct sec_merge_sec_info *)); +static void merge_strings + PARAMS ((struct sec_merge_info *)); + +/* Routine to create an entry in a section merge hashtab. */ + +static struct bfd_hash_entry * +sec_merge_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct sec_merge_hash_entry *ret = (struct sec_merge_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct sec_merge_hash_entry *) NULL) + ret = ((struct sec_merge_hash_entry *) + bfd_hash_allocate (table, sizeof (struct sec_merge_hash_entry))); + if (ret == (struct sec_merge_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct sec_merge_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->u.suffix = NULL; + ret->alignment = 0; + ret->secinfo = NULL; + ret->next = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in a section merge hash table. */ + +static struct sec_merge_hash_entry * +sec_merge_hash_lookup (table, string, alignment, create) + struct sec_merge_hash *table; + const char *string; + unsigned int alignment; + bfd_boolean create; +{ + register const unsigned char *s; + register unsigned long hash; + register unsigned int c; + struct sec_merge_hash_entry *hashp; + unsigned int len, i; + unsigned int index; + + hash = 0; + len = 0; + s = (const unsigned char *) string; + if (table->strings) + { + if (table->entsize == 1) + { + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + ++len; + } + hash += len + (len << 17); + } + else + { + for (;;) + { + for (i = 0; i < table->entsize; ++i) + if (s[i] != '\0') + break; + if (i == table->entsize) + break; + for (i = 0; i < table->entsize; ++i) + { + c = *s++; + hash += c + (c << 17); + hash ^= hash >> 2; + } + ++len; + } + hash += len + (len << 17); + len *= table->entsize; + } + hash ^= hash >> 2; + len += table->entsize; + } + else + { + for (i = 0; i < table->entsize; ++i) + { + c = *s++; + hash += c + (c << 17); + hash ^= hash >> 2; + } + len = table->entsize; + } + + index = hash % table->table.size; + for (hashp = (struct sec_merge_hash_entry *) table->table.table[index]; + hashp != (struct sec_merge_hash_entry *) NULL; + hashp = (struct sec_merge_hash_entry *) hashp->root.next) + { + if (hashp->root.hash == hash + && len == hashp->len + && memcmp (hashp->root.string, string, len) == 0) + { + /* If the string we found does not have at least the required + alignment, we need to insert another copy. */ + if (hashp->alignment < alignment) + { + /* Mark the less aligned copy as deleted. */ + hashp->len = 0; + hashp->alignment = 0; + break; + } + return hashp; + } + } + + if (! create) + return (struct sec_merge_hash_entry *) NULL; + + hashp = (struct sec_merge_hash_entry *) + sec_merge_hash_newfunc ((struct bfd_hash_entry *) NULL, + (struct bfd_hash_table *) table, string); + if (hashp == (struct sec_merge_hash_entry *) NULL) + return (struct sec_merge_hash_entry *) NULL; + hashp->root.string = string; + hashp->root.hash = hash; + hashp->len = len; + hashp->alignment = alignment; + hashp->root.next = table->table.table[index]; + table->table.table[index] = (struct bfd_hash_entry *) hashp; + + return hashp; +} + +/* Create a new hash table. */ + +static struct sec_merge_hash * +sec_merge_init (entsize, strings) + unsigned int entsize; + bfd_boolean strings; +{ + struct sec_merge_hash *table; + bfd_size_type amt = sizeof (struct sec_merge_hash); + + table = (struct sec_merge_hash *) bfd_malloc (amt); + if (table == NULL) + return NULL; + + if (! bfd_hash_table_init (&table->table, sec_merge_hash_newfunc)) + { + free (table); + return NULL; + } + + table->size = 0; + table->first = NULL; + table->last = NULL; + table->entsize = entsize; + table->strings = strings; + + return table; +} + +/* Get the index of an entity in a hash table, adding it if it is not + already present. */ + +static struct sec_merge_hash_entry * +sec_merge_add (tab, str, alignment, secinfo) + struct sec_merge_hash *tab; + const char *str; + unsigned int alignment; + struct sec_merge_sec_info *secinfo; +{ + register struct sec_merge_hash_entry *entry; + + entry = sec_merge_hash_lookup (tab, str, alignment, TRUE); + if (entry == NULL) + return NULL; + + if (entry->secinfo == NULL) + { + tab->size++; + entry->secinfo = secinfo; + if (tab->first == NULL) + tab->first = entry; + else + tab->last->next = entry; + tab->last = entry; + } + + return entry; +} + +static bfd_boolean +sec_merge_emit (abfd, entry) + register bfd *abfd; + struct sec_merge_hash_entry *entry; +{ + struct sec_merge_sec_info *secinfo = entry->secinfo; + asection *sec = secinfo->sec; + char *pad = ""; + bfd_size_type off = 0; + int alignment_power = bfd_get_section_alignment (abfd, sec->output_section); + + if (alignment_power) + pad = bfd_zmalloc ((bfd_size_type) 1 << alignment_power); + + for (; entry != NULL && entry->secinfo == secinfo; entry = entry->next) + { + register const char *str; + register size_t len; + + len = off & (entry->alignment - 1); + if (len) + { + len = entry->alignment - len; + if (bfd_bwrite ((PTR) pad, (bfd_size_type) len, abfd) != len) + break; + off += len; + } + + str = entry->root.string; + len = entry->len; + + if (bfd_bwrite ((PTR) str, (bfd_size_type) len, abfd) != len) + break; + + off += len; + } + + if (alignment_power) + free (pad); + + return entry == NULL || entry->secinfo != secinfo; +} + +/* This function is called for each input file from the add_symbols + pass of the linker. */ + +bfd_boolean +_bfd_merge_section (abfd, psinfo, sec, psecinfo) + bfd *abfd; + PTR *psinfo; + asection *sec; + PTR *psecinfo; +{ + struct sec_merge_info *sinfo; + struct sec_merge_sec_info *secinfo; + unsigned int align; + bfd_size_type amt; + + if (sec->_raw_size == 0 + || (sec->flags & SEC_EXCLUDE) + || (sec->flags & SEC_MERGE) == 0 + || sec->entsize == 0) + return TRUE; + + if ((sec->flags & SEC_RELOC) != 0) + { + /* We aren't prepared to handle relocations in merged sections. */ + return TRUE; + } + + align = bfd_get_section_alignment (sec->owner, sec); + if ((sec->entsize < (unsigned int)(1 << align) + && ((sec->entsize & (sec->entsize - 1)) + || !(sec->flags & SEC_STRINGS))) + || (sec->entsize > (unsigned int)(1 << align) + && (sec->entsize & ((1 << align) - 1)))) + { + /* Sanity check. If string character size is smaller than + alignment, then we require character size to be a power + of 2, otherwise character size must be integer multiple + of alignment. For non-string constants, alignment must + be smaller than or equal to entity size and entity size + must be integer multiple of alignment. */ + return TRUE; + } + + for (sinfo = (struct sec_merge_info *) *psinfo; sinfo; sinfo = sinfo->next) + if ((secinfo = sinfo->chain) + && ! ((secinfo->sec->flags ^ sec->flags) & (SEC_MERGE | SEC_STRINGS)) + && secinfo->sec->entsize == sec->entsize + && ! strcmp (secinfo->sec->name, sec->name)) + break; + + if (sinfo == NULL) + { + /* Initialize the information we need to keep track of. */ + amt = sizeof (struct sec_merge_info); + sinfo = (struct sec_merge_info *) bfd_alloc (abfd, amt); + if (sinfo == NULL) + goto error_return; + sinfo->next = (struct sec_merge_info *) *psinfo; + sinfo->chain = NULL; + *psinfo = (PTR) sinfo; + sinfo->htab = sec_merge_init (sec->entsize, (sec->flags & SEC_STRINGS)); + if (sinfo->htab == NULL) + goto error_return; + } + + /* Read the section from abfd. */ + + amt = sizeof (struct sec_merge_sec_info) + sec->_raw_size - 1; + *psecinfo = bfd_alloc (abfd, amt); + if (*psecinfo == NULL) + goto error_return; + + secinfo = (struct sec_merge_sec_info *)*psecinfo; + if (sinfo->chain) + { + secinfo->next = sinfo->chain->next; + sinfo->chain->next = secinfo; + } + else + secinfo->next = secinfo; + sinfo->chain = secinfo; + secinfo->sec = sec; + secinfo->psecinfo = psecinfo; + secinfo->htab = sinfo->htab; + secinfo->first = NULL; + + if (! bfd_get_section_contents (sec->owner, sec, secinfo->contents, + (bfd_vma) 0, sec->_raw_size)) + goto error_return; + + return TRUE; + + error_return: + *psecinfo = NULL; + return FALSE; +} + +/* Compare two sec_merge_hash_entry structures. This is called via qsort. */ + +static int +cmplengthentry (a, b) + const PTR a; + const PTR b; +{ + struct sec_merge_hash_entry * A = *(struct sec_merge_hash_entry **) a; + struct sec_merge_hash_entry * B = *(struct sec_merge_hash_entry **) b; + + if (A->len < B->len) + return 1; + else if (A->len > B->len) + return -1; + + return memcmp (A->root.string, B->root.string, A->len); +} + +static int +last4_eq (a, b) + const PTR a; + const PTR b; +{ + struct sec_merge_hash_entry * A = (struct sec_merge_hash_entry *) a; + struct sec_merge_hash_entry * B = (struct sec_merge_hash_entry *) b; + + if (memcmp (A->root.string + A->len - 5 * A->u.entsize, + B->root.string + B->len - 5 * A->u.entsize, + 4 * A->u.entsize) != 0) + /* This was a hashtable collision. */ + return 0; + + if (A->len <= B->len) + /* B cannot be a suffix of A unless A is equal to B, which is guaranteed + not to be equal by the hash table. */ + return 0; + + if (A->alignment < B->alignment + || ((A->len - B->len) & (B->alignment - 1))) + /* The suffix is not sufficiently aligned. */ + return 0; + + return memcmp (A->root.string + (A->len - B->len), + B->root.string, B->len - 5 * A->u.entsize) == 0; +} + +static int +last_eq (a, b) + const PTR a; + const PTR b; +{ + struct sec_merge_hash_entry * A = (struct sec_merge_hash_entry *) a; + struct sec_merge_hash_entry * B = (struct sec_merge_hash_entry *) b; + + if (B->len >= 5 * A->u.entsize) + /* Longer strings are just pushed into the hash table, + they'll be used when looking up for very short strings. */ + return 0; + + if (memcmp (A->root.string + A->len - 2 * A->u.entsize, + B->root.string + B->len - 2 * A->u.entsize, + A->u.entsize) != 0) + /* This was a hashtable collision. */ + return 0; + + if (A->len <= B->len) + /* B cannot be a suffix of A unless A is equal to B, which is guaranteed + not to be equal by the hash table. */ + return 0; + + if (A->alignment < B->alignment + || ((A->len - B->len) & (B->alignment - 1))) + /* The suffix is not sufficiently aligned. */ + return 0; + + return memcmp (A->root.string + (A->len - B->len), + B->root.string, B->len - 2 * A->u.entsize) == 0; +} + +/* Record one section into the hash table. */ +static bfd_boolean +record_section (sinfo, secinfo) + struct sec_merge_info *sinfo; + struct sec_merge_sec_info *secinfo; +{ + asection *sec = secinfo->sec; + struct sec_merge_hash_entry *entry; + bfd_boolean nul; + unsigned char *p, *end; + bfd_vma mask, eltalign; + unsigned int align, i; + + align = bfd_get_section_alignment (sec->owner, sec); + end = secinfo->contents + sec->_raw_size; + nul = FALSE; + mask = ((bfd_vma) 1 << align) - 1; + if (sec->flags & SEC_STRINGS) + { + for (p = secinfo->contents; p < end; ) + { + eltalign = p - secinfo->contents; + eltalign = ((eltalign ^ (eltalign - 1)) + 1) >> 1; + if (!eltalign || eltalign > mask) + eltalign = mask + 1; + entry = sec_merge_add (sinfo->htab, p, (unsigned) eltalign, secinfo); + if (! entry) + goto error_return; + p += entry->len; + if (sec->entsize == 1) + { + while (p < end && *p == 0) + { + if (!nul && !((p - secinfo->contents) & mask)) + { + nul = TRUE; + entry = sec_merge_add (sinfo->htab, "", + (unsigned) mask + 1, secinfo); + if (! entry) + goto error_return; + } + p++; + } + } + else + { + while (p < end) + { + for (i = 0; i < sec->entsize; i++) + if (p[i] != '\0') + break; + if (i != sec->entsize) + break; + if (!nul && !((p - secinfo->contents) & mask)) + { + nul = TRUE; + entry = sec_merge_add (sinfo->htab, p, + (unsigned) mask + 1, secinfo); + if (! entry) + goto error_return; + } + p += sec->entsize; + } + } + } + } + else + { + for (p = secinfo->contents; p < end; p += sec->entsize) + { + entry = sec_merge_add (sinfo->htab, p, 1, secinfo); + if (! entry) + goto error_return; + } + } + + return TRUE; + +error_return: + for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) + *secinfo->psecinfo = NULL; + return FALSE; +} + +/* This is a helper function for _bfd_merge_sections. It attempts to + merge strings matching suffixes of longer strings. */ +static void +merge_strings (sinfo) + struct sec_merge_info *sinfo; +{ + struct sec_merge_hash_entry **array, **a, **end, *e; + struct sec_merge_sec_info *secinfo; + htab_t lasttab = NULL, last4tab = NULL; + bfd_size_type size, amt; + + /* Now sort the strings by length, longest first. */ + array = NULL; + amt = sinfo->htab->size * sizeof (struct sec_merge_hash_entry *); + array = (struct sec_merge_hash_entry **) bfd_malloc (amt); + if (array == NULL) + goto alloc_failure; + + for (e = sinfo->htab->first, a = array; e; e = e->next) + if (e->alignment) + *a++ = e; + + sinfo->htab->size = a - array; + + qsort (array, (size_t) sinfo->htab->size, + sizeof (struct sec_merge_hash_entry *), cmplengthentry); + + last4tab = htab_create_alloc ((size_t) sinfo->htab->size * 4, + NULL, last4_eq, NULL, calloc, free); + lasttab = htab_create_alloc ((size_t) sinfo->htab->size * 4, + NULL, last_eq, NULL, calloc, free); + if (lasttab == NULL || last4tab == NULL) + goto alloc_failure; + + /* Now insert the strings into hash tables (strings with last 4 characters + and strings with last character equal), look for longer strings which + we're suffix of. */ + for (a = array, end = array + sinfo->htab->size; a < end; a++) + { + register hashval_t hash; + unsigned int c; + unsigned int i; + const unsigned char *s; + PTR *p; + + e = *a; + e->u.entsize = sinfo->htab->entsize; + if (e->len <= e->u.entsize) + break; + if (e->len > 4 * e->u.entsize) + { + s = (const unsigned char *) (e->root.string + e->len - e->u.entsize); + hash = 0; + for (i = 0; i < 4 * e->u.entsize; i++) + { + c = *--s; + hash += c + (c << 17); + hash ^= hash >> 2; + } + p = htab_find_slot_with_hash (last4tab, e, hash, INSERT); + if (p == NULL) + goto alloc_failure; + if (*p) + { + struct sec_merge_hash_entry *ent; + + ent = (struct sec_merge_hash_entry *) *p; + e->u.suffix = ent; + e->alignment = 0; + continue; + } + else + *p = (PTR) e; + } + s = (const unsigned char *) (e->root.string + e->len - e->u.entsize); + hash = 0; + for (i = 0; i < e->u.entsize; i++) + { + c = *--s; + hash += c + (c << 17); + hash ^= hash >> 2; + } + p = htab_find_slot_with_hash (lasttab, e, hash, INSERT); + if (p == NULL) + goto alloc_failure; + if (*p) + { + struct sec_merge_hash_entry *ent; + + ent = (struct sec_merge_hash_entry *) *p; + e->u.suffix = ent; + e->alignment = 0; + } + else + *p = (PTR) e; + } + +alloc_failure: + if (array) + free (array); + if (lasttab) + htab_delete (lasttab); + if (last4tab) + htab_delete (last4tab); + + /* Now assign positions to the strings we want to keep. */ + size = 0; + secinfo = sinfo->htab->first->secinfo; + for (e = sinfo->htab->first; e; e = e->next) + { + if (e->secinfo != secinfo) + { + secinfo->sec->_cooked_size = size; + secinfo = e->secinfo; + } + if (e->alignment) + { + if (e->secinfo->first == NULL) + { + e->secinfo->first = e; + size = 0; + } + size = (size + e->alignment - 1) & ~((bfd_vma) e->alignment - 1); + e->u.index = size; + size += e->len; + } + } + secinfo->sec->_cooked_size = size; + + /* And now adjust the rest, removing them from the chain (but not hashtable) + at the same time. */ + for (a = &sinfo->htab->first, e = *a; e; e = e->next) + if (e->alignment) + a = &e->next; + else + { + *a = e->next; + if (e->len) + { + e->secinfo = e->u.suffix->secinfo; + e->alignment = e->u.suffix->alignment; + e->u.index = e->u.suffix->u.index + (e->u.suffix->len - e->len); + } + } +} + +/* This function is called once after all SEC_MERGE sections are registered + with _bfd_merge_section. */ + +bfd_boolean +_bfd_merge_sections (abfd, xsinfo, remove_hook) + bfd *abfd ATTRIBUTE_UNUSED; + PTR xsinfo; + void (*remove_hook) PARAMS((bfd *, asection *)); +{ + struct sec_merge_info *sinfo; + + for (sinfo = (struct sec_merge_info *) xsinfo; sinfo; sinfo = sinfo->next) + { + struct sec_merge_sec_info * secinfo; + + if (! sinfo->chain) + continue; + + /* Move sinfo->chain to head of the chain, terminate it. */ + secinfo = sinfo->chain; + sinfo->chain = secinfo->next; + secinfo->next = NULL; + + /* Record the sections into the hash table. */ + for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) + if (secinfo->sec->flags & SEC_EXCLUDE) + { + *secinfo->psecinfo = NULL; + if (remove_hook) + (*remove_hook) (abfd, secinfo->sec); + } + else if (! record_section (sinfo, secinfo)) + break; + + if (secinfo) + continue; + + if (sinfo->htab->first == NULL) + continue; + + if (sinfo->htab->strings) + merge_strings (sinfo); + else + { + struct sec_merge_hash_entry *e; + bfd_size_type size = 0; + + /* Things are much simpler for non-strings. + Just assign them slots in the section. */ + secinfo = NULL; + for (e = sinfo->htab->first; e; e = e->next) + { + if (e->secinfo->first == NULL) + { + if (secinfo) + secinfo->sec->_cooked_size = size; + e->secinfo->first = e; + size = 0; + } + size = (size + e->alignment - 1) + & ~((bfd_vma) e->alignment - 1); + e->u.index = size; + size += e->len; + secinfo = e->secinfo; + } + secinfo->sec->_cooked_size = size; + } + + /* Finally shrink all input sections which have not made it into + the hash table at all. */ + for (secinfo = sinfo->chain; secinfo; secinfo = secinfo->next) + if (secinfo->first == NULL) + secinfo->sec->_cooked_size = 0; + } + + return TRUE; +} + +/* Write out the merged section. */ + +bfd_boolean +_bfd_write_merged_section (output_bfd, sec, psecinfo) + bfd *output_bfd; + asection *sec; + PTR psecinfo; +{ + struct sec_merge_sec_info *secinfo; + file_ptr pos; + + secinfo = (struct sec_merge_sec_info *) psecinfo; + + if (!secinfo->first) + return TRUE; + + pos = sec->output_section->filepos + sec->output_offset; + if (bfd_seek (output_bfd, pos, SEEK_SET) != 0) + return FALSE; + + if (! sec_merge_emit (output_bfd, secinfo->first)) + return FALSE; + + return TRUE; +} + +/* Adjust an address in the SEC_MERGE section. Given OFFSET within + *PSEC, this returns the new offset in the adjusted SEC_MERGE + section and writes the new section back into *PSEC. */ + +bfd_vma +_bfd_merged_section_offset (output_bfd, psec, psecinfo, offset, addend) + bfd *output_bfd ATTRIBUTE_UNUSED; + asection **psec; + PTR psecinfo; + bfd_vma offset, addend; +{ + struct sec_merge_sec_info *secinfo; + struct sec_merge_hash_entry *entry; + unsigned char *p; + asection *sec = *psec; + + secinfo = (struct sec_merge_sec_info *) psecinfo; + + if (offset + addend >= sec->_raw_size) + { + if (offset + addend > sec->_raw_size) + { + (*_bfd_error_handler) + (_("%s: access beyond end of merged section (%ld + %ld)"), + bfd_get_filename (sec->owner), (long) offset, (long) addend); + } + return (secinfo->first ? sec->_cooked_size : 0); + } + + if (secinfo->htab->strings) + { + if (sec->entsize == 1) + { + p = secinfo->contents + offset + addend - 1; + while (p >= secinfo->contents && *p) + --p; + ++p; + } + else + { + p = secinfo->contents + + ((offset + addend) / sec->entsize) * sec->entsize; + p -= sec->entsize; + while (p >= secinfo->contents) + { + unsigned int i; + + for (i = 0; i < sec->entsize; ++i) + if (p[i] != '\0') + break; + if (i == sec->entsize) + break; + p -= sec->entsize; + } + p += sec->entsize; + } + } + else + { + p = secinfo->contents + + ((offset + addend) / sec->entsize) * sec->entsize; + } + entry = sec_merge_hash_lookup (secinfo->htab, p, 0, FALSE); + if (!entry) + { + if (! secinfo->htab->strings) + abort (); + /* This should only happen if somebody points into the padding + after a NUL character but before next entity. */ + if (*p) + abort (); + if (! secinfo->htab->first) + abort (); + entry = secinfo->htab->first; + p = secinfo->contents + + ((offset + addend) / sec->entsize + 1) * sec->entsize + - entry->len; + } + + *psec = entry->secinfo->sec; + return entry->u.index + (secinfo->contents + offset - p); +} diff --git a/contrib/binutils-2.14/bfd/opncls.c b/contrib/binutils-2.14/bfd/opncls.c new file mode 100644 index 0000000000..47719797df --- /dev/null +++ b/contrib/binutils-2.14/bfd/opncls.c @@ -0,0 +1,1039 @@ +/* opncls.c -- open and close a BFD. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, + 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "objalloc.h" +#include "libbfd.h" +#include "libiberty.h" + +#ifndef S_IXUSR +#define S_IXUSR 0100 /* Execute by owner. */ +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 /* Execute by group. */ +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 /* Execute by others. */ +#endif + +/* Counter used to initialize the bfd identifier. */ + +static unsigned int _bfd_id_counter = 0; + +/* fdopen is a loser -- we should use stdio exclusively. Unfortunately + if we do that we can't use fcntl. */ + +/* Return a new BFD. All BFD's are allocated through this routine. */ + +bfd * +_bfd_new_bfd () +{ + bfd *nbfd; + + nbfd = (bfd *) bfd_zmalloc ((bfd_size_type) sizeof (bfd)); + if (nbfd == NULL) + return NULL; + + nbfd->id = _bfd_id_counter++; + + nbfd->memory = (PTR) objalloc_create (); + if (nbfd->memory == NULL) + { + bfd_set_error (bfd_error_no_memory); + free (nbfd); + return NULL; + } + + nbfd->arch_info = &bfd_default_arch_struct; + + nbfd->direction = no_direction; + nbfd->iostream = NULL; + nbfd->where = 0; + if (!bfd_hash_table_init_n (&nbfd->section_htab, + bfd_section_hash_newfunc, + 251)) + { + free (nbfd); + return NULL; + } + nbfd->sections = (asection *) NULL; + nbfd->section_tail = &nbfd->sections; + nbfd->format = bfd_unknown; + nbfd->my_archive = (bfd *) NULL; + nbfd->origin = 0; + nbfd->opened_once = FALSE; + nbfd->output_has_begun = FALSE; + nbfd->section_count = 0; + nbfd->usrdata = (PTR) NULL; + nbfd->cacheable = FALSE; + nbfd->flags = BFD_NO_FLAGS; + nbfd->mtime_set = FALSE; + + return nbfd; +} + +/* Allocate a new BFD as a member of archive OBFD. */ + +bfd * +_bfd_new_bfd_contained_in (obfd) + bfd *obfd; +{ + bfd *nbfd; + + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + return NULL; + nbfd->xvec = obfd->xvec; + nbfd->my_archive = obfd; + nbfd->direction = read_direction; + nbfd->target_defaulted = obfd->target_defaulted; + return nbfd; +} + +/* Delete a BFD. */ + +void +_bfd_delete_bfd (abfd) + bfd *abfd; +{ + bfd_hash_table_free (&abfd->section_htab); + objalloc_free ((struct objalloc *) abfd->memory); + free (abfd); +} + +/* +SECTION + Opening and closing BFDs + +*/ + +/* +FUNCTION + bfd_openr + +SYNOPSIS + bfd *bfd_openr(const char *filename, const char *target); + +DESCRIPTION + Open the file @var{filename} (using <>) with the target + @var{target}. Return a pointer to the created BFD. + + Calls <>, so @var{target} is interpreted as by + that function. + + If <> is returned then an error has occured. Possible errors + are <>, <> or + <> error. +*/ + +bfd * +bfd_openr (filename, target) + const char *filename; + const char *target; +{ + bfd *nbfd; + const bfd_target *target_vec; + + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + return NULL; + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + + nbfd->filename = filename; + nbfd->direction = read_direction; + + if (bfd_open_file (nbfd) == NULL) + { + /* File didn't exist, or some such. */ + bfd_set_error (bfd_error_system_call); + _bfd_delete_bfd (nbfd); + return NULL; + } + + return nbfd; +} + +/* Don't try to `optimize' this function: + + o - We lock using stack space so that interrupting the locking + won't cause a storage leak. + o - We open the file stream last, since we don't want to have to + close it if anything goes wrong. Closing the stream means closing + the file descriptor too, even though we didn't open it. */ +/* +FUNCTION + bfd_fdopenr + +SYNOPSIS + bfd *bfd_fdopenr(const char *filename, const char *target, int fd); + +DESCRIPTION + <> is to <> much like <> is to + <>. It opens a BFD on a file already described by the + @var{fd} supplied. + + When the file is later <>d, the file descriptor will + be closed. If the caller desires that this file descriptor be + cached by BFD (opened as needed, closed as needed to free + descriptors for other opens), with the supplied @var{fd} used as + an initial file descriptor (but subject to closure at any time), + call bfd_set_cacheable(bfd, 1) on the returned BFD. The default + is to assume no cacheing; the file descriptor will remain open + until <>, and will not be affected by BFD operations + on other files. + + Possible errors are <>, + <> and <>. +*/ + +bfd * +bfd_fdopenr (filename, target, fd) + const char *filename; + const char *target; + int fd; +{ + bfd *nbfd; + const bfd_target *target_vec; + int fdflags; + + bfd_set_error (bfd_error_system_call); +#if ! defined(HAVE_FCNTL) || ! defined(F_GETFL) + fdflags = O_RDWR; /* Assume full access. */ +#else + fdflags = fcntl (fd, F_GETFL, NULL); +#endif + if (fdflags == -1) + return NULL; + + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + return NULL; + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + +#ifndef HAVE_FDOPEN + nbfd->iostream = (PTR) fopen (filename, FOPEN_RB); +#else + /* (O_ACCMODE) parens are to avoid Ultrix header file bug. */ + switch (fdflags & (O_ACCMODE)) + { + case O_RDONLY: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RB); break; + case O_WRONLY: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break; + case O_RDWR: nbfd->iostream = (PTR) fdopen (fd, FOPEN_RUB); break; + default: abort (); + } +#endif + + if (nbfd->iostream == NULL) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + + /* OK, put everything where it belongs. */ + nbfd->filename = filename; + + /* As a special case we allow a FD open for read/write to + be written through, although doing so requires that we end + the previous clause with a preposition. */ + /* (O_ACCMODE) parens are to avoid Ultrix header file bug. */ + switch (fdflags & (O_ACCMODE)) + { + case O_RDONLY: nbfd->direction = read_direction; break; + case O_WRONLY: nbfd->direction = write_direction; break; + case O_RDWR: nbfd->direction = both_direction; break; + default: abort (); + } + + if (! bfd_cache_init (nbfd)) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + nbfd->opened_once = TRUE; + + return nbfd; +} + +/* +FUNCTION + bfd_openstreamr + +SYNOPSIS + bfd *bfd_openstreamr(const char *, const char *, PTR); + +DESCRIPTION + + Open a BFD for read access on an existing stdio stream. When + the BFD is passed to <>, the stream will be closed. +*/ + +bfd * +bfd_openstreamr (filename, target, streamarg) + const char *filename; + const char *target; + PTR streamarg; +{ + FILE *stream = (FILE *) streamarg; + bfd *nbfd; + const bfd_target *target_vec; + + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + return NULL; + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + + nbfd->iostream = (PTR) stream; + nbfd->filename = filename; + nbfd->direction = read_direction; + + if (! bfd_cache_init (nbfd)) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + + return nbfd; +} + +/* bfd_openw -- open for writing. + Returns a pointer to a freshly-allocated BFD on success, or NULL. + + See comment by bfd_fdopenr before you try to modify this function. */ + +/* +FUNCTION + bfd_openw + +SYNOPSIS + bfd *bfd_openw(const char *filename, const char *target); + +DESCRIPTION + Create a BFD, associated with file @var{filename}, using the + file format @var{target}, and return a pointer to it. + + Possible errors are <>, <>, + <>. +*/ + +bfd * +bfd_openw (filename, target) + const char *filename; + const char *target; +{ + bfd *nbfd; + const bfd_target *target_vec; + + /* nbfd has to point to head of malloc'ed block so that bfd_close may + reclaim it correctly. */ + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + return NULL; + + target_vec = bfd_find_target (target, nbfd); + if (target_vec == NULL) + { + _bfd_delete_bfd (nbfd); + return NULL; + } + + nbfd->filename = filename; + nbfd->direction = write_direction; + + if (bfd_open_file (nbfd) == NULL) + { + /* File not writeable, etc. */ + bfd_set_error (bfd_error_system_call); + _bfd_delete_bfd (nbfd); + return NULL; + } + + return nbfd; +} + +/* + +FUNCTION + bfd_close + +SYNOPSIS + bfd_boolean bfd_close (bfd *abfd); + +DESCRIPTION + + Close a BFD. If the BFD was open for writing, then pending + operations are completed and the file written out and closed. + If the created file is executable, then <> is called + to mark it as such. + + All memory attached to the BFD is released. + + The file descriptor associated with the BFD is closed (even + if it was passed in to BFD by <>). + +RETURNS + <> is returned if all is ok, otherwise <>. +*/ + + +bfd_boolean +bfd_close (abfd) + bfd *abfd; +{ + bfd_boolean ret; + + if (bfd_write_p (abfd)) + { + if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd))) + return FALSE; + } + + if (! BFD_SEND (abfd, _close_and_cleanup, (abfd))) + return FALSE; + + ret = bfd_cache_close (abfd); + + /* If the file was open for writing and is now executable, + make it so. */ + if (ret + && abfd->direction == write_direction + && abfd->flags & EXEC_P) + { + struct stat buf; + + if (stat (abfd->filename, &buf) == 0) + { + unsigned int mask = umask (0); + + umask (mask); + chmod (abfd->filename, + (0777 + & (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask)))); + } + } + + _bfd_delete_bfd (abfd); + + return ret; +} + +/* +FUNCTION + bfd_close_all_done + +SYNOPSIS + bfd_boolean bfd_close_all_done (bfd *); + +DESCRIPTION + Close a BFD. Differs from <> since it does not + complete any pending operations. This routine would be used + if the application had just used BFD for swapping and didn't + want to use any of the writing code. + + If the created file is executable, then <> is called + to mark it as such. + + All memory attached to the BFD is released. + +RETURNS + <> is returned if all is ok, otherwise <>. +*/ + +bfd_boolean +bfd_close_all_done (abfd) + bfd *abfd; +{ + bfd_boolean ret; + + ret = bfd_cache_close (abfd); + + /* If the file was open for writing and is now executable, + make it so. */ + if (ret + && abfd->direction == write_direction + && abfd->flags & EXEC_P) + { + struct stat buf; + + if (stat (abfd->filename, &buf) == 0) + { + unsigned int mask = umask (0); + + umask (mask); + chmod (abfd->filename, + (0777 + & (buf.st_mode | ((S_IXUSR | S_IXGRP | S_IXOTH) &~ mask)))); + } + } + + _bfd_delete_bfd (abfd); + + return ret; +} + +/* +FUNCTION + bfd_create + +SYNOPSIS + bfd *bfd_create(const char *filename, bfd *templ); + +DESCRIPTION + Create a new BFD in the manner of <>, but without + opening a file. The new BFD takes the target from the target + used by @var{template}. The format is always set to <>. +*/ + +bfd * +bfd_create (filename, templ) + const char *filename; + bfd *templ; +{ + bfd *nbfd; + + nbfd = _bfd_new_bfd (); + if (nbfd == NULL) + return NULL; + nbfd->filename = filename; + if (templ) + nbfd->xvec = templ->xvec; + nbfd->direction = no_direction; + bfd_set_format (nbfd, bfd_object); + + return nbfd; +} + +/* +FUNCTION + bfd_make_writable + +SYNOPSIS + bfd_boolean bfd_make_writable (bfd *abfd); + +DESCRIPTION + Takes a BFD as created by <> and converts it + into one like as returned by <>. It does this + by converting the BFD to BFD_IN_MEMORY. It's assumed that + you will call <> on this bfd later. + +RETURNS + <> is returned if all is ok, otherwise <>. +*/ + +bfd_boolean +bfd_make_writable(abfd) + bfd *abfd; +{ + struct bfd_in_memory *bim; + + if (abfd->direction != no_direction) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + bim = ((struct bfd_in_memory *) + bfd_malloc ((bfd_size_type) sizeof (struct bfd_in_memory))); + abfd->iostream = (PTR) bim; + /* bfd_bwrite will grow these as needed. */ + bim->size = 0; + bim->buffer = 0; + + abfd->flags |= BFD_IN_MEMORY; + abfd->direction = write_direction; + abfd->where = 0; + + return TRUE; +} + +/* +FUNCTION + bfd_make_readable + +SYNOPSIS + bfd_boolean bfd_make_readable (bfd *abfd); + +DESCRIPTION + Takes a BFD as created by <> and + <> and converts it into one like as + returned by <>. It does this by writing the + contents out to the memory buffer, then reversing the + direction. + +RETURNS + <> is returned if all is ok, otherwise <>. */ + +bfd_boolean +bfd_make_readable(abfd) + bfd *abfd; +{ + if (abfd->direction != write_direction || !(abfd->flags & BFD_IN_MEMORY)) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + if (! BFD_SEND_FMT (abfd, _bfd_write_contents, (abfd))) + return FALSE; + + if (! BFD_SEND (abfd, _close_and_cleanup, (abfd))) + return FALSE; + + + abfd->arch_info = &bfd_default_arch_struct; + + abfd->where = 0; + abfd->format = bfd_unknown; + abfd->my_archive = (bfd *) NULL; + abfd->origin = 0; + abfd->opened_once = FALSE; + abfd->output_has_begun = FALSE; + abfd->section_count = 0; + abfd->usrdata = (PTR) NULL; + abfd->cacheable = FALSE; + abfd->flags = BFD_IN_MEMORY; + abfd->mtime_set = FALSE; + + abfd->target_defaulted = TRUE; + abfd->direction = read_direction; + abfd->sections = 0; + abfd->symcount = 0; + abfd->outsymbols = 0; + abfd->tdata.any = 0; + + bfd_section_list_clear (abfd); + bfd_check_format (abfd, bfd_object); + + return TRUE; +} + +/* +INTERNAL_FUNCTION + bfd_alloc + +SYNOPSIS + PTR bfd_alloc (bfd *abfd, size_t wanted); + +DESCRIPTION + Allocate a block of @var{wanted} bytes of memory attached to + <> and return a pointer to it. +*/ + + +PTR +bfd_alloc (abfd, size) + bfd *abfd; + bfd_size_type size; +{ + PTR ret; + + if (size != (unsigned long) size) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + + ret = objalloc_alloc (abfd->memory, (unsigned long) size); + if (ret == NULL) + bfd_set_error (bfd_error_no_memory); + return ret; +} + +PTR +bfd_zalloc (abfd, size) + bfd *abfd; + bfd_size_type size; +{ + PTR res; + + res = bfd_alloc (abfd, size); + if (res) + memset (res, 0, (size_t) size); + return res; +} + +/* Free a block allocated for a BFD. + Note: Also frees all more recently allocated blocks! */ + +void +bfd_release (abfd, block) + bfd *abfd; + PTR block; +{ + objalloc_free_block ((struct objalloc *) abfd->memory, block); +} + + +/* + GNU Extension: separate debug-info files + + The idea here is that a special section called .gnu_debuglink might be + embedded in a binary file, which indicates that some *other* file + contains the real debugging information. This special section contains a + filename and CRC32 checksum, which we read and resolve to another file, + if it exists. + + This facilitates "optional" provision of debugging information, without + having to provide two complete copies of every binary object (with and + without debug symbols). +*/ + +static unsigned long calc_crc32 PARAMS ((unsigned long, const unsigned char *, size_t)); +static char * get_debug_link_info PARAMS ((bfd *, unsigned long *)); +static bfd_boolean separate_debug_file_exists PARAMS ((const char *, const unsigned long)); +static char * find_separate_debug_file PARAMS ((bfd *, const char *)); + +/* +INTERNAL_FUNCTION + calc_crc32 + +SYNOPSIS + unsigned long calc_crc32 (unsigned long crc, const unsigned char *buf, size_t len); + +DESCRIPTION + Advance the CRC32 given by @var{crc} through @var{len} + bytes of @var{buf}. Return the updated CRC32 value. +*/ + +static unsigned long +calc_crc32 (crc, buf, len) + unsigned long crc; + const unsigned char *buf; + size_t len; +{ + static const unsigned long crc32_table[256] = + { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d + }; + const unsigned char *end; + + crc = ~crc & 0xffffffff; + for (end = buf + len; buf < end; ++ buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc & 0xffffffff;; +} + + +/* +INTERNAL_FUNCTION + get_debug_link_info + +SYNOPSIS + char *get_debug_link_info (bfd *abfd, unsigned long *crc32_out) + +DESCRIPTION + fetch the filename and CRC32 value for any separate debuginfo + associated with @var{abfd}. Return NULL if no such info found, + otherwise return filename and update @var{crc32_out}. +*/ + +static char * +get_debug_link_info (abfd, crc32_out) + bfd *abfd; + unsigned long *crc32_out; +{ + asection * sect; + bfd_size_type debuglink_size; + unsigned long crc32; + char * contents; + int crc_offset; + bfd_boolean ret; + + BFD_ASSERT (abfd); + BFD_ASSERT (crc32_out); + + sect = bfd_get_section_by_name (abfd, ".gnu_debuglink"); + + if (sect == NULL) + return NULL; + + debuglink_size = bfd_section_size (abfd, sect); + + contents = xmalloc (debuglink_size); + ret = bfd_get_section_contents (abfd, sect, contents, + (file_ptr)0, debuglink_size); + if (! ret) + { + free (contents); + return NULL; + } + + /* Crc value is stored after the filename, aligned up to 4 bytes. */ + crc_offset = strlen (contents) + 1; + crc_offset = (crc_offset + 3) & ~3; + + crc32 = bfd_get_32 (abfd, (bfd_byte *) (contents + crc_offset)); + + *crc32_out = crc32; + return contents; +} + +/* +INTERNAL_FUNCTION + separate_debug_file_exists + +SYNOPSIS + bfd_boolean separate_debug_file_exists (char * name, unsigned long crc32) + +DESCRIPTION + Checks to see if @var{name} is a file and if its contents + match @var{crc32}. +*/ + +static bfd_boolean +separate_debug_file_exists (name, crc) + const char *name; + const unsigned long crc; +{ + static char buffer [8 * 1024]; + unsigned long file_crc = 0; + int fd; + int count; + + BFD_ASSERT (name); + + fd = open (name, O_RDONLY); + if (fd < 0) + return FALSE; + + while ((count = read (fd, buffer, sizeof (buffer))) > 0) + file_crc = calc_crc32 (file_crc, buffer, count); + + close (fd); + + return crc == file_crc; +} + + +/* +INTERNAL_FUNCTION + find_separate_debug_file + +SYNOPSIS + char * find_separate_debug_file (bfd *abfd) + +DESCRIPTION + Searches @var{abfd} for a reference to separate debugging + information, scans various locations in the filesystem, including + the file tree rooted at @var{debug_file_directory}, and returns a + filename of such debugging information if the file is found and has + matching CRC32. Returns NULL if no reference to debugging file + exists, or file cannot be found. +*/ + +static char * +find_separate_debug_file (abfd, debug_file_directory) + bfd *abfd; + const char *debug_file_directory; +{ + char *basename; + char *dir; + char *debugfile; + unsigned long crc32; + int i; + + BFD_ASSERT (abfd); + if (debug_file_directory == NULL) + debug_file_directory = "."; + + /* BFD may have been opened from a stream. */ + if (! abfd->filename) + return NULL; + + basename = get_debug_link_info (abfd, & crc32); + + if (basename == NULL) + return NULL; + if (strlen (basename) < 1) + { + free (basename); + return NULL; + } + + dir = xstrdup (abfd->filename); + BFD_ASSERT (strlen (dir) != 0); + + /* Strip off filename part. */ + for (i = strlen (dir) - 1; i >= 0; i--) + if (IS_DIR_SEPARATOR (dir[i])) + break; + + dir[i + 1] = '\0'; + BFD_ASSERT (dir[i] == '/' || dir[0] == '\0') + + debugfile = xmalloc (strlen (debug_file_directory) + 1 + + strlen (dir) + + strlen (".debug/") + + strlen (basename) + + 1); + + /* First try in the same directory as the original file: */ + strcpy (debugfile, dir); + strcat (debugfile, basename); + + if (separate_debug_file_exists (debugfile, crc32)) + { + free (basename); + free (dir); + return debugfile; + } + + /* Then try in a subdirectory called .debug. */ + strcpy (debugfile, dir); + strcat (debugfile, ".debug/"); + strcat (debugfile, basename); + + if (separate_debug_file_exists (debugfile, crc32)) + { + free (basename); + free (dir); + return debugfile; + } + + /* Then try in the global debugfile directory. */ + strcpy (debugfile, debug_file_directory); + i = strlen (debug_file_directory) - 1; + if (i > 0 + && debug_file_directory[i] != '/' + && dir[0] != '/') + strcat (debugfile, "/"); + strcat (debugfile, dir); + strcat (debugfile, basename); + + if (separate_debug_file_exists (debugfile, crc32)) + { + free (basename); + free (dir); + return debugfile; + } + + free (debugfile); + free (basename); + free (dir); + return NULL; +} + + +/* +FUNCTION + bfd_follow_gnu_debuglink + +SYNOPSIS + char * bfd_follow_gnu_debuglink(bfd *abfd, const char *dir); + +DESCRIPTION + + Takes a BFD and searches it for a .gnu_debuglink section. If this + section is found, examines the section for the name and checksum of + a '.debug' file containing auxiliary debugging + information. Searches filesystem for .debug file in some standard + locations, including the directory tree rooted at @var{dir}, and if + found returns the full filename. If @var{dir} is NULL, will search + default path configured into libbfd at build time. + +RETURNS + <> on any errors or failure to locate the .debug file, + otherwise a pointer to a heap-allocated string containing the + filename. The caller is responsible for freeing this string. +*/ + +char * +bfd_follow_gnu_debuglink (abfd, dir) + bfd *abfd; + const char * dir; +{ +#if 0 /* Disabled until DEBUGDIR can be defined by configure.in */ + if (dir == NULL) + dir = DEBUGDIR; +#endif + return find_separate_debug_file (abfd, dir); +} diff --git a/contrib/binutils-2.14/bfd/reloc.c b/contrib/binutils-2.14/bfd/reloc.c new file mode 100644 index 0000000000..6aea881f38 --- /dev/null +++ b/contrib/binutils-2.14/bfd/reloc.c @@ -0,0 +1,4188 @@ +/* BFD support for handling relocation entries. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + Relocations + + BFD maintains relocations in much the same way it maintains + symbols: they are left alone until required, then read in + en-masse and translated into an internal form. A common + routine <> acts upon the + canonical form to do the fixup. + + Relocations are maintained on a per section basis, + while symbols are maintained on a per BFD basis. + + All that a back end has to do to fit the BFD interface is to create + a <> for each relocation + in a particular section, and fill in the right bits of the structures. + +@menu +@* typedef arelent:: +@* howto manager:: +@end menu + +*/ + +/* DO compile in the reloc_code name table from libbfd.h. */ +#define _BFD_MAKE_TABLE_bfd_reloc_code_real + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libbfd.h" +/* +DOCDD +INODE + typedef arelent, howto manager, Relocations, Relocations + +SUBSECTION + typedef arelent + + This is the structure of a relocation entry: + +CODE_FRAGMENT +. +.typedef enum bfd_reloc_status +.{ +. {* No errors detected. *} +. bfd_reloc_ok, +. +. {* The relocation was performed, but there was an overflow. *} +. bfd_reloc_overflow, +. +. {* The address to relocate was not within the section supplied. *} +. bfd_reloc_outofrange, +. +. {* Used by special functions. *} +. bfd_reloc_continue, +. +. {* Unsupported relocation size requested. *} +. bfd_reloc_notsupported, +. +. {* Unused. *} +. bfd_reloc_other, +. +. {* The symbol to relocate against was undefined. *} +. bfd_reloc_undefined, +. +. {* The relocation was performed, but may not be ok - presently +. generated only when linking i960 coff files with i960 b.out +. symbols. If this type is returned, the error_message argument +. to bfd_perform_relocation will be set. *} +. bfd_reloc_dangerous +. } +. bfd_reloc_status_type; +. +. +.typedef struct reloc_cache_entry +.{ +. {* A pointer into the canonical table of pointers. *} +. struct symbol_cache_entry **sym_ptr_ptr; +. +. {* offset in section. *} +. bfd_size_type address; +. +. {* addend for relocation value. *} +. bfd_vma addend; +. +. {* Pointer to how to perform the required relocation. *} +. reloc_howto_type *howto; +. +.} +.arelent; +. +*/ + +/* +DESCRIPTION + + Here is a description of each of the fields within an <>: + + o <> + + The symbol table pointer points to a pointer to the symbol + associated with the relocation request. It is + the pointer into the table returned by the back end's + <> action. @xref{Symbols}. The symbol is referenced + through a pointer to a pointer so that tools like the linker + can fix up all the symbols of the same name by modifying only + one pointer. The relocation routine looks in the symbol and + uses the base of the section the symbol is attached to and the + value of the symbol as the initial relocation offset. If the + symbol pointer is zero, then the section provided is looked up. + + o <
> + + The <
> field gives the offset in bytes from the base of + the section data which owns the relocation record to the first + byte of relocatable information. The actual data relocated + will be relative to this point; for example, a relocation + type which modifies the bottom two bytes of a four byte word + would not touch the first byte pointed to in a big endian + world. + + o <> + + The <> is a value provided by the back end to be added (!) + to the relocation offset. Its interpretation is dependent upon + the howto. For example, on the 68k the code: + +| char foo[]; +| main() +| { +| return foo[0x12345678]; +| } + + Could be compiled into: + +| linkw fp,#-4 +| moveb @@#12345678,d0 +| extbl d0 +| unlk fp +| rts + + This could create a reloc pointing to <>, but leave the + offset in the data, something like: + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000006 32 _foo +| +|00000000 4e56 fffc ; linkw fp,#-4 +|00000004 1039 1234 5678 ; moveb @@#12345678,d0 +|0000000a 49c0 ; extbl d0 +|0000000c 4e5e ; unlk fp +|0000000e 4e75 ; rts + + Using coff and an 88k, some instructions don't have enough + space in them to represent the full address range, and + pointers have to be loaded in two parts. So you'd get something like: + +| or.u r13,r0,hi16(_foo+0x12345678) +| ld.b r2,r13,lo16(_foo+0x12345678) +| jmp r1 + + This should create two relocs, both pointing to <<_foo>>, and with + 0x12340000 in their addend field. The data would consist of: + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000002 HVRT16 _foo+0x12340000 +|00000006 LVRT16 _foo+0x12340000 +| +|00000000 5da05678 ; or.u r13,r0,0x5678 +|00000004 1c4d5678 ; ld.b r2,r13,0x5678 +|00000008 f400c001 ; jmp r1 + + The relocation routine digs out the value from the data, adds + it to the addend to get the original offset, and then adds the + value of <<_foo>>. Note that all 32 bits have to be kept around + somewhere, to cope with carry from bit 15 to bit 16. + + One further example is the sparc and the a.out format. The + sparc has a similar problem to the 88k, in that some + instructions don't have room for an entire offset, but on the + sparc the parts are created in odd sized lumps. The designers of + the a.out format chose to not use the data within the section + for storing part of the offset; all the offset is kept within + the reloc. Anything in the data should be ignored. + +| save %sp,-112,%sp +| sethi %hi(_foo+0x12345678),%g2 +| ldsb [%g2+%lo(_foo+0x12345678)],%i0 +| ret +| restore + + Both relocs contain a pointer to <>, and the offsets + contain junk. + +|RELOCATION RECORDS FOR [.text]: +|offset type value +|00000004 HI22 _foo+0x12345678 +|00000008 LO10 _foo+0x12345678 +| +|00000000 9de3bf90 ; save %sp,-112,%sp +|00000004 05000000 ; sethi %hi(_foo+0),%g2 +|00000008 f048a000 ; ldsb [%g2+%lo(_foo+0)],%i0 +|0000000c 81c7e008 ; ret +|00000010 81e80000 ; restore + + o <> + + The <> field can be imagined as a + relocation instruction. It is a pointer to a structure which + contains information on what to do with all of the other + information in the reloc record and data section. A back end + would normally have a relocation instruction set and turn + relocations into pointers to the correct structure on input - + but it would be possible to create each howto field on demand. + +*/ + +/* +SUBSUBSECTION + <> + + Indicates what sort of overflow checking should be done when + performing a relocation. + +CODE_FRAGMENT +. +.enum complain_overflow +.{ +. {* Do not complain on overflow. *} +. complain_overflow_dont, +. +. {* Complain if the bitfield overflows, whether it is considered +. as signed or unsigned. *} +. complain_overflow_bitfield, +. +. {* Complain if the value overflows when considered as signed +. number. *} +. complain_overflow_signed, +. +. {* Complain if the value overflows when considered as an +. unsigned number. *} +. complain_overflow_unsigned +.}; + +*/ + +/* +SUBSUBSECTION + <> + + The <> is a structure which contains all the + information that libbfd needs to know to tie up a back end's data. + +CODE_FRAGMENT +.struct symbol_cache_entry; {* Forward declaration. *} +. +.struct reloc_howto_struct +.{ +. {* The type field has mainly a documentary use - the back end can +. do what it wants with it, though normally the back end's +. external idea of what a reloc number is stored +. in this field. For example, a PC relative word relocation +. in a coff environment has the type 023 - because that's +. what the outside world calls a R_PCRWORD reloc. *} +. unsigned int type; +. +. {* The value the final relocation is shifted right by. This drops +. unwanted data from the relocation. *} +. unsigned int rightshift; +. +. {* The size of the item to be relocated. This is *not* a +. power-of-two measure. To get the number of bytes operated +. on by a type of relocation, use bfd_get_reloc_size. *} +. int size; +. +. {* The number of bits in the item to be relocated. This is used +. when doing overflow checking. *} +. unsigned int bitsize; +. +. {* Notes that the relocation is relative to the location in the +. data section of the addend. The relocation function will +. subtract from the relocation value the address of the location +. being relocated. *} +. bfd_boolean pc_relative; +. +. {* The bit position of the reloc value in the destination. +. The relocated value is left shifted by this amount. *} +. unsigned int bitpos; +. +. {* What type of overflow error should be checked for when +. relocating. *} +. enum complain_overflow complain_on_overflow; +. +. {* If this field is non null, then the supplied function is +. called rather than the normal function. This allows really +. strange relocation methods to be accomodated (e.g., i960 callj +. instructions). *} +. bfd_reloc_status_type (*special_function) +. PARAMS ((bfd *, arelent *, struct symbol_cache_entry *, PTR, asection *, +. bfd *, char **)); +. +. {* The textual name of the relocation type. *} +. char *name; +. +. {* Some formats record a relocation addend in the section contents +. rather than with the relocation. For ELF formats this is the +. distinction between USE_REL and USE_RELA (though the code checks +. for USE_REL == 1/0). The value of this field is TRUE if the +. addend is recorded with the section contents; when performing a +. partial link (ld -r) the section contents (the data) will be +. modified. The value of this field is FALSE if addends are +. recorded with the relocation (in arelent.addend); when performing +. a partial link the relocation will be modified. +. All relocations for all ELF USE_RELA targets should set this field +. to FALSE (values of TRUE should be looked on with suspicion). +. However, the converse is not true: not all relocations of all ELF +. USE_REL targets set this field to TRUE. Why this is so is peculiar +. to each particular target. For relocs that aren't used in partial +. links (e.g. GOT stuff) it doesn't matter what this is set to. *} +. bfd_boolean partial_inplace; +. +. {* src_mask selects the part of the instruction (or data) to be used +. in the relocation sum. If the target relocations don't have an +. addend in the reloc, eg. ELF USE_REL, src_mask will normally equal +. dst_mask to extract the addend from the section contents. If +. relocations do have an addend in the reloc, eg. ELF USE_RELA, this +. field should be zero. Non-zero values for ELF USE_RELA targets are +. bogus as in those cases the value in the dst_mask part of the +. section contents should be treated as garbage. *} +. bfd_vma src_mask; +. +. {* dst_mask selects which parts of the instruction (or data) are +. replaced with a relocated value. *} +. bfd_vma dst_mask; +. +. {* When some formats create PC relative instructions, they leave +. the value of the pc of the place being relocated in the offset +. slot of the instruction, so that a PC relative relocation can +. be made just by adding in an ordinary offset (e.g., sun3 a.out). +. Some formats leave the displacement part of an instruction +. empty (e.g., m88k bcs); this flag signals the fact. *} +. bfd_boolean pcrel_offset; +.}; +. +*/ + +/* +FUNCTION + The HOWTO Macro + +DESCRIPTION + The HOWTO define is horrible and will go away. + +.#define HOWTO(C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ +. { (unsigned) C, R, S, B, P, BI, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC } + +DESCRIPTION + And will be replaced with the totally magic way. But for the + moment, we are compatible, so do it this way. + +.#define NEWHOWTO(FUNCTION, NAME, SIZE, REL, IN) \ +. HOWTO (0, 0, SIZE, 0, REL, 0, complain_overflow_dont, FUNCTION, \ +. NAME, FALSE, 0, 0, IN) +. + +DESCRIPTION + This is used to fill in an empty howto entry in an array. + +.#define EMPTY_HOWTO(C) \ +. HOWTO ((C), 0, 0, 0, FALSE, 0, complain_overflow_dont, NULL, \ +. NULL, FALSE, 0, 0, FALSE) +. + +DESCRIPTION + Helper routine to turn a symbol into a relocation value. + +.#define HOWTO_PREPARE(relocation, symbol) \ +. { \ +. if (symbol != (asymbol *) NULL) \ +. { \ +. if (bfd_is_com_section (symbol->section)) \ +. { \ +. relocation = 0; \ +. } \ +. else \ +. { \ +. relocation = symbol->value; \ +. } \ +. } \ +. } +. +*/ + +/* +FUNCTION + bfd_get_reloc_size + +SYNOPSIS + unsigned int bfd_get_reloc_size (reloc_howto_type *); + +DESCRIPTION + For a reloc_howto_type that operates on a fixed number of bytes, + this returns the number of bytes operated on. + */ + +unsigned int +bfd_get_reloc_size (howto) + reloc_howto_type *howto; +{ + switch (howto->size) + { + case 0: return 1; + case 1: return 2; + case 2: return 4; + case 3: return 0; + case 4: return 8; + case 8: return 16; + case -2: return 4; + default: abort (); + } +} + +/* +TYPEDEF + arelent_chain + +DESCRIPTION + + How relocs are tied together in an <>: + +.typedef struct relent_chain +.{ +. arelent relent; +. struct relent_chain *next; +.} +.arelent_chain; +. +*/ + +/* N_ONES produces N one bits, without overflowing machine arithmetic. */ +#define N_ONES(n) (((((bfd_vma) 1 << ((n) - 1)) - 1) << 1) | 1) + +/* +FUNCTION + bfd_check_overflow + +SYNOPSIS + bfd_reloc_status_type + bfd_check_overflow + (enum complain_overflow how, + unsigned int bitsize, + unsigned int rightshift, + unsigned int addrsize, + bfd_vma relocation); + +DESCRIPTION + Perform overflow checking on @var{relocation} which has + @var{bitsize} significant bits and will be shifted right by + @var{rightshift} bits, on a machine with addresses containing + @var{addrsize} significant bits. The result is either of + @code{bfd_reloc_ok} or @code{bfd_reloc_overflow}. + +*/ + +bfd_reloc_status_type +bfd_check_overflow (how, bitsize, rightshift, addrsize, relocation) + enum complain_overflow how; + unsigned int bitsize; + unsigned int rightshift; + unsigned int addrsize; + bfd_vma relocation; +{ + bfd_vma fieldmask, addrmask, signmask, ss, a; + bfd_reloc_status_type flag = bfd_reloc_ok; + + a = relocation; + + /* Note: BITSIZE should always be <= ADDRSIZE, but in case it's not, + we'll be permissive: extra bits in the field mask will + automatically extend the address mask for purposes of the + overflow check. */ + fieldmask = N_ONES (bitsize); + addrmask = N_ONES (addrsize) | fieldmask; + + switch (how) + { + case complain_overflow_dont: + break; + + 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. */ + a = (a & addrmask) >> rightshift; + signmask = ~ (fieldmask >> 1); + ss = a & signmask; + if (ss != 0 && ss != ((addrmask >> rightshift) & signmask)) + flag = bfd_reloc_overflow; + break; + + case complain_overflow_unsigned: + /* We have an overflow if the address does not fit in the field. */ + a = (a & addrmask) >> rightshift; + if ((a & ~ fieldmask) != 0) + flag = bfd_reloc_overflow; + break; + + case complain_overflow_bitfield: + /* Bitfields are sometimes signed, sometimes unsigned. We + explicitly allow an address wrap too, which means a bitfield + of n bits is allowed to store -2**n to 2**n-1. Thus overflow + if the value has some, but not all, bits set outside the + field. */ + a >>= rightshift; + ss = a & ~ fieldmask; + if (ss != 0 && ss != (((bfd_vma) -1 >> rightshift) & ~ fieldmask)) + flag = bfd_reloc_overflow; + break; + + default: + abort (); + } + + return flag; +} + +/* +FUNCTION + bfd_perform_relocation + +SYNOPSIS + bfd_reloc_status_type + bfd_perform_relocation + (bfd *abfd, + arelent *reloc_entry, + PTR data, + asection *input_section, + bfd *output_bfd, + char **error_message); + +DESCRIPTION + If @var{output_bfd} is supplied to this function, the + generated image will be relocatable; the relocations are + copied to the output file after they have been changed to + reflect the new state of the world. There are two ways of + reflecting the results of partial linkage in an output file: + by modifying the output data in place, and by modifying the + relocation record. Some native formats (e.g., basic a.out and + basic coff) have no way of specifying an addend in the + relocation type, so the addend has to go in the output data. + This is no big deal since in these formats the output data + slot will always be big enough for the addend. Complex reloc + types with addends were invented to solve just this problem. + The @var{error_message} argument is set to an error message if + this return @code{bfd_reloc_dangerous}. + +*/ + +bfd_reloc_status_type +bfd_perform_relocation (abfd, reloc_entry, data, input_section, output_bfd, + error_message) + bfd *abfd; + arelent *reloc_entry; + PTR data; + asection *input_section; + bfd *output_bfd; + char **error_message; +{ + bfd_vma relocation; + bfd_reloc_status_type flag = bfd_reloc_ok; + bfd_size_type octets = reloc_entry->address * bfd_octets_per_byte (abfd); + bfd_vma output_base = 0; + reloc_howto_type *howto = reloc_entry->howto; + asection *reloc_target_output_section; + asymbol *symbol; + + symbol = *(reloc_entry->sym_ptr_ptr); + if (bfd_is_abs_section (symbol->section) + && output_bfd != (bfd *) NULL) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If we are not producing relocateable output, return an error if + the symbol is not defined. An undefined weak symbol is + considered to have a value of zero (SVR4 ABI, p. 4-27). */ + if (bfd_is_und_section (symbol->section) + && (symbol->flags & BSF_WEAK) == 0 + && output_bfd == (bfd *) NULL) + flag = bfd_reloc_undefined; + + /* If there is a function supplied to handle this relocation type, + call it. It'll return `bfd_reloc_continue' if further processing + can be done. */ + if (howto->special_function) + { + bfd_reloc_status_type cont; + cont = howto->special_function (abfd, reloc_entry, symbol, data, + input_section, output_bfd, + error_message); + if (cont != bfd_reloc_continue) + return cont; + } + + /* Is the address of the relocation really within the section? */ + if (reloc_entry->address > (input_section->_cooked_size + / bfd_octets_per_byte (abfd))) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if ((output_bfd && ! howto->partial_inplace) + || reloc_target_output_section == NULL) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += reloc_entry->addend; + + /* Here the variable relocation holds the final address of the + symbol we are relocating against, plus any addend. */ + + if (howto->pc_relative) + { + /* This is a PC relative relocation. We want to set RELOCATION + to the distance between the address of the symbol and the + location. RELOCATION is already the address of the symbol. + + We start by subtracting the address of the section containing + the location. + + If pcrel_offset is set, we must further subtract the position + of the location within the section. Some targets arrange for + the addend to be the negative of the position of the location + within the section; for example, i386-aout does this. For + i386-aout, pcrel_offset is FALSE. Some other targets do not + include the position of the location; for example, m88kbcs, + or ELF. For those targets, pcrel_offset is TRUE. + + If we are producing relocateable output, then we must ensure + that this reloc will be correctly computed when the final + relocation is done. If pcrel_offset is FALSE we want to wind + up with the negative of the location within the section, + which means we must adjust the existing addend by the change + in the location within the section. If pcrel_offset is TRUE + we do not want to adjust the existing addend at all. + + FIXME: This seems logical to me, but for the case of + producing relocateable output it is not what the code + actually does. I don't want to change it, because it seems + far too likely that something will break. */ + + relocation -= + input_section->output_section->vma + input_section->output_offset; + + if (howto->pcrel_offset) + relocation -= reloc_entry->address; + } + + if (output_bfd != (bfd *) NULL) + { + if (! howto->partial_inplace) + { + /* This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Modify the reloc + inplace to reflect what we now know. */ + reloc_entry->addend = relocation; + reloc_entry->address += input_section->output_offset; + return flag; + } + else + { + /* This is a partial relocation, but inplace, so modify the + reloc record a bit. + + If we've relocated with a symbol with a section, change + into a ref to the section belonging to the symbol. */ + + reloc_entry->address += input_section->output_offset; + + /* WTF?? */ + if (abfd->xvec->flavour == bfd_target_coff_flavour + && strcmp (abfd->xvec->name, "coff-Intel-little") != 0 + && strcmp (abfd->xvec->name, "coff-Intel-big") != 0) + { +#if 1 + /* For m68k-coff, the addend was being subtracted twice during + relocation with -r. Removing the line below this comment + fixes that problem; see PR 2953. + +However, Ian wrote the following, regarding removing the line below, +which explains why it is still enabled: --djm + +If you put a patch like that into BFD you need to check all the COFF +linkers. I am fairly certain that patch will break coff-i386 (e.g., +SCO); see coff_i386_reloc in coff-i386.c where I worked around the +problem in a different way. There may very well be a reason that the +code works as it does. + +Hmmm. The first obvious point is that bfd_perform_relocation should +not have any tests that depend upon the flavour. It's seem like +entirely the wrong place for such a thing. The second obvious point +is that the current code ignores the reloc addend when producing +relocateable output for COFF. That's peculiar. In fact, I really +have no idea what the point of the line you want to remove is. + +A typical COFF reloc subtracts the old value of the symbol and adds in +the new value to the location in the object file (if it's a pc +relative reloc it adds the difference between the symbol value and the +location). When relocating we need to preserve that property. + +BFD handles this by setting the addend to the negative of the old +value of the symbol. Unfortunately it handles common symbols in a +non-standard way (it doesn't subtract the old value) but that's a +different story (we can't change it without losing backward +compatibility with old object files) (coff-i386 does subtract the old +value, to be compatible with existing coff-i386 targets, like SCO). + +So everything works fine when not producing relocateable output. When +we are producing relocateable output, logically we should do exactly +what we do when not producing relocateable output. Therefore, your +patch is correct. In fact, it should probably always just set +reloc_entry->addend to 0 for all cases, since it is, in fact, going to +add the value into the object file. This won't hurt the COFF code, +which doesn't use the addend; I'm not sure what it will do to other +formats (the thing to check for would be whether any formats both use +the addend and set partial_inplace). + +When I wanted to make coff-i386 produce relocateable output, I ran +into the problem that you are running into: I wanted to remove that +line. Rather than risk it, I made the coff-i386 relocs use a special +function; it's coff_i386_reloc in coff-i386.c. The function +specifically adds the addend field into the object file, knowing that +bfd_perform_relocation is not going to. If you remove that line, then +coff-i386.c will wind up adding the addend field in twice. It's +trivial to fix; it just needs to be done. + +The problem with removing the line is just that it may break some +working code. With BFD it's hard to be sure of anything. The right +way to deal with this is simply to build and test at least all the +supported COFF targets. It should be straightforward if time and disk +space consuming. For each target: + 1) build the linker + 2) generate some executable, and link it using -r (I would + probably use paranoia.o and link against newlib/libc.a, which + for all the supported targets would be available in + /usr/cygnus/progressive/H-host/target/lib/libc.a). + 3) make the change to reloc.c + 4) rebuild the linker + 5) repeat step 2 + 6) if the resulting object files are the same, you have at least + made it no worse + 7) if they are different you have to figure out which version is + right +*/ + relocation -= reloc_entry->addend; +#endif + reloc_entry->addend = 0; + } + else + { + reloc_entry->addend = relocation; + } + } + } + else + { + reloc_entry->addend = 0; + } + + /* FIXME: This overflow checking is incomplete, because the value + might have overflowed before we get here. For a correct check we + need to compute the value in a size larger than bitsize, but we + can't reasonably do that for a reloc the same size as a host + machine word. + FIXME: We should also do overflow checking on the result after + adding in the value contained in the object file. */ + if (howto->complain_on_overflow != complain_overflow_dont + && flag == bfd_reloc_ok) + flag = bfd_check_overflow (howto->complain_on_overflow, + howto->bitsize, + howto->rightshift, + bfd_arch_bits_per_address (abfd), + relocation); + + /* Either we are relocating all the way, or we don't want to apply + the relocation to the reloc entry (probably because there isn't + any room in the output format to describe addends to relocs). */ + + /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler + (OSF version 1.3, compiler version 3.11). It miscompiles the + following program: + + struct str + { + unsigned int i0; + } s = { 0 }; + + int + main () + { + unsigned long x; + + x = 0x100000000; + x <<= (unsigned long) s.i0; + if (x == 0) + printf ("failed\n"); + else + printf ("succeeded (%lx)\n", x); + } + */ + + relocation >>= (bfd_vma) howto->rightshift; + + /* Shift everything up to where it's going to be used. */ + relocation <<= (bfd_vma) howto->bitpos; + + /* Wait for the day when all have the mask in them. */ + + /* What we do: + i instruction to be left alone + o offset within instruction + r relocation offset to apply + S src mask + D dst mask + N ~dst mask + A part 1 + B part 2 + R result + + Do this: + (( i i i i i o o o o o from bfd_get + and S S S S S) to get the size offset we want + + r r r r r r r r r r) to get the final value to place + and D D D D D to chop to right size + ----------------------- + = A A A A A + And this: + ( i i i i i o o o o o from bfd_get + and N N N N N ) get instruction + ----------------------- + = B B B B B + + And then: + ( B B B B B + or A A A A A) + ----------------------- + = R R R R R R R R R R put into bfd_put + */ + +#define DOIT(x) \ + x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, (char *) data + octets); + DOIT (x); + bfd_put_8 (abfd, x, (unsigned char *) data + octets); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, (bfd_byte *) data + octets); + DOIT (x); + bfd_put_16 (abfd, (bfd_vma) x, (unsigned char *) data + octets); + } + break; + case 2: + { + long x = bfd_get_32 (abfd, (bfd_byte *) data + octets); + DOIT (x); + bfd_put_32 (abfd, (bfd_vma) x, (bfd_byte *) data + octets); + } + break; + case -2: + { + long x = bfd_get_32 (abfd, (bfd_byte *) data + octets); + relocation = -relocation; + DOIT (x); + bfd_put_32 (abfd, (bfd_vma) x, (bfd_byte *) data + octets); + } + break; + + case -1: + { + long x = bfd_get_16 (abfd, (bfd_byte *) data + octets); + relocation = -relocation; + DOIT (x); + bfd_put_16 (abfd, (bfd_vma) x, (bfd_byte *) data + octets); + } + break; + + case 3: + /* Do nothing */ + break; + + case 4: +#ifdef BFD64 + { + bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + octets); + DOIT (x); + bfd_put_64 (abfd, x, (bfd_byte *) data + octets); + } +#else + abort (); +#endif + break; + default: + return bfd_reloc_other; + } + + return flag; +} + +/* +FUNCTION + bfd_install_relocation + +SYNOPSIS + bfd_reloc_status_type + bfd_install_relocation + (bfd *abfd, + arelent *reloc_entry, + PTR data, bfd_vma data_start, + asection *input_section, + char **error_message); + +DESCRIPTION + This looks remarkably like <>, except it + does not expect that the section contents have been filled in. + I.e., it's suitable for use when creating, rather than applying + a relocation. + + For now, this function should be considered reserved for the + assembler. +*/ + +bfd_reloc_status_type +bfd_install_relocation (abfd, reloc_entry, data_start, data_start_offset, + input_section, error_message) + bfd *abfd; + arelent *reloc_entry; + PTR data_start; + bfd_vma data_start_offset; + asection *input_section; + char **error_message; +{ + bfd_vma relocation; + bfd_reloc_status_type flag = bfd_reloc_ok; + bfd_size_type octets = reloc_entry->address * bfd_octets_per_byte (abfd); + bfd_vma output_base = 0; + reloc_howto_type *howto = reloc_entry->howto; + asection *reloc_target_output_section; + asymbol *symbol; + bfd_byte *data; + + symbol = *(reloc_entry->sym_ptr_ptr); + if (bfd_is_abs_section (symbol->section)) + { + reloc_entry->address += input_section->output_offset; + return bfd_reloc_ok; + } + + /* If there is a function supplied to handle this relocation type, + call it. It'll return `bfd_reloc_continue' if further processing + can be done. */ + if (howto->special_function) + { + bfd_reloc_status_type cont; + + /* XXX - The special_function calls haven't been fixed up to deal + with creating new relocations and section contents. */ + cont = howto->special_function (abfd, reloc_entry, symbol, + /* XXX - Non-portable! */ + ((bfd_byte *) data_start + - data_start_offset), + input_section, abfd, error_message); + if (cont != bfd_reloc_continue) + return cont; + } + + /* Is the address of the relocation really within the section? */ + if (reloc_entry->address > (input_section->_cooked_size + / bfd_octets_per_byte (abfd))) + return bfd_reloc_outofrange; + + /* Work out which section the relocation is targetted at and the + initial relocation command value. */ + + /* Get symbol value. (Common symbols are special.) */ + if (bfd_is_com_section (symbol->section)) + relocation = 0; + else + relocation = symbol->value; + + reloc_target_output_section = symbol->section->output_section; + + /* Convert input-section-relative symbol value to absolute. */ + if (! howto->partial_inplace) + output_base = 0; + else + output_base = reloc_target_output_section->vma; + + relocation += output_base + symbol->section->output_offset; + + /* Add in supplied addend. */ + relocation += reloc_entry->addend; + + /* Here the variable relocation holds the final address of the + symbol we are relocating against, plus any addend. */ + + if (howto->pc_relative) + { + /* This is a PC relative relocation. We want to set RELOCATION + to the distance between the address of the symbol and the + location. RELOCATION is already the address of the symbol. + + We start by subtracting the address of the section containing + the location. + + If pcrel_offset is set, we must further subtract the position + of the location within the section. Some targets arrange for + the addend to be the negative of the position of the location + within the section; for example, i386-aout does this. For + i386-aout, pcrel_offset is FALSE. Some other targets do not + include the position of the location; for example, m88kbcs, + or ELF. For those targets, pcrel_offset is TRUE. + + If we are producing relocateable output, then we must ensure + that this reloc will be correctly computed when the final + relocation is done. If pcrel_offset is FALSE we want to wind + up with the negative of the location within the section, + which means we must adjust the existing addend by the change + in the location within the section. If pcrel_offset is TRUE + we do not want to adjust the existing addend at all. + + FIXME: This seems logical to me, but for the case of + producing relocateable output it is not what the code + actually does. I don't want to change it, because it seems + far too likely that something will break. */ + + relocation -= + input_section->output_section->vma + input_section->output_offset; + + if (howto->pcrel_offset && howto->partial_inplace) + relocation -= reloc_entry->address; + } + + if (! howto->partial_inplace) + { + /* This is a partial relocation, and we want to apply the relocation + to the reloc entry rather than the raw data. Modify the reloc + inplace to reflect what we now know. */ + reloc_entry->addend = relocation; + reloc_entry->address += input_section->output_offset; + return flag; + } + else + { + /* This is a partial relocation, but inplace, so modify the + reloc record a bit. + + If we've relocated with a symbol with a section, change + into a ref to the section belonging to the symbol. */ + reloc_entry->address += input_section->output_offset; + + /* WTF?? */ + if (abfd->xvec->flavour == bfd_target_coff_flavour + && strcmp (abfd->xvec->name, "coff-Intel-little") != 0 + && strcmp (abfd->xvec->name, "coff-Intel-big") != 0) + { +#if 1 +/* For m68k-coff, the addend was being subtracted twice during + relocation with -r. Removing the line below this comment + fixes that problem; see PR 2953. + +However, Ian wrote the following, regarding removing the line below, +which explains why it is still enabled: --djm + +If you put a patch like that into BFD you need to check all the COFF +linkers. I am fairly certain that patch will break coff-i386 (e.g., +SCO); see coff_i386_reloc in coff-i386.c where I worked around the +problem in a different way. There may very well be a reason that the +code works as it does. + +Hmmm. The first obvious point is that bfd_install_relocation should +not have any tests that depend upon the flavour. It's seem like +entirely the wrong place for such a thing. The second obvious point +is that the current code ignores the reloc addend when producing +relocateable output for COFF. That's peculiar. In fact, I really +have no idea what the point of the line you want to remove is. + +A typical COFF reloc subtracts the old value of the symbol and adds in +the new value to the location in the object file (if it's a pc +relative reloc it adds the difference between the symbol value and the +location). When relocating we need to preserve that property. + +BFD handles this by setting the addend to the negative of the old +value of the symbol. Unfortunately it handles common symbols in a +non-standard way (it doesn't subtract the old value) but that's a +different story (we can't change it without losing backward +compatibility with old object files) (coff-i386 does subtract the old +value, to be compatible with existing coff-i386 targets, like SCO). + +So everything works fine when not producing relocateable output. When +we are producing relocateable output, logically we should do exactly +what we do when not producing relocateable output. Therefore, your +patch is correct. In fact, it should probably always just set +reloc_entry->addend to 0 for all cases, since it is, in fact, going to +add the value into the object file. This won't hurt the COFF code, +which doesn't use the addend; I'm not sure what it will do to other +formats (the thing to check for would be whether any formats both use +the addend and set partial_inplace). + +When I wanted to make coff-i386 produce relocateable output, I ran +into the problem that you are running into: I wanted to remove that +line. Rather than risk it, I made the coff-i386 relocs use a special +function; it's coff_i386_reloc in coff-i386.c. The function +specifically adds the addend field into the object file, knowing that +bfd_install_relocation is not going to. If you remove that line, then +coff-i386.c will wind up adding the addend field in twice. It's +trivial to fix; it just needs to be done. + +The problem with removing the line is just that it may break some +working code. With BFD it's hard to be sure of anything. The right +way to deal with this is simply to build and test at least all the +supported COFF targets. It should be straightforward if time and disk +space consuming. For each target: + 1) build the linker + 2) generate some executable, and link it using -r (I would + probably use paranoia.o and link against newlib/libc.a, which + for all the supported targets would be available in + /usr/cygnus/progressive/H-host/target/lib/libc.a). + 3) make the change to reloc.c + 4) rebuild the linker + 5) repeat step 2 + 6) if the resulting object files are the same, you have at least + made it no worse + 7) if they are different you have to figure out which version is + right. */ + relocation -= reloc_entry->addend; +#endif + reloc_entry->addend = 0; + } + else + { + reloc_entry->addend = relocation; + } + } + + /* FIXME: This overflow checking is incomplete, because the value + might have overflowed before we get here. For a correct check we + need to compute the value in a size larger than bitsize, but we + can't reasonably do that for a reloc the same size as a host + machine word. + FIXME: We should also do overflow checking on the result after + adding in the value contained in the object file. */ + if (howto->complain_on_overflow != complain_overflow_dont) + flag = bfd_check_overflow (howto->complain_on_overflow, + howto->bitsize, + howto->rightshift, + bfd_arch_bits_per_address (abfd), + relocation); + + /* Either we are relocating all the way, or we don't want to apply + the relocation to the reloc entry (probably because there isn't + any room in the output format to describe addends to relocs). */ + + /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler + (OSF version 1.3, compiler version 3.11). It miscompiles the + following program: + + struct str + { + unsigned int i0; + } s = { 0 }; + + int + main () + { + unsigned long x; + + x = 0x100000000; + x <<= (unsigned long) s.i0; + if (x == 0) + printf ("failed\n"); + else + printf ("succeeded (%lx)\n", x); + } + */ + + relocation >>= (bfd_vma) howto->rightshift; + + /* Shift everything up to where it's going to be used. */ + relocation <<= (bfd_vma) howto->bitpos; + + /* Wait for the day when all have the mask in them. */ + + /* What we do: + i instruction to be left alone + o offset within instruction + r relocation offset to apply + S src mask + D dst mask + N ~dst mask + A part 1 + B part 2 + R result + + Do this: + (( i i i i i o o o o o from bfd_get + and S S S S S) to get the size offset we want + + r r r r r r r r r r) to get the final value to place + and D D D D D to chop to right size + ----------------------- + = A A A A A + And this: + ( i i i i i o o o o o from bfd_get + and N N N N N ) get instruction + ----------------------- + = B B B B B + + And then: + ( B B B B B + or A A A A A) + ----------------------- + = R R R R R R R R R R put into bfd_put + */ + +#define DOIT(x) \ + x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) + + data = (bfd_byte *) data_start + (octets - data_start_offset); + + switch (howto->size) + { + case 0: + { + char x = bfd_get_8 (abfd, (char *) data); + DOIT (x); + bfd_put_8 (abfd, x, (unsigned char *) data); + } + break; + + case 1: + { + short x = bfd_get_16 (abfd, (bfd_byte *) data); + DOIT (x); + bfd_put_16 (abfd, (bfd_vma) x, (unsigned char *) data); + } + break; + case 2: + { + long x = bfd_get_32 (abfd, (bfd_byte *) data); + DOIT (x); + bfd_put_32 (abfd, (bfd_vma) x, (bfd_byte *) data); + } + break; + case -2: + { + long x = bfd_get_32 (abfd, (bfd_byte *) data); + relocation = -relocation; + DOIT (x); + bfd_put_32 (abfd, (bfd_vma) x, (bfd_byte *) data); + } + break; + + case 3: + /* Do nothing */ + break; + + case 4: + { + bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data); + DOIT (x); + bfd_put_64 (abfd, x, (bfd_byte *) data); + } + break; + default: + return bfd_reloc_other; + } + + return flag; +} + +/* This relocation routine is used by some of the backend linkers. + They do not construct asymbol or arelent structures, so there is no + reason for them to use bfd_perform_relocation. Also, + bfd_perform_relocation is so hacked up it is easier to write a new + function than to try to deal with it. + + This routine does a final relocation. Whether it is useful for a + relocateable link depends upon how the object format defines + relocations. + + FIXME: This routine ignores any special_function in the HOWTO, + since the existing special_function values have been written for + bfd_perform_relocation. + + HOWTO is the reloc howto information. + INPUT_BFD is the BFD which the reloc applies to. + INPUT_SECTION is the section which the reloc applies to. + CONTENTS is the contents of the section. + ADDRESS is the address of the reloc within INPUT_SECTION. + VALUE is the value of the symbol the reloc refers to. + ADDEND is the addend of the reloc. */ + +bfd_reloc_status_type +_bfd_final_link_relocate (howto, input_bfd, input_section, contents, address, + value, addend) + 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 > input_section->_raw_size) + 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 _bfd_relocate_contents (howto, input_bfd, relocation, + contents + address); +} + +/* Relocate a given location using a given value and howto. */ + +bfd_reloc_status_type +_bfd_relocate_contents (howto, input_bfd, relocation, location) + 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: + case 0: + abort (); + case 1: + x = bfd_get_8 (input_bfd, location); + break; + case 2: + x = bfd_get_16 (input_bfd, location); + break; + case 4: + x = bfd_get_32 (input_bfd, location); + break; + case 8: +#ifdef BFD64 + x = bfd_get_64 (input_bfd, location); +#else + abort (); +#endif + 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); + addrmask = N_ONES (bfd_arch_bits_per_address (input_bfd)) | fieldmask; + a = relocation; + b = x & howto->src_mask; + + switch (howto->complain_on_overflow) + { + case complain_overflow_signed: + a = (a & addrmask) >> rightshift; + + /* 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); + 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. */ + signmask = ((~ howto->src_mask) >> 1) & howto->src_mask; + + /* Set all the bits above the sign bit. */ + b = (b ^ signmask) - signmask; + + b = (b & addrmask) >> bitpos; + + /* 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) + */ + signmask = (fieldmask >> 1) + 1; + if (((~ (a ^ b)) & (a ^ sum)) & signmask) + 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. */ + a = (a & addrmask) >> rightshift; + b = (b & addrmask) >> bitpos; + sum = (a + b) & addrmask; + if ((a | b | sum) & ~ fieldmask) + flag = bfd_reloc_overflow; + + break; + + case complain_overflow_bitfield: + /* Much like the signed check, but for a field one bit + wider, and no trimming inputs with addrmask. 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. */ + a >>= rightshift; + + signmask = ~ fieldmask; + ss = a & signmask; + if (ss != 0 && ss != (((bfd_vma) -1 >> rightshift) & signmask)) + flag = bfd_reloc_overflow; + + signmask = ((~ howto->src_mask) >> 1) & howto->src_mask; + b = (b ^ signmask) - signmask; + + b >>= bitpos; + + sum = a + b; + + /* 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. */ + signmask = fieldmask + 1; + if (((~ (a ^ b)) & (a ^ sum)) & signmask & addrmask) + 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. */ + x = ((x & ~howto->dst_mask) + | (((x & howto->src_mask) + relocation) & howto->dst_mask)); + + /* Put the relocated value back in the object file. */ + switch (size) + { + default: + case 0: + abort (); + case 1: + bfd_put_8 (input_bfd, x, location); + break; + case 2: + bfd_put_16 (input_bfd, x, location); + break; + case 4: + bfd_put_32 (input_bfd, x, location); + break; + case 8: +#ifdef BFD64 + bfd_put_64 (input_bfd, x, location); +#else + abort (); +#endif + break; + } + + return flag; +} + +/* +DOCDD +INODE + howto manager, , typedef arelent, Relocations + +SECTION + The howto manager + + When an application wants to create a relocation, but doesn't + know what the target machine might call it, it can find out by + using this bit of code. + +*/ + +/* +TYPEDEF + bfd_reloc_code_type + +DESCRIPTION + The insides of a reloc code. The idea is that, eventually, there + will be one enumerator for every type of relocation we ever do. + Pass one of these values to <>, and it'll + return a howto pointer. + + This does mean that the application must determine the correct + enumerator value; you can't get a howto pointer from a random set + of attributes. + +SENUM + bfd_reloc_code_real + +ENUM + BFD_RELOC_64 +ENUMX + BFD_RELOC_32 +ENUMX + BFD_RELOC_26 +ENUMX + BFD_RELOC_24 +ENUMX + BFD_RELOC_16 +ENUMX + BFD_RELOC_14 +ENUMX + BFD_RELOC_8 +ENUMDOC + Basic absolute relocations of N bits. + +ENUM + BFD_RELOC_64_PCREL +ENUMX + BFD_RELOC_32_PCREL +ENUMX + BFD_RELOC_24_PCREL +ENUMX + BFD_RELOC_16_PCREL +ENUMX + BFD_RELOC_12_PCREL +ENUMX + BFD_RELOC_8_PCREL +ENUMDOC + PC-relative relocations. Sometimes these are relative to the address +of the relocation itself; sometimes they are relative to the start of +the section containing the relocation. It depends on the specific target. + +The 24-bit relocation is used in some Intel 960 configurations. + +ENUM + BFD_RELOC_32_GOT_PCREL +ENUMX + BFD_RELOC_16_GOT_PCREL +ENUMX + BFD_RELOC_8_GOT_PCREL +ENUMX + BFD_RELOC_32_GOTOFF +ENUMX + BFD_RELOC_16_GOTOFF +ENUMX + BFD_RELOC_LO16_GOTOFF +ENUMX + BFD_RELOC_HI16_GOTOFF +ENUMX + BFD_RELOC_HI16_S_GOTOFF +ENUMX + BFD_RELOC_8_GOTOFF +ENUMX + BFD_RELOC_64_PLT_PCREL +ENUMX + BFD_RELOC_32_PLT_PCREL +ENUMX + BFD_RELOC_24_PLT_PCREL +ENUMX + BFD_RELOC_16_PLT_PCREL +ENUMX + BFD_RELOC_8_PLT_PCREL +ENUMX + BFD_RELOC_64_PLTOFF +ENUMX + BFD_RELOC_32_PLTOFF +ENUMX + BFD_RELOC_16_PLTOFF +ENUMX + BFD_RELOC_LO16_PLTOFF +ENUMX + BFD_RELOC_HI16_PLTOFF +ENUMX + BFD_RELOC_HI16_S_PLTOFF +ENUMX + BFD_RELOC_8_PLTOFF +ENUMDOC + For ELF. + +ENUM + BFD_RELOC_68K_GLOB_DAT +ENUMX + BFD_RELOC_68K_JMP_SLOT +ENUMX + BFD_RELOC_68K_RELATIVE +ENUMDOC + Relocations used by 68K ELF. + +ENUM + BFD_RELOC_32_BASEREL +ENUMX + BFD_RELOC_16_BASEREL +ENUMX + BFD_RELOC_LO16_BASEREL +ENUMX + BFD_RELOC_HI16_BASEREL +ENUMX + BFD_RELOC_HI16_S_BASEREL +ENUMX + BFD_RELOC_8_BASEREL +ENUMX + BFD_RELOC_RVA +ENUMDOC + Linkage-table relative. + +ENUM + BFD_RELOC_8_FFnn +ENUMDOC + Absolute 8-bit relocation, but used to form an address like 0xFFnn. + +ENUM + BFD_RELOC_32_PCREL_S2 +ENUMX + BFD_RELOC_16_PCREL_S2 +ENUMX + BFD_RELOC_23_PCREL_S2 +ENUMDOC + These PC-relative relocations are stored as word displacements -- +i.e., byte displacements shifted right two bits. The 30-bit word +displacement (<<32_PCREL_S2>> -- 32 bits, shifted 2) is used on the +SPARC. (SPARC tools generally refer to this as <>.) The +signed 16-bit displacement is used on the MIPS, and the 23-bit +displacement is used on the Alpha. + +ENUM + BFD_RELOC_HI22 +ENUMX + BFD_RELOC_LO10 +ENUMDOC + High 22 bits and low 10 bits of 32-bit value, placed into lower bits of +the target word. These are used on the SPARC. + +ENUM + BFD_RELOC_GPREL16 +ENUMX + BFD_RELOC_GPREL32 +ENUMDOC + For systems that allocate a Global Pointer register, these are +displacements off that register. These relocation types are +handled specially, because the value the register will have is +decided relatively late. + +ENUM + BFD_RELOC_I960_CALLJ +ENUMDOC + Reloc types used for i960/b.out. + +ENUM + BFD_RELOC_NONE +ENUMX + BFD_RELOC_SPARC_WDISP22 +ENUMX + BFD_RELOC_SPARC22 +ENUMX + BFD_RELOC_SPARC13 +ENUMX + BFD_RELOC_SPARC_GOT10 +ENUMX + BFD_RELOC_SPARC_GOT13 +ENUMX + BFD_RELOC_SPARC_GOT22 +ENUMX + BFD_RELOC_SPARC_PC10 +ENUMX + BFD_RELOC_SPARC_PC22 +ENUMX + BFD_RELOC_SPARC_WPLT30 +ENUMX + BFD_RELOC_SPARC_COPY +ENUMX + BFD_RELOC_SPARC_GLOB_DAT +ENUMX + BFD_RELOC_SPARC_JMP_SLOT +ENUMX + BFD_RELOC_SPARC_RELATIVE +ENUMX + BFD_RELOC_SPARC_UA16 +ENUMX + BFD_RELOC_SPARC_UA32 +ENUMX + BFD_RELOC_SPARC_UA64 +ENUMDOC + SPARC ELF relocations. There is probably some overlap with other + relocation types already defined. + +ENUM + BFD_RELOC_SPARC_BASE13 +ENUMX + BFD_RELOC_SPARC_BASE22 +ENUMDOC + I think these are specific to SPARC a.out (e.g., Sun 4). + +ENUMEQ + BFD_RELOC_SPARC_64 + BFD_RELOC_64 +ENUMX + BFD_RELOC_SPARC_10 +ENUMX + BFD_RELOC_SPARC_11 +ENUMX + BFD_RELOC_SPARC_OLO10 +ENUMX + BFD_RELOC_SPARC_HH22 +ENUMX + BFD_RELOC_SPARC_HM10 +ENUMX + BFD_RELOC_SPARC_LM22 +ENUMX + BFD_RELOC_SPARC_PC_HH22 +ENUMX + BFD_RELOC_SPARC_PC_HM10 +ENUMX + BFD_RELOC_SPARC_PC_LM22 +ENUMX + BFD_RELOC_SPARC_WDISP16 +ENUMX + BFD_RELOC_SPARC_WDISP19 +ENUMX + BFD_RELOC_SPARC_7 +ENUMX + BFD_RELOC_SPARC_6 +ENUMX + BFD_RELOC_SPARC_5 +ENUMEQX + BFD_RELOC_SPARC_DISP64 + BFD_RELOC_64_PCREL +ENUMX + BFD_RELOC_SPARC_PLT32 +ENUMX + BFD_RELOC_SPARC_PLT64 +ENUMX + BFD_RELOC_SPARC_HIX22 +ENUMX + BFD_RELOC_SPARC_LOX10 +ENUMX + BFD_RELOC_SPARC_H44 +ENUMX + BFD_RELOC_SPARC_M44 +ENUMX + BFD_RELOC_SPARC_L44 +ENUMX + BFD_RELOC_SPARC_REGISTER +ENUMDOC + SPARC64 relocations + +ENUM + BFD_RELOC_SPARC_REV32 +ENUMDOC + SPARC little endian relocation +ENUM + BFD_RELOC_SPARC_TLS_GD_HI22 +ENUMX + BFD_RELOC_SPARC_TLS_GD_LO10 +ENUMX + BFD_RELOC_SPARC_TLS_GD_ADD +ENUMX + BFD_RELOC_SPARC_TLS_GD_CALL +ENUMX + BFD_RELOC_SPARC_TLS_LDM_HI22 +ENUMX + BFD_RELOC_SPARC_TLS_LDM_LO10 +ENUMX + BFD_RELOC_SPARC_TLS_LDM_ADD +ENUMX + BFD_RELOC_SPARC_TLS_LDM_CALL +ENUMX + BFD_RELOC_SPARC_TLS_LDO_HIX22 +ENUMX + BFD_RELOC_SPARC_TLS_LDO_LOX10 +ENUMX + BFD_RELOC_SPARC_TLS_LDO_ADD +ENUMX + BFD_RELOC_SPARC_TLS_IE_HI22 +ENUMX + BFD_RELOC_SPARC_TLS_IE_LO10 +ENUMX + BFD_RELOC_SPARC_TLS_IE_LD +ENUMX + BFD_RELOC_SPARC_TLS_IE_LDX +ENUMX + BFD_RELOC_SPARC_TLS_IE_ADD +ENUMX + BFD_RELOC_SPARC_TLS_LE_HIX22 +ENUMX + BFD_RELOC_SPARC_TLS_LE_LOX10 +ENUMX + BFD_RELOC_SPARC_TLS_DTPMOD32 +ENUMX + BFD_RELOC_SPARC_TLS_DTPMOD64 +ENUMX + BFD_RELOC_SPARC_TLS_DTPOFF32 +ENUMX + BFD_RELOC_SPARC_TLS_DTPOFF64 +ENUMX + BFD_RELOC_SPARC_TLS_TPOFF32 +ENUMX + BFD_RELOC_SPARC_TLS_TPOFF64 +ENUMDOC + SPARC TLS relocations + +ENUM + BFD_RELOC_ALPHA_GPDISP_HI16 +ENUMDOC + Alpha ECOFF and ELF relocations. Some of these treat the symbol or + "addend" in some special way. + For GPDISP_HI16 ("gpdisp") relocations, the symbol is ignored when + writing; when reading, it will be the absolute section symbol. The + addend is the displacement in bytes of the "lda" instruction from + the "ldah" instruction (which is at the address of this reloc). +ENUM + BFD_RELOC_ALPHA_GPDISP_LO16 +ENUMDOC + For GPDISP_LO16 ("ignore") relocations, the symbol is handled as + with GPDISP_HI16 relocs. The addend is ignored when writing the + relocations out, and is filled in with the file's GP value on + reading, for convenience. + +ENUM + BFD_RELOC_ALPHA_GPDISP +ENUMDOC + The ELF GPDISP relocation is exactly the same as the GPDISP_HI16 + relocation except that there is no accompanying GPDISP_LO16 + relocation. + +ENUM + BFD_RELOC_ALPHA_LITERAL +ENUMX + BFD_RELOC_ALPHA_ELF_LITERAL +ENUMX + BFD_RELOC_ALPHA_LITUSE +ENUMDOC + The Alpha LITERAL/LITUSE relocs are produced by a symbol reference; + the assembler turns it into a LDQ instruction to load the address of + the symbol, and then fills in a register in the real instruction. + + The LITERAL reloc, at the LDQ instruction, refers to the .lita + section symbol. The addend is ignored when writing, but is filled + in with the file's GP value on reading, for convenience, as with the + GPDISP_LO16 reloc. + + The ELF_LITERAL reloc is somewhere between 16_GOTOFF and GPDISP_LO16. + It should refer to the symbol to be referenced, as with 16_GOTOFF, + but it generates output not based on the position within the .got + section, but relative to the GP value chosen for the file during the + final link stage. + + The LITUSE reloc, on the instruction using the loaded address, gives + information to the linker that it might be able to use to optimize + away some literal section references. The symbol is ignored (read + as the absolute section symbol), and the "addend" indicates the type + of instruction using the register: + 1 - "memory" fmt insn + 2 - byte-manipulation (byte offset reg) + 3 - jsr (target of branch) + +ENUM + BFD_RELOC_ALPHA_HINT +ENUMDOC + The HINT relocation indicates a value that should be filled into the + "hint" field of a jmp/jsr/ret instruction, for possible branch- + prediction logic which may be provided on some processors. + +ENUM + BFD_RELOC_ALPHA_LINKAGE +ENUMDOC + The LINKAGE relocation outputs a linkage pair in the object file, + which is filled by the linker. + +ENUM + BFD_RELOC_ALPHA_CODEADDR +ENUMDOC + The CODEADDR relocation outputs a STO_CA in the object file, + which is filled by the linker. + +ENUM + BFD_RELOC_ALPHA_GPREL_HI16 +ENUMX + BFD_RELOC_ALPHA_GPREL_LO16 +ENUMDOC + The GPREL_HI/LO relocations together form a 32-bit offset from the + GP register. + +ENUM + BFD_RELOC_ALPHA_BRSGP +ENUMDOC + Like BFD_RELOC_23_PCREL_S2, except that the source and target must + share a common GP, and the target address is adjusted for + STO_ALPHA_STD_GPLOAD. + +ENUM + BFD_RELOC_ALPHA_TLSGD +ENUMX + BFD_RELOC_ALPHA_TLSLDM +ENUMX + BFD_RELOC_ALPHA_DTPMOD64 +ENUMX + BFD_RELOC_ALPHA_GOTDTPREL16 +ENUMX + BFD_RELOC_ALPHA_DTPREL64 +ENUMX + BFD_RELOC_ALPHA_DTPREL_HI16 +ENUMX + BFD_RELOC_ALPHA_DTPREL_LO16 +ENUMX + BFD_RELOC_ALPHA_DTPREL16 +ENUMX + BFD_RELOC_ALPHA_GOTTPREL16 +ENUMX + BFD_RELOC_ALPHA_TPREL64 +ENUMX + BFD_RELOC_ALPHA_TPREL_HI16 +ENUMX + BFD_RELOC_ALPHA_TPREL_LO16 +ENUMX + BFD_RELOC_ALPHA_TPREL16 +ENUMDOC + Alpha thread-local storage relocations. + +ENUM + BFD_RELOC_MIPS_JMP +ENUMDOC + Bits 27..2 of the relocation address shifted right 2 bits; + simple reloc otherwise. + +ENUM + BFD_RELOC_MIPS16_JMP +ENUMDOC + The MIPS16 jump instruction. + +ENUM + BFD_RELOC_MIPS16_GPREL +ENUMDOC + MIPS16 GP relative reloc. + +ENUM + BFD_RELOC_HI16 +ENUMDOC + High 16 bits of 32-bit value; simple reloc. +ENUM + BFD_RELOC_HI16_S +ENUMDOC + High 16 bits of 32-bit value but the low 16 bits will be sign + extended and added to form the final result. If the low 16 + bits form a negative number, we need to add one to the high value + to compensate for the borrow when the low bits are added. +ENUM + BFD_RELOC_LO16 +ENUMDOC + Low 16 bits. +ENUM + BFD_RELOC_PCREL_HI16_S +ENUMDOC + Like BFD_RELOC_HI16_S, but PC relative. +ENUM + BFD_RELOC_PCREL_LO16 +ENUMDOC + Like BFD_RELOC_LO16, but PC relative. + +ENUM + BFD_RELOC_MIPS_LITERAL +ENUMDOC + Relocation against a MIPS literal section. + +ENUM + BFD_RELOC_MIPS_GOT16 +ENUMX + BFD_RELOC_MIPS_CALL16 +ENUMX + BFD_RELOC_MIPS_GOT_HI16 +ENUMX + BFD_RELOC_MIPS_GOT_LO16 +ENUMX + BFD_RELOC_MIPS_CALL_HI16 +ENUMX + BFD_RELOC_MIPS_CALL_LO16 +ENUMX + BFD_RELOC_MIPS_SUB +ENUMX + BFD_RELOC_MIPS_GOT_PAGE +ENUMX + BFD_RELOC_MIPS_GOT_OFST +ENUMX + BFD_RELOC_MIPS_GOT_DISP +ENUMX + BFD_RELOC_MIPS_SHIFT5 +ENUMX + BFD_RELOC_MIPS_SHIFT6 +ENUMX + BFD_RELOC_MIPS_INSERT_A +ENUMX + BFD_RELOC_MIPS_INSERT_B +ENUMX + BFD_RELOC_MIPS_DELETE +ENUMX + BFD_RELOC_MIPS_HIGHEST +ENUMX + BFD_RELOC_MIPS_HIGHER +ENUMX + BFD_RELOC_MIPS_SCN_DISP +ENUMX + BFD_RELOC_MIPS_REL16 +ENUMX + BFD_RELOC_MIPS_RELGOT +ENUMX + BFD_RELOC_MIPS_JALR +COMMENT +ENUM + BFD_RELOC_FRV_LABEL16 +ENUMX + BFD_RELOC_FRV_LABEL24 +ENUMX + BFD_RELOC_FRV_LO16 +ENUMX + BFD_RELOC_FRV_HI16 +ENUMX + BFD_RELOC_FRV_GPREL12 +ENUMX + BFD_RELOC_FRV_GPRELU12 +ENUMX + BFD_RELOC_FRV_GPREL32 +ENUMX + BFD_RELOC_FRV_GPRELHI +ENUMX + BFD_RELOC_FRV_GPRELLO +ENUMDOC + Fujitsu Frv Relocations. +COMMENT +COMMENT +ENUMDOC + MIPS ELF relocations. + +COMMENT + +ENUM + BFD_RELOC_386_GOT32 +ENUMX + BFD_RELOC_386_PLT32 +ENUMX + BFD_RELOC_386_COPY +ENUMX + BFD_RELOC_386_GLOB_DAT +ENUMX + BFD_RELOC_386_JUMP_SLOT +ENUMX + BFD_RELOC_386_RELATIVE +ENUMX + BFD_RELOC_386_GOTOFF +ENUMX + BFD_RELOC_386_GOTPC +ENUMX + BFD_RELOC_386_TLS_TPOFF +ENUMX + BFD_RELOC_386_TLS_IE +ENUMX + BFD_RELOC_386_TLS_GOTIE +ENUMX + BFD_RELOC_386_TLS_LE +ENUMX + BFD_RELOC_386_TLS_GD +ENUMX + BFD_RELOC_386_TLS_LDM +ENUMX + BFD_RELOC_386_TLS_LDO_32 +ENUMX + BFD_RELOC_386_TLS_IE_32 +ENUMX + BFD_RELOC_386_TLS_LE_32 +ENUMX + BFD_RELOC_386_TLS_DTPMOD32 +ENUMX + BFD_RELOC_386_TLS_DTPOFF32 +ENUMX + BFD_RELOC_386_TLS_TPOFF32 +ENUMDOC + i386/elf relocations + +ENUM + BFD_RELOC_X86_64_GOT32 +ENUMX + BFD_RELOC_X86_64_PLT32 +ENUMX + BFD_RELOC_X86_64_COPY +ENUMX + BFD_RELOC_X86_64_GLOB_DAT +ENUMX + BFD_RELOC_X86_64_JUMP_SLOT +ENUMX + BFD_RELOC_X86_64_RELATIVE +ENUMX + BFD_RELOC_X86_64_GOTPCREL +ENUMX + BFD_RELOC_X86_64_32S +ENUMX + BFD_RELOC_X86_64_DTPMOD64 +ENUMX + BFD_RELOC_X86_64_DTPOFF64 +ENUMX + BFD_RELOC_X86_64_TPOFF64 +ENUMX + BFD_RELOC_X86_64_TLSGD +ENUMX + BFD_RELOC_X86_64_TLSLD +ENUMX + BFD_RELOC_X86_64_DTPOFF32 +ENUMX + BFD_RELOC_X86_64_GOTTPOFF +ENUMX + BFD_RELOC_X86_64_TPOFF32 +ENUMDOC + x86-64/elf relocations + +ENUM + BFD_RELOC_NS32K_IMM_8 +ENUMX + BFD_RELOC_NS32K_IMM_16 +ENUMX + BFD_RELOC_NS32K_IMM_32 +ENUMX + BFD_RELOC_NS32K_IMM_8_PCREL +ENUMX + BFD_RELOC_NS32K_IMM_16_PCREL +ENUMX + BFD_RELOC_NS32K_IMM_32_PCREL +ENUMX + BFD_RELOC_NS32K_DISP_8 +ENUMX + BFD_RELOC_NS32K_DISP_16 +ENUMX + BFD_RELOC_NS32K_DISP_32 +ENUMX + BFD_RELOC_NS32K_DISP_8_PCREL +ENUMX + BFD_RELOC_NS32K_DISP_16_PCREL +ENUMX + BFD_RELOC_NS32K_DISP_32_PCREL +ENUMDOC + ns32k relocations + +ENUM + BFD_RELOC_PDP11_DISP_8_PCREL +ENUMX + BFD_RELOC_PDP11_DISP_6_PCREL +ENUMDOC + PDP11 relocations + +ENUM + BFD_RELOC_PJ_CODE_HI16 +ENUMX + BFD_RELOC_PJ_CODE_LO16 +ENUMX + BFD_RELOC_PJ_CODE_DIR16 +ENUMX + BFD_RELOC_PJ_CODE_DIR32 +ENUMX + BFD_RELOC_PJ_CODE_REL16 +ENUMX + BFD_RELOC_PJ_CODE_REL32 +ENUMDOC + Picojava relocs. Not all of these appear in object files. + +ENUM + BFD_RELOC_PPC_B26 +ENUMX + BFD_RELOC_PPC_BA26 +ENUMX + BFD_RELOC_PPC_TOC16 +ENUMX + BFD_RELOC_PPC_B16 +ENUMX + BFD_RELOC_PPC_B16_BRTAKEN +ENUMX + BFD_RELOC_PPC_B16_BRNTAKEN +ENUMX + BFD_RELOC_PPC_BA16 +ENUMX + BFD_RELOC_PPC_BA16_BRTAKEN +ENUMX + BFD_RELOC_PPC_BA16_BRNTAKEN +ENUMX + BFD_RELOC_PPC_COPY +ENUMX + BFD_RELOC_PPC_GLOB_DAT +ENUMX + BFD_RELOC_PPC_JMP_SLOT +ENUMX + BFD_RELOC_PPC_RELATIVE +ENUMX + BFD_RELOC_PPC_LOCAL24PC +ENUMX + BFD_RELOC_PPC_EMB_NADDR32 +ENUMX + BFD_RELOC_PPC_EMB_NADDR16 +ENUMX + BFD_RELOC_PPC_EMB_NADDR16_LO +ENUMX + BFD_RELOC_PPC_EMB_NADDR16_HI +ENUMX + BFD_RELOC_PPC_EMB_NADDR16_HA +ENUMX + BFD_RELOC_PPC_EMB_SDAI16 +ENUMX + BFD_RELOC_PPC_EMB_SDA2I16 +ENUMX + BFD_RELOC_PPC_EMB_SDA2REL +ENUMX + BFD_RELOC_PPC_EMB_SDA21 +ENUMX + BFD_RELOC_PPC_EMB_MRKREF +ENUMX + BFD_RELOC_PPC_EMB_RELSEC16 +ENUMX + BFD_RELOC_PPC_EMB_RELST_LO +ENUMX + BFD_RELOC_PPC_EMB_RELST_HI +ENUMX + BFD_RELOC_PPC_EMB_RELST_HA +ENUMX + BFD_RELOC_PPC_EMB_BIT_FLD +ENUMX + BFD_RELOC_PPC_EMB_RELSDA +ENUMX + BFD_RELOC_PPC64_HIGHER +ENUMX + BFD_RELOC_PPC64_HIGHER_S +ENUMX + BFD_RELOC_PPC64_HIGHEST +ENUMX + BFD_RELOC_PPC64_HIGHEST_S +ENUMX + BFD_RELOC_PPC64_TOC16_LO +ENUMX + BFD_RELOC_PPC64_TOC16_HI +ENUMX + BFD_RELOC_PPC64_TOC16_HA +ENUMX + BFD_RELOC_PPC64_TOC +ENUMX + BFD_RELOC_PPC64_PLTGOT16 +ENUMX + BFD_RELOC_PPC64_PLTGOT16_LO +ENUMX + BFD_RELOC_PPC64_PLTGOT16_HI +ENUMX + BFD_RELOC_PPC64_PLTGOT16_HA +ENUMX + BFD_RELOC_PPC64_ADDR16_DS +ENUMX + BFD_RELOC_PPC64_ADDR16_LO_DS +ENUMX + BFD_RELOC_PPC64_GOT16_DS +ENUMX + BFD_RELOC_PPC64_GOT16_LO_DS +ENUMX + BFD_RELOC_PPC64_PLT16_LO_DS +ENUMX + BFD_RELOC_PPC64_SECTOFF_DS +ENUMX + BFD_RELOC_PPC64_SECTOFF_LO_DS +ENUMX + BFD_RELOC_PPC64_TOC16_DS +ENUMX + BFD_RELOC_PPC64_TOC16_LO_DS +ENUMX + BFD_RELOC_PPC64_PLTGOT16_DS +ENUMX + BFD_RELOC_PPC64_PLTGOT16_LO_DS +ENUMDOC + Power(rs6000) and PowerPC relocations. + +ENUM + BFD_RELOC_PPC_TLS +ENUMX + BFD_RELOC_PPC_DTPMOD +ENUMX + BFD_RELOC_PPC_TPREL16 +ENUMX + BFD_RELOC_PPC_TPREL16_LO +ENUMX + BFD_RELOC_PPC_TPREL16_HI +ENUMX + BFD_RELOC_PPC_TPREL16_HA +ENUMX + BFD_RELOC_PPC_TPREL +ENUMX + BFD_RELOC_PPC_DTPREL16 +ENUMX + BFD_RELOC_PPC_DTPREL16_LO +ENUMX + BFD_RELOC_PPC_DTPREL16_HI +ENUMX + BFD_RELOC_PPC_DTPREL16_HA +ENUMX + BFD_RELOC_PPC_DTPREL +ENUMX + BFD_RELOC_PPC_GOT_TLSGD16 +ENUMX + BFD_RELOC_PPC_GOT_TLSGD16_LO +ENUMX + BFD_RELOC_PPC_GOT_TLSGD16_HI +ENUMX + BFD_RELOC_PPC_GOT_TLSGD16_HA +ENUMX + BFD_RELOC_PPC_GOT_TLSLD16 +ENUMX + BFD_RELOC_PPC_GOT_TLSLD16_LO +ENUMX + BFD_RELOC_PPC_GOT_TLSLD16_HI +ENUMX + BFD_RELOC_PPC_GOT_TLSLD16_HA +ENUMX + BFD_RELOC_PPC_GOT_TPREL16 +ENUMX + BFD_RELOC_PPC_GOT_TPREL16_LO +ENUMX + BFD_RELOC_PPC_GOT_TPREL16_HI +ENUMX + BFD_RELOC_PPC_GOT_TPREL16_HA +ENUMX + BFD_RELOC_PPC_GOT_DTPREL16 +ENUMX + BFD_RELOC_PPC_GOT_DTPREL16_LO +ENUMX + BFD_RELOC_PPC_GOT_DTPREL16_HI +ENUMX + BFD_RELOC_PPC_GOT_DTPREL16_HA +ENUMX + BFD_RELOC_PPC64_TPREL16_DS +ENUMX + BFD_RELOC_PPC64_TPREL16_LO_DS +ENUMX + BFD_RELOC_PPC64_TPREL16_HIGHER +ENUMX + BFD_RELOC_PPC64_TPREL16_HIGHERA +ENUMX + BFD_RELOC_PPC64_TPREL16_HIGHEST +ENUMX + BFD_RELOC_PPC64_TPREL16_HIGHESTA +ENUMX + BFD_RELOC_PPC64_DTPREL16_DS +ENUMX + BFD_RELOC_PPC64_DTPREL16_LO_DS +ENUMX + BFD_RELOC_PPC64_DTPREL16_HIGHER +ENUMX + BFD_RELOC_PPC64_DTPREL16_HIGHERA +ENUMX + BFD_RELOC_PPC64_DTPREL16_HIGHEST +ENUMX + BFD_RELOC_PPC64_DTPREL16_HIGHESTA +ENUMDOC + PowerPC and PowerPC64 thread-local storage relocations. + +ENUM + BFD_RELOC_I370_D12 +ENUMDOC + IBM 370/390 relocations + +ENUM + BFD_RELOC_CTOR +ENUMDOC + The type of reloc used to build a contructor table - at the moment + probably a 32 bit wide absolute relocation, but the target can choose. + It generally does map to one of the other relocation types. + +ENUM + BFD_RELOC_ARM_PCREL_BRANCH +ENUMDOC + ARM 26 bit pc-relative branch. The lowest two bits must be zero and are + not stored in the instruction. +ENUM + BFD_RELOC_ARM_PCREL_BLX +ENUMDOC + ARM 26 bit pc-relative branch. The lowest bit must be zero and is + not stored in the instruction. The 2nd lowest bit comes from a 1 bit + field in the instruction. +ENUM + BFD_RELOC_THUMB_PCREL_BLX +ENUMDOC + Thumb 22 bit pc-relative branch. The lowest bit must be zero and is + not stored in the instruction. The 2nd lowest bit comes from a 1 bit + field in the instruction. +ENUM + BFD_RELOC_ARM_IMMEDIATE +ENUMX + BFD_RELOC_ARM_ADRL_IMMEDIATE +ENUMX + BFD_RELOC_ARM_OFFSET_IMM +ENUMX + BFD_RELOC_ARM_SHIFT_IMM +ENUMX + BFD_RELOC_ARM_SWI +ENUMX + BFD_RELOC_ARM_MULTI +ENUMX + BFD_RELOC_ARM_CP_OFF_IMM +ENUMX + BFD_RELOC_ARM_CP_OFF_IMM_S2 +ENUMX + BFD_RELOC_ARM_ADR_IMM +ENUMX + BFD_RELOC_ARM_LDR_IMM +ENUMX + BFD_RELOC_ARM_LITERAL +ENUMX + BFD_RELOC_ARM_IN_POOL +ENUMX + BFD_RELOC_ARM_OFFSET_IMM8 +ENUMX + BFD_RELOC_ARM_HWLITERAL +ENUMX + BFD_RELOC_ARM_THUMB_ADD +ENUMX + BFD_RELOC_ARM_THUMB_IMM +ENUMX + BFD_RELOC_ARM_THUMB_SHIFT +ENUMX + BFD_RELOC_ARM_THUMB_OFFSET +ENUMX + BFD_RELOC_ARM_GOT12 +ENUMX + BFD_RELOC_ARM_GOT32 +ENUMX + BFD_RELOC_ARM_JUMP_SLOT +ENUMX + BFD_RELOC_ARM_COPY +ENUMX + BFD_RELOC_ARM_GLOB_DAT +ENUMX + BFD_RELOC_ARM_PLT32 +ENUMX + BFD_RELOC_ARM_RELATIVE +ENUMX + BFD_RELOC_ARM_GOTOFF +ENUMX + BFD_RELOC_ARM_GOTPC +ENUMDOC + These relocs are only used within the ARM assembler. They are not + (at present) written to any object files. + +ENUM + BFD_RELOC_SH_PCDISP8BY2 +ENUMX + BFD_RELOC_SH_PCDISP12BY2 +ENUMX + BFD_RELOC_SH_IMM4 +ENUMX + BFD_RELOC_SH_IMM4BY2 +ENUMX + BFD_RELOC_SH_IMM4BY4 +ENUMX + BFD_RELOC_SH_IMM8 +ENUMX + BFD_RELOC_SH_IMM8BY2 +ENUMX + BFD_RELOC_SH_IMM8BY4 +ENUMX + BFD_RELOC_SH_PCRELIMM8BY2 +ENUMX + BFD_RELOC_SH_PCRELIMM8BY4 +ENUMX + BFD_RELOC_SH_SWITCH16 +ENUMX + BFD_RELOC_SH_SWITCH32 +ENUMX + BFD_RELOC_SH_USES +ENUMX + BFD_RELOC_SH_COUNT +ENUMX + BFD_RELOC_SH_ALIGN +ENUMX + BFD_RELOC_SH_CODE +ENUMX + BFD_RELOC_SH_DATA +ENUMX + BFD_RELOC_SH_LABEL +ENUMX + BFD_RELOC_SH_LOOP_START +ENUMX + BFD_RELOC_SH_LOOP_END +ENUMX + BFD_RELOC_SH_COPY +ENUMX + BFD_RELOC_SH_GLOB_DAT +ENUMX + BFD_RELOC_SH_JMP_SLOT +ENUMX + BFD_RELOC_SH_RELATIVE +ENUMX + BFD_RELOC_SH_GOTPC +ENUMX + BFD_RELOC_SH_GOT_LOW16 +ENUMX + BFD_RELOC_SH_GOT_MEDLOW16 +ENUMX + BFD_RELOC_SH_GOT_MEDHI16 +ENUMX + BFD_RELOC_SH_GOT_HI16 +ENUMX + BFD_RELOC_SH_GOTPLT_LOW16 +ENUMX + BFD_RELOC_SH_GOTPLT_MEDLOW16 +ENUMX + BFD_RELOC_SH_GOTPLT_MEDHI16 +ENUMX + BFD_RELOC_SH_GOTPLT_HI16 +ENUMX + BFD_RELOC_SH_PLT_LOW16 +ENUMX + BFD_RELOC_SH_PLT_MEDLOW16 +ENUMX + BFD_RELOC_SH_PLT_MEDHI16 +ENUMX + BFD_RELOC_SH_PLT_HI16 +ENUMX + BFD_RELOC_SH_GOTOFF_LOW16 +ENUMX + BFD_RELOC_SH_GOTOFF_MEDLOW16 +ENUMX + BFD_RELOC_SH_GOTOFF_MEDHI16 +ENUMX + BFD_RELOC_SH_GOTOFF_HI16 +ENUMX + BFD_RELOC_SH_GOTPC_LOW16 +ENUMX + BFD_RELOC_SH_GOTPC_MEDLOW16 +ENUMX + BFD_RELOC_SH_GOTPC_MEDHI16 +ENUMX + BFD_RELOC_SH_GOTPC_HI16 +ENUMX + BFD_RELOC_SH_COPY64 +ENUMX + BFD_RELOC_SH_GLOB_DAT64 +ENUMX + BFD_RELOC_SH_JMP_SLOT64 +ENUMX + BFD_RELOC_SH_RELATIVE64 +ENUMX + BFD_RELOC_SH_GOT10BY4 +ENUMX + BFD_RELOC_SH_GOT10BY8 +ENUMX + BFD_RELOC_SH_GOTPLT10BY4 +ENUMX + BFD_RELOC_SH_GOTPLT10BY8 +ENUMX + BFD_RELOC_SH_GOTPLT32 +ENUMX + BFD_RELOC_SH_SHMEDIA_CODE +ENUMX + BFD_RELOC_SH_IMMU5 +ENUMX + BFD_RELOC_SH_IMMS6 +ENUMX + BFD_RELOC_SH_IMMS6BY32 +ENUMX + BFD_RELOC_SH_IMMU6 +ENUMX + BFD_RELOC_SH_IMMS10 +ENUMX + BFD_RELOC_SH_IMMS10BY2 +ENUMX + BFD_RELOC_SH_IMMS10BY4 +ENUMX + BFD_RELOC_SH_IMMS10BY8 +ENUMX + BFD_RELOC_SH_IMMS16 +ENUMX + BFD_RELOC_SH_IMMU16 +ENUMX + BFD_RELOC_SH_IMM_LOW16 +ENUMX + BFD_RELOC_SH_IMM_LOW16_PCREL +ENUMX + BFD_RELOC_SH_IMM_MEDLOW16 +ENUMX + BFD_RELOC_SH_IMM_MEDLOW16_PCREL +ENUMX + BFD_RELOC_SH_IMM_MEDHI16 +ENUMX + BFD_RELOC_SH_IMM_MEDHI16_PCREL +ENUMX + BFD_RELOC_SH_IMM_HI16 +ENUMX + BFD_RELOC_SH_IMM_HI16_PCREL +ENUMX + BFD_RELOC_SH_PT_16 +ENUMX + BFD_RELOC_SH_TLS_GD_32 +ENUMX + BFD_RELOC_SH_TLS_LD_32 +ENUMX + BFD_RELOC_SH_TLS_LDO_32 +ENUMX + BFD_RELOC_SH_TLS_IE_32 +ENUMX + BFD_RELOC_SH_TLS_LE_32 +ENUMX + BFD_RELOC_SH_TLS_DTPMOD32 +ENUMX + BFD_RELOC_SH_TLS_DTPOFF32 +ENUMX + BFD_RELOC_SH_TLS_TPOFF32 +ENUMDOC + Renesas / SuperH SH relocs. Not all of these appear in object files. + +ENUM + BFD_RELOC_THUMB_PCREL_BRANCH9 +ENUMX + BFD_RELOC_THUMB_PCREL_BRANCH12 +ENUMX + BFD_RELOC_THUMB_PCREL_BRANCH23 +ENUMDOC + Thumb 23-, 12- and 9-bit pc-relative branches. The lowest bit must + be zero and is not stored in the instruction. + +ENUM + BFD_RELOC_ARC_B22_PCREL +ENUMDOC + ARC Cores relocs. + ARC 22 bit pc-relative branch. The lowest two bits must be zero and are + not stored in the instruction. The high 20 bits are installed in bits 26 + through 7 of the instruction. +ENUM + BFD_RELOC_ARC_B26 +ENUMDOC + ARC 26 bit absolute branch. The lowest two bits must be zero and are not + stored in the instruction. The high 24 bits are installed in bits 23 + through 0. + +ENUM + BFD_RELOC_D10V_10_PCREL_R +ENUMDOC + Mitsubishi D10V relocs. + This is a 10-bit reloc with the right 2 bits + assumed to be 0. +ENUM + BFD_RELOC_D10V_10_PCREL_L +ENUMDOC + Mitsubishi D10V relocs. + This is a 10-bit reloc with the right 2 bits + assumed to be 0. This is the same as the previous reloc + except it is in the left container, i.e., + shifted left 15 bits. +ENUM + BFD_RELOC_D10V_18 +ENUMDOC + This is an 18-bit reloc with the right 2 bits + assumed to be 0. +ENUM + BFD_RELOC_D10V_18_PCREL +ENUMDOC + This is an 18-bit reloc with the right 2 bits + assumed to be 0. + +ENUM + BFD_RELOC_D30V_6 +ENUMDOC + Mitsubishi D30V relocs. + This is a 6-bit absolute reloc. +ENUM + BFD_RELOC_D30V_9_PCREL +ENUMDOC + This is a 6-bit pc-relative reloc with + the right 3 bits assumed to be 0. +ENUM + BFD_RELOC_D30V_9_PCREL_R +ENUMDOC + This is a 6-bit pc-relative reloc with + the right 3 bits assumed to be 0. Same + as the previous reloc but on the right side + of the container. +ENUM + BFD_RELOC_D30V_15 +ENUMDOC + This is a 12-bit absolute reloc with the + right 3 bitsassumed to be 0. +ENUM + BFD_RELOC_D30V_15_PCREL +ENUMDOC + This is a 12-bit pc-relative reloc with + the right 3 bits assumed to be 0. +ENUM + BFD_RELOC_D30V_15_PCREL_R +ENUMDOC + This is a 12-bit pc-relative reloc with + the right 3 bits assumed to be 0. Same + as the previous reloc but on the right side + of the container. +ENUM + BFD_RELOC_D30V_21 +ENUMDOC + This is an 18-bit absolute reloc with + the right 3 bits assumed to be 0. +ENUM + BFD_RELOC_D30V_21_PCREL +ENUMDOC + This is an 18-bit pc-relative reloc with + the right 3 bits assumed to be 0. +ENUM + BFD_RELOC_D30V_21_PCREL_R +ENUMDOC + This is an 18-bit pc-relative reloc with + the right 3 bits assumed to be 0. Same + as the previous reloc but on the right side + of the container. +ENUM + BFD_RELOC_D30V_32 +ENUMDOC + This is a 32-bit absolute reloc. +ENUM + BFD_RELOC_D30V_32_PCREL +ENUMDOC + This is a 32-bit pc-relative reloc. + +ENUM + BFD_RELOC_DLX_HI16_S +ENUMDOC + DLX relocs +ENUM + BFD_RELOC_DLX_LO16 +ENUMDOC + DLX relocs +ENUM + BFD_RELOC_DLX_JMP26 +ENUMDOC + DLX relocs + +ENUM + BFD_RELOC_M32R_24 +ENUMDOC + Renesas M32R (formerly Mitsubishi M32R) relocs. + This is a 24 bit absolute address. +ENUM + BFD_RELOC_M32R_10_PCREL +ENUMDOC + This is a 10-bit pc-relative reloc with the right 2 bits assumed to be 0. +ENUM + BFD_RELOC_M32R_18_PCREL +ENUMDOC + This is an 18-bit reloc with the right 2 bits assumed to be 0. +ENUM + BFD_RELOC_M32R_26_PCREL +ENUMDOC + This is a 26-bit reloc with the right 2 bits assumed to be 0. +ENUM + BFD_RELOC_M32R_HI16_ULO +ENUMDOC + This is a 16-bit reloc containing the high 16 bits of an address + used when the lower 16 bits are treated as unsigned. +ENUM + BFD_RELOC_M32R_HI16_SLO +ENUMDOC + This is a 16-bit reloc containing the high 16 bits of an address + used when the lower 16 bits are treated as signed. +ENUM + BFD_RELOC_M32R_LO16 +ENUMDOC + This is a 16-bit reloc containing the lower 16 bits of an address. +ENUM + BFD_RELOC_M32R_SDA16 +ENUMDOC + This is a 16-bit reloc containing the small data area offset for use in + add3, load, and store instructions. + +ENUM + BFD_RELOC_V850_9_PCREL +ENUMDOC + This is a 9-bit reloc +ENUM + BFD_RELOC_V850_22_PCREL +ENUMDOC + This is a 22-bit reloc + +ENUM + BFD_RELOC_V850_SDA_16_16_OFFSET +ENUMDOC + This is a 16 bit offset from the short data area pointer. +ENUM + BFD_RELOC_V850_SDA_15_16_OFFSET +ENUMDOC + This is a 16 bit offset (of which only 15 bits are used) from the + short data area pointer. +ENUM + BFD_RELOC_V850_ZDA_16_16_OFFSET +ENUMDOC + This is a 16 bit offset from the zero data area pointer. +ENUM + BFD_RELOC_V850_ZDA_15_16_OFFSET +ENUMDOC + This is a 16 bit offset (of which only 15 bits are used) from the + zero data area pointer. +ENUM + BFD_RELOC_V850_TDA_6_8_OFFSET +ENUMDOC + This is an 8 bit offset (of which only 6 bits are used) from the + tiny data area pointer. +ENUM + BFD_RELOC_V850_TDA_7_8_OFFSET +ENUMDOC + This is an 8bit offset (of which only 7 bits are used) from the tiny + data area pointer. +ENUM + BFD_RELOC_V850_TDA_7_7_OFFSET +ENUMDOC + This is a 7 bit offset from the tiny data area pointer. +ENUM + BFD_RELOC_V850_TDA_16_16_OFFSET +ENUMDOC + This is a 16 bit offset from the tiny data area pointer. +COMMENT +ENUM + BFD_RELOC_V850_TDA_4_5_OFFSET +ENUMDOC + This is a 5 bit offset (of which only 4 bits are used) from the tiny + data area pointer. +ENUM + BFD_RELOC_V850_TDA_4_4_OFFSET +ENUMDOC + This is a 4 bit offset from the tiny data area pointer. +ENUM + BFD_RELOC_V850_SDA_16_16_SPLIT_OFFSET +ENUMDOC + This is a 16 bit offset from the short data area pointer, with the + bits placed non-contigously in the instruction. +ENUM + BFD_RELOC_V850_ZDA_16_16_SPLIT_OFFSET +ENUMDOC + This is a 16 bit offset from the zero data area pointer, with the + bits placed non-contigously in the instruction. +ENUM + BFD_RELOC_V850_CALLT_6_7_OFFSET +ENUMDOC + This is a 6 bit offset from the call table base pointer. +ENUM + BFD_RELOC_V850_CALLT_16_16_OFFSET +ENUMDOC + This is a 16 bit offset from the call table base pointer. +ENUM + BFD_RELOC_V850_LONGCALL +ENUMDOC + Used for relaxing indirect function calls. +ENUM + BFD_RELOC_V850_LONGJUMP +ENUMDOC + Used for relaxing indirect jumps. +ENUM + BFD_RELOC_V850_ALIGN +ENUMDOC + Used to maintain alignment whilst relaxing. +ENUM + BFD_RELOC_MN10300_32_PCREL +ENUMDOC + This is a 32bit pcrel reloc for the mn10300, offset by two bytes in the + instruction. +ENUM + BFD_RELOC_MN10300_16_PCREL +ENUMDOC + This is a 16bit pcrel reloc for the mn10300, offset by two bytes in the + instruction. + +ENUM + BFD_RELOC_TIC30_LDP +ENUMDOC + This is a 8bit DP reloc for the tms320c30, where the most + significant 8 bits of a 24 bit word are placed into the least + significant 8 bits of the opcode. + +ENUM + BFD_RELOC_TIC54X_PARTLS7 +ENUMDOC + This is a 7bit reloc for the tms320c54x, where the least + significant 7 bits of a 16 bit word are placed into the least + significant 7 bits of the opcode. + +ENUM + BFD_RELOC_TIC54X_PARTMS9 +ENUMDOC + This is a 9bit DP reloc for the tms320c54x, where the most + significant 9 bits of a 16 bit word are placed into the least + significant 9 bits of the opcode. + +ENUM + BFD_RELOC_TIC54X_23 +ENUMDOC + This is an extended address 23-bit reloc for the tms320c54x. + +ENUM + BFD_RELOC_TIC54X_16_OF_23 +ENUMDOC + This is a 16-bit reloc for the tms320c54x, where the least + significant 16 bits of a 23-bit extended address are placed into + the opcode. + +ENUM + BFD_RELOC_TIC54X_MS7_OF_23 +ENUMDOC + This is a reloc for the tms320c54x, where the most + significant 7 bits of a 23-bit extended address are placed into + the opcode. + +ENUM + BFD_RELOC_FR30_48 +ENUMDOC + This is a 48 bit reloc for the FR30 that stores 32 bits. +ENUM + BFD_RELOC_FR30_20 +ENUMDOC + This is a 32 bit reloc for the FR30 that stores 20 bits split up into + two sections. +ENUM + BFD_RELOC_FR30_6_IN_4 +ENUMDOC + This is a 16 bit reloc for the FR30 that stores a 6 bit word offset in + 4 bits. +ENUM + BFD_RELOC_FR30_8_IN_8 +ENUMDOC + This is a 16 bit reloc for the FR30 that stores an 8 bit byte offset + into 8 bits. +ENUM + BFD_RELOC_FR30_9_IN_8 +ENUMDOC + This is a 16 bit reloc for the FR30 that stores a 9 bit short offset + into 8 bits. +ENUM + BFD_RELOC_FR30_10_IN_8 +ENUMDOC + This is a 16 bit reloc for the FR30 that stores a 10 bit word offset + into 8 bits. +ENUM + BFD_RELOC_FR30_9_PCREL +ENUMDOC + This is a 16 bit reloc for the FR30 that stores a 9 bit pc relative + short offset into 8 bits. +ENUM + BFD_RELOC_FR30_12_PCREL +ENUMDOC + This is a 16 bit reloc for the FR30 that stores a 12 bit pc relative + short offset into 11 bits. + +ENUM + BFD_RELOC_MCORE_PCREL_IMM8BY4 +ENUMX + BFD_RELOC_MCORE_PCREL_IMM11BY2 +ENUMX + BFD_RELOC_MCORE_PCREL_IMM4BY2 +ENUMX + BFD_RELOC_MCORE_PCREL_32 +ENUMX + BFD_RELOC_MCORE_PCREL_JSR_IMM11BY2 +ENUMX + BFD_RELOC_MCORE_RVA +ENUMDOC + Motorola Mcore relocations. + +ENUM + BFD_RELOC_MMIX_GETA +ENUMX + BFD_RELOC_MMIX_GETA_1 +ENUMX + BFD_RELOC_MMIX_GETA_2 +ENUMX + BFD_RELOC_MMIX_GETA_3 +ENUMDOC + These are relocations for the GETA instruction. +ENUM + BFD_RELOC_MMIX_CBRANCH +ENUMX + BFD_RELOC_MMIX_CBRANCH_J +ENUMX + BFD_RELOC_MMIX_CBRANCH_1 +ENUMX + BFD_RELOC_MMIX_CBRANCH_2 +ENUMX + BFD_RELOC_MMIX_CBRANCH_3 +ENUMDOC + These are relocations for a conditional branch instruction. +ENUM + BFD_RELOC_MMIX_PUSHJ +ENUMX + BFD_RELOC_MMIX_PUSHJ_1 +ENUMX + BFD_RELOC_MMIX_PUSHJ_2 +ENUMX + BFD_RELOC_MMIX_PUSHJ_3 +ENUMDOC + These are relocations for the PUSHJ instruction. +ENUM + BFD_RELOC_MMIX_JMP +ENUMX + BFD_RELOC_MMIX_JMP_1 +ENUMX + BFD_RELOC_MMIX_JMP_2 +ENUMX + BFD_RELOC_MMIX_JMP_3 +ENUMDOC + These are relocations for the JMP instruction. +ENUM + BFD_RELOC_MMIX_ADDR19 +ENUMDOC + This is a relocation for a relative address as in a GETA instruction or + a branch. +ENUM + BFD_RELOC_MMIX_ADDR27 +ENUMDOC + This is a relocation for a relative address as in a JMP instruction. +ENUM + BFD_RELOC_MMIX_REG_OR_BYTE +ENUMDOC + This is a relocation for an instruction field that may be a general + register or a value 0..255. +ENUM + BFD_RELOC_MMIX_REG +ENUMDOC + This is a relocation for an instruction field that may be a general + register. +ENUM + BFD_RELOC_MMIX_BASE_PLUS_OFFSET +ENUMDOC + This is a relocation for two instruction fields holding a register and + an offset, the equivalent of the relocation. +ENUM + BFD_RELOC_MMIX_LOCAL +ENUMDOC + This relocation is an assertion that the expression is not allocated as + a global register. It does not modify contents. + +ENUM + BFD_RELOC_AVR_7_PCREL +ENUMDOC + This is a 16 bit reloc for the AVR that stores 8 bit pc relative + short offset into 7 bits. +ENUM + BFD_RELOC_AVR_13_PCREL +ENUMDOC + This is a 16 bit reloc for the AVR that stores 13 bit pc relative + short offset into 12 bits. +ENUM + BFD_RELOC_AVR_16_PM +ENUMDOC + This is a 16 bit reloc for the AVR that stores 17 bit value (usually + program memory address) into 16 bits. +ENUM + BFD_RELOC_AVR_LO8_LDI +ENUMDOC + This is a 16 bit reloc for the AVR that stores 8 bit value (usually + data memory address) into 8 bit immediate value of LDI insn. +ENUM + BFD_RELOC_AVR_HI8_LDI +ENUMDOC + This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit + of data memory address) into 8 bit immediate value of LDI insn. +ENUM + BFD_RELOC_AVR_HH8_LDI +ENUMDOC + This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit + of program memory address) into 8 bit immediate value of LDI insn. +ENUM + BFD_RELOC_AVR_LO8_LDI_NEG +ENUMDOC + This is a 16 bit reloc for the AVR that stores negated 8 bit value + (usually data memory address) into 8 bit immediate value of SUBI insn. +ENUM + BFD_RELOC_AVR_HI8_LDI_NEG +ENUMDOC + This is a 16 bit reloc for the AVR that stores negated 8 bit value + (high 8 bit of data memory address) into 8 bit immediate value of + SUBI insn. +ENUM + BFD_RELOC_AVR_HH8_LDI_NEG +ENUMDOC + This is a 16 bit reloc for the AVR that stores negated 8 bit value + (most high 8 bit of program memory address) into 8 bit immediate value + of LDI or SUBI insn. +ENUM + BFD_RELOC_AVR_LO8_LDI_PM +ENUMDOC + This is a 16 bit reloc for the AVR that stores 8 bit value (usually + command address) into 8 bit immediate value of LDI insn. +ENUM + BFD_RELOC_AVR_HI8_LDI_PM +ENUMDOC + This is a 16 bit reloc for the AVR that stores 8 bit value (high 8 bit + of command address) into 8 bit immediate value of LDI insn. +ENUM + BFD_RELOC_AVR_HH8_LDI_PM +ENUMDOC + This is a 16 bit reloc for the AVR that stores 8 bit value (most high 8 bit + of command address) into 8 bit immediate value of LDI insn. +ENUM + BFD_RELOC_AVR_LO8_LDI_PM_NEG +ENUMDOC + This is a 16 bit reloc for the AVR that stores negated 8 bit value + (usually command address) into 8 bit immediate value of SUBI insn. +ENUM + BFD_RELOC_AVR_HI8_LDI_PM_NEG +ENUMDOC + This is a 16 bit reloc for the AVR that stores negated 8 bit value + (high 8 bit of 16 bit command address) into 8 bit immediate value + of SUBI insn. +ENUM + BFD_RELOC_AVR_HH8_LDI_PM_NEG +ENUMDOC + This is a 16 bit reloc for the AVR that stores negated 8 bit value + (high 6 bit of 22 bit command address) into 8 bit immediate + value of SUBI insn. +ENUM + BFD_RELOC_AVR_CALL +ENUMDOC + This is a 32 bit reloc for the AVR that stores 23 bit value + into 22 bits. + +ENUM + BFD_RELOC_390_12 +ENUMDOC + Direct 12 bit. +ENUM + BFD_RELOC_390_GOT12 +ENUMDOC + 12 bit GOT offset. +ENUM + BFD_RELOC_390_PLT32 +ENUMDOC + 32 bit PC relative PLT address. +ENUM + BFD_RELOC_390_COPY +ENUMDOC + Copy symbol at runtime. +ENUM + BFD_RELOC_390_GLOB_DAT +ENUMDOC + Create GOT entry. +ENUM + BFD_RELOC_390_JMP_SLOT +ENUMDOC + Create PLT entry. +ENUM + BFD_RELOC_390_RELATIVE +ENUMDOC + Adjust by program base. +ENUM + BFD_RELOC_390_GOTPC +ENUMDOC + 32 bit PC relative offset to GOT. +ENUM + BFD_RELOC_390_GOT16 +ENUMDOC + 16 bit GOT offset. +ENUM + BFD_RELOC_390_PC16DBL +ENUMDOC + PC relative 16 bit shifted by 1. +ENUM + BFD_RELOC_390_PLT16DBL +ENUMDOC + 16 bit PC rel. PLT shifted by 1. +ENUM + BFD_RELOC_390_PC32DBL +ENUMDOC + PC relative 32 bit shifted by 1. +ENUM + BFD_RELOC_390_PLT32DBL +ENUMDOC + 32 bit PC rel. PLT shifted by 1. +ENUM + BFD_RELOC_390_GOTPCDBL +ENUMDOC + 32 bit PC rel. GOT shifted by 1. +ENUM + BFD_RELOC_390_GOT64 +ENUMDOC + 64 bit GOT offset. +ENUM + BFD_RELOC_390_PLT64 +ENUMDOC + 64 bit PC relative PLT address. +ENUM + BFD_RELOC_390_GOTENT +ENUMDOC + 32 bit rel. offset to GOT entry. +ENUM + BFD_RELOC_390_GOTOFF64 +ENUMDOC + 64 bit offset to GOT. +ENUM + BFD_RELOC_390_GOTPLT12 +ENUMDOC + 12-bit offset to symbol-entry within GOT, with PLT handling. +ENUM + BFD_RELOC_390_GOTPLT16 +ENUMDOC + 16-bit offset to symbol-entry within GOT, with PLT handling. +ENUM + BFD_RELOC_390_GOTPLT32 +ENUMDOC + 32-bit offset to symbol-entry within GOT, with PLT handling. +ENUM + BFD_RELOC_390_GOTPLT64 +ENUMDOC + 64-bit offset to symbol-entry within GOT, with PLT handling. +ENUM + BFD_RELOC_390_GOTPLTENT +ENUMDOC + 32-bit rel. offset to symbol-entry within GOT, with PLT handling. +ENUM + BFD_RELOC_390_PLTOFF16 +ENUMDOC + 16-bit rel. offset from the GOT to a PLT entry. +ENUM + BFD_RELOC_390_PLTOFF32 +ENUMDOC + 32-bit rel. offset from the GOT to a PLT entry. +ENUM + BFD_RELOC_390_PLTOFF64 +ENUMDOC + 64-bit rel. offset from the GOT to a PLT entry. + +ENUM + BFD_RELOC_390_TLS_LOAD +ENUMX + BFD_RELOC_390_TLS_GDCALL +ENUMX + BFD_RELOC_390_TLS_LDCALL +ENUMX + BFD_RELOC_390_TLS_GD32 +ENUMX + BFD_RELOC_390_TLS_GD64 +ENUMX + BFD_RELOC_390_TLS_GOTIE12 +ENUMX + BFD_RELOC_390_TLS_GOTIE32 +ENUMX + BFD_RELOC_390_TLS_GOTIE64 +ENUMX + BFD_RELOC_390_TLS_LDM32 +ENUMX + BFD_RELOC_390_TLS_LDM64 +ENUMX + BFD_RELOC_390_TLS_IE32 +ENUMX + BFD_RELOC_390_TLS_IE64 +ENUMX + BFD_RELOC_390_TLS_IEENT +ENUMX + BFD_RELOC_390_TLS_LE32 +ENUMX + BFD_RELOC_390_TLS_LE64 +ENUMX + BFD_RELOC_390_TLS_LDO32 +ENUMX + BFD_RELOC_390_TLS_LDO64 +ENUMX + BFD_RELOC_390_TLS_DTPMOD +ENUMX + BFD_RELOC_390_TLS_DTPOFF +ENUMX + BFD_RELOC_390_TLS_TPOFF +ENUMDOC + s390 tls relocations. + +ENUM + BFD_RELOC_IP2K_FR9 +ENUMDOC + Scenix IP2K - 9-bit register number / data address +ENUM + BFD_RELOC_IP2K_BANK +ENUMDOC + Scenix IP2K - 4-bit register/data bank number +ENUM + BFD_RELOC_IP2K_ADDR16CJP +ENUMDOC + Scenix IP2K - low 13 bits of instruction word address +ENUM + BFD_RELOC_IP2K_PAGE3 +ENUMDOC + Scenix IP2K - high 3 bits of instruction word address +ENUM + BFD_RELOC_IP2K_LO8DATA +ENUMX + BFD_RELOC_IP2K_HI8DATA +ENUMX + BFD_RELOC_IP2K_EX8DATA +ENUMDOC + Scenix IP2K - ext/low/high 8 bits of data address +ENUM + BFD_RELOC_IP2K_LO8INSN +ENUMX + BFD_RELOC_IP2K_HI8INSN +ENUMDOC + Scenix IP2K - low/high 8 bits of instruction word address +ENUM + BFD_RELOC_IP2K_PC_SKIP +ENUMDOC + Scenix IP2K - even/odd PC modifier to modify snb pcl.0 +ENUM + BFD_RELOC_IP2K_TEXT +ENUMDOC + Scenix IP2K - 16 bit word address in text section. +ENUM + BFD_RELOC_IP2K_FR_OFFSET +ENUMDOC + Scenix IP2K - 7-bit sp or dp offset +ENUM + BFD_RELOC_VPE4KMATH_DATA +ENUMX + BFD_RELOC_VPE4KMATH_INSN +ENUMDOC + Scenix VPE4K coprocessor - data/insn-space addressing + +ENUM + BFD_RELOC_VTABLE_INHERIT +ENUMX + BFD_RELOC_VTABLE_ENTRY +ENUMDOC + These two relocations are used by the linker to determine which of + the entries in a C++ virtual function table are actually used. When + the --gc-sections option is given, the linker will zero out the entries + that are not used, so that the code for those functions need not be + included in the output. + + VTABLE_INHERIT is a zero-space relocation used to describe to the + linker the inheritence tree of a C++ virtual function table. The + relocation's symbol should be the parent class' vtable, and the + relocation should be located at the child vtable. + + VTABLE_ENTRY is a zero-space relocation that describes the use of a + virtual function table entry. The reloc's symbol should refer to the + table of the class mentioned in the code. Off of that base, an offset + describes the entry that is being used. For Rela hosts, this offset + is stored in the reloc's addend. For Rel hosts, we are forced to put + this offset in the reloc's section offset. + +ENUM + BFD_RELOC_IA64_IMM14 +ENUMX + BFD_RELOC_IA64_IMM22 +ENUMX + BFD_RELOC_IA64_IMM64 +ENUMX + BFD_RELOC_IA64_DIR32MSB +ENUMX + BFD_RELOC_IA64_DIR32LSB +ENUMX + BFD_RELOC_IA64_DIR64MSB +ENUMX + BFD_RELOC_IA64_DIR64LSB +ENUMX + BFD_RELOC_IA64_GPREL22 +ENUMX + BFD_RELOC_IA64_GPREL64I +ENUMX + BFD_RELOC_IA64_GPREL32MSB +ENUMX + BFD_RELOC_IA64_GPREL32LSB +ENUMX + BFD_RELOC_IA64_GPREL64MSB +ENUMX + BFD_RELOC_IA64_GPREL64LSB +ENUMX + BFD_RELOC_IA64_LTOFF22 +ENUMX + BFD_RELOC_IA64_LTOFF64I +ENUMX + BFD_RELOC_IA64_PLTOFF22 +ENUMX + BFD_RELOC_IA64_PLTOFF64I +ENUMX + BFD_RELOC_IA64_PLTOFF64MSB +ENUMX + BFD_RELOC_IA64_PLTOFF64LSB +ENUMX + BFD_RELOC_IA64_FPTR64I +ENUMX + BFD_RELOC_IA64_FPTR32MSB +ENUMX + BFD_RELOC_IA64_FPTR32LSB +ENUMX + BFD_RELOC_IA64_FPTR64MSB +ENUMX + BFD_RELOC_IA64_FPTR64LSB +ENUMX + BFD_RELOC_IA64_PCREL21B +ENUMX + BFD_RELOC_IA64_PCREL21BI +ENUMX + BFD_RELOC_IA64_PCREL21M +ENUMX + BFD_RELOC_IA64_PCREL21F +ENUMX + BFD_RELOC_IA64_PCREL22 +ENUMX + BFD_RELOC_IA64_PCREL60B +ENUMX + BFD_RELOC_IA64_PCREL64I +ENUMX + BFD_RELOC_IA64_PCREL32MSB +ENUMX + BFD_RELOC_IA64_PCREL32LSB +ENUMX + BFD_RELOC_IA64_PCREL64MSB +ENUMX + BFD_RELOC_IA64_PCREL64LSB +ENUMX + BFD_RELOC_IA64_LTOFF_FPTR22 +ENUMX + BFD_RELOC_IA64_LTOFF_FPTR64I +ENUMX + BFD_RELOC_IA64_LTOFF_FPTR32MSB +ENUMX + BFD_RELOC_IA64_LTOFF_FPTR32LSB +ENUMX + BFD_RELOC_IA64_LTOFF_FPTR64MSB +ENUMX + BFD_RELOC_IA64_LTOFF_FPTR64LSB +ENUMX + BFD_RELOC_IA64_SEGREL32MSB +ENUMX + BFD_RELOC_IA64_SEGREL32LSB +ENUMX + BFD_RELOC_IA64_SEGREL64MSB +ENUMX + BFD_RELOC_IA64_SEGREL64LSB +ENUMX + BFD_RELOC_IA64_SECREL32MSB +ENUMX + BFD_RELOC_IA64_SECREL32LSB +ENUMX + BFD_RELOC_IA64_SECREL64MSB +ENUMX + BFD_RELOC_IA64_SECREL64LSB +ENUMX + BFD_RELOC_IA64_REL32MSB +ENUMX + BFD_RELOC_IA64_REL32LSB +ENUMX + BFD_RELOC_IA64_REL64MSB +ENUMX + BFD_RELOC_IA64_REL64LSB +ENUMX + BFD_RELOC_IA64_LTV32MSB +ENUMX + BFD_RELOC_IA64_LTV32LSB +ENUMX + BFD_RELOC_IA64_LTV64MSB +ENUMX + BFD_RELOC_IA64_LTV64LSB +ENUMX + BFD_RELOC_IA64_IPLTMSB +ENUMX + BFD_RELOC_IA64_IPLTLSB +ENUMX + BFD_RELOC_IA64_COPY +ENUMX + BFD_RELOC_IA64_LTOFF22X +ENUMX + BFD_RELOC_IA64_LDXMOV +ENUMX + BFD_RELOC_IA64_TPREL14 +ENUMX + BFD_RELOC_IA64_TPREL22 +ENUMX + BFD_RELOC_IA64_TPREL64I +ENUMX + BFD_RELOC_IA64_TPREL64MSB +ENUMX + BFD_RELOC_IA64_TPREL64LSB +ENUMX + BFD_RELOC_IA64_LTOFF_TPREL22 +ENUMX + BFD_RELOC_IA64_DTPMOD64MSB +ENUMX + BFD_RELOC_IA64_DTPMOD64LSB +ENUMX + BFD_RELOC_IA64_LTOFF_DTPMOD22 +ENUMX + BFD_RELOC_IA64_DTPREL14 +ENUMX + BFD_RELOC_IA64_DTPREL22 +ENUMX + BFD_RELOC_IA64_DTPREL64I +ENUMX + BFD_RELOC_IA64_DTPREL32MSB +ENUMX + BFD_RELOC_IA64_DTPREL32LSB +ENUMX + BFD_RELOC_IA64_DTPREL64MSB +ENUMX + BFD_RELOC_IA64_DTPREL64LSB +ENUMX + BFD_RELOC_IA64_LTOFF_DTPREL22 +ENUMDOC + Intel IA64 Relocations. + +ENUM + BFD_RELOC_M68HC11_HI8 +ENUMDOC + Motorola 68HC11 reloc. + This is the 8 bit high part of an absolute address. +ENUM + BFD_RELOC_M68HC11_LO8 +ENUMDOC + Motorola 68HC11 reloc. + This is the 8 bit low part of an absolute address. +ENUM + BFD_RELOC_M68HC11_3B +ENUMDOC + Motorola 68HC11 reloc. + This is the 3 bit of a value. +ENUM + BFD_RELOC_M68HC11_RL_JUMP +ENUMDOC + Motorola 68HC11 reloc. + This reloc marks the beginning of a jump/call instruction. + It is used for linker relaxation to correctly identify beginning + of instruction and change some branchs to use PC-relative + addressing mode. +ENUM + BFD_RELOC_M68HC11_RL_GROUP +ENUMDOC + Motorola 68HC11 reloc. + This reloc marks a group of several instructions that gcc generates + and for which the linker relaxation pass can modify and/or remove + some of them. +ENUM + BFD_RELOC_M68HC11_LO16 +ENUMDOC + Motorola 68HC11 reloc. + This is the 16-bit lower part of an address. It is used for 'call' + instruction to specify the symbol address without any special + transformation (due to memory bank window). +ENUM + BFD_RELOC_M68HC11_PAGE +ENUMDOC + Motorola 68HC11 reloc. + This is a 8-bit reloc that specifies the page number of an address. + It is used by 'call' instruction to specify the page number of + the symbol. +ENUM + BFD_RELOC_M68HC11_24 +ENUMDOC + Motorola 68HC11 reloc. + This is a 24-bit reloc that represents the address with a 16-bit + value and a 8-bit page number. The symbol address is transformed + to follow the 16K memory bank of 68HC12 (seen as mapped in the window). + +ENUM + BFD_RELOC_CRIS_BDISP8 +ENUMX + BFD_RELOC_CRIS_UNSIGNED_5 +ENUMX + BFD_RELOC_CRIS_SIGNED_6 +ENUMX + BFD_RELOC_CRIS_UNSIGNED_6 +ENUMX + BFD_RELOC_CRIS_UNSIGNED_4 +ENUMDOC + These relocs are only used within the CRIS assembler. They are not + (at present) written to any object files. +ENUM + BFD_RELOC_CRIS_COPY +ENUMX + BFD_RELOC_CRIS_GLOB_DAT +ENUMX + BFD_RELOC_CRIS_JUMP_SLOT +ENUMX + BFD_RELOC_CRIS_RELATIVE +ENUMDOC + Relocs used in ELF shared libraries for CRIS. +ENUM + BFD_RELOC_CRIS_32_GOT +ENUMDOC + 32-bit offset to symbol-entry within GOT. +ENUM + BFD_RELOC_CRIS_16_GOT +ENUMDOC + 16-bit offset to symbol-entry within GOT. +ENUM + BFD_RELOC_CRIS_32_GOTPLT +ENUMDOC + 32-bit offset to symbol-entry within GOT, with PLT handling. +ENUM + BFD_RELOC_CRIS_16_GOTPLT +ENUMDOC + 16-bit offset to symbol-entry within GOT, with PLT handling. +ENUM + BFD_RELOC_CRIS_32_GOTREL +ENUMDOC + 32-bit offset to symbol, relative to GOT. +ENUM + BFD_RELOC_CRIS_32_PLT_GOTREL +ENUMDOC + 32-bit offset to symbol with PLT entry, relative to GOT. +ENUM + BFD_RELOC_CRIS_32_PLT_PCREL +ENUMDOC + 32-bit offset to symbol with PLT entry, relative to this relocation. + +ENUM + BFD_RELOC_860_COPY +ENUMX + BFD_RELOC_860_GLOB_DAT +ENUMX + BFD_RELOC_860_JUMP_SLOT +ENUMX + BFD_RELOC_860_RELATIVE +ENUMX + BFD_RELOC_860_PC26 +ENUMX + BFD_RELOC_860_PLT26 +ENUMX + BFD_RELOC_860_PC16 +ENUMX + BFD_RELOC_860_LOW0 +ENUMX + BFD_RELOC_860_SPLIT0 +ENUMX + BFD_RELOC_860_LOW1 +ENUMX + BFD_RELOC_860_SPLIT1 +ENUMX + BFD_RELOC_860_LOW2 +ENUMX + BFD_RELOC_860_SPLIT2 +ENUMX + BFD_RELOC_860_LOW3 +ENUMX + BFD_RELOC_860_LOGOT0 +ENUMX + BFD_RELOC_860_SPGOT0 +ENUMX + BFD_RELOC_860_LOGOT1 +ENUMX + BFD_RELOC_860_SPGOT1 +ENUMX + BFD_RELOC_860_LOGOTOFF0 +ENUMX + BFD_RELOC_860_SPGOTOFF0 +ENUMX + BFD_RELOC_860_LOGOTOFF1 +ENUMX + BFD_RELOC_860_SPGOTOFF1 +ENUMX + BFD_RELOC_860_LOGOTOFF2 +ENUMX + BFD_RELOC_860_LOGOTOFF3 +ENUMX + BFD_RELOC_860_LOPC +ENUMX + BFD_RELOC_860_HIGHADJ +ENUMX + BFD_RELOC_860_HAGOT +ENUMX + BFD_RELOC_860_HAGOTOFF +ENUMX + BFD_RELOC_860_HAPC +ENUMX + BFD_RELOC_860_HIGH +ENUMX + BFD_RELOC_860_HIGOT +ENUMX + BFD_RELOC_860_HIGOTOFF +ENUMDOC + Intel i860 Relocations. + +ENUM + BFD_RELOC_OPENRISC_ABS_26 +ENUMX + BFD_RELOC_OPENRISC_REL_26 +ENUMDOC + OpenRISC Relocations. + +ENUM + BFD_RELOC_H8_DIR16A8 +ENUMX + BFD_RELOC_H8_DIR16R8 +ENUMX + BFD_RELOC_H8_DIR24A8 +ENUMX + BFD_RELOC_H8_DIR24R8 +ENUMX + BFD_RELOC_H8_DIR32A16 +ENUMDOC + H8 elf Relocations. + +ENUM + BFD_RELOC_XSTORMY16_REL_12 +ENUMX + BFD_RELOC_XSTORMY16_12 +ENUMX + BFD_RELOC_XSTORMY16_24 +ENUMX + BFD_RELOC_XSTORMY16_FPTR16 +ENUMDOC + Sony Xstormy16 Relocations. + +ENUM + BFD_RELOC_VAX_GLOB_DAT +ENUMX + BFD_RELOC_VAX_JMP_SLOT +ENUMX + BFD_RELOC_VAX_RELATIVE +ENUMDOC + Relocations used by VAX ELF. + +ENUM + BFD_RELOC_MSP430_10_PCREL +ENUMX + BFD_RELOC_MSP430_16_PCREL +ENUMX + BFD_RELOC_MSP430_16 +ENUMX + BFD_RELOC_MSP430_16_PCREL_BYTE +ENUMX + BFD_RELOC_MSP430_16_BYTE +ENUMDOC + msp430 specific relocation codes + +ENUM + BFD_RELOC_IQ2000_OFFSET_16 +ENUMX + BFD_RELOC_IQ2000_OFFSET_21 +ENUMX + BFD_RELOC_IQ2000_UHI16 +ENUMDOC + IQ2000 Relocations. + +ENUM + BFD_RELOC_XTENSA_RTLD +ENUMDOC + Special Xtensa relocation used only by PLT entries in ELF shared + objects to indicate that the runtime linker should set the value + to one of its own internal functions or data structures. +ENUM + BFD_RELOC_XTENSA_GLOB_DAT +ENUMX + BFD_RELOC_XTENSA_JMP_SLOT +ENUMX + BFD_RELOC_XTENSA_RELATIVE +ENUMDOC + Xtensa relocations for ELF shared objects. +ENUM + BFD_RELOC_XTENSA_PLT +ENUMDOC + Xtensa relocation used in ELF object files for symbols that may require + PLT entries. Otherwise, this is just a generic 32-bit relocation. +ENUM + BFD_RELOC_XTENSA_OP0 +ENUMX + BFD_RELOC_XTENSA_OP1 +ENUMX + BFD_RELOC_XTENSA_OP2 +ENUMDOC + Generic Xtensa relocations. Only the operand number is encoded + in the relocation. The details are determined by extracting the + instruction opcode. +ENUM + BFD_RELOC_XTENSA_ASM_EXPAND +ENUMDOC + Xtensa relocation to mark that the assembler expanded the + instructions from an original target. The expansion size is + encoded in the reloc size. +ENUM + BFD_RELOC_XTENSA_ASM_SIMPLIFY +ENUMDOC + Xtensa relocation to mark that the linker should simplify + assembler-expanded instructions. This is commonly used + internally by the linker after analysis of a + BFD_RELOC_XTENSA_ASM_EXPAND. + +ENDSENUM + BFD_RELOC_UNUSED +CODE_FRAGMENT +. +.typedef enum bfd_reloc_code_real bfd_reloc_code_real_type; +*/ + +/* +FUNCTION + bfd_reloc_type_lookup + +SYNOPSIS + reloc_howto_type * + bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code); + +DESCRIPTION + Return a pointer to a howto structure which, when + invoked, will perform the relocation @var{code} on data from the + architecture noted. + +*/ + +reloc_howto_type * +bfd_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + return BFD_SEND (abfd, reloc_type_lookup, (abfd, code)); +} + +static reloc_howto_type bfd_howto_32 = +HOWTO (0, 00, 2, 32, FALSE, 0, complain_overflow_bitfield, 0, "VRT32", FALSE, 0xffffffff, 0xffffffff, TRUE); + +/* +INTERNAL_FUNCTION + bfd_default_reloc_type_lookup + +SYNOPSIS + reloc_howto_type *bfd_default_reloc_type_lookup + (bfd *abfd, bfd_reloc_code_real_type code); + +DESCRIPTION + Provides a default relocation lookup routine for any architecture. + +*/ + +reloc_howto_type * +bfd_default_reloc_type_lookup (abfd, code) + bfd *abfd; + bfd_reloc_code_real_type code; +{ + switch (code) + { + case BFD_RELOC_CTOR: + /* The type of reloc used in a ctor, which will be as wide as the + address - so either a 64, 32, or 16 bitter. */ + switch (bfd_get_arch_info (abfd)->bits_per_address) + { + case 64: + BFD_FAIL (); + case 32: + return &bfd_howto_32; + case 16: + BFD_FAIL (); + default: + BFD_FAIL (); + } + default: + BFD_FAIL (); + } + return (reloc_howto_type *) NULL; +} + +/* +FUNCTION + bfd_get_reloc_code_name + +SYNOPSIS + const char *bfd_get_reloc_code_name (bfd_reloc_code_real_type code); + +DESCRIPTION + Provides a printable name for the supplied relocation code. + Useful mainly for printing error messages. +*/ + +const char * +bfd_get_reloc_code_name (code) + bfd_reloc_code_real_type code; +{ + if ((int) code > (int) BFD_RELOC_UNUSED) + return 0; + return bfd_reloc_code_real_names[(int)code]; +} + +/* +INTERNAL_FUNCTION + bfd_generic_relax_section + +SYNOPSIS + bfd_boolean bfd_generic_relax_section + (bfd *abfd, + asection *section, + struct bfd_link_info *, + bfd_boolean *); + +DESCRIPTION + Provides default handling for relaxing for back ends which + don't do relaxing -- i.e., does nothing. +*/ + +bfd_boolean +bfd_generic_relax_section (abfd, section, link_info, again) + bfd *abfd ATTRIBUTE_UNUSED; + asection *section ATTRIBUTE_UNUSED; + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; + bfd_boolean *again; +{ + *again = FALSE; + return TRUE; +} + +/* +INTERNAL_FUNCTION + bfd_generic_gc_sections + +SYNOPSIS + bfd_boolean bfd_generic_gc_sections + (bfd *, struct bfd_link_info *); + +DESCRIPTION + Provides default handling for relaxing for back ends which + don't do section gc -- i.e., does nothing. +*/ + +bfd_boolean +bfd_generic_gc_sections (abfd, link_info) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +/* +INTERNAL_FUNCTION + bfd_generic_merge_sections + +SYNOPSIS + bfd_boolean bfd_generic_merge_sections + (bfd *, struct bfd_link_info *); + +DESCRIPTION + Provides default handling for SEC_MERGE section merging for back ends + which don't have SEC_MERGE support -- i.e., does nothing. +*/ + +bfd_boolean +bfd_generic_merge_sections (abfd, link_info) + bfd *abfd ATTRIBUTE_UNUSED; + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +/* +INTERNAL_FUNCTION + bfd_generic_get_relocated_section_contents + +SYNOPSIS + bfd_byte * + bfd_generic_get_relocated_section_contents (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocateable, + asymbol **symbols); + +DESCRIPTION + Provides default handling of relocation effort for back ends + which can't be bothered to do it efficiently. + +*/ + +bfd_byte * +bfd_generic_get_relocated_section_contents (abfd, link_info, link_order, data, + relocateable, symbols) + bfd *abfd; + struct bfd_link_info *link_info; + struct bfd_link_order *link_order; + bfd_byte *data; + bfd_boolean relocateable; + asymbol **symbols; +{ + /* Get enough memory to hold the stuff. */ + bfd *input_bfd = link_order->u.indirect.section->owner; + asection *input_section = link_order->u.indirect.section; + + long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); + arelent **reloc_vector = NULL; + long reloc_count; + + if (reloc_size < 0) + goto error_return; + + reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + goto error_return; + + /* Read in the section. */ + if (!bfd_get_section_contents (input_bfd, + input_section, + (PTR) data, + (bfd_vma) 0, + input_section->_raw_size)) + goto error_return; + + /* We're not relaxing the section, so just copy the size info. */ + input_section->_cooked_size = input_section->_raw_size; + input_section->reloc_done = TRUE; + + 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 != (arelent *) NULL; + parent++) + { + char *error_message = (char *) NULL; + bfd_reloc_status_type r = + bfd_perform_relocation (input_bfd, + *parent, + (PTR) data, + input_section, + relocateable ? abfd : (bfd *) NULL, + &error_message); + + if (relocateable) + { + 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 != (char *) 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, 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: + default: + abort (); + break; + } + + } + } + } + if (reloc_vector != NULL) + free (reloc_vector); + return data; + +error_return: + if (reloc_vector != NULL) + free (reloc_vector); + return NULL; +} diff --git a/contrib/binutils-2.14/bfd/section.c b/contrib/binutils-2.14/bfd/section.c new file mode 100644 index 0000000000..04f439e9b4 --- /dev/null +++ b/contrib/binutils-2.14/bfd/section.c @@ -0,0 +1,1391 @@ +/* Object file "section" support for the BFD library. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + Sections + + The raw data contained within a BFD is maintained through the + section abstraction. A single BFD may have any number of + sections. It keeps hold of them by pointing to the first; + each one points to the next in the list. + + Sections are supported in BFD in <>. + +@menu +@* Section Input:: +@* Section Output:: +@* typedef asection:: +@* section prototypes:: +@end menu + +INODE +Section Input, Section Output, Sections, Sections +SUBSECTION + Section input + + When a BFD is opened for reading, the section structures are + created and attached to the BFD. + + Each section has a name which describes the section in the + outside world---for example, <> would contain at least + three sections, called <<.text>>, <<.data>> and <<.bss>>. + + Names need not be unique; for example a COFF file may have several + sections named <<.data>>. + + Sometimes a BFD will contain more than the ``natural'' number of + sections. A back end may attach other sections containing + constructor data, or an application may add a section (using + <>) to the sections attached to an already open + BFD. For example, the linker creates an extra section + <> for each input file's BFD to hold information about + common storage. + + The raw data is not necessarily read in when + the section descriptor is created. Some targets may leave the + data in place until a <> call is + made. Other back ends may read in all the data at once. For + example, an S-record file has to be read once to determine the + size of the data. An IEEE-695 file doesn't contain raw data in + sections, but data and relocation expressions intermixed, so + the data area has to be parsed to get out the data and + relocations. + +INODE +Section Output, typedef asection, Section Input, Sections + +SUBSECTION + Section output + + To write a new object style BFD, the various sections to be + written have to be created. They are attached to the BFD in + the same way as input sections; data is written to the + sections using <>. + + Any program that creates or combines sections (e.g., the assembler + and linker) must use the <> fields <> and + <> to indicate the file sections to which each + section must be written. (If the section is being created from + scratch, <> should probably point to the section + itself and <> should probably be zero.) + + The data to be written comes from input sections attached + (via <> pointers) to + the output sections. The output section structure can be + considered a filter for the input section: the output section + determines the vma of the output data and the name, but the + input section determines the offset into the output section of + the data to be written. + + E.g., to create a section "O", starting at 0x100, 0x123 long, + containing two subsections, "A" at offset 0x0 (i.e., at vma + 0x100) and "B" at offset 0x20 (i.e., at vma 0x120) the <> + structures would look like: + +| section name "A" +| output_offset 0x00 +| size 0x20 +| output_section -----------> section name "O" +| | vma 0x100 +| section name "B" | size 0x123 +| output_offset 0x20 | +| size 0x103 | +| output_section --------| + +SUBSECTION + Link orders + + The data within a section is stored in a @dfn{link_order}. + These are much like the fixups in <>. The link_order + abstraction allows a section to grow and shrink within itself. + + A link_order knows how big it is, and which is the next + link_order and where the raw data for it is; it also points to + a list of relocations which apply to it. + + The link_order is used by the linker to perform relaxing on + final code. The compiler creates code which is as big as + necessary to make it work without relaxing, and the user can + select whether to relax. Sometimes relaxing takes a lot of + time. The linker runs around the relocations to see if any + are attached to data which can be shrunk, if so it does it on + a link_order by link_order basis. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" + +/* +DOCDD +INODE +typedef asection, section prototypes, Section Output, Sections +SUBSECTION + typedef asection + + Here is the section structure: + +CODE_FRAGMENT +. +.{* 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 bfd_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; +.}; +. +.typedef struct sec +.{ +. {* The name of the section; the name isn't a copy, the pointer is +. the same as that passed to bfd_make_section. *} +. const char *name; +. +. {* A unique sequence number. *} +. int id; +. +. {* Which section in the bfd; 0..n-1 as sections are created in a bfd. *} +. int index; +. +. {* The next section in the list belonging to the BFD, or NULL. *} +. struct sec *next; +. +. {* The field flags contains attributes of the section. Some +. flags are read in from the object file, and some are +. synthesized from other information. *} +. flagword flags; +. +.#define SEC_NO_FLAGS 0x000 +. +. {* Tells the OS to allocate space for this section when loading. +. This is clear for a section containing debug information only. *} +.#define SEC_ALLOC 0x001 +. +. {* Tells the OS to load the section from the file when loading. +. This is clear for a .bss section. *} +.#define SEC_LOAD 0x002 +. +. {* The section contains data still to be relocated, so there is +. some relocation information too. *} +.#define SEC_RELOC 0x004 +. +. {* ELF reserves 4 processor specific bits and 8 operating system +. specific bits in sh_flags; at present we can get away with just +. one in communicating between the assembler and BFD, but this +. isn't a good long-term solution. *} +.#define SEC_ARCH_BIT_0 0x008 +. +. {* A signal to the OS that the section contains read only data. *} +.#define SEC_READONLY 0x010 +. +. {* The section contains code only. *} +.#define SEC_CODE 0x020 +. +. {* The section contains data only. *} +.#define SEC_DATA 0x040 +. +. {* The section will reside in ROM. *} +.#define SEC_ROM 0x080 +. +. {* The section contains constructor information. This section +. type is used by the linker to create lists of constructors and +. destructors used by <>. When a back end sees a symbol +. which should be used in a constructor list, it creates a new +. section for the type of name (e.g., <<__CTOR_LIST__>>), attaches +. the symbol to it, and builds a relocation. To build the lists +. of constructors, all the linker has to do is catenate all the +. sections called <<__CTOR_LIST__>> and relocate the data +. contained within - exactly the operations it would peform on +. standard data. *} +.#define SEC_CONSTRUCTOR 0x100 +. +. {* The section has contents - a data section could be +. <> | <>; a debug section could be +. <> *} +.#define SEC_HAS_CONTENTS 0x200 +. +. {* An instruction to the linker to not output the section +. even if it has information which would normally be written. *} +.#define SEC_NEVER_LOAD 0x400 +. +. {* The section is a COFF shared library section. This flag is +. only for the linker. If this type of section appears in +. the input file, the linker must copy it to the output file +. without changing the vma or size. FIXME: Although this +. was originally intended to be general, it really is COFF +. specific (and the flag was renamed to indicate this). It +. might be cleaner to have some more general mechanism to +. allow the back end to control what the linker does with +. sections. *} +.#define SEC_COFF_SHARED_LIBRARY 0x800 +. +. {* The section contains thread local data. *} +.#define SEC_THREAD_LOCAL 0x1000 +. +. {* The section has GOT references. This flag is only for the +. linker, and is currently only used by the elf32-hppa back end. +. It will be set if global offset table references were detected +. in this section, which indicate to the linker that the section +. contains PIC code, and must be handled specially when doing a +. static link. *} +.#define SEC_HAS_GOT_REF 0x4000 +. +. {* The section contains common symbols (symbols may be defined +. multiple times, the value of a symbol is the amount of +. space it requires, and the largest symbol value is the one +. used). Most targets have exactly one of these (which we +. translate to bfd_com_section_ptr), but ECOFF has two. *} +.#define SEC_IS_COMMON 0x8000 +. +. {* The section contains only debugging information. For +. example, this is set for ELF .debug and .stab sections. +. strip tests this flag to see if a section can be +. discarded. *} +.#define SEC_DEBUGGING 0x10000 +. +. {* The contents of this section are held in memory pointed to +. by the contents field. This is checked by bfd_get_section_contents, +. and the data is retrieved from memory if appropriate. *} +.#define SEC_IN_MEMORY 0x20000 +. +. {* The contents of this section are to be excluded by the +. linker for executable and shared objects unless those +. objects are to be further relocated. *} +.#define SEC_EXCLUDE 0x40000 +. +. {* The contents of this section are to be sorted based on the sum of +. the symbol and addend values specified by the associated relocation +. entries. Entries without associated relocation entries will be +. appended to the end of the section in an unspecified order. *} +.#define SEC_SORT_ENTRIES 0x80000 +. +. {* When linking, duplicate sections of the same name should be +. discarded, rather than being combined into a single section as +. is usually done. This is similar to how common symbols are +. handled. See SEC_LINK_DUPLICATES below. *} +.#define SEC_LINK_ONCE 0x100000 +. +. {* If SEC_LINK_ONCE is set, this bitfield describes how the linker +. should handle duplicate sections. *} +.#define SEC_LINK_DUPLICATES 0x600000 +. +. {* This value for SEC_LINK_DUPLICATES means that duplicate +. sections with the same name should simply be discarded. *} +.#define SEC_LINK_DUPLICATES_DISCARD 0x0 +. +. {* This value for SEC_LINK_DUPLICATES means that the linker +. should warn if there are any duplicate sections, although +. it should still only link one copy. *} +.#define SEC_LINK_DUPLICATES_ONE_ONLY 0x200000 +. +. {* This value for SEC_LINK_DUPLICATES means that the linker +. should warn if any duplicate sections are a different size. *} +.#define SEC_LINK_DUPLICATES_SAME_SIZE 0x400000 +. +. {* This value for SEC_LINK_DUPLICATES means that the linker +. should warn if any duplicate sections contain different +. contents. *} +.#define SEC_LINK_DUPLICATES_SAME_CONTENTS 0x600000 +. +. {* This section was created by the linker as part of dynamic +. relocation or other arcane processing. It is skipped when +. going through the first-pass output, trusting that someone +. else up the line will take care of it later. *} +.#define SEC_LINKER_CREATED 0x800000 +. +. {* This section should not be subject to garbage collection. *} +.#define SEC_KEEP 0x1000000 +. +. {* This section contains "short" data, and should be placed +. "near" the GP. *} +.#define SEC_SMALL_DATA 0x2000000 +. +. {* This section contains data which may be shared with other +. executables or shared objects. *} +.#define SEC_SHARED 0x4000000 +. +. {* 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, it +. should be aligned on a page boundary. *} +.#define SEC_BLOCK 0x8000000 +. +. {* Conditionally link this section; do not link if there are no +. references found to any symbol in the section. *} +.#define SEC_CLINK 0x10000000 +. +. {* Attempt to merge identical entities in the section. +. Entity size is given in the entsize field. *} +.#define SEC_MERGE 0x20000000 +. +. {* If given with SEC_MERGE, entities to merge are zero terminated +. strings where entsize specifies character size instead of fixed +. size entries. *} +.#define SEC_STRINGS 0x40000000 +. +. {* This section contains data about section groups. *} +.#define SEC_GROUP 0x80000000 +. +. {* End of section flags. *} +. +. {* Some internal packed boolean fields. *} +. +. {* See the vma field. *} +. unsigned int user_set_vma : 1; +. +. {* Whether relocations have been processed. *} +. unsigned int reloc_done : 1; +. +. {* A mark flag used by some of the linker backends. *} +. unsigned int linker_mark : 1; +. +. {* Another mark flag used by some of the linker backends. Set for +. output sections that have an input section. *} +. unsigned int linker_has_input : 1; +. +. {* A mark flag used by some linker backends for garbage collection. *} +. unsigned int gc_mark : 1; +. +. {* The following flags are used by the ELF linker. *} +. +. {* Mark sections which have been allocated to segments. *} +. unsigned int segment_mark : 1; +. +. {* Type of sec_info information. *} +. unsigned int sec_info_type:3; +.#define ELF_INFO_TYPE_NONE 0 +.#define ELF_INFO_TYPE_STABS 1 +.#define ELF_INFO_TYPE_MERGE 2 +.#define ELF_INFO_TYPE_EH_FRAME 3 +.#define ELF_INFO_TYPE_JUST_SYMS 4 +. +. {* Nonzero if this section uses RELA relocations, rather than REL. *} +. unsigned int use_rela_p:1; +. +. {* Bits used by various backends. *} +. unsigned int has_tls_reloc:1; +. +. {* Nonzero if this section needs the relax finalize pass. *} +. unsigned int need_finalize_relax:1; +. +. {* Usused bits. *} +. unsigned int flag12:1; +. unsigned int flag13:1; +. unsigned int flag14:1; +. unsigned int flag15:1; +. unsigned int flag16:4; +. unsigned int flag20:4; +. unsigned int flag24:8; +. +. {* End of internal packed boolean fields. *} +. +. {* The virtual memory address of the section - where it will be +. at run time. The symbols are relocated against this. The +. user_set_vma flag is maintained by bfd; if it's not set, the +. backend can assign addresses (for example, in <>, where +. the default address for <<.data>> is dependent on the specific +. target and various flags). *} +. bfd_vma vma; +. +. {* The load address of the section - where it would be in a +. rom image; really only used for writing section header +. information. *} +. bfd_vma lma; +. +. {* The size of the section in octets, as it will be output. +. Contains a value even if the section has no contents (e.g., the +. size of <<.bss>>). This will be filled in after relocation. *} +. bfd_size_type _cooked_size; +. +. {* The original size on disk of the section, in octets. Normally this +. value is the same as the size, but if some relaxing has +. been done, then this value will be bigger. *} +. bfd_size_type _raw_size; +. +. {* If this section is going to be output, then this value is the +. offset in *bytes* into the output section of the first byte in the +. input section (byte ==> smallest addressable unit on the +. target). In most cases, if this was going to start at the +. 100th octet (8-bit quantity) in the output section, this value +. would be 100. However, if the target byte size is 16 bits +. (bfd_octets_per_byte is "2"), this value would be 50. *} +. bfd_vma output_offset; +. +. {* The output section through which to map on output. *} +. struct sec *output_section; +. +. {* The alignment requirement of the section, as an exponent of 2 - +. e.g., 3 aligns to 2^3 (or 8). *} +. unsigned int alignment_power; +. +. {* If an input section, a pointer to a vector of relocation +. records for the data in this section. *} +. struct reloc_cache_entry *relocation; +. +. {* If an output section, a pointer to a vector of pointers to +. relocation records for the data in this section. *} +. struct reloc_cache_entry **orelocation; +. +. {* The number of relocation records in one of the above. *} +. unsigned reloc_count; +. +. {* Information below is back end specific - and not always used +. or updated. *} +. +. {* File position of section data. *} +. file_ptr filepos; +. +. {* File position of relocation info. *} +. file_ptr rel_filepos; +. +. {* File position of line data. *} +. file_ptr line_filepos; +. +. {* Pointer to data for applications. *} +. PTR userdata; +. +. {* If the SEC_IN_MEMORY flag is set, this points to the actual +. contents. *} +. unsigned char *contents; +. +. {* Attached line number information. *} +. alent *lineno; +. +. {* Number of line number records. *} +. unsigned int lineno_count; +. +. {* Entity size for merging purposes. *} +. unsigned int entsize; +. +. {* Optional information about a COMDAT entry; NULL if not COMDAT. *} +. struct bfd_comdat_info *comdat; +. +. {* When a section is being output, this value changes as more +. linenumbers are written out. *} +. file_ptr moving_line_filepos; +. +. {* What the section number is in the target world. *} +. int target_index; +. +. PTR used_by_bfd; +. +. {* If this is a constructor section then here is a list of the +. relocations created to relocate items within it. *} +. struct relent_chain *constructor_chain; +. +. {* The BFD which owns the section. *} +. bfd *owner; +. +. {* A symbol which points at this section only. *} +. struct symbol_cache_entry *symbol; +. struct symbol_cache_entry **symbol_ptr_ptr; +. +. struct bfd_link_order *link_order_head; +. struct bfd_link_order *link_order_tail; +.} asection; +. +.{* 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. New code should use the section_ptr macros rather +. than referring directly to the const sections. The const sections +. may eventually vanish. *} +.#define BFD_ABS_SECTION_NAME "*ABS*" +.#define BFD_UND_SECTION_NAME "*UND*" +.#define BFD_COM_SECTION_NAME "*COM*" +.#define BFD_IND_SECTION_NAME "*IND*" +. +.{* The absolute section. *} +.extern const asection bfd_abs_section; +.#define bfd_abs_section_ptr ((asection *) &bfd_abs_section) +.#define bfd_is_abs_section(sec) ((sec) == bfd_abs_section_ptr) +.{* Pointer to the undefined section. *} +.extern const asection bfd_und_section; +.#define bfd_und_section_ptr ((asection *) &bfd_und_section) +.#define bfd_is_und_section(sec) ((sec) == bfd_und_section_ptr) +.{* Pointer to the common section. *} +.extern const asection bfd_com_section; +.#define bfd_com_section_ptr ((asection *) &bfd_com_section) +.{* Pointer to the indirect section. *} +.extern const asection bfd_ind_section; +.#define bfd_ind_section_ptr ((asection *) &bfd_ind_section) +.#define bfd_is_ind_section(sec) ((sec) == bfd_ind_section_ptr) +. +.#define bfd_is_const_section(SEC) \ +. ( ((SEC) == bfd_abs_section_ptr) \ +. || ((SEC) == bfd_und_section_ptr) \ +. || ((SEC) == bfd_com_section_ptr) \ +. || ((SEC) == bfd_ind_section_ptr)) +. +.extern const struct symbol_cache_entry * const bfd_abs_symbol; +.extern const struct symbol_cache_entry * const bfd_com_symbol; +.extern const struct symbol_cache_entry * const bfd_und_symbol; +.extern const struct symbol_cache_entry * const bfd_ind_symbol; +.#define bfd_get_section_size_before_reloc(section) \ +. ((section)->reloc_done ? (abort (), (bfd_size_type) 1) \ +. : (section)->_raw_size) +.#define bfd_get_section_size_after_reloc(section) \ +. ((section)->reloc_done ? (section)->_cooked_size \ +. : (abort (), (bfd_size_type) 1)) +. +.{* Macros to handle insertion and deletion of a bfd's sections. These +. only handle the list pointers, ie. do not adjust section_count, +. target_index etc. *} +.#define bfd_section_list_remove(ABFD, PS) \ +. do \ +. { \ +. asection **_ps = PS; \ +. asection *_s = *_ps; \ +. *_ps = _s->next; \ +. if (_s->next == NULL) \ +. (ABFD)->section_tail = _ps; \ +. } \ +. while (0) +.#define bfd_section_list_insert(ABFD, PS, S) \ +. do \ +. { \ +. asection **_ps = PS; \ +. asection *_s = S; \ +. _s->next = *_ps; \ +. *_ps = _s; \ +. if (_s->next == NULL) \ +. (ABFD)->section_tail = &_s->next; \ +. } \ +. while (0) +. +*/ + +/* We use a macro to initialize the static asymbol structures because + traditional C does not permit us to initialize a union member while + gcc warns if we don't initialize it. */ + /* the_bfd, name, value, attr, section [, udata] */ +#ifdef __STDC__ +#define GLOBAL_SYM_INIT(NAME, SECTION) \ + { 0, NAME, 0, BSF_SECTION_SYM, (asection *) SECTION, { 0 }} +#else +#define GLOBAL_SYM_INIT(NAME, SECTION) \ + { 0, NAME, 0, BSF_SECTION_SYM, (asection *) SECTION } +#endif + +/* These symbols are global, not specific to any BFD. Therefore, anything + that tries to change them is broken, and should be repaired. */ + +static const asymbol global_syms[] = +{ + GLOBAL_SYM_INIT (BFD_COM_SECTION_NAME, &bfd_com_section), + GLOBAL_SYM_INIT (BFD_UND_SECTION_NAME, &bfd_und_section), + GLOBAL_SYM_INIT (BFD_ABS_SECTION_NAME, &bfd_abs_section), + GLOBAL_SYM_INIT (BFD_IND_SECTION_NAME, &bfd_ind_section) +}; + +#define STD_SECTION(SEC, FLAGS, SYM, NAME, IDX) \ + const asymbol * const SYM = (asymbol *) &global_syms[IDX]; \ + const asection SEC = \ + /* name, id, index, next, flags, user_set_vma, reloc_done, */ \ + { NAME, IDX, 0, NULL, FLAGS, 0, 0, \ + \ + /* linker_mark, linker_has_input, gc_mark, segment_mark, */ \ + 0, 0, 1, 0, \ + \ + /* sec_info_type, use_rela_p, has_tls_reloc, need_finalize_relax, flag12, */ \ + 0, 0, 0, 0, 0, \ + \ + /* flag13, flag14, flag15, flag16, flag20, flag24, */ \ + 0, 0, 0, 0, 0, 0, \ + \ + /* vma, lma, _cooked_size, _raw_size, */ \ + 0, 0, 0, 0, \ + \ + /* output_offset, output_section, alignment_power, */ \ + 0, (struct sec *) &SEC, 0, \ + \ + /* relocation, orelocation, reloc_count, filepos, rel_filepos, */ \ + NULL, NULL, 0, 0, 0, \ + \ + /* line_filepos, userdata, contents, lineno, lineno_count, */ \ + 0, NULL, NULL, NULL, 0, \ + \ + /* entsize, comdat, moving_line_filepos, */ \ + 0, NULL, 0, \ + \ + /* target_index, used_by_bfd, constructor_chain, owner, */ \ + 0, NULL, NULL, NULL, \ + \ + /* symbol, */ \ + (struct symbol_cache_entry *) &global_syms[IDX], \ + \ + /* symbol_ptr_ptr, */ \ + (struct symbol_cache_entry **) &SYM, \ + \ + /* link_order_head, link_order_tail */ \ + NULL, NULL \ + } + +STD_SECTION (bfd_com_section, SEC_IS_COMMON, bfd_com_symbol, + BFD_COM_SECTION_NAME, 0); +STD_SECTION (bfd_und_section, 0, bfd_und_symbol, BFD_UND_SECTION_NAME, 1); +STD_SECTION (bfd_abs_section, 0, bfd_abs_symbol, BFD_ABS_SECTION_NAME, 2); +STD_SECTION (bfd_ind_section, 0, bfd_ind_symbol, BFD_IND_SECTION_NAME, 3); +#undef STD_SECTION + +struct section_hash_entry +{ + struct bfd_hash_entry root; + asection section; +}; + +/* Initialize an entry in the section hash table. */ + +struct bfd_hash_entry * +bfd_section_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + /* 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 (struct section_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = bfd_hash_newfunc (entry, table, string); + if (entry != NULL) + { + memset ((PTR) &((struct section_hash_entry *) entry)->section, + 0, sizeof (asection)); + } + + return entry; +} + +#define section_hash_lookup(table, string, create, copy) \ + ((struct section_hash_entry *) \ + bfd_hash_lookup ((table), (string), (create), (copy))) + +/* Initializes a new section. NEWSECT->NAME is already set. */ + +static asection *bfd_section_init PARAMS ((bfd *, asection *)); + +static asection * +bfd_section_init (abfd, newsect) + bfd *abfd; + asection *newsect; +{ + static int section_id = 0x10; /* id 0 to 3 used by STD_SECTION. */ + + newsect->id = section_id; + newsect->index = abfd->section_count; + newsect->owner = abfd; + + /* Create a symbol whose only job is to point to this section. This + is useful for things like relocs which are relative to the base + of a section. */ + newsect->symbol = bfd_make_empty_symbol (abfd); + if (newsect->symbol == NULL) + return NULL; + + newsect->symbol->name = newsect->name; + newsect->symbol->value = 0; + newsect->symbol->section = newsect; + newsect->symbol->flags = BSF_SECTION_SYM; + + newsect->symbol_ptr_ptr = &newsect->symbol; + + if (! BFD_SEND (abfd, _new_section_hook, (abfd, newsect))) + return NULL; + + section_id++; + abfd->section_count++; + *abfd->section_tail = newsect; + abfd->section_tail = &newsect->next; + return newsect; +} + +/* +DOCDD +INODE +section prototypes, , typedef asection, Sections +SUBSECTION + Section prototypes + +These are the functions exported by the section handling part of BFD. +*/ + +/* +FUNCTION + bfd_section_list_clear + +SYNOPSIS + void bfd_section_list_clear (bfd *); + +DESCRIPTION + Clears the section list, and also resets the section count and + hash table entries. +*/ + +void +bfd_section_list_clear (abfd) + bfd *abfd; +{ + abfd->sections = NULL; + abfd->section_tail = &abfd->sections; + abfd->section_count = 0; + memset ((PTR) abfd->section_htab.table, 0, + abfd->section_htab.size * sizeof (struct bfd_hash_entry *)); +} + +/* +FUNCTION + bfd_get_section_by_name + +SYNOPSIS + asection *bfd_get_section_by_name(bfd *abfd, const char *name); + +DESCRIPTION + Run through @var{abfd} and return the one of the + <>s whose name matches @var{name}, otherwise <>. + @xref{Sections}, for more information. + + This should only be used in special cases; the normal way to process + all sections of a given name is to use <> and + <> on the name (or better yet, base it on the section flags + or something else) for each section. +*/ + +asection * +bfd_get_section_by_name (abfd, name) + bfd *abfd; + const char *name; +{ + struct section_hash_entry *sh; + + sh = section_hash_lookup (&abfd->section_htab, name, FALSE, FALSE); + if (sh != NULL) + return &sh->section; + + return NULL; +} + +/* +FUNCTION + bfd_get_unique_section_name + +SYNOPSIS + char *bfd_get_unique_section_name(bfd *abfd, + const char *templat, + int *count); + +DESCRIPTION + Invent a section name that is unique in @var{abfd} by tacking + a dot and a digit suffix onto the original @var{templat}. If + @var{count} is non-NULL, then it specifies the first number + tried as a suffix to generate a unique name. The value + pointed to by @var{count} will be incremented in this case. +*/ + +char * +bfd_get_unique_section_name (abfd, templat, count) + bfd *abfd; + const char *templat; + int *count; +{ + int num; + unsigned int len; + char *sname; + + len = strlen (templat); + sname = bfd_malloc ((bfd_size_type) len + 8); + if (sname == NULL) + return NULL; + memcpy (sname, templat, len); + num = 1; + if (count != NULL) + num = *count; + + do + { + /* If we have a million sections, something is badly wrong. */ + if (num > 999999) + abort (); + sprintf (sname + len, ".%d", num++); + } + while (section_hash_lookup (&abfd->section_htab, sname, FALSE, FALSE)); + + if (count != NULL) + *count = num; + return sname; +} + +/* +FUNCTION + bfd_make_section_old_way + +SYNOPSIS + asection *bfd_make_section_old_way(bfd *abfd, const char *name); + +DESCRIPTION + Create a new empty section called @var{name} + and attach it to the end of the chain of sections for the + BFD @var{abfd}. An attempt to create a section with a name which + is already in use returns its pointer without changing the + section chain. + + It has the funny name since this is the way it used to be + before it was rewritten.... + + Possible errors are: + o <> - + If output has already started for this BFD. + o <> - + If memory allocation fails. + +*/ + +asection * +bfd_make_section_old_way (abfd, name) + bfd *abfd; + const char *name; +{ + struct section_hash_entry *sh; + asection *newsect; + + if (abfd->output_has_begun) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + if (strcmp (name, BFD_ABS_SECTION_NAME) == 0) + return bfd_abs_section_ptr; + + if (strcmp (name, BFD_COM_SECTION_NAME) == 0) + return bfd_com_section_ptr; + + if (strcmp (name, BFD_UND_SECTION_NAME) == 0) + return bfd_und_section_ptr; + + if (strcmp (name, BFD_IND_SECTION_NAME) == 0) + return bfd_ind_section_ptr; + + sh = section_hash_lookup (&abfd->section_htab, name, TRUE, FALSE); + if (sh == NULL) + return NULL; + + newsect = &sh->section; + if (newsect->name != NULL) + { + /* Section already exists. */ + return newsect; + } + + newsect->name = name; + return bfd_section_init (abfd, newsect); +} + +/* +FUNCTION + bfd_make_section_anyway + +SYNOPSIS + asection *bfd_make_section_anyway(bfd *abfd, const char *name); + +DESCRIPTION + Create a new empty section called @var{name} and attach it to the end of + the chain of sections for @var{abfd}. Create a new section even if there + is already a section with that name. + + Return <> and set <> on error; possible errors are: + o <> - If output has already started for @var{abfd}. + o <> - If memory allocation fails. +*/ + +sec_ptr +bfd_make_section_anyway (abfd, name) + bfd *abfd; + const char *name; +{ + struct section_hash_entry *sh; + asection *newsect; + + if (abfd->output_has_begun) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + sh = section_hash_lookup (&abfd->section_htab, name, TRUE, FALSE); + if (sh == NULL) + return NULL; + + newsect = &sh->section; + if (newsect->name != NULL) + { + /* We are making a section of the same name. It can't go in + section_htab without generating a unique section name and + that would be pointless; We don't need to traverse the + hash table. */ + newsect = (asection *) bfd_zalloc (abfd, sizeof (asection)); + if (newsect == NULL) + return NULL; + } + + newsect->name = name; + return bfd_section_init (abfd, newsect); +} + +/* +FUNCTION + bfd_make_section + +SYNOPSIS + asection *bfd_make_section(bfd *, const char *name); + +DESCRIPTION + Like <>, but return <> (without calling + bfd_set_error ()) without changing the section chain if there is already a + section named @var{name}. If there is an error, return <> and set + <>. +*/ + +asection * +bfd_make_section (abfd, name) + bfd *abfd; + const char *name; +{ + struct section_hash_entry *sh; + asection *newsect; + + if (abfd->output_has_begun) + { + bfd_set_error (bfd_error_invalid_operation); + return NULL; + } + + if (strcmp (name, BFD_ABS_SECTION_NAME) == 0 + || strcmp (name, BFD_COM_SECTION_NAME) == 0 + || strcmp (name, BFD_UND_SECTION_NAME) == 0 + || strcmp (name, BFD_IND_SECTION_NAME) == 0) + return NULL; + + sh = section_hash_lookup (&abfd->section_htab, name, TRUE, FALSE); + if (sh == NULL) + return NULL; + + newsect = &sh->section; + if (newsect->name != NULL) + { + /* Section already exists. */ + return newsect; + } + + newsect->name = name; + return bfd_section_init (abfd, newsect); +} + +/* +FUNCTION + bfd_set_section_flags + +SYNOPSIS + bfd_boolean bfd_set_section_flags (bfd *abfd, asection *sec, flagword flags); + +DESCRIPTION + Set the attributes of the section @var{sec} in the BFD + @var{abfd} to the value @var{flags}. Return <> on success, + <> on error. Possible error returns are: + + o <> - + The section cannot have one or more of the attributes + requested. For example, a .bss section in <> may not + have the <> field set. + +*/ + +/*ARGSUSED*/ +bfd_boolean +bfd_set_section_flags (abfd, section, flags) + bfd *abfd ATTRIBUTE_UNUSED; + sec_ptr section; + flagword flags; +{ +#if 0 + /* If you try to copy a text section from an input file (where it + has the SEC_CODE flag set) to an output file, this loses big if + the bfd_applicable_section_flags (abfd) doesn't have the SEC_CODE + set - which it doesn't, at least not for a.out. FIXME */ + + if ((flags & bfd_applicable_section_flags (abfd)) != flags) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } +#endif + + section->flags = flags; + return TRUE; +} + +/* +FUNCTION + bfd_map_over_sections + +SYNOPSIS + void bfd_map_over_sections(bfd *abfd, + void (*func) (bfd *abfd, + asection *sect, + PTR obj), + PTR obj); + +DESCRIPTION + Call the provided function @var{func} for each section + attached to the BFD @var{abfd}, passing @var{obj} as an + argument. The function will be called as if by + +| func(abfd, the_section, obj); + + This is the prefered method for iterating over sections; an + alternative would be to use a loop: + +| section *p; +| for (p = abfd->sections; p != NULL; p = p->next) +| func(abfd, p, ...) + +*/ + +/*VARARGS2*/ +void +bfd_map_over_sections (abfd, operation, user_storage) + bfd *abfd; + void (*operation) PARAMS ((bfd * abfd, asection * sect, PTR obj)); + PTR user_storage; +{ + asection *sect; + unsigned int i = 0; + + for (sect = abfd->sections; sect != NULL; i++, sect = sect->next) + (*operation) (abfd, sect, user_storage); + + if (i != abfd->section_count) /* Debugging */ + abort (); +} + +/* +FUNCTION + bfd_set_section_size + +SYNOPSIS + bfd_boolean bfd_set_section_size (bfd *abfd, asection *sec, bfd_size_type val); + +DESCRIPTION + Set @var{sec} to the size @var{val}. If the operation is + ok, then <> is returned, else <>. + + Possible error returns: + o <> - + Writing has started to the BFD, so setting the size is invalid. + +*/ + +bfd_boolean +bfd_set_section_size (abfd, ptr, val) + bfd *abfd; + sec_ptr ptr; + bfd_size_type val; +{ + /* Once you've started writing to any section you cannot create or change + the size of any others. */ + + if (abfd->output_has_begun) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + ptr->_cooked_size = val; + ptr->_raw_size = val; + + return TRUE; +} + +/* +FUNCTION + bfd_set_section_contents + +SYNOPSIS + bfd_boolean bfd_set_section_contents (bfd *abfd, asection *section, + PTR data, file_ptr offset, + bfd_size_type count); + +DESCRIPTION + Sets the contents of the section @var{section} in BFD + @var{abfd} to the data starting in memory at @var{data}. The + data is written to the output section starting at offset + @var{offset} for @var{count} octets. + + Normally <> is returned, else <>. Possible error + returns are: + o <> - + The output section does not have the <> + attribute, so nothing can be written to it. + o and some more too + + This routine is front end to the back end function + <<_bfd_set_section_contents>>. + +*/ + +#define bfd_get_section_size_now(abfd,sec) \ +(sec->reloc_done \ + ? bfd_get_section_size_after_reloc (sec) \ + : bfd_get_section_size_before_reloc (sec)) + +bfd_boolean +bfd_set_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + bfd_size_type sz; + + if (!(bfd_get_section_flags (abfd, section) & SEC_HAS_CONTENTS)) + { + bfd_set_error (bfd_error_no_contents); + return FALSE; + } + + sz = bfd_get_section_size_now (abfd, section); + if ((bfd_size_type) offset > sz + || count > sz + || offset + count > sz + || count != (size_t) count) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + switch (abfd->direction) + { + case read_direction: + case no_direction: + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + + case write_direction: + break; + + case both_direction: + /* File is opened for update. `output_has_begun' some time ago when + the file was created. Do not recompute sections sizes or alignments + in _bfd_set_section_content. */ + abfd->output_has_begun = TRUE; + break; + } + + /* Record a copy of the data in memory if desired. */ + if (section->contents + && location != (PTR) (section->contents + offset)) + memcpy (section->contents + offset, location, (size_t) count); + + if (BFD_SEND (abfd, _bfd_set_section_contents, + (abfd, section, location, offset, count))) + { + abfd->output_has_begun = TRUE; + return TRUE; + } + + return FALSE; +} + +/* +FUNCTION + bfd_get_section_contents + +SYNOPSIS + bfd_boolean bfd_get_section_contents (bfd *abfd, asection *section, + PTR location, file_ptr offset, + bfd_size_type count); + +DESCRIPTION + Read data from @var{section} in BFD @var{abfd} + into memory starting at @var{location}. The data is read at an + offset of @var{offset} from the start of the input section, + and is read for @var{count} bytes. + + If the contents of a constructor with the <> + flag set are requested or if the section does not have the + <> flag set, then the @var{location} is filled + with zeroes. If no errors occur, <> is returned, else + <>. + +*/ +bfd_boolean +bfd_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + bfd_size_type sz; + + if (section->flags & SEC_CONSTRUCTOR) + { + memset (location, 0, (size_t) count); + return TRUE; + } + + /* Even if reloc_done is TRUE, this function reads unrelocated + contents, so we want the raw size. */ + sz = section->_raw_size; + if ((bfd_size_type) offset > sz + || count > sz + || offset + count > sz + || count != (size_t) count) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + if (count == 0) + /* Don't bother. */ + return TRUE; + + if ((section->flags & SEC_HAS_CONTENTS) == 0) + { + memset (location, 0, (size_t) count); + return TRUE; + } + + if ((section->flags & SEC_IN_MEMORY) != 0) + { + memcpy (location, section->contents + offset, (size_t) count); + return TRUE; + } + + return BFD_SEND (abfd, _bfd_get_section_contents, + (abfd, section, location, offset, count)); +} + +/* +FUNCTION + bfd_copy_private_section_data + +SYNOPSIS + bfd_boolean bfd_copy_private_section_data (bfd *ibfd, asection *isec, + bfd *obfd, asection *osec); + +DESCRIPTION + Copy private section information from @var{isec} in the BFD + @var{ibfd} to the section @var{osec} in the BFD @var{obfd}. + Return <> on success, <> on error. Possible error + returns are: + + o <> - + Not enough memory exists to create private data for @var{osec}. + +.#define bfd_copy_private_section_data(ibfd, isection, obfd, osection) \ +. BFD_SEND (obfd, _bfd_copy_private_section_data, \ +. (ibfd, isection, obfd, osection)) +*/ + +/* +FUNCTION + _bfd_strip_section_from_output + +SYNOPSIS + void _bfd_strip_section_from_output + (struct bfd_link_info *info, asection *section); + +DESCRIPTION + Remove @var{section} from the output. If the output section + becomes empty, remove it from the output bfd. + + This function won't actually do anything except twiddle flags + if called too late in the linking process, when it's not safe + to remove sections. +*/ +void +_bfd_strip_section_from_output (info, s) + struct bfd_link_info *info; + asection *s; +{ + asection *os; + asection *is; + bfd *abfd; + + s->flags |= SEC_EXCLUDE; + + /* If the section wasn't assigned to an output section, or the + section has been discarded by the linker script, there's nothing + more to do. */ + os = s->output_section; + if (os == NULL || os->owner == NULL) + return; + + /* If the output section has other (non-excluded) input sections, we + can't remove it. */ + for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) + for (is = abfd->sections; is != NULL; is = is->next) + if (is->output_section == os && (is->flags & SEC_EXCLUDE) == 0) + return; + + /* If the output section is empty, flag it for removal too. + See ldlang.c:strip_excluded_output_sections for the action. */ + os->flags |= SEC_EXCLUDE; +} + +/* +FUNCTION + bfd_generic_discard_group + +SYNOPSIS + bfd_boolean bfd_generic_discard_group (bfd *abfd, asection *group); + +DESCRIPTION + Remove all members of @var{group} from the output. +*/ + +bfd_boolean +bfd_generic_discard_group (abfd, group) + bfd *abfd ATTRIBUTE_UNUSED; + asection *group ATTRIBUTE_UNUSED; +{ + return TRUE; +} diff --git a/contrib/binutils-2.14/bfd/simple.c b/contrib/binutils-2.14/bfd/simple.c new file mode 100644 index 0000000000..a247f1153b --- /dev/null +++ b/contrib/binutils-2.14/bfd/simple.c @@ -0,0 +1,292 @@ +/* simple.c -- BFD simple client routines + Copyright 2002, 2003 + Free Software Foundation, Inc. + Contributed by MontaVista Software, 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "bfdlink.h" + +static bfd_boolean simple_dummy_warning + PARAMS ((struct bfd_link_info *, const char *, const char *, bfd *, + asection *, bfd_vma)); + +static bfd_boolean simple_dummy_undefined_symbol + PARAMS ((struct bfd_link_info *, const char *, bfd *, asection *, + bfd_vma, bfd_boolean)); + +static bfd_boolean simple_dummy_reloc_overflow + PARAMS ((struct bfd_link_info *, const char *, const char *, bfd_vma, + bfd *, asection *, bfd_vma)); + +static bfd_boolean simple_dummy_reloc_dangerous + PARAMS ((struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma)); + +static bfd_boolean simple_dummy_unattached_reloc + PARAMS ((struct bfd_link_info *, const char *, bfd *, asection *, bfd_vma)); + +static void simple_save_output_info + PARAMS ((bfd *, asection *, PTR)); + +static void simple_restore_output_info + PARAMS ((bfd *, asection *, PTR)); + +bfd_byte * bfd_simple_get_relocated_section_contents + PARAMS ((bfd *, asection *, bfd_byte *, asymbol **)); + +static bfd_boolean +simple_dummy_warning (link_info, warning, symbol, abfd, section, address) + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; + const char *warning ATTRIBUTE_UNUSED; + const char *symbol ATTRIBUTE_UNUSED; + bfd *abfd ATTRIBUTE_UNUSED; + asection *section ATTRIBUTE_UNUSED; + bfd_vma address ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +static bfd_boolean +simple_dummy_undefined_symbol (link_info, name, abfd, section, address, fatal) + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; + bfd *abfd ATTRIBUTE_UNUSED; + asection *section ATTRIBUTE_UNUSED; + bfd_vma address ATTRIBUTE_UNUSED; + bfd_boolean fatal ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +static bfd_boolean +simple_dummy_reloc_overflow (link_info, name, reloc_name, addend, abfd, + section, address) + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; + const char *reloc_name ATTRIBUTE_UNUSED; + bfd_vma addend ATTRIBUTE_UNUSED; + bfd *abfd ATTRIBUTE_UNUSED; + asection *section ATTRIBUTE_UNUSED; + bfd_vma address ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +static bfd_boolean +simple_dummy_reloc_dangerous (link_info, message, abfd, section, address) + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; + const char *message ATTRIBUTE_UNUSED; + bfd *abfd ATTRIBUTE_UNUSED; + asection *section ATTRIBUTE_UNUSED; + bfd_vma address ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +static bfd_boolean +simple_dummy_unattached_reloc (link_info, name, abfd, section, address) + struct bfd_link_info *link_info ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; + bfd *abfd ATTRIBUTE_UNUSED; + asection *section ATTRIBUTE_UNUSED; + bfd_vma address ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +struct saved_output_info +{ + bfd_vma offset; + asection *section; +}; + +static void +simple_save_output_info (abfd, section, ptr) + bfd *abfd ATTRIBUTE_UNUSED; + asection *section; + PTR ptr; +{ + struct saved_output_info *output_info = (struct saved_output_info *) ptr; + output_info[section->index].offset = section->output_offset; + output_info[section->index].section = section->output_section; + section->output_offset = 0; + section->output_section = section; +} + +static void +simple_restore_output_info (abfd, section, ptr) + bfd *abfd ATTRIBUTE_UNUSED; + asection *section; + PTR ptr; +{ + struct saved_output_info *output_info = (struct saved_output_info *) ptr; + section->output_offset = output_info[section->index].offset; + section->output_section = output_info[section->index].section; +} + +/* +FUNCTION + bfd_simple_relocate_secton + +SYNOPSIS + bfd_byte *bfd_simple_get_relocated_section_contents (bfd *abfd, asection *sec, bfd_byte *outbuf, asymbol **symbol_table); + +DESCRIPTION + Returns the relocated contents of section @var{sec}. The symbols in + @var{symbol_table} will be used, or the symbols from @var{abfd} if + @var{symbol_table} is NULL. The output offsets for all sections will + be temporarily reset to 0. The result will be stored at @var{outbuf} + or allocated with @code{bfd_malloc} if @var{outbuf} is @code{NULL}. + + Generally all sections in @var{abfd} should have their + @code{output_section} pointing back to the original section. + + Returns @code{NULL} on a fatal error; ignores errors applying + particular relocations. +*/ + +bfd_byte * +bfd_simple_get_relocated_section_contents (abfd, sec, outbuf, symbol_table) + bfd *abfd; + asection *sec; + bfd_byte *outbuf; + asymbol **symbol_table; +{ + struct bfd_link_info link_info; + struct bfd_link_order link_order; + struct bfd_link_callbacks callbacks; + bfd_byte *contents, *data; + int storage_needed; + PTR saved_offsets; + + if (! (sec->flags & SEC_RELOC)) + { + bfd_size_type size = bfd_section_size (abfd, sec); + + if (outbuf == NULL) + contents = bfd_malloc (size); + else + contents = outbuf; + + if (contents) + bfd_get_section_contents (abfd, sec, contents, 0, size); + + return contents; + } + + /* In order to use bfd_get_relocated_section_contents, we need + to forge some data structures that it expects. */ + + /* Fill in the bare minimum number of fields for our purposes. */ + memset (&link_info, 0, sizeof (link_info)); + link_info.input_bfds = abfd; + + link_info.hash = bfd_link_hash_table_create (abfd); + link_info.callbacks = &callbacks; + callbacks.warning = simple_dummy_warning; + callbacks.undefined_symbol = simple_dummy_undefined_symbol; + callbacks.reloc_overflow = simple_dummy_reloc_overflow; + callbacks.reloc_dangerous = simple_dummy_reloc_dangerous; + callbacks.unattached_reloc = simple_dummy_unattached_reloc; + + memset (&link_order, 0, sizeof (link_order)); + link_order.next = NULL; + link_order.type = bfd_indirect_link_order; + link_order.offset = 0; + link_order.size = bfd_section_size (abfd, sec); + link_order.u.indirect.section = sec; + + data = NULL; + if (outbuf == NULL) + { + data = bfd_malloc (bfd_section_size (abfd, sec)); + if (data == NULL) + return NULL; + outbuf = data; + } + + /* The sections in ABFD may already have output sections and offsets set. + Because this function is primarily for debug sections, and GCC uses the + knowledge that debug sections will generally have VMA 0 when emiting + relocations between DWARF-2 sections (which are supposed to be + section-relative offsets anyway), we need to reset the output offsets + to zero. We also need to arrange for section->output_section->vma plus + section->output_offset to equal section->vma, which we do by setting + section->output_section to point back to section. Save the original + output offset and output section to restore later. */ + saved_offsets = malloc (sizeof (struct saved_output_info) + * abfd->section_count); + if (saved_offsets == NULL) + { + if (data) + free (data); + return NULL; + } + bfd_map_over_sections (abfd, simple_save_output_info, saved_offsets); + + if (symbol_table == NULL) + { + bfd_link_add_symbols (abfd, &link_info); + + storage_needed = bfd_get_symtab_upper_bound (abfd); + symbol_table = (asymbol **) bfd_malloc (storage_needed); + bfd_canonicalize_symtab (abfd, symbol_table); + } + else + storage_needed = 0; + + contents = bfd_get_relocated_section_contents (abfd, + &link_info, + &link_order, + outbuf, + 0, + symbol_table); + if (contents == NULL && data != NULL) + free (data); + +#if 0 + /* NOTE: cagney/2003-04-05: This free, which was introduced on + 2003-03-31 to stop a memory leak, caused a memory corruption + between GDB and BFD. The problem, which is stabs specific, can + be identified by a bunch of failures in relocate.exp vis: + + gdb.base/relocate.exp: get address of static_bar + + Details of the problem can be found on the binutils@ mailing + list, see the discussion thread: "gdb.mi/mi-cli.exp failures". */ + if (storage_needed != 0) + free (symbol_table); +#endif + + bfd_map_over_sections (abfd, simple_restore_output_info, saved_offsets); + free (saved_offsets); + + /* Foul hack to prevent bfd_section_size aborts. This flag only controls + that macro (and the related size macros), selecting between _raw_size + and _cooked_size. Debug sections won't change size while we're only + relocating. There may be trouble here someday if it tries to run + relaxation unexpectedly, so make sure. */ + BFD_ASSERT (sec->_raw_size == sec->_cooked_size); + sec->reloc_done = 0; + + bfd_link_hash_table_free (abfd, link_info.hash); + + return contents; +} diff --git a/contrib/binutils-2.14/bfd/srec.c b/contrib/binutils-2.14/bfd/srec.c new file mode 100644 index 0000000000..cd31907ba9 --- /dev/null +++ b/contrib/binutils-2.14/bfd/srec.c @@ -0,0 +1,1403 @@ +/* BFD back-end for s-record objects. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 + Free Software Foundation, Inc. + Written by Steve Chamberlain of 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SUBSECTION + S-Record handling + +DESCRIPTION + + Ordinary S-Records cannot hold anything but addresses and + data, so that's all that we implement. + + The only interesting thing is that S-Records may come out of + order and there is no header, so an initial scan is required + to discover the minimum and maximum addresses used to create + the vma and size of the only section we create. We + arbitrarily call this section ".text". + + When bfd_get_section_contents is called the file is read + again, and this time the data is placed into a bfd_alloc'd + area. + + Any number of sections may be created for output, we save them + up and output them when it's time to close the bfd. + + An s record looks like: + +EXAMPLE + S
+ +DESCRIPTION + Where + o length + is the number of bytes following upto the checksum. Note that + this is not the number of chars following, since it takes two + chars to represent a byte. + o type + is one of: + 0) header record + 1) two byte address data record + 2) three byte address data record + 3) four byte address data record + 7) four byte address termination record + 8) three byte address termination record + 9) two byte address termination record + + o address + is the start address of the data following, or in the case of + a termination record, the start address of the image + o data + is the data. + o checksum + is the sum of all the raw byte data in the record, from the length + upwards, modulo 256 and subtracted from 255. + +SUBSECTION + Symbol S-Record handling + +DESCRIPTION + Some ICE equipment understands an addition to the standard + S-Record format; symbols and their addresses can be sent + before the data. + + The format of this is: + ($$ + (
)*) + $$ + + so a short symbol table could look like: + +EXAMPLE + $$ flash.x + $$ flash.c + _port6 $0 + _delay $4 + _start $14 + _etext $8036 + _edata $8036 + _end $8036 + $$ + +DESCRIPTION + We allow symbols to be anywhere in the data stream - the module names + are always ignored. + +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libiberty.h" +#include "safe-ctype.h" + +static void srec_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *)); +static void srec_print_symbol + PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type)); +static void srec_init PARAMS ((void)); +static bfd_boolean srec_mkobject PARAMS ((bfd *)); +static int srec_get_byte PARAMS ((bfd *, bfd_boolean *)); +static void srec_bad_byte PARAMS ((bfd *, unsigned int, int, bfd_boolean)); +static bfd_boolean srec_scan PARAMS ((bfd *)); +static const bfd_target *srec_object_p PARAMS ((bfd *)); +static const bfd_target *symbolsrec_object_p PARAMS ((bfd *)); +static bfd_boolean srec_read_section PARAMS ((bfd *, asection *, bfd_byte *)); + +static bfd_boolean srec_write_record + PARAMS ((bfd *, unsigned int, bfd_vma, const bfd_byte *, const bfd_byte *)); +static bfd_boolean srec_write_header PARAMS ((bfd *)); +static bfd_boolean srec_write_symbols PARAMS ((bfd *)); +static bfd_boolean srec_new_symbol PARAMS ((bfd *, const char *, bfd_vma)); +static bfd_boolean srec_get_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static bfd_boolean srec_set_arch_mach + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); +static bfd_boolean srec_set_section_contents + PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); +static bfd_boolean internal_srec_write_object_contents PARAMS ((bfd *, int)); +static bfd_boolean srec_write_object_contents PARAMS ((bfd *)); +static bfd_boolean symbolsrec_write_object_contents PARAMS ((bfd *)); +static int srec_sizeof_headers PARAMS ((bfd *, bfd_boolean)); +static long srec_get_symtab_upper_bound PARAMS ((bfd *)); +static long srec_get_symtab PARAMS ((bfd *, asymbol **)); + +/* Macros for converting between hex and binary. */ + +static const char digs[] = "0123456789ABCDEF"; + +#define NIBBLE(x) hex_value(x) +#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1])) +#define TOHEX(d, x, ch) \ + d[1] = digs[(x) & 0xf]; \ + d[0] = digs[((x)>>4)&0xf]; \ + ch += ((x) & 0xff); +#define ISHEX(x) hex_p(x) + +/* Initialize by filling in the hex conversion array. */ + +static void +srec_init () +{ + static bfd_boolean inited = FALSE; + + if (! inited) + { + inited = TRUE; + hex_init (); + } +} + +/* The maximum number of address+data+crc bytes on a line is FF. */ +#define MAXCHUNK 0xff + +/* Default size for a CHUNK. */ +#define DEFAULT_CHUNK 16 + +/* The number of data bytes we actually fit onto a line on output. + This variable can be modified by objcopy's --srec-len parameter. + For a 0x75 byte record you should set --srec-len=0x70. */ +unsigned int Chunk = DEFAULT_CHUNK; + +/* The type of srec output (free or forced to S3). + This variable can be modified by objcopy's --srec-forceS3 + parameter. */ +bfd_boolean S3Forced = FALSE; + +/* When writing an S-record file, the S-records can not be output as + they are seen. This structure is used to hold them in memory. */ + +struct srec_data_list_struct +{ + struct srec_data_list_struct *next; + bfd_byte *data; + bfd_vma where; + bfd_size_type size; +}; + +typedef struct srec_data_list_struct srec_data_list_type; + +/* When scanning the S-record file, a linked list of srec_symbol + structures is built to represent the symbol table (if there is + one). */ + +struct srec_symbol +{ + struct srec_symbol *next; + const char *name; + bfd_vma val; +}; + +/* The S-record tdata information. */ + +typedef struct srec_data_struct + { + srec_data_list_type *head; + srec_data_list_type *tail; + unsigned int type; + struct srec_symbol *symbols; + struct srec_symbol *symtail; + asymbol *csymbols; + } +tdata_type; + +static bfd_boolean srec_write_section + PARAMS ((bfd *, tdata_type *, srec_data_list_type *)); +static bfd_boolean srec_write_terminator + PARAMS ((bfd *, tdata_type *)); + +/* Set up the S-record tdata information. */ + +static bfd_boolean +srec_mkobject (abfd) + bfd *abfd; +{ + bfd_size_type amt; + tdata_type *tdata; + + srec_init (); + + amt = sizeof (tdata_type); + tdata = (tdata_type *) bfd_alloc (abfd, amt); + if (tdata == NULL) + return FALSE; + + abfd->tdata.srec_data = tdata; + tdata->type = 1; + tdata->head = NULL; + tdata->tail = NULL; + tdata->symbols = NULL; + tdata->symtail = NULL; + tdata->csymbols = NULL; + + return TRUE; +} + +/* Read a byte from an S record file. Set *ERRORPTR if an error + occurred. Return EOF on error or end of file. */ + +static int +srec_get_byte (abfd, errorptr) + bfd *abfd; + bfd_boolean *errorptr; +{ + bfd_byte c; + + if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1) + { + if (bfd_get_error () != bfd_error_file_truncated) + *errorptr = TRUE; + return EOF; + } + + return (int) (c & 0xff); +} + +/* Report a problem in an S record file. FIXME: This probably should + not call fprintf, but we really do need some mechanism for printing + error messages. */ + +static void +srec_bad_byte (abfd, lineno, c, error) + bfd *abfd; + unsigned int lineno; + int c; + bfd_boolean error; +{ + if (c == EOF) + { + if (! error) + bfd_set_error (bfd_error_file_truncated); + } + else + { + char buf[10]; + + if (! ISPRINT (c)) + sprintf (buf, "\\%03o", (unsigned int) c); + else + { + buf[0] = c; + buf[1] = '\0'; + } + (*_bfd_error_handler) + (_("%s:%d: Unexpected character `%s' in S-record file\n"), + bfd_archive_filename (abfd), lineno, buf); + bfd_set_error (bfd_error_bad_value); + } +} + +/* Add a new symbol found in an S-record file. */ + +static bfd_boolean +srec_new_symbol (abfd, name, val) + bfd *abfd; + const char *name; + bfd_vma val; +{ + struct srec_symbol *n; + bfd_size_type amt = sizeof (struct srec_symbol); + + n = (struct srec_symbol *) bfd_alloc (abfd, amt); + if (n == NULL) + return FALSE; + + n->name = name; + n->val = val; + + if (abfd->tdata.srec_data->symbols == NULL) + abfd->tdata.srec_data->symbols = n; + else + abfd->tdata.srec_data->symtail->next = n; + abfd->tdata.srec_data->symtail = n; + n->next = NULL; + + ++abfd->symcount; + + return TRUE; +} + +/* Read the S record file and turn it into sections. We create a new + section for each contiguous set of bytes. */ + +static bfd_boolean +srec_scan (abfd) + bfd *abfd; +{ + int c; + unsigned int lineno = 1; + bfd_boolean error = FALSE; + bfd_byte *buf = NULL; + size_t bufsize = 0; + asection *sec = NULL; + char *symbuf = NULL; + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + goto error_return; + + while ((c = srec_get_byte (abfd, &error)) != EOF) + { + /* We only build sections from contiguous S-records, so if this + is not an S-record, then stop building a section. */ + if (c != 'S' && c != '\r' && c != '\n') + sec = NULL; + + switch (c) + { + default: + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + + case '\n': + ++lineno; + break; + + case '\r': + break; + + case '$': + /* Starting a module name, which we ignore. */ + while ((c = srec_get_byte (abfd, &error)) != '\n' + && c != EOF) + ; + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + ++lineno; + + break; + + case ' ': + do + { + bfd_size_type alc; + char *p, *symname; + bfd_vma symval; + + /* Starting a symbol definition. */ + while ((c = srec_get_byte (abfd, &error)) != EOF + && (c == ' ' || c == '\t')) + ; + + if (c == '\n' || c == '\r') + break; + + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + alc = 10; + symbuf = (char *) bfd_malloc (alc + 1); + if (symbuf == NULL) + goto error_return; + + p = symbuf; + + *p++ = c; + while ((c = srec_get_byte (abfd, &error)) != EOF + && ! ISSPACE (c)) + { + if ((bfd_size_type) (p - symbuf) >= alc) + { + char *n; + + alc *= 2; + n = (char *) bfd_realloc (symbuf, alc + 1); + if (n == NULL) + goto error_return; + p = n + (p - symbuf); + symbuf = n; + } + + *p++ = c; + } + + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + *p++ = '\0'; + symname = bfd_alloc (abfd, (bfd_size_type) (p - symbuf)); + if (symname == NULL) + goto error_return; + strcpy (symname, symbuf); + free (symbuf); + symbuf = NULL; + + while ((c = srec_get_byte (abfd, &error)) != EOF + && (c == ' ' || c == '\t')) + ; + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + /* Skip a dollar sign before the hex value. */ + if (c == '$') + { + c = srec_get_byte (abfd, &error); + if (c == EOF) + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + } + + symval = 0; + while (ISHEX (c)) + { + symval <<= 4; + symval += NIBBLE (c); + c = srec_get_byte (abfd, &error); + } + + if (! srec_new_symbol (abfd, symname, symval)) + goto error_return; + } + while (c == ' ' || c == '\t') + ; + + if (c == '\n') + ++lineno; + else if (c != '\r') + { + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + break; + + case 'S': + { + file_ptr pos; + char hdr[3]; + unsigned int bytes; + bfd_vma address; + bfd_byte *data; + + /* Starting an S-record. */ + + pos = bfd_tell (abfd) - 1; + + if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3) + goto error_return; + + if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2])) + { + if (! ISHEX (hdr[1])) + c = hdr[1]; + else + c = hdr[2]; + srec_bad_byte (abfd, lineno, c, error); + goto error_return; + } + + bytes = HEX (hdr + 1); + if (bytes * 2 > bufsize) + { + if (buf != NULL) + free (buf); + buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2); + if (buf == NULL) + goto error_return; + bufsize = bytes * 2; + } + + if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2) + goto error_return; + + /* Ignore the checksum byte. */ + --bytes; + + address = 0; + data = buf; + switch (hdr[0]) + { + case '0': + case '5': + /* Prologue--ignore the file name, but stop building a + section at this point. */ + sec = NULL; + break; + + case '3': + address = HEX (data); + data += 2; + --bytes; + /* Fall through. */ + case '2': + address = (address << 8) | HEX (data); + data += 2; + --bytes; + /* Fall through. */ + case '1': + address = (address << 8) | HEX (data); + data += 2; + address = (address << 8) | HEX (data); + data += 2; + bytes -= 2; + + if (sec != NULL + && sec->vma + sec->_raw_size == address) + { + /* This data goes at the end of the section we are + currently building. */ + sec->_raw_size += bytes; + } + else + { + char secbuf[20]; + char *secname; + bfd_size_type amt; + + sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1); + amt = strlen (secbuf) + 1; + secname = (char *) bfd_alloc (abfd, amt); + strcpy (secname, secbuf); + sec = bfd_make_section (abfd, secname); + if (sec == NULL) + goto error_return; + sec->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; + sec->vma = address; + sec->lma = address; + sec->_raw_size = bytes; + sec->filepos = pos; + } + + break; + + case '7': + address = HEX (data); + data += 2; + /* Fall through. */ + case '8': + address = (address << 8) | HEX (data); + data += 2; + /* Fall through. */ + case '9': + address = (address << 8) | HEX (data); + data += 2; + address = (address << 8) | HEX (data); + data += 2; + + /* This is a termination record. */ + abfd->start_address = address; + + if (buf != NULL) + free (buf); + + return TRUE; + } + } + break; + } + } + + if (error) + goto error_return; + + if (buf != NULL) + free (buf); + + return TRUE; + + error_return: + if (symbuf != NULL) + free (symbuf); + if (buf != NULL) + free (buf); + return FALSE; +} + +/* Check whether an existing file is an S-record file. */ + +static const bfd_target * +srec_object_p (abfd) + bfd *abfd; +{ + PTR tdata_save; + bfd_byte b[4]; + + srec_init (); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || bfd_bread (b, (bfd_size_type) 4, abfd) != 4) + return NULL; + + if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + tdata_save = abfd->tdata.any; + if (! srec_mkobject (abfd) || ! srec_scan (abfd)) + { + if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) + bfd_release (abfd, abfd->tdata.any); + abfd->tdata.any = tdata_save; + return NULL; + } + + if (abfd->symcount > 0) + abfd->flags |= HAS_SYMS; + + return abfd->xvec; +} + +/* Check whether an existing file is an S-record file with symbols. */ + +static const bfd_target * +symbolsrec_object_p (abfd) + bfd *abfd; +{ + PTR tdata_save; + char b[2]; + + srec_init (); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || bfd_bread (b, (bfd_size_type) 2, abfd) != 2) + return NULL; + + if (b[0] != '$' || b[1] != '$') + { + bfd_set_error (bfd_error_wrong_format); + return NULL; + } + + tdata_save = abfd->tdata.any; + if (! srec_mkobject (abfd) || ! srec_scan (abfd)) + { + if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) + bfd_release (abfd, abfd->tdata.any); + abfd->tdata.any = tdata_save; + return NULL; + } + + if (abfd->symcount > 0) + abfd->flags |= HAS_SYMS; + + return abfd->xvec; +} + +/* Read in the contents of a section in an S-record file. */ + +static bfd_boolean +srec_read_section (abfd, section, contents) + bfd *abfd; + asection *section; + bfd_byte *contents; +{ + int c; + bfd_size_type sofar = 0; + bfd_boolean error = FALSE; + bfd_byte *buf = NULL; + size_t bufsize = 0; + + if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0) + goto error_return; + + while ((c = srec_get_byte (abfd, &error)) != EOF) + { + bfd_byte hdr[3]; + unsigned int bytes; + bfd_vma address; + bfd_byte *data; + + if (c == '\r' || c == '\n') + continue; + + /* This is called after srec_scan has already been called, so we + ought to know the exact format. */ + BFD_ASSERT (c == 'S'); + + if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3) + goto error_return; + + BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2])); + + bytes = HEX (hdr + 1); + + if (bytes * 2 > bufsize) + { + if (buf != NULL) + free (buf); + buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2); + if (buf == NULL) + goto error_return; + bufsize = bytes * 2; + } + + if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2) + goto error_return; + + address = 0; + data = buf; + switch (hdr[0]) + { + default: + BFD_ASSERT (sofar == section->_raw_size); + if (buf != NULL) + free (buf); + return TRUE; + + case '3': + address = HEX (data); + data += 2; + --bytes; + /* Fall through. */ + case '2': + address = (address << 8) | HEX (data); + data += 2; + --bytes; + /* Fall through. */ + case '1': + address = (address << 8) | HEX (data); + data += 2; + address = (address << 8) | HEX (data); + data += 2; + bytes -= 2; + + if (address != section->vma + sofar) + { + /* We've come to the end of this section. */ + BFD_ASSERT (sofar == section->_raw_size); + if (buf != NULL) + free (buf); + return TRUE; + } + + /* Don't consider checksum. */ + --bytes; + + while (bytes-- != 0) + { + contents[sofar] = HEX (data); + data += 2; + ++sofar; + } + + break; + } + } + + if (error) + goto error_return; + + BFD_ASSERT (sofar == section->_raw_size); + + if (buf != NULL) + free (buf); + + return TRUE; + + error_return: + if (buf != NULL) + free (buf); + return FALSE; +} + +/* Get the contents of a section in an S-record file. */ + +static bfd_boolean +srec_get_section_contents (abfd, section, location, offset, count) + bfd *abfd; + asection *section; + PTR location; + file_ptr offset; + bfd_size_type count; +{ + if (section->used_by_bfd == NULL) + { + section->used_by_bfd = bfd_alloc (abfd, section->_raw_size); + if (section->used_by_bfd == NULL && section->_raw_size != 0) + return FALSE; + + if (! srec_read_section (abfd, section, section->used_by_bfd)) + return FALSE; + } + + memcpy (location, (bfd_byte *) section->used_by_bfd + offset, + (size_t) count); + + return TRUE; +} + +/* Set the architecture. We accept an unknown architecture here. */ + +static bfd_boolean +srec_set_arch_mach (abfd, arch, mach) + bfd *abfd; + enum bfd_architecture arch; + unsigned long mach; +{ + if (arch == bfd_arch_unknown) + { + abfd->arch_info = &bfd_default_arch_struct; + return TRUE; + } + return bfd_default_set_arch_mach (abfd, arch, mach); +} + +/* We have to save up all the Srecords for a splurge before output. */ + +static bfd_boolean +srec_set_section_contents (abfd, section, location, offset, bytes_to_do) + bfd *abfd; + sec_ptr section; + PTR location; + file_ptr offset; + bfd_size_type bytes_to_do; +{ + tdata_type *tdata = abfd->tdata.srec_data; + register srec_data_list_type *entry; + + entry = ((srec_data_list_type *) + bfd_alloc (abfd, (bfd_size_type) sizeof (srec_data_list_type))); + if (entry == NULL) + return FALSE; + + if (bytes_to_do + && (section->flags & SEC_ALLOC) + && (section->flags & SEC_LOAD)) + { + bfd_byte *data; + + data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do); + if (data == NULL) + return FALSE; + memcpy ((PTR) data, location, (size_t) bytes_to_do); + + /* Ff S3Forced is TRUE then always select S3 records, + regardless of the siez of the addresses. */ + if (S3Forced) + tdata->type = 3; + else if ((section->lma + offset + bytes_to_do - 1) <= 0xffff) + ; /* The default, S1, is OK. */ + else if ((section->lma + offset + bytes_to_do - 1) <= 0xffffff + && tdata->type <= 2) + tdata->type = 2; + else + tdata->type = 3; + + entry->data = data; + entry->where = section->lma + offset; + entry->size = bytes_to_do; + + /* Sort the records by address. Optimize for the common case of + adding a record to the end of the list. */ + if (tdata->tail != NULL + && entry->where >= tdata->tail->where) + { + tdata->tail->next = entry; + entry->next = NULL; + tdata->tail = entry; + } + else + { + register srec_data_list_type **look; + + for (look = &tdata->head; + *look != NULL && (*look)->where < entry->where; + look = &(*look)->next) + ; + entry->next = *look; + *look = entry; + if (entry->next == NULL) + tdata->tail = entry; + } + } + return TRUE; +} + +/* Write a record of type, of the supplied number of bytes. The + supplied bytes and length don't have a checksum. That's worked out + here. */ + +static bfd_boolean +srec_write_record (abfd, type, address, data, end) + bfd *abfd; + unsigned int type; + bfd_vma address; + const bfd_byte *data; + const bfd_byte *end; +{ + char buffer[2 * MAXCHUNK + 6]; + unsigned int check_sum = 0; + const bfd_byte *src = data; + char *dst = buffer; + char *length; + bfd_size_type wrlen; + + *dst++ = 'S'; + *dst++ = '0' + type; + + length = dst; + dst += 2; /* Leave room for dst. */ + + switch (type) + { + case 3: + case 7: + TOHEX (dst, (address >> 24), check_sum); + dst += 2; + case 8: + case 2: + TOHEX (dst, (address >> 16), check_sum); + dst += 2; + case 9: + case 1: + case 0: + TOHEX (dst, (address >> 8), check_sum); + dst += 2; + TOHEX (dst, (address), check_sum); + dst += 2; + break; + + } + for (src = data; src < end; src++) + { + TOHEX (dst, *src, check_sum); + dst += 2; + } + + /* Fill in the length. */ + TOHEX (length, (dst - length) / 2, check_sum); + check_sum &= 0xff; + check_sum = 255 - check_sum; + TOHEX (dst, check_sum, check_sum); + dst += 2; + + *dst++ = '\r'; + *dst++ = '\n'; + wrlen = dst - buffer; + if (bfd_bwrite ((PTR) buffer, wrlen, abfd) != wrlen) + return FALSE; + return TRUE; +} + +static bfd_boolean +srec_write_header (abfd) + bfd *abfd; +{ + unsigned int len = strlen (abfd->filename); + + /* I'll put an arbitary 40 char limit on header size. */ + if (len > 40) + len = 40; + + return srec_write_record (abfd, 0, (bfd_vma) 0, + abfd->filename, abfd->filename + len); +} + +static bfd_boolean +srec_write_section (abfd, tdata, list) + bfd *abfd; + tdata_type *tdata; + srec_data_list_type *list; +{ + unsigned int octets_written = 0; + bfd_byte *location = list->data; + + /* Validate number of data bytes to write. The srec length byte + counts the address, data and crc bytes. S1 (tdata->type == 1) + records have two address bytes, S2 (tdata->type == 2) records + have three, and S3 (tdata->type == 3) records have four. + The total length can't exceed 255, and a zero data length will + spin for a long time. */ + if (Chunk == 0) + Chunk = 1; + else if (Chunk > MAXCHUNK - tdata->type - 2) + Chunk = MAXCHUNK - tdata->type - 2; + + while (octets_written < list->size) + { + bfd_vma address; + unsigned int octets_this_chunk = list->size - octets_written; + + if (octets_this_chunk > Chunk) + octets_this_chunk = Chunk; + + address = list->where + octets_written / bfd_octets_per_byte (abfd); + + if (! srec_write_record (abfd, + tdata->type, + address, + location, + location + octets_this_chunk)) + return FALSE; + + octets_written += octets_this_chunk; + location += octets_this_chunk; + } + + return TRUE; +} + +static bfd_boolean +srec_write_terminator (abfd, tdata) + bfd *abfd; + tdata_type *tdata; +{ + return srec_write_record (abfd, 10 - tdata->type, + abfd->start_address, NULL, NULL); +} + +static bfd_boolean +srec_write_symbols (abfd) + bfd *abfd; +{ + /* Dump out the symbols of a bfd. */ + int i; + int count = bfd_get_symcount (abfd); + + if (count) + { + bfd_size_type len; + asymbol **table = bfd_get_outsymbols (abfd); + len = strlen (abfd->filename); + if (bfd_bwrite ("$$ ", (bfd_size_type) 3, abfd) != 3 + || bfd_bwrite (abfd->filename, len, abfd) != len + || bfd_bwrite ("\r\n", (bfd_size_type) 2, abfd) != 2) + return FALSE; + + for (i = 0; i < count; i++) + { + asymbol *s = table[i]; + if (! bfd_is_local_label (abfd, s) + && (s->flags & BSF_DEBUGGING) == 0) + { + /* Just dump out non debug symbols. */ + char buf[43], *p; + + len = strlen (s->name); + if (bfd_bwrite (" ", (bfd_size_type) 2, abfd) != 2 + || bfd_bwrite (s->name, len, abfd) != len) + return FALSE; + + sprintf_vma (buf + 2, (s->value + + s->section->output_section->lma + + s->section->output_offset)); + p = buf + 2; + while (p[0] == '0' && p[1] != 0) + p++; + len = strlen (p); + p[len] = '\r'; + p[len + 1] = '\n'; + *--p = '$'; + *--p = ' '; + len += 4; + if (bfd_bwrite (p, len, abfd) != len) + return FALSE; + } + } + if (bfd_bwrite ("$$ \r\n", (bfd_size_type) 5, abfd) != 5) + return FALSE; + } + + return TRUE; +} + +static bfd_boolean +internal_srec_write_object_contents (abfd, symbols) + bfd *abfd; + int symbols; +{ + tdata_type *tdata = abfd->tdata.srec_data; + srec_data_list_type *list; + + if (symbols) + { + if (! srec_write_symbols (abfd)) + return FALSE; + } + + if (! srec_write_header (abfd)) + return FALSE; + + /* Now wander though all the sections provided and output them. */ + list = tdata->head; + + while (list != (srec_data_list_type *) NULL) + { + if (! srec_write_section (abfd, tdata, list)) + return FALSE; + list = list->next; + } + return srec_write_terminator (abfd, tdata); +} + +static bfd_boolean +srec_write_object_contents (abfd) + bfd *abfd; +{ + return internal_srec_write_object_contents (abfd, 0); +} + +static bfd_boolean +symbolsrec_write_object_contents (abfd) + bfd *abfd; +{ + return internal_srec_write_object_contents (abfd, 1); +} + +static int +srec_sizeof_headers (abfd, exec) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_boolean exec ATTRIBUTE_UNUSED; +{ + return 0; +} + +/* Return the amount of memory needed to read the symbol table. */ + +static long +srec_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *); +} + +/* Return the symbol table. */ + +static long +srec_get_symtab (abfd, alocation) + bfd *abfd; + asymbol **alocation; +{ + bfd_size_type symcount = bfd_get_symcount (abfd); + asymbol *csymbols; + unsigned int i; + + csymbols = abfd->tdata.srec_data->csymbols; + if (csymbols == NULL) + { + asymbol *c; + struct srec_symbol *s; + + csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol)); + if (csymbols == NULL && symcount != 0) + return 0; + abfd->tdata.srec_data->csymbols = csymbols; + + for (s = abfd->tdata.srec_data->symbols, c = csymbols; + s != NULL; + s = s->next, ++c) + { + c->the_bfd = abfd; + c->name = s->name; + c->value = s->val; + c->flags = BSF_GLOBAL; + c->section = bfd_abs_section_ptr; + c->udata.p = NULL; + } + } + + for (i = 0; i < symcount; i++) + *alocation++ = csymbols++; + *alocation = NULL; + + return symcount; +} + +static void +srec_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +static void +srec_print_symbol (abfd, afile, symbol, how) + bfd *abfd; + PTR afile; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) afile; + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + default: + bfd_print_symbol_vandf (abfd, (PTR) file, symbol); + fprintf (file, " %-5s %s", + symbol->section->name, + symbol->name); + + } +} + +#define srec_close_and_cleanup _bfd_generic_close_and_cleanup +#define srec_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define srec_new_section_hook _bfd_generic_new_section_hook + +#define srec_bfd_is_local_label_name bfd_generic_is_local_label_name +#define srec_get_lineno _bfd_nosymbols_get_lineno +#define srec_find_nearest_line _bfd_nosymbols_find_nearest_line +#define srec_make_empty_symbol _bfd_generic_make_empty_symbol +#define srec_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define srec_read_minisymbols _bfd_generic_read_minisymbols +#define srec_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define srec_get_reloc_upper_bound \ + ((long (*) PARAMS ((bfd *, asection *))) bfd_0l) +#define srec_canonicalize_reloc \ + ((long (*) PARAMS ((bfd *, asection *, arelent **, asymbol **))) bfd_0l) +#define srec_bfd_reloc_type_lookup _bfd_norelocs_bfd_reloc_type_lookup + +#define srec_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +#define srec_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define srec_bfd_relax_section bfd_generic_relax_section +#define srec_bfd_gc_sections bfd_generic_gc_sections +#define srec_bfd_merge_sections bfd_generic_merge_sections +#define srec_bfd_discard_group bfd_generic_discard_group +#define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define srec_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +#define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define srec_bfd_link_just_syms _bfd_generic_link_just_syms +#define srec_bfd_final_link _bfd_generic_final_link +#define srec_bfd_link_split_section _bfd_generic_link_split_section + +const bfd_target srec_vec = +{ + "srec", /* name */ + bfd_target_srec_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + srec_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + srec_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + srec_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (srec), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (srec), + BFD_JUMP_TABLE_RELOCS (srec), + BFD_JUMP_TABLE_WRITE (srec), + BFD_JUMP_TABLE_LINK (srec), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + NULL, + + (PTR) 0 +}; + +const bfd_target symbolsrec_vec = +{ + "symbolsrec", /* name */ + bfd_target_srec_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (HAS_RELOC | EXEC_P | /* object flags */ + HAS_LINENO | HAS_DEBUG | + HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + symbolsrec_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + srec_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + symbolsrec_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (srec), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (srec), + BFD_JUMP_TABLE_RELOCS (srec), + BFD_JUMP_TABLE_WRITE (srec), + BFD_JUMP_TABLE_LINK (srec), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + NULL, + + (PTR) 0 +}; diff --git a/contrib/binutils-2.14/bfd/stab-syms.c b/contrib/binutils-2.14/bfd/stab-syms.c new file mode 100644 index 0000000000..a685e31eb8 --- /dev/null +++ b/contrib/binutils-2.14/bfd/stab-syms.c @@ -0,0 +1,58 @@ +/* Table of stab names for the BFD library. + Copyright 1990, 1991, 1992, 1994, 1995, 1996, 2000 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" + +#define ARCH_SIZE 32 /* Value doesn't matter. */ +#include "libaout.h" +#include "aout/aout64.h" + +/* Ignore duplicate stab codes; just return the string for the first + one. */ +#define __define_stab(NAME, CODE, STRING) __define_name(CODE, STRING) +#define __define_stab_duplicate(NAME, CODE, STRING) + +/* These are not really stab symbols, but it is + convenient to have them here for the sake of nm. + For completeness, we could also add N_TEXT etc, but those + are never needed, since nm treats those specially. */ +#define EXTRA_SYMBOLS \ + __define_name (N_SETA, "SETA")/* Absolute set element symbol */ \ + __define_name (N_SETT, "SETT")/* Text set element symbol */ \ + __define_name (N_SETD, "SETD")/* Data set element symbol */ \ + __define_name (N_SETB, "SETB")/* Bss set element symbol */ \ + __define_name (N_SETV, "SETV")/* Pointer to set vector in data area. */ \ + __define_name (N_INDR, "INDR") \ + __define_name (N_WARNING, "WARNING") + +const char * +bfd_get_stab_name (code) + int code; +{ + switch (code) + { +#define __define_name(val, str) case val: return str; +#include "aout/stab.def" + EXTRA_SYMBOLS + } + + return (const char *) 0; +} diff --git a/contrib/binutils-2.14/bfd/stabs.c b/contrib/binutils-2.14/bfd/stabs.c new file mode 100644 index 0000000000..6e6d290d46 --- /dev/null +++ b/contrib/binutils-2.14/bfd/stabs.c @@ -0,0 +1,836 @@ +/* Stabs in sections linking support. + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + Written by Ian Lance Taylor, 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file contains support for linking stabs in sections, as used + on COFF and ELF. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "aout/stab_gnu.h" +#include "safe-ctype.h" + +/* Stabs entries use a 12 byte format: + 4 byte string table index + 1 byte stab type + 1 byte stab other field + 2 byte stab desc field + 4 byte stab value + FIXME: This will have to change for a 64 bit object format. + + The stabs symbols are divided into compilation units. For the + first entry in each unit, the type of 0, the value is the length of + the string table for this unit, and the desc field is the number of + stabs symbols for this unit. */ + +#define STRDXOFF (0) +#define TYPEOFF (4) +#define OTHEROFF (5) +#define DESCOFF (6) +#define VALOFF (8) +#define STABSIZE (12) + +/* A hash table used for header files with N_BINCL entries. */ + +struct stab_link_includes_table +{ + struct bfd_hash_table root; +}; + +/* A linked list of totals that we have found for a particular header + file. */ + +struct stab_link_includes_totals +{ + struct stab_link_includes_totals *next; + bfd_vma total; +}; + +/* An entry in the header file hash table. */ + +struct stab_link_includes_entry +{ + struct bfd_hash_entry root; + /* List of totals we have found for this file. */ + struct stab_link_includes_totals *totals; +}; + +/* Look up an entry in an the header file hash table. */ + +#define stab_link_includes_lookup(table, string, create, copy) \ + ((struct stab_link_includes_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +/* This structure is used to hold a list of N_BINCL symbols, some of + which might be converted into N_EXCL symbols. */ + +struct stab_excl_list +{ + /* The next symbol to convert. */ + struct stab_excl_list *next; + /* The offset to this symbol in the section contents. */ + bfd_size_type offset; + /* The value to use for the symbol. */ + bfd_vma val; + /* The type of this symbol (N_BINCL or N_EXCL). */ + int type; +}; + +/* This structure is stored with each .stab section. */ + +struct stab_section_info +{ + /* This is a linked list of N_BINCL symbols which should be + converted into N_EXCL symbols. */ + struct stab_excl_list *excls; + + /* This is used to map input stab offsets within their sections + to output stab offsets, to take into account stabs that have + been deleted. If it is NULL, the output offsets are the same + as the input offsets, because no stabs have been deleted from + this section. Otherwise the i'th entry is the number of + bytes of stabs that have been deleted prior to the i'th + stab. */ + bfd_size_type *cumulative_skips; + + /* This is an array of string indices. For each stab symbol, we + store the string index here. If a stab symbol should not be + included in the final output, the string index is -1. */ + bfd_size_type stridxs[1]; +}; + +/* This structure is used to keep track of stabs in sections + information while linking. */ + +struct stab_info +{ + /* A hash table used to hold stabs strings. */ + struct bfd_strtab_hash *strings; + /* The header file hash table. */ + struct stab_link_includes_table includes; + /* The first .stabstr section. */ + asection *stabstr; +}; + +static struct bfd_hash_entry *stab_link_includes_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); + +/* The function to create a new entry in the header file hash table. */ + +static struct bfd_hash_entry * +stab_link_includes_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct stab_link_includes_entry *ret = + (struct stab_link_includes_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct stab_link_includes_entry *) NULL) + ret = ((struct stab_link_includes_entry *) + bfd_hash_allocate (table, + sizeof (struct stab_link_includes_entry))); + if (ret == (struct stab_link_includes_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct stab_link_includes_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + if (ret) + { + /* Set local fields. */ + ret->totals = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* This function is called for each input file from the add_symbols + pass of the linker. */ + +bfd_boolean +_bfd_link_section_stabs (abfd, psinfo, stabsec, stabstrsec, psecinfo) + bfd *abfd; + PTR *psinfo; + asection *stabsec; + asection *stabstrsec; + PTR *psecinfo; +{ + bfd_boolean first; + struct stab_info *sinfo; + bfd_size_type count, amt; + struct stab_section_info *secinfo; + bfd_byte *stabbuf = NULL; + bfd_byte *stabstrbuf = NULL; + bfd_byte *sym, *symend; + bfd_size_type stroff, next_stroff, skip; + bfd_size_type *pstridx; + + if (stabsec->_raw_size == 0 + || stabstrsec->_raw_size == 0) + { + /* This file does not contain stabs debugging information. */ + return TRUE; + } + + if (stabsec->_raw_size % STABSIZE != 0) + { + /* Something is wrong with the format of these stab symbols. + Don't try to optimize them. */ + return TRUE; + } + + if ((stabstrsec->flags & SEC_RELOC) != 0) + { + /* We shouldn't see relocations in the strings, and we aren't + prepared to handle them. */ + return TRUE; + } + + if ((stabsec->output_section != NULL + && bfd_is_abs_section (stabsec->output_section)) + || (stabstrsec->output_section != NULL + && bfd_is_abs_section (stabstrsec->output_section))) + { + /* At least one of the sections is being discarded from the + link, so we should just ignore them. */ + return TRUE; + } + + first = FALSE; + + if (*psinfo == NULL) + { + /* Initialize the stabs information we need to keep track of. */ + first = TRUE; + amt = sizeof (struct stab_info); + *psinfo = (PTR) bfd_alloc (abfd, amt); + if (*psinfo == NULL) + goto error_return; + sinfo = (struct stab_info *) *psinfo; + sinfo->strings = _bfd_stringtab_init (); + if (sinfo->strings == NULL) + goto error_return; + /* Make sure the first byte is zero. */ + (void) _bfd_stringtab_add (sinfo->strings, "", TRUE, TRUE); + if (! bfd_hash_table_init_n (&sinfo->includes.root, + stab_link_includes_newfunc, + 251)) + goto error_return; + sinfo->stabstr = bfd_make_section_anyway (abfd, ".stabstr"); + sinfo->stabstr->flags |= SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING; + } + + sinfo = (struct stab_info *) *psinfo; + + /* Initialize the information we are going to store for this .stab + section. */ + + count = stabsec->_raw_size / STABSIZE; + + amt = sizeof (struct stab_section_info); + amt += (count - 1) * sizeof (bfd_size_type); + *psecinfo = bfd_alloc (abfd, amt); + if (*psecinfo == NULL) + goto error_return; + + secinfo = (struct stab_section_info *) *psecinfo; + secinfo->excls = NULL; + secinfo->cumulative_skips = NULL; + memset (secinfo->stridxs, 0, (size_t) count * sizeof (bfd_size_type)); + + /* Read the stabs information from abfd. */ + + stabbuf = (bfd_byte *) bfd_malloc (stabsec->_raw_size); + stabstrbuf = (bfd_byte *) bfd_malloc (stabstrsec->_raw_size); + if (stabbuf == NULL || stabstrbuf == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, stabsec, stabbuf, (bfd_vma) 0, + stabsec->_raw_size) + || ! bfd_get_section_contents (abfd, stabstrsec, stabstrbuf, (bfd_vma) 0, + stabstrsec->_raw_size)) + goto error_return; + + /* Look through the stabs symbols, work out the new string indices, + and identify N_BINCL symbols which can be eliminated. */ + + stroff = 0; + next_stroff = 0; + skip = 0; + + symend = stabbuf + stabsec->_raw_size; + for (sym = stabbuf, pstridx = secinfo->stridxs; + sym < symend; + sym += STABSIZE, ++pstridx) + { + bfd_size_type symstroff; + int type; + const char *string; + + if (*pstridx != 0) + { + /* This symbol has already been handled by an N_BINCL pass. */ + continue; + } + + type = sym[TYPEOFF]; + + if (type == 0) + { + /* Special type 0 stabs indicate the offset to the next + string table. We only copy the very first one. */ + stroff = next_stroff; + next_stroff += bfd_get_32 (abfd, sym + 8); + if (! first) + { + *pstridx = (bfd_size_type) -1; + ++skip; + continue; + } + first = FALSE; + } + + /* Store the string in the hash table, and record the index. */ + symstroff = stroff + bfd_get_32 (abfd, sym + STRDXOFF); + if (symstroff >= stabstrsec->_raw_size) + { + (*_bfd_error_handler) + (_("%s(%s+0x%lx): Stabs entry has invalid string index."), + bfd_archive_filename (abfd), + bfd_get_section_name (abfd, stabsec), + (long) (sym - stabbuf)); + bfd_set_error (bfd_error_bad_value); + goto error_return; + } + string = (char *) stabstrbuf + symstroff; + *pstridx = _bfd_stringtab_add (sinfo->strings, string, TRUE, TRUE); + + /* An N_BINCL symbol indicates the start of the stabs entries + for a header file. We need to scan ahead to the next N_EINCL + symbol, ignoring nesting, adding up all the characters in the + symbol names, not including the file numbers in types (the + first number after an open parenthesis). */ + if (type == (int) N_BINCL) + { + bfd_vma val; + int nest; + bfd_byte *incl_sym; + struct stab_link_includes_entry *incl_entry; + struct stab_link_includes_totals *t; + struct stab_excl_list *ne; + + val = 0; + nest = 0; + for (incl_sym = sym + STABSIZE; + incl_sym < symend; + incl_sym += STABSIZE) + { + int incl_type; + + incl_type = incl_sym[TYPEOFF]; + if (incl_type == 0) + break; + else if (incl_type == (int) N_EINCL) + { + if (nest == 0) + break; + --nest; + } + else if (incl_type == (int) N_BINCL) + ++nest; + else if (nest == 0) + { + const char *str; + + str = ((char *) stabstrbuf + + stroff + + bfd_get_32 (abfd, incl_sym + STRDXOFF)); + for (; *str != '\0'; str++) + { + val += *str; + if (*str == '(') + { + /* Skip the file number. */ + ++str; + while (ISDIGIT (*str)) + ++str; + --str; + } + } + } + } + + /* If we have already included a header file with the same + value, then replaced this one with an N_EXCL symbol. */ + incl_entry = stab_link_includes_lookup (&sinfo->includes, string, + TRUE, TRUE); + if (incl_entry == NULL) + goto error_return; + + for (t = incl_entry->totals; t != NULL; t = t->next) + if (t->total == val) + break; + + /* Record this symbol, so that we can set the value + correctly. */ + amt = sizeof *ne; + ne = (struct stab_excl_list *) bfd_alloc (abfd, amt); + if (ne == NULL) + goto error_return; + ne->offset = sym - stabbuf; + ne->val = val; + ne->type = (int) N_BINCL; + ne->next = secinfo->excls; + secinfo->excls = ne; + + if (t == NULL) + { + /* This is the first time we have seen this header file + with this set of stabs strings. */ + t = ((struct stab_link_includes_totals *) + bfd_hash_allocate (&sinfo->includes.root, sizeof *t)); + if (t == NULL) + goto error_return; + t->total = val; + t->next = incl_entry->totals; + incl_entry->totals = t; + } + else + { + bfd_size_type *incl_pstridx; + + /* We have seen this header file before. Tell the final + pass to change the type to N_EXCL. */ + ne->type = (int) N_EXCL; + + /* Mark the skipped symbols. */ + + nest = 0; + for (incl_sym = sym + STABSIZE, incl_pstridx = pstridx + 1; + incl_sym < symend; + incl_sym += STABSIZE, ++incl_pstridx) + { + int incl_type; + + incl_type = incl_sym[TYPEOFF]; + + if (incl_type == (int) N_EINCL) + { + if (nest == 0) + { + *incl_pstridx = (bfd_size_type) -1; + ++skip; + break; + } + --nest; + } + else if (incl_type == (int) N_BINCL) + ++nest; + else if (nest == 0) + { + *incl_pstridx = (bfd_size_type) -1; + ++skip; + } + } + } + } + } + + free (stabbuf); + stabbuf = NULL; + free (stabstrbuf); + stabstrbuf = NULL; + + /* We need to set the section sizes such that the linker will + compute the output section sizes correctly. We set the .stab + size to not include the entries we don't want. We set + SEC_EXCLUDE for the .stabstr section, so that it will be dropped + from the link. We record the size of the strtab in the first + .stabstr section we saw, and make sure we don't set SEC_EXCLUDE + for that section. */ + stabsec->_cooked_size = (count - skip) * STABSIZE; + if (stabsec->_cooked_size == 0) + stabsec->flags |= SEC_EXCLUDE; + stabstrsec->flags |= SEC_EXCLUDE; + sinfo->stabstr->_cooked_size = _bfd_stringtab_size (sinfo->strings); + + /* Calculate the `cumulative_skips' array now that stabs have been + deleted for this section. */ + + if (skip != 0) + { + bfd_size_type i, offset; + bfd_size_type *pskips; + + amt = count * sizeof (bfd_size_type); + secinfo->cumulative_skips = (bfd_size_type *) bfd_alloc (abfd, amt); + if (secinfo->cumulative_skips == NULL) + goto error_return; + + pskips = secinfo->cumulative_skips; + pstridx = secinfo->stridxs; + offset = 0; + + for (i = 0; i < count; i++, pskips++, pstridx++) + { + *pskips = offset; + if (*pstridx == (bfd_size_type) -1) + offset += STABSIZE; + } + + BFD_ASSERT (offset != 0); + } + + return TRUE; + + error_return: + if (stabbuf != NULL) + free (stabbuf); + if (stabstrbuf != NULL) + free (stabstrbuf); + return FALSE; +} + + +/* This function is called for each input file before the stab + section is relocated. It discards stab entries for discarded + functions and variables. The function returns TRUE iff + any entries have been deleted. +*/ + +bfd_boolean +_bfd_discard_section_stabs (abfd, stabsec, psecinfo, + reloc_symbol_deleted_p, cookie) + bfd *abfd; + asection *stabsec; + PTR psecinfo; + bfd_boolean (*reloc_symbol_deleted_p) PARAMS ((bfd_vma, PTR)); + PTR cookie; +{ + bfd_size_type count, amt; + struct stab_section_info *secinfo; + bfd_byte *stabbuf = NULL; + bfd_byte *sym, *symend; + bfd_size_type skip; + bfd_size_type *pstridx; + int deleting; + + if (stabsec->_raw_size == 0) + { + /* This file does not contain stabs debugging information. */ + return FALSE; + } + + if (stabsec->_raw_size % STABSIZE != 0) + { + /* Something is wrong with the format of these stab symbols. + Don't try to optimize them. */ + return FALSE; + } + + if ((stabsec->output_section != NULL + && bfd_is_abs_section (stabsec->output_section))) + { + /* At least one of the sections is being discarded from the + link, so we should just ignore them. */ + return FALSE; + } + + /* We should have initialized our data in _bfd_link_stab_sections. + If there was some bizarre error reading the string sections, though, + we might not have. Bail rather than asserting. */ + if (psecinfo == NULL) + return FALSE; + + count = stabsec->_raw_size / STABSIZE; + secinfo = (struct stab_section_info *) psecinfo; + + /* Read the stabs information from abfd. */ + + stabbuf = (bfd_byte *) bfd_malloc (stabsec->_raw_size); + if (stabbuf == NULL) + goto error_return; + + if (! bfd_get_section_contents (abfd, stabsec, stabbuf, (bfd_vma) 0, + stabsec->_raw_size)) + goto error_return; + + /* Look through the stabs symbols and discard any information for + discarded functions. */ + + skip = 0; + deleting = -1; + + symend = stabbuf + stabsec->_raw_size; + for (sym = stabbuf, pstridx = secinfo->stridxs; + sym < symend; + sym += STABSIZE, ++pstridx) + { + int type; + + if (*pstridx == (bfd_size_type) -1) + { + /* This stab was deleted in a previous pass. */ + continue; + } + + type = sym[TYPEOFF]; + + if (type == (int) N_FUN) + { + int strx = bfd_get_32 (abfd, sym + STRDXOFF); + + if (strx == 0) + { + if (deleting) + { + skip++; + *pstridx = -1; + } + deleting = -1; + continue; + } + deleting = 0; + if ((*reloc_symbol_deleted_p) (sym + VALOFF - stabbuf, cookie)) + deleting = 1; + } + + if (deleting == 1) + { + *pstridx = -1; + skip++; + } + else if (deleting == -1) + { + /* Outside of a function. Check for deleted variables. */ + if (type == (int) N_STSYM || type == (int) N_LCSYM) + if ((*reloc_symbol_deleted_p) (sym + VALOFF - stabbuf, cookie)) + { + *pstridx = -1; + skip ++; + } + /* We should also check for N_GSYM entries which reference a + deleted global, but those are less harmful to debuggers + and would require parsing the stab strings. */ + } + } + + free (stabbuf); + stabbuf = NULL; + + /* Shrink the stabsec as needed. */ + stabsec->_cooked_size -= skip * STABSIZE; + if (stabsec->_cooked_size == 0) + stabsec->flags |= SEC_EXCLUDE; + + /* Recalculate the `cumulative_skips' array now that stabs have been + deleted for this section. */ + + if (skip != 0) + { + bfd_size_type i, offset; + bfd_size_type *pskips; + + if (secinfo->cumulative_skips == NULL) + { + amt = count * sizeof (bfd_size_type); + secinfo->cumulative_skips = (bfd_size_type *) bfd_alloc (abfd, amt); + if (secinfo->cumulative_skips == NULL) + goto error_return; + } + + pskips = secinfo->cumulative_skips; + pstridx = secinfo->stridxs; + offset = 0; + + for (i = 0; i < count; i++, pskips++, pstridx++) + { + *pskips = offset; + if (*pstridx == (bfd_size_type) -1) + offset += STABSIZE; + } + + BFD_ASSERT (offset != 0); + } + + return skip > 0; + + error_return: + if (stabbuf != NULL) + free (stabbuf); + return FALSE; +} + +/* Write out the stab section. This is called with the relocated + contents. */ + +bfd_boolean +_bfd_write_section_stabs (output_bfd, psinfo, stabsec, psecinfo, contents) + bfd *output_bfd; + PTR *psinfo; + asection *stabsec; + PTR *psecinfo; + bfd_byte *contents; +{ + struct stab_info *sinfo; + struct stab_section_info *secinfo; + struct stab_excl_list *e; + bfd_byte *sym, *tosym, *symend; + bfd_size_type *pstridx; + + sinfo = (struct stab_info *) *psinfo; + secinfo = (struct stab_section_info *) *psecinfo; + + if (secinfo == NULL) + return bfd_set_section_contents (output_bfd, stabsec->output_section, + contents, + (file_ptr) stabsec->output_offset, + stabsec->_raw_size); + + /* Handle each N_BINCL entry. */ + for (e = secinfo->excls; e != NULL; e = e->next) + { + bfd_byte *excl_sym; + + BFD_ASSERT (e->offset < stabsec->_raw_size); + excl_sym = contents + e->offset; + bfd_put_32 (output_bfd, e->val, excl_sym + VALOFF); + excl_sym[TYPEOFF] = e->type; + } + + /* Copy over all the stabs symbols, omitting the ones we don't want, + and correcting the string indices for those we do want. */ + tosym = contents; + symend = contents + stabsec->_raw_size; + for (sym = contents, pstridx = secinfo->stridxs; + sym < symend; + sym += STABSIZE, ++pstridx) + { + if (*pstridx != (bfd_size_type) -1) + { + if (tosym != sym) + memcpy (tosym, sym, STABSIZE); + bfd_put_32 (output_bfd, *pstridx, tosym + STRDXOFF); + + if (sym[TYPEOFF] == 0) + { + /* This is the header symbol for the stabs section. We + don't really need one, since we have merged all the + input stabs sections into one, but we generate one + for the benefit of readers which expect to see one. */ + BFD_ASSERT (sym == contents); + bfd_put_32 (output_bfd, _bfd_stringtab_size (sinfo->strings), + tosym + VALOFF); + bfd_put_16 (output_bfd, + stabsec->output_section->_raw_size / STABSIZE - 1, + tosym + DESCOFF); + } + + tosym += STABSIZE; + } + } + + BFD_ASSERT ((bfd_size_type) (tosym - contents) == stabsec->_cooked_size); + + return bfd_set_section_contents (output_bfd, stabsec->output_section, + contents, (file_ptr) stabsec->output_offset, + stabsec->_cooked_size); +} + +/* Write out the .stabstr section. */ + +bfd_boolean +_bfd_write_stab_strings (output_bfd, psinfo) + bfd *output_bfd; + PTR *psinfo; +{ + struct stab_info *sinfo; + + sinfo = (struct stab_info *) *psinfo; + + if (sinfo == NULL) + return TRUE; + + if (bfd_is_abs_section (sinfo->stabstr->output_section)) + { + /* The section was discarded from the link. */ + return TRUE; + } + + BFD_ASSERT ((sinfo->stabstr->output_offset + + _bfd_stringtab_size (sinfo->strings)) + <= sinfo->stabstr->output_section->_raw_size); + + if (bfd_seek (output_bfd, + (file_ptr) (sinfo->stabstr->output_section->filepos + + sinfo->stabstr->output_offset), + SEEK_SET) != 0) + return FALSE; + + if (! _bfd_stringtab_emit (output_bfd, sinfo->strings)) + return FALSE; + + /* We no longer need the stabs information. */ + _bfd_stringtab_free (sinfo->strings); + bfd_hash_table_free (&sinfo->includes.root); + + return TRUE; +} + +/* Adjust an address in the .stab section. Given OFFSET within + STABSEC, this returns the new offset in the adjusted stab section, + or -1 if the address refers to a stab which has been removed. */ + +bfd_vma +_bfd_stab_section_offset (output_bfd, psinfo, stabsec, psecinfo, offset) + bfd *output_bfd ATTRIBUTE_UNUSED; + PTR *psinfo ATTRIBUTE_UNUSED; + asection *stabsec; + PTR *psecinfo; + bfd_vma offset; +{ + struct stab_section_info *secinfo; + + secinfo = (struct stab_section_info *) *psecinfo; + + if (secinfo == NULL) + return offset; + + if (offset >= stabsec->_raw_size) + return offset - (stabsec->_cooked_size - stabsec->_raw_size); + + if (secinfo->cumulative_skips) + { + bfd_vma i; + + i = offset / STABSIZE; + + if (secinfo->stridxs [i] == (bfd_size_type) -1) + return (bfd_vma) -1; + + return offset - secinfo->cumulative_skips [i]; + } + + return offset; +} diff --git a/contrib/binutils-2.14/bfd/syms.c b/contrib/binutils-2.14/bfd/syms.c new file mode 100644 index 0000000000..d65a8689ca --- /dev/null +++ b/contrib/binutils-2.14/bfd/syms.c @@ -0,0 +1,1385 @@ +/* Generic symbol-table support for the BFD library. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SECTION + Symbols + + BFD tries to maintain as much symbol information as it can when + it moves information from file to file. BFD passes information + to applications though the <> structure. When the + application requests the symbol table, BFD reads the table in + the native form and translates parts of it into the internal + format. To maintain more than the information passed to + applications, some targets keep some information ``behind the + scenes'' in a structure only the particular back end knows + about. For example, the coff back end keeps the original + symbol table structure as well as the canonical structure when + a BFD is read in. On output, the coff back end can reconstruct + the output symbol table so that no information is lost, even + information unique to coff which BFD doesn't know or + understand. If a coff symbol table were read, but were written + through an a.out back end, all the coff specific information + would be lost. The symbol table of a BFD + is not necessarily read in until a canonicalize request is + made. Then the BFD back end fills in a table provided by the + application with pointers to the canonical information. To + output symbols, the application provides BFD with a table of + pointers to pointers to <>s. This allows applications + like the linker to output a symbol as it was read, since the ``behind + the scenes'' information will be still available. +@menu +@* Reading Symbols:: +@* Writing Symbols:: +@* Mini Symbols:: +@* typedef asymbol:: +@* symbol handling functions:: +@end menu + +INODE +Reading Symbols, Writing Symbols, Symbols, Symbols +SUBSECTION + Reading symbols + + There are two stages to reading a symbol table from a BFD: + allocating storage, and the actual reading process. This is an + excerpt from an application which reads the symbol table: + +| long storage_needed; +| asymbol **symbol_table; +| long number_of_symbols; +| long i; +| +| storage_needed = bfd_get_symtab_upper_bound (abfd); +| +| if (storage_needed < 0) +| FAIL +| +| if (storage_needed == 0) +| return; +| +| symbol_table = (asymbol **) xmalloc (storage_needed); +| ... +| number_of_symbols = +| bfd_canonicalize_symtab (abfd, symbol_table); +| +| if (number_of_symbols < 0) +| FAIL +| +| for (i = 0; i < number_of_symbols; i++) +| process_symbol (symbol_table[i]); + + All storage for the symbols themselves is in an objalloc + connected to the BFD; it is freed when the BFD is closed. + +INODE +Writing Symbols, Mini Symbols, Reading Symbols, Symbols +SUBSECTION + Writing symbols + + Writing of a symbol table is automatic when a BFD open for + writing is closed. The application attaches a vector of + pointers to pointers to symbols to the BFD being written, and + fills in the symbol count. The close and cleanup code reads + through the table provided and performs all the necessary + operations. The BFD output code must always be provided with an + ``owned'' symbol: one which has come from another BFD, or one + which has been created using <>. Here is an + example showing the creation of a symbol table with only one element: + +| #include "bfd.h" +| int main (void) +| { +| bfd *abfd; +| asymbol *ptrs[2]; +| asymbol *new; +| +| abfd = bfd_openw ("foo","a.out-sunos-big"); +| bfd_set_format (abfd, bfd_object); +| new = bfd_make_empty_symbol (abfd); +| new->name = "dummy_symbol"; +| new->section = bfd_make_section_old_way (abfd, ".text"); +| new->flags = BSF_GLOBAL; +| new->value = 0x12345; +| +| ptrs[0] = new; +| ptrs[1] = (asymbol *)0; +| +| bfd_set_symtab (abfd, ptrs, 1); +| bfd_close (abfd); +| return 0; +| } +| +| ./makesym +| nm foo +| 00012345 A dummy_symbol + + Many formats cannot represent arbitary symbol information; for + instance, the <> object format does not allow an + arbitary number of sections. A symbol pointing to a section + which is not one of <<.text>>, <<.data>> or <<.bss>> cannot + be described. + +INODE +Mini Symbols, typedef asymbol, Writing Symbols, Symbols +SUBSECTION + Mini Symbols + + Mini symbols provide read-only access to the symbol table. + They use less memory space, but require more time to access. + They can be useful for tools like nm or objdump, which may + have to handle symbol tables of extremely large executables. + + The <> function will read the symbols + into memory in an internal form. It will return a <> + pointer to a block of memory, a symbol count, and the size of + each symbol. The pointer is allocated using <>, and + should be freed by the caller when it is no longer needed. + + The function <> will take a pointer + to a minisymbol, and a pointer to a structure returned by + <>, and return a <> structure. + The return value may or may not be the same as the value from + <> which was passed in. + +*/ + +/* +DOCDD +INODE +typedef asymbol, symbol handling functions, Mini Symbols, Symbols + +*/ +/* +SUBSECTION + typedef asymbol + + An <> has the form: + +*/ + +/* +CODE_FRAGMENT + +. +.typedef struct symbol_cache_entry +.{ +. {* A pointer to the BFD which owns the symbol. This information +. is necessary so that a back end can work out what additional +. information (invisible to the application writer) is carried +. with the symbol. +. +. This field is *almost* redundant, since you can use section->owner +. instead, except that some symbols point to the global sections +. bfd_{abs,com,und}_section. This could be fixed by making +. these globals be per-bfd (or per-target-flavor). FIXME. *} +. struct bfd *the_bfd; {* Use bfd_asymbol_bfd(sym) to access this field. *} +. +. {* The text of the symbol. The name is left alone, and not copied; the +. application may not alter it. *} +. const char *name; +. +. {* The value of the symbol. This really should be a union of a +. numeric value with a pointer, since some flags indicate that +. a pointer to another symbol is stored here. *} +. symvalue value; +. +. {* Attributes of a symbol. *} +.#define BSF_NO_FLAGS 0x00 +. +. {* The symbol has local scope; <> in <>. The value +. is the offset into the section of the data. *} +.#define BSF_LOCAL 0x01 +. +. {* The symbol has global scope; initialized data in <>. The +. value is the offset into the section of the data. *} +.#define BSF_GLOBAL 0x02 +. +. {* The symbol has global scope and is exported. The value is +. the offset into the section of the data. *} +.#define BSF_EXPORT BSF_GLOBAL {* No real difference. *} +. +. {* A normal C symbol would be one of: +. <>, <>, <> or +. <>. *} +. +. {* The symbol is a debugging record. The value has an arbitary +. meaning, unless BSF_DEBUGGING_RELOC is also set. *} +.#define BSF_DEBUGGING 0x08 +. +. {* The symbol denotes a function entry point. Used in ELF, +. perhaps others someday. *} +.#define BSF_FUNCTION 0x10 +. +. {* Used by the linker. *} +.#define BSF_KEEP 0x20 +.#define BSF_KEEP_G 0x40 +. +. {* A weak global symbol, overridable without warnings by +. a regular global symbol of the same name. *} +.#define BSF_WEAK 0x80 +. +. {* This symbol was created to point to a section, e.g. ELF's +. STT_SECTION symbols. *} +.#define BSF_SECTION_SYM 0x100 +. +. {* The symbol used to be a common symbol, but now it is +. allocated. *} +.#define BSF_OLD_COMMON 0x200 +. +. {* The default value for common data. *} +.#define BFD_FORT_COMM_DEFAULT_VALUE 0 +. +. {* In some files the type of a symbol sometimes alters its +. location in an output file - ie in coff a <> symbol +. which is also <> symbol appears where it was +. declared and not at the end of a section. This bit is set +. by the target BFD part to convey this information. *} +.#define BSF_NOT_AT_END 0x400 +. +. {* Signal that the symbol is the label of constructor section. *} +.#define BSF_CONSTRUCTOR 0x800 +. +. {* Signal that the symbol is a warning symbol. The name is a +. warning. The name of the next symbol is the one to warn about; +. if a reference is made to a symbol with the same name as the next +. symbol, a warning is issued by the linker. *} +.#define BSF_WARNING 0x1000 +. +. {* Signal that the symbol is indirect. This symbol is an indirect +. pointer to the symbol with the same name as the next symbol. *} +.#define BSF_INDIRECT 0x2000 +. +. {* BSF_FILE marks symbols that contain a file name. This is used +. for ELF STT_FILE symbols. *} +.#define BSF_FILE 0x4000 +. +. {* Symbol is from dynamic linking information. *} +.#define BSF_DYNAMIC 0x8000 +. +. {* The symbol denotes a data object. Used in ELF, and perhaps +. others someday. *} +.#define BSF_OBJECT 0x10000 +. +. {* This symbol is a debugging symbol. The value is the offset +. into the section of the data. BSF_DEBUGGING should be set +. as well. *} +.#define BSF_DEBUGGING_RELOC 0x20000 +. +. {* This symbol is thread local. Used in ELF. *} +.#define BSF_THREAD_LOCAL 0x40000 +. +. flagword flags; +. +. {* A pointer to the section to which this symbol is +. relative. This will always be non NULL, there are special +. sections for undefined and absolute symbols. *} +. struct sec *section; +. +. {* Back end special data. *} +. union +. { +. PTR p; +. bfd_vma i; +. } +. udata; +.} +.asymbol; +. +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "safe-ctype.h" +#include "bfdlink.h" +#include "aout/stab_gnu.h" + +static char coff_section_type PARAMS ((const char *)); +static char decode_section_type PARAMS ((const struct sec *)); +static int cmpindexentry PARAMS ((const PTR, const PTR)); + +/* +DOCDD +INODE +symbol handling functions, , typedef asymbol, Symbols +SUBSECTION + Symbol handling functions +*/ + +/* +FUNCTION + bfd_get_symtab_upper_bound + +DESCRIPTION + Return the number of bytes required to store a vector of pointers + to <> for all the symbols in the BFD @var{abfd}, + including a terminal NULL pointer. If there are no symbols in + the BFD, then return 0. If an error occurs, return -1. + +.#define bfd_get_symtab_upper_bound(abfd) \ +. BFD_SEND (abfd, _bfd_get_symtab_upper_bound, (abfd)) +. +*/ + +/* +FUNCTION + bfd_is_local_label + +SYNOPSIS + bfd_boolean bfd_is_local_label (bfd *abfd, asymbol *sym); + +DESCRIPTION + Return TRUE if the given symbol @var{sym} in the BFD @var{abfd} is + a compiler generated local label, else return FALSE. +*/ + +bfd_boolean +bfd_is_local_label (abfd, sym) + bfd *abfd; + asymbol *sym; +{ + /* The BSF_SECTION_SYM check is needed for IA-64, where every label that + starts with '.' is local. This would accidentally catch section names + if we didn't reject them here. */ + if ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_SECTION_SYM)) != 0) + return FALSE; + if (sym->name == NULL) + return FALSE; + return bfd_is_local_label_name (abfd, sym->name); +} + +/* +FUNCTION + bfd_is_local_label_name + +SYNOPSIS + bfd_boolean bfd_is_local_label_name (bfd *abfd, const char *name); + +DESCRIPTION + Return TRUE if a symbol with the name @var{name} in the BFD + @var{abfd} is a compiler generated local label, else return + FALSE. This just checks whether the name has the form of a + local label. + +.#define bfd_is_local_label_name(abfd, name) \ +. BFD_SEND (abfd, _bfd_is_local_label_name, (abfd, name)) +. +*/ + +/* +FUNCTION + bfd_canonicalize_symtab + +DESCRIPTION + Read the symbols from the BFD @var{abfd}, and fills in + the vector @var{location} with pointers to the symbols and + a trailing NULL. + Return the actual number of symbol pointers, not + including the NULL. + +.#define bfd_canonicalize_symtab(abfd, location) \ +. BFD_SEND (abfd, _bfd_canonicalize_symtab,\ +. (abfd, location)) +. +*/ + +/* +FUNCTION + bfd_set_symtab + +SYNOPSIS + bfd_boolean bfd_set_symtab (bfd *abfd, asymbol **location, unsigned int count); + +DESCRIPTION + Arrange that when the output BFD @var{abfd} is closed, + the table @var{location} of @var{count} pointers to symbols + will be written. +*/ + +bfd_boolean +bfd_set_symtab (abfd, location, symcount) + bfd *abfd; + asymbol **location; + unsigned int symcount; +{ + if ((abfd->format != bfd_object) || (bfd_read_p (abfd))) + { + bfd_set_error (bfd_error_invalid_operation); + return FALSE; + } + + bfd_get_outsymbols (abfd) = location; + bfd_get_symcount (abfd) = symcount; + return TRUE; +} + +/* +FUNCTION + bfd_print_symbol_vandf + +SYNOPSIS + void bfd_print_symbol_vandf (bfd *abfd, PTR file, asymbol *symbol); + +DESCRIPTION + Print the value and flags of the @var{symbol} supplied to the + stream @var{file}. +*/ +void +bfd_print_symbol_vandf (abfd, arg, symbol) + bfd *abfd; + PTR arg; + asymbol *symbol; +{ + FILE *file = (FILE *) arg; + + flagword type = symbol->flags; + + if (symbol->section != (asection *) NULL) + bfd_fprintf_vma (abfd, file, + symbol->value + symbol->section->vma); + else + bfd_fprintf_vma (abfd, file, symbol->value); + + /* This presumes that a symbol can not be both BSF_DEBUGGING and + BSF_DYNAMIC, nor more than one of BSF_FUNCTION, BSF_FILE, and + BSF_OBJECT. */ + fprintf (file, " %c%c%c%c%c%c%c", + ((type & BSF_LOCAL) + ? (type & BSF_GLOBAL) ? '!' : 'l' + : (type & BSF_GLOBAL) ? 'g' : ' '), + (type & BSF_WEAK) ? 'w' : ' ', + (type & BSF_CONSTRUCTOR) ? 'C' : ' ', + (type & BSF_WARNING) ? 'W' : ' ', + (type & BSF_INDIRECT) ? 'I' : ' ', + (type & BSF_DEBUGGING) ? 'd' : (type & BSF_DYNAMIC) ? 'D' : ' ', + ((type & BSF_FUNCTION) + ? 'F' + : ((type & BSF_FILE) + ? 'f' + : ((type & BSF_OBJECT) ? 'O' : ' ')))); +} + +/* +FUNCTION + bfd_make_empty_symbol + +DESCRIPTION + Create a new <> structure for the BFD @var{abfd} + and return a pointer to it. + + This routine is necessary because each back end has private + information surrounding the <>. Building your own + <> and pointing to it will not create the private + information, and will cause problems later on. + +.#define bfd_make_empty_symbol(abfd) \ +. BFD_SEND (abfd, _bfd_make_empty_symbol, (abfd)) +. +*/ + +/* +FUNCTION + _bfd_generic_make_empty_symbol + +SYNOPSIS + asymbol * _bfd_generic_make_empty_symbol (bfd *); + +DESCRIPTION + Create a new <> structure for the BFD @var{abfd} + and return a pointer to it. Used by core file routines, + binary back-end and anywhere else where no private info + is needed. +*/ + +asymbol * +_bfd_generic_make_empty_symbol (abfd) + bfd *abfd; +{ + bfd_size_type amt = sizeof (asymbol); + asymbol *new = (asymbol *) bfd_zalloc (abfd, amt); + if (new) + new->the_bfd = abfd; + return new; +} + +/* +FUNCTION + bfd_make_debug_symbol + +DESCRIPTION + Create a new <> structure for the BFD @var{abfd}, + to be used as a debugging symbol. Further details of its use have + yet to be worked out. + +.#define bfd_make_debug_symbol(abfd,ptr,size) \ +. BFD_SEND (abfd, _bfd_make_debug_symbol, (abfd, ptr, size)) +. +*/ + +struct section_to_type +{ + const char *section; + char type; +}; + +/* Map section names to POSIX/BSD single-character symbol types. + This table is probably incomplete. It is sorted for convenience of + adding entries. Since it is so short, a linear search is used. */ +static const struct section_to_type stt[] = +{ + {".bss", 'b'}, + {"code", 't'}, /* MRI .text */ + {".data", 'd'}, + {"*DEBUG*", 'N'}, + {".debug", 'N'}, /* MSVC's .debug (non-standard debug syms) */ + {".drectve", 'i'}, /* MSVC's .drective section */ + {".edata", 'e'}, /* MSVC's .edata (export) section */ + {".fini", 't'}, /* ELF fini section */ + {".idata", 'i'}, /* MSVC's .idata (import) section */ + {".init", 't'}, /* ELF init section */ + {".pdata", 'p'}, /* MSVC's .pdata (stack unwind) section */ + {".rdata", 'r'}, /* Read only data. */ + {".rodata", 'r'}, /* Read only data. */ + {".sbss", 's'}, /* Small BSS (uninitialized data). */ + {".scommon", 'c'}, /* Small common. */ + {".sdata", 'g'}, /* Small initialized data. */ + {".text", 't'}, + {"vars", 'd'}, /* MRI .data */ + {"zerovars", 'b'}, /* MRI .bss */ + {0, 0} +}; + +/* Return the single-character symbol type corresponding to + section S, or '?' for an unknown COFF section. + + Check for any leading string which matches, so .text5 returns + 't' as well as .text */ + +static char +coff_section_type (s) + const char *s; +{ + const struct section_to_type *t; + + for (t = &stt[0]; t->section; t++) + if (!strncmp (s, t->section, strlen (t->section))) + return t->type; + + return '?'; +} + +/* Return the single-character symbol type corresponding to section + SECTION, or '?' for an unknown section. This uses section flags to + identify sections. + + FIXME These types are unhandled: c, i, e, p. If we handled these also, + we could perhaps obsolete coff_section_type. */ + +static char +decode_section_type (section) + const struct sec *section; +{ + if (section->flags & SEC_CODE) + return 't'; + if (section->flags & SEC_DATA) + { + if (section->flags & SEC_READONLY) + return 'r'; + else if (section->flags & SEC_SMALL_DATA) + return 'g'; + else + return 'd'; + } + if ((section->flags & SEC_HAS_CONTENTS) == 0) + { + if (section->flags & SEC_SMALL_DATA) + return 's'; + else + return 'b'; + } + if (section->flags & SEC_DEBUGGING) + return 'N'; + + return '?'; +} + +/* +FUNCTION + bfd_decode_symclass + +DESCRIPTION + Return a character corresponding to the symbol + class of @var{symbol}, or '?' for an unknown class. + +SYNOPSIS + int bfd_decode_symclass (asymbol *symbol); +*/ +int +bfd_decode_symclass (symbol) + asymbol *symbol; +{ + char c; + + if (bfd_is_com_section (symbol->section)) + return 'C'; + if (bfd_is_und_section (symbol->section)) + { + if (symbol->flags & BSF_WEAK) + { + /* If weak, determine if it's specifically an object + or non-object weak. */ + if (symbol->flags & BSF_OBJECT) + return 'v'; + else + return 'w'; + } + else + return 'U'; + } + if (bfd_is_ind_section (symbol->section)) + return 'I'; + if (symbol->flags & BSF_WEAK) + { + /* If weak, determine if it's specifically an object + or non-object weak. */ + if (symbol->flags & BSF_OBJECT) + return 'V'; + else + return 'W'; + } + if (!(symbol->flags & (BSF_GLOBAL | BSF_LOCAL))) + return '?'; + + if (bfd_is_abs_section (symbol->section)) + c = 'a'; + else if (symbol->section) + { + c = coff_section_type (symbol->section->name); + if (c == '?') + c = decode_section_type (symbol->section); + } + else + return '?'; + if (symbol->flags & BSF_GLOBAL) + c = TOUPPER (c); + return c; + + /* We don't have to handle these cases just yet, but we will soon: + N_SETV: 'v'; + N_SETA: 'l'; + N_SETT: 'x'; + N_SETD: 'z'; + N_SETB: 's'; + N_INDR: 'i'; + */ +} + +/* +FUNCTION + bfd_is_undefined_symclass + +DESCRIPTION + Returns non-zero if the class symbol returned by + bfd_decode_symclass represents an undefined symbol. + Returns zero otherwise. + +SYNOPSIS + bfd_boolean bfd_is_undefined_symclass (int symclass); +*/ + +bfd_boolean +bfd_is_undefined_symclass (symclass) + int symclass; +{ + return symclass == 'U' || symclass == 'w' || symclass == 'v'; +} + +/* +FUNCTION + bfd_symbol_info + +DESCRIPTION + Fill in the basic info about symbol that nm needs. + Additional info may be added by the back-ends after + calling this function. + +SYNOPSIS + void bfd_symbol_info (asymbol *symbol, symbol_info *ret); +*/ + +void +bfd_symbol_info (symbol, ret) + asymbol *symbol; + symbol_info *ret; +{ + ret->type = bfd_decode_symclass (symbol); + + if (bfd_is_undefined_symclass (ret->type)) + ret->value = 0; + else + ret->value = symbol->value + symbol->section->vma; + + ret->name = symbol->name; +} + +/* +FUNCTION + bfd_copy_private_symbol_data + +SYNOPSIS + bfd_boolean bfd_copy_private_symbol_data (bfd *ibfd, asymbol *isym, bfd *obfd, asymbol *osym); + +DESCRIPTION + Copy private symbol information from @var{isym} in the BFD + @var{ibfd} to the symbol @var{osym} in the BFD @var{obfd}. + Return <> on success, <> on error. Possible error + returns are: + + o <> - + Not enough memory exists to create private data for @var{osec}. + +.#define bfd_copy_private_symbol_data(ibfd, isymbol, obfd, osymbol) \ +. BFD_SEND (obfd, _bfd_copy_private_symbol_data, \ +. (ibfd, isymbol, obfd, osymbol)) +. +*/ + +/* The generic version of the function which returns mini symbols. + This is used when the backend does not provide a more efficient + version. It just uses BFD asymbol structures as mini symbols. */ + +long +_bfd_generic_read_minisymbols (abfd, dynamic, minisymsp, sizep) + bfd *abfd; + bfd_boolean dynamic; + PTR *minisymsp; + unsigned int *sizep; +{ + long storage; + asymbol **syms = NULL; + long symcount; + + if (dynamic) + storage = bfd_get_dynamic_symtab_upper_bound (abfd); + else + storage = bfd_get_symtab_upper_bound (abfd); + if (storage < 0) + goto error_return; + if (storage == 0) + return 0; + + syms = (asymbol **) bfd_malloc ((bfd_size_type) storage); + if (syms == NULL) + goto error_return; + + if (dynamic) + symcount = bfd_canonicalize_dynamic_symtab (abfd, syms); + else + symcount = bfd_canonicalize_symtab (abfd, syms); + if (symcount < 0) + goto error_return; + + *minisymsp = (PTR) syms; + *sizep = sizeof (asymbol *); + return symcount; + + error_return: + bfd_set_error (bfd_error_no_symbols); + if (syms != NULL) + free (syms); + return -1; +} + +/* The generic version of the function which converts a minisymbol to + an asymbol. We don't worry about the sym argument we are passed; + we just return the asymbol the minisymbol points to. */ + +asymbol * +_bfd_generic_minisymbol_to_symbol (abfd, dynamic, minisym, sym) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_boolean dynamic ATTRIBUTE_UNUSED; + const PTR minisym; + asymbol *sym ATTRIBUTE_UNUSED; +{ + return *(asymbol **) minisym; +} + +/* Look through stabs debugging information in .stab and .stabstr + sections to find the source file and line closest to a desired + location. This is used by COFF and ELF targets. It sets *pfound + to TRUE if it finds some information. The *pinfo field is used to + pass cached information in and out of this routine; this first time + the routine is called for a BFD, *pinfo should be NULL. The value + placed in *pinfo should be saved with the BFD, and passed back each + time this function is called. */ + +/* We use a cache by default. */ + +#define ENABLE_CACHING + +/* We keep an array of indexentry structures to record where in the + stabs section we should look to find line number information for a + particular address. */ + +struct indexentry +{ + bfd_vma val; + bfd_byte *stab; + bfd_byte *str; + char *directory_name; + char *file_name; + char *function_name; +}; + +/* Compare two indexentry structures. This is called via qsort. */ + +static int +cmpindexentry (a, b) + const PTR a; + const PTR b; +{ + const struct indexentry *contestantA = (const struct indexentry *) a; + const struct indexentry *contestantB = (const struct indexentry *) b; + + if (contestantA->val < contestantB->val) + return -1; + else if (contestantA->val > contestantB->val) + return 1; + else + return 0; +} + +/* A pointer to this structure is stored in *pinfo. */ + +struct stab_find_info +{ + /* The .stab section. */ + asection *stabsec; + /* The .stabstr section. */ + asection *strsec; + /* The contents of the .stab section. */ + bfd_byte *stabs; + /* The contents of the .stabstr section. */ + bfd_byte *strs; + + /* A table that indexes stabs by memory address. */ + struct indexentry *indextable; + /* The number of entries in indextable. */ + int indextablesize; + +#ifdef ENABLE_CACHING + /* Cached values to restart quickly. */ + struct indexentry *cached_indexentry; + bfd_vma cached_offset; + bfd_byte *cached_stab; + char *cached_file_name; +#endif + + /* Saved ptr to malloc'ed filename. */ + char *filename; +}; + +bfd_boolean +_bfd_stab_section_find_nearest_line (abfd, symbols, section, offset, pfound, + pfilename, pfnname, pline, pinfo) + bfd *abfd; + asymbol **symbols; + asection *section; + bfd_vma offset; + bfd_boolean *pfound; + const char **pfilename; + const char **pfnname; + unsigned int *pline; + PTR *pinfo; +{ + struct stab_find_info *info; + bfd_size_type stabsize, strsize; + bfd_byte *stab, *str; + bfd_byte *last_stab = NULL; + bfd_size_type stroff; + struct indexentry *indexentry; + char *file_name; + char *directory_name; + int saw_fun; + bfd_boolean saw_line, saw_func; + + *pfound = FALSE; + *pfilename = bfd_get_filename (abfd); + *pfnname = NULL; + *pline = 0; + + /* Stabs entries use a 12 byte format: + 4 byte string table index + 1 byte stab type + 1 byte stab other field + 2 byte stab desc field + 4 byte stab value + FIXME: This will have to change for a 64 bit object format. + + The stabs symbols are divided into compilation units. For the + first entry in each unit, the type of 0, the value is the length + of the string table for this unit, and the desc field is the + number of stabs symbols for this unit. */ + +#define STRDXOFF (0) +#define TYPEOFF (4) +#define OTHEROFF (5) +#define DESCOFF (6) +#define VALOFF (8) +#define STABSIZE (12) + + info = (struct stab_find_info *) *pinfo; + if (info != NULL) + { + if (info->stabsec == NULL || info->strsec == NULL) + { + /* No stabs debugging information. */ + return TRUE; + } + + stabsize = info->stabsec->_raw_size; + strsize = info->strsec->_raw_size; + } + else + { + long reloc_size, reloc_count; + arelent **reloc_vector; + int i; + char *name; + char *function_name; + bfd_size_type amt = sizeof *info; + + info = (struct stab_find_info *) bfd_zalloc (abfd, amt); + if (info == NULL) + return FALSE; + + /* FIXME: When using the linker --split-by-file or + --split-by-reloc options, it is possible for the .stab and + .stabstr sections to be split. We should handle that. */ + + info->stabsec = bfd_get_section_by_name (abfd, ".stab"); + info->strsec = bfd_get_section_by_name (abfd, ".stabstr"); + + if (info->stabsec == NULL || info->strsec == NULL) + { + /* No stabs debugging information. Set *pinfo so that we + can return quickly in the info != NULL case above. */ + *pinfo = (PTR) info; + return TRUE; + } + + stabsize = info->stabsec->_raw_size; + strsize = info->strsec->_raw_size; + + info->stabs = (bfd_byte *) bfd_alloc (abfd, stabsize); + info->strs = (bfd_byte *) bfd_alloc (abfd, strsize); + if (info->stabs == NULL || info->strs == NULL) + return FALSE; + + if (! bfd_get_section_contents (abfd, info->stabsec, info->stabs, + (bfd_vma) 0, stabsize) + || ! bfd_get_section_contents (abfd, info->strsec, info->strs, + (bfd_vma) 0, strsize)) + return FALSE; + + /* If this is a relocateable object file, we have to relocate + the entries in .stab. This should always be simple 32 bit + relocations against symbols defined in this object file, so + this should be no big deal. */ + reloc_size = bfd_get_reloc_upper_bound (abfd, info->stabsec); + if (reloc_size < 0) + return FALSE; + reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); + if (reloc_vector == NULL && reloc_size != 0) + return FALSE; + reloc_count = bfd_canonicalize_reloc (abfd, info->stabsec, reloc_vector, + symbols); + if (reloc_count < 0) + { + if (reloc_vector != NULL) + free (reloc_vector); + return FALSE; + } + if (reloc_count > 0) + { + arelent **pr; + + for (pr = reloc_vector; *pr != NULL; pr++) + { + arelent *r; + unsigned long val; + asymbol *sym; + + r = *pr; + if (r->howto->rightshift != 0 + || r->howto->size != 2 + || r->howto->bitsize != 32 + || r->howto->pc_relative + || r->howto->bitpos != 0 + || r->howto->dst_mask != 0xffffffff) + { + (*_bfd_error_handler) + (_("Unsupported .stab relocation")); + bfd_set_error (bfd_error_invalid_operation); + if (reloc_vector != NULL) + free (reloc_vector); + return FALSE; + } + + val = bfd_get_32 (abfd, info->stabs + r->address); + val &= r->howto->src_mask; + sym = *r->sym_ptr_ptr; + val += sym->value + sym->section->vma + r->addend; + bfd_put_32 (abfd, (bfd_vma) val, info->stabs + r->address); + } + } + + if (reloc_vector != NULL) + free (reloc_vector); + + /* First time through this function, build a table matching + function VM addresses to stabs, then sort based on starting + VM address. Do this in two passes: once to count how many + table entries we'll need, and a second to actually build the + table. */ + + info->indextablesize = 0; + saw_fun = 1; + for (stab = info->stabs; stab < info->stabs + stabsize; stab += STABSIZE) + { + if (stab[TYPEOFF] == (bfd_byte) N_SO) + { + /* N_SO with null name indicates EOF */ + if (bfd_get_32 (abfd, stab + STRDXOFF) == 0) + continue; + + /* if we did not see a function def, leave space for one. */ + if (saw_fun == 0) + ++info->indextablesize; + + saw_fun = 0; + + /* two N_SO's in a row is a filename and directory. Skip */ + if (stab + STABSIZE < info->stabs + stabsize + && *(stab + STABSIZE + TYPEOFF) == (bfd_byte) N_SO) + { + stab += STABSIZE; + } + } + else if (stab[TYPEOFF] == (bfd_byte) N_FUN) + { + saw_fun = 1; + ++info->indextablesize; + } + } + + if (saw_fun == 0) + ++info->indextablesize; + + if (info->indextablesize == 0) + return TRUE; + ++info->indextablesize; + + amt = info->indextablesize; + amt *= sizeof (struct indexentry); + info->indextable = (struct indexentry *) bfd_alloc (abfd, amt); + if (info->indextable == NULL) + return FALSE; + + file_name = NULL; + directory_name = NULL; + saw_fun = 1; + + for (i = 0, stroff = 0, stab = info->stabs, str = info->strs; + i < info->indextablesize && stab < info->stabs + stabsize; + stab += STABSIZE) + { + switch (stab[TYPEOFF]) + { + case 0: + /* This is the first entry in a compilation unit. */ + if ((bfd_size_type) ((info->strs + strsize) - str) < stroff) + break; + str += stroff; + stroff = bfd_get_32 (abfd, stab + VALOFF); + break; + + case N_SO: + /* The main file name. */ + + /* The following code creates a new indextable entry with + a NULL function name if there were no N_FUNs in a file. + Note that a N_SO without a file name is an EOF and + there could be 2 N_SO following it with the new filename + and directory. */ + if (saw_fun == 0) + { + info->indextable[i].val = bfd_get_32 (abfd, last_stab + VALOFF); + info->indextable[i].stab = last_stab; + info->indextable[i].str = str; + info->indextable[i].directory_name = directory_name; + info->indextable[i].file_name = file_name; + info->indextable[i].function_name = NULL; + ++i; + } + saw_fun = 0; + + file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + if (*file_name == '\0') + { + directory_name = NULL; + file_name = NULL; + saw_fun = 1; + } + else + { + last_stab = stab; + if (stab + STABSIZE >= info->stabs + stabsize + || *(stab + STABSIZE + TYPEOFF) != (bfd_byte) N_SO) + { + directory_name = NULL; + } + else + { + /* Two consecutive N_SOs are a directory and a + file name. */ + stab += STABSIZE; + directory_name = file_name; + file_name = ((char *) str + + bfd_get_32 (abfd, stab + STRDXOFF)); + } + } + break; + + case N_SOL: + /* The name of an include file. */ + file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + break; + + case N_FUN: + /* A function name. */ + saw_fun = 1; + name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + + if (*name == '\0') + name = NULL; + + function_name = name; + + if (name == NULL) + continue; + + info->indextable[i].val = bfd_get_32 (abfd, stab + VALOFF); + info->indextable[i].stab = stab; + info->indextable[i].str = str; + info->indextable[i].directory_name = directory_name; + info->indextable[i].file_name = file_name; + info->indextable[i].function_name = function_name; + ++i; + break; + } + } + + if (saw_fun == 0) + { + info->indextable[i].val = bfd_get_32 (abfd, last_stab + VALOFF); + info->indextable[i].stab = last_stab; + info->indextable[i].str = str; + info->indextable[i].directory_name = directory_name; + info->indextable[i].file_name = file_name; + info->indextable[i].function_name = NULL; + ++i; + } + + info->indextable[i].val = (bfd_vma) -1; + info->indextable[i].stab = info->stabs + stabsize; + info->indextable[i].str = str; + info->indextable[i].directory_name = NULL; + info->indextable[i].file_name = NULL; + info->indextable[i].function_name = NULL; + ++i; + + info->indextablesize = i; + qsort (info->indextable, (size_t) i, sizeof (struct indexentry), + cmpindexentry); + + *pinfo = (PTR) info; + } + + /* We are passed a section relative offset. The offsets in the + stabs information are absolute. */ + offset += bfd_get_section_vma (abfd, section); + +#ifdef ENABLE_CACHING + if (info->cached_indexentry != NULL + && offset >= info->cached_offset + && offset < (info->cached_indexentry + 1)->val) + { + stab = info->cached_stab; + indexentry = info->cached_indexentry; + file_name = info->cached_file_name; + } + else +#endif + { + long low, high; + long mid = -1; + + /* Cache non-existant or invalid. Do binary search on + indextable. */ + indexentry = NULL; + + low = 0; + high = info->indextablesize - 1; + while (low != high) + { + mid = (high + low) / 2; + if (offset >= info->indextable[mid].val + && offset < info->indextable[mid + 1].val) + { + indexentry = &info->indextable[mid]; + break; + } + + if (info->indextable[mid].val > offset) + high = mid; + else + low = mid + 1; + } + + if (indexentry == NULL) + return TRUE; + + stab = indexentry->stab + STABSIZE; + file_name = indexentry->file_name; + } + + directory_name = indexentry->directory_name; + str = indexentry->str; + + saw_line = FALSE; + saw_func = FALSE; + for (; stab < (indexentry+1)->stab; stab += STABSIZE) + { + bfd_boolean done; + bfd_vma val; + + done = FALSE; + + switch (stab[TYPEOFF]) + { + case N_SOL: + /* The name of an include file. */ + val = bfd_get_32 (abfd, stab + VALOFF); + if (val <= offset) + { + file_name = (char *) str + bfd_get_32 (abfd, stab + STRDXOFF); + *pline = 0; + } + break; + + case N_SLINE: + case N_DSLINE: + case N_BSLINE: + /* A line number. If the function was specified, then the value + is relative to the start of the function. Otherwise, the + value is an absolute address. */ + val = ((indexentry->function_name ? indexentry->val : 0) + + bfd_get_32 (abfd, stab + VALOFF)); + /* If this line starts before our desired offset, or if it's + the first line we've been able to find, use it. The + !saw_line check works around a bug in GCC 2.95.3, which emits + the first N_SLINE late. */ + if (!saw_line || val <= offset) + { + *pline = bfd_get_16 (abfd, stab + DESCOFF); + +#ifdef ENABLE_CACHING + info->cached_stab = stab; + info->cached_offset = val; + info->cached_file_name = file_name; + info->cached_indexentry = indexentry; +#endif + } + if (val > offset) + done = TRUE; + saw_line = TRUE; + break; + + case N_FUN: + case N_SO: + if (saw_func || saw_line) + done = TRUE; + saw_func = TRUE; + break; + } + + if (done) + break; + } + + *pfound = TRUE; + + if (file_name == NULL || IS_ABSOLUTE_PATH (file_name) + || directory_name == NULL) + *pfilename = file_name; + else + { + size_t dirlen; + + dirlen = strlen (directory_name); + if (info->filename == NULL + || strncmp (info->filename, directory_name, dirlen) != 0 + || strcmp (info->filename + dirlen, file_name) != 0) + { + size_t len; + + if (info->filename != NULL) + free (info->filename); + len = strlen (file_name) + 1; + info->filename = (char *) bfd_malloc ((bfd_size_type) dirlen + len); + if (info->filename == NULL) + return FALSE; + memcpy (info->filename, directory_name, dirlen); + memcpy (info->filename + dirlen, file_name, len); + } + + *pfilename = info->filename; + } + + if (indexentry->function_name != NULL) + { + char *s; + + /* This will typically be something like main:F(0,1), so we want + to clobber the colon. It's OK to change the name, since the + string is in our own local storage anyhow. */ + s = strchr (indexentry->function_name, ':'); + if (s != NULL) + *s = '\0'; + + *pfnname = indexentry->function_name; + } + + return TRUE; +} diff --git a/contrib/binutils-2.14/bfd/sysdep.h b/contrib/binutils-2.14/bfd/sysdep.h new file mode 100644 index 0000000000..1338d6b826 --- /dev/null +++ b/contrib/binutils-2.14/bfd/sysdep.h @@ -0,0 +1,164 @@ +/* sysdep.h -- handle host dependencies for the BFD library + Copyright 1995, 1996, 1997, 1998, 1999, 2000 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef BFD_SYSDEP_H +#define BFD_SYSDEP_H + +#include "ansidecl.h" + +#include "config.h" + +#ifdef HAVE_STDDEF_H +#include +#endif + +#include +#include +#include + +#include +#if !(defined(errno) || defined(_MSC_VER) && defined(_INC_ERRNO)) +extern int errno; +#endif + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#else +extern char *strchr (); +extern char *strrchr (); +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef TIME_WITH_SYS_TIME +#include +#include +#else +#ifdef HAVE_SYS_TIME_H +#include +#else +#include +#endif +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef USE_BINARY_FOPEN +#include "fopen-bin.h" +#else +#include "fopen-same.h" +#endif + +#ifdef HAVE_FCNTL_H +#include +#else +#ifdef HAVE_SYS_FILE_H +#include +#endif +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif +#ifndef O_WRONLY +#define O_WRONLY 1 +#endif +#ifndef O_RDWR +#define O_RDWR 2 +#endif +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#include "filenames.h" + +#ifdef NEED_DECLARATION_STRSTR +extern char *strstr (); +#endif + +#ifdef NEED_DECLARATION_MALLOC +extern PTR malloc (); +#endif + +#ifdef NEED_DECLARATION_REALLOC +extern PTR realloc (); +#endif + +#ifdef NEED_DECLARATION_FREE +extern void free (); +#endif + +#ifdef NEED_DECLARATION_GETENV +extern char *getenv (); +#endif + +/* Define offsetof for those systems which lack it */ + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#ifdef ENABLE_NLS +#include +/* Note the use of dgetext() and PACKAGE here, rather than gettext(). + + This is because the code in this directory is used to build a library which + will be linked with code in other directories to form programs. We want to + maintain a seperate translation file for this directory however, rather + than being forced to merge it with that of any program linked to libbfd. + This is a library, so it cannot depend on the catalog currently loaded. + + In order to do this, we have to make sure that when we extract messages we + use the OPCODES domain rather than the domain of the program that included + the bfd library, (eg OBJDUMP). Hence we use dgettext (PACKAGE, String) + and define PACKAGE to be 'bfd'. (See the code in configure). */ +#define _(String) dgettext (PACKAGE, String) +#ifdef gettext_noop +#define N_(String) gettext_noop (String) +#else +#define N_(String) (String) +#endif +#else +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define textdomain(Domainname) while (0) /* nothing */ +# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */ +# define _(String) (String) +# define N_(String) (String) +#endif + +#endif /* ! defined (BFD_SYSDEP_H) */ diff --git a/contrib/binutils-2.14/bfd/targets.c b/contrib/binutils-2.14/bfd/targets.c new file mode 100644 index 0000000000..5ccae2a992 --- /dev/null +++ b/contrib/binutils-2.14/bfd/targets.c @@ -0,0 +1,1350 @@ +/* Generic target-file-type support for the BFD library. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "fnmatch.h" + +/* +SECTION + Targets + +DESCRIPTION + Each port of BFD to a different machine requries the creation + of a target back end. All the back end provides to the root + part of BFD is a structure containing pointers to functions + which perform certain low level operations on files. BFD + translates the applications's requests through a pointer into + calls to the back end routines. + + When a file is opened with <>, its format and + target are unknown. BFD uses various mechanisms to determine + how to interpret the file. The operations performed are: + + o Create a BFD by calling the internal routine + <<_bfd_new_bfd>>, then call <> with the + target string supplied to <> and the new BFD pointer. + + o If a null target string was provided to <>, + look up the environment variable <> and use + that as the target string. + + o If the target string is still <>, or the target string is + <>, then use the first item in the target vector + as the target type, and set <> in the BFD to + cause <> to loop through all the targets. + @xref{bfd_target}. @xref{Formats}. + + o Otherwise, inspect the elements in the target vector + one by one, until a match on target name is found. When found, + use it. + + o Otherwise return the error <> to + <>. + + o <> attempts to open the file using + <>, and returns the BFD. + + Once the BFD has been opened and the target selected, the file + format may be determined. This is done by calling + <> on the BFD with a suggested format. + If <> has been set, each possible target + type is tried to see if it recognizes the specified format. + <> returns <> when the caller guesses right. +@menu +@* bfd_target:: +@end menu +*/ + +/* + +INODE + bfd_target, , Targets, Targets +DOCDD +SUBSECTION + bfd_target + +DESCRIPTION + This structure contains everything that BFD knows about a + target. It includes things like its byte order, name, and which + routines to call to do various operations. + + Every BFD points to a target structure with its <> + member. + + The macros below are used to dispatch to functions through the + <> vector. They are used in a number of macros further + down in @file{bfd.h}, and are also used when calling various + routines by hand inside the BFD implementation. The @var{arglist} + argument must be parenthesized; it contains all the arguments + to the called function. + + They make the documentation (more) unpleasant to read, so if + someone wants to fix this and not break the above, please do. + +.#define BFD_SEND(bfd, message, arglist) \ +. ((*((bfd)->xvec->message)) arglist) +. +.#ifdef DEBUG_BFD_SEND +.#undef BFD_SEND +.#define BFD_SEND(bfd, message, arglist) \ +. (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ +. ((*((bfd)->xvec->message)) arglist) : \ +. (bfd_assert (__FILE__,__LINE__), NULL)) +.#endif + + For operations which index on the BFD format: + +.#define BFD_SEND_FMT(bfd, message, arglist) \ +. (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) +. +.#ifdef DEBUG_BFD_SEND +.#undef BFD_SEND_FMT +.#define BFD_SEND_FMT(bfd, message, arglist) \ +. (((bfd) && (bfd)->xvec && (bfd)->xvec->message) ? \ +. (((bfd)->xvec->message[(int) ((bfd)->format)]) arglist) : \ +. (bfd_assert (__FILE__,__LINE__), NULL)) +.#endif +. + This is the structure which defines the type of BFD this is. The + <> member of the struct <> itself points here. Each + module that implements access to a different target under BFD, + defines one of these. + + FIXME, these names should be rationalised with the names of + the entry points which call them. Too bad we can't have one + macro to define them both! + +.enum bfd_flavour +.{ +. bfd_target_unknown_flavour, +. bfd_target_aout_flavour, +. bfd_target_coff_flavour, +. bfd_target_ecoff_flavour, +. bfd_target_xcoff_flavour, +. bfd_target_elf_flavour, +. bfd_target_ieee_flavour, +. bfd_target_nlm_flavour, +. bfd_target_oasys_flavour, +. bfd_target_tekhex_flavour, +. bfd_target_srec_flavour, +. bfd_target_ihex_flavour, +. bfd_target_som_flavour, +. bfd_target_os9k_flavour, +. bfd_target_versados_flavour, +. bfd_target_msdos_flavour, +. bfd_target_ovax_flavour, +. bfd_target_evax_flavour, +. bfd_target_mmo_flavour, +. bfd_target_mach_o_flavour, +. bfd_target_pef_flavour, +. bfd_target_pef_xlib_flavour, +. bfd_target_sym_flavour +.}; +. +.enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN }; +. +.{* Forward declaration. *} +.typedef struct bfd_link_info _bfd_link_info; +. +.typedef struct bfd_target +.{ +. {* Identifies the kind of target, e.g., SunOS4, Ultrix, etc. *} +. char *name; +. +. {* The "flavour" of a back end is a general indication about +. the contents of a file. *} +. enum bfd_flavour flavour; +. +. {* The order of bytes within the data area of a file. *} +. enum bfd_endian byteorder; +. +. {* The order of bytes within the header parts of a file. *} +. enum bfd_endian header_byteorder; +. +. {* A mask of all the flags which an executable may have set - +. from the set <>, <>, ...<>. *} +. flagword object_flags; +. +. {* A mask of all the flags which a section may have set - from +. the set <>, <>, ...<>. *} +. flagword section_flags; +. +. {* The character normally found at the front of a symbol. +. (if any), perhaps `_'. *} +. char symbol_leading_char; +. +. {* The pad character for file names within an archive header. *} +. char ar_pad_char; +. +. {* The maximum number of characters in an archive header. *} +. unsigned short ar_max_namelen; +. +. {* Entries for byte swapping for data. These are different from the +. other entry points, since they don't take a BFD asthe first argument. +. Certain other handlers could do the same. *} +. bfd_vma (*bfd_getx64) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_64) PARAMS ((const bfd_byte *)); +. void (*bfd_putx64) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_getx32) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_32) PARAMS ((const bfd_byte *)); +. void (*bfd_putx32) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_getx16) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_getx_signed_16) PARAMS ((const bfd_byte *)); +. void (*bfd_putx16) PARAMS ((bfd_vma, bfd_byte *)); +. +. {* Byte swapping for the headers. *} +. bfd_vma (*bfd_h_getx64) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_64) PARAMS ((const bfd_byte *)); +. void (*bfd_h_putx64) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_h_getx32) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_32) PARAMS ((const bfd_byte *)); +. void (*bfd_h_putx32) PARAMS ((bfd_vma, bfd_byte *)); +. bfd_vma (*bfd_h_getx16) PARAMS ((const bfd_byte *)); +. bfd_signed_vma (*bfd_h_getx_signed_16) PARAMS ((const bfd_byte *)); +. void (*bfd_h_putx16) PARAMS ((bfd_vma, bfd_byte *)); +. +. {* Format dependent routines: these are vectors of entry points +. within the target vector structure, one for each format to check. *} +. +. {* Check the format of a file being read. Return a <> or zero. *} +. const struct bfd_target *(*_bfd_check_format[bfd_type_end]) PARAMS ((bfd *)); +. +. {* Set the format of a file being written. *} +. bfd_boolean (*_bfd_set_format[bfd_type_end]) PARAMS ((bfd *)); +. +. {* Write cached information into a file being written, at <>. *} +. bfd_boolean (*_bfd_write_contents[bfd_type_end]) PARAMS ((bfd *)); +. +The general target vector. These vectors are initialized using the +BFD_JUMP_TABLE macros. +. +. {* Generic entry points. *} +Do not "beautify" the CONCAT* macro args. Traditional C will not +remove whitespace added here, and thus will fail to concatenate +the tokens. +.#define BFD_JUMP_TABLE_GENERIC(NAME) \ +.CONCAT2 (NAME,_close_and_cleanup), \ +.CONCAT2 (NAME,_bfd_free_cached_info), \ +.CONCAT2 (NAME,_new_section_hook), \ +.CONCAT2 (NAME,_get_section_contents), \ +.CONCAT2 (NAME,_get_section_contents_in_window) +. +. {* Called when the BFD is being closed to do any necessary cleanup. *} +. bfd_boolean (*_close_and_cleanup) PARAMS ((bfd *)); +. {* Ask the BFD to free all cached information. *} +. bfd_boolean (*_bfd_free_cached_info) PARAMS ((bfd *)); +. {* Called when a new section is created. *} +. bfd_boolean (*_new_section_hook) PARAMS ((bfd *, sec_ptr)); +. {* Read the contents of a section. *} +. bfd_boolean (*_bfd_get_section_contents) +. PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); +. bfd_boolean (*_bfd_get_section_contents_in_window) +. PARAMS ((bfd *, sec_ptr, bfd_window *, file_ptr, bfd_size_type)); +. +. {* Entry points to copy private data. *} +.#define BFD_JUMP_TABLE_COPY(NAME) \ +.CONCAT2 (NAME,_bfd_copy_private_bfd_data), \ +.CONCAT2 (NAME,_bfd_merge_private_bfd_data), \ +.CONCAT2 (NAME,_bfd_copy_private_section_data), \ +.CONCAT2 (NAME,_bfd_copy_private_symbol_data), \ +.CONCAT2 (NAME,_bfd_set_private_flags), \ +.CONCAT2 (NAME,_bfd_print_private_bfd_data) \ +. {* Called to copy BFD general private data from one object file +. to another. *} +. bfd_boolean (*_bfd_copy_private_bfd_data) PARAMS ((bfd *, bfd *)); +. {* Called to merge BFD general private data from one object file +. to a common output file when linking. *} +. bfd_boolean (*_bfd_merge_private_bfd_data) PARAMS ((bfd *, bfd *)); +. {* Called to copy BFD private section data from one object file +. to another. *} +. bfd_boolean (*_bfd_copy_private_section_data) +. PARAMS ((bfd *, sec_ptr, bfd *, sec_ptr)); +. {* Called to copy BFD private symbol data from one symbol +. to another. *} +. bfd_boolean (*_bfd_copy_private_symbol_data) +. PARAMS ((bfd *, asymbol *, bfd *, asymbol *)); +. {* Called to set private backend flags. *} +. bfd_boolean (*_bfd_set_private_flags) PARAMS ((bfd *, flagword)); +. +. {* Called to print private BFD data. *} +. bfd_boolean (*_bfd_print_private_bfd_data) PARAMS ((bfd *, PTR)); +. +. {* Core file entry points. *} +.#define BFD_JUMP_TABLE_CORE(NAME) \ +.CONCAT2 (NAME,_core_file_failing_command), \ +.CONCAT2 (NAME,_core_file_failing_signal), \ +.CONCAT2 (NAME,_core_file_matches_executable_p) +. char * (*_core_file_failing_command) PARAMS ((bfd *)); +. int (*_core_file_failing_signal) PARAMS ((bfd *)); +. bfd_boolean (*_core_file_matches_executable_p) PARAMS ((bfd *, bfd *)); +. +. {* Archive entry points. *} +.#define BFD_JUMP_TABLE_ARCHIVE(NAME) \ +.CONCAT2 (NAME,_slurp_armap), \ +.CONCAT2 (NAME,_slurp_extended_name_table), \ +.CONCAT2 (NAME,_construct_extended_name_table), \ +.CONCAT2 (NAME,_truncate_arname), \ +.CONCAT2 (NAME,_write_armap), \ +.CONCAT2 (NAME,_read_ar_hdr), \ +.CONCAT2 (NAME,_openr_next_archived_file), \ +.CONCAT2 (NAME,_get_elt_at_index), \ +.CONCAT2 (NAME,_generic_stat_arch_elt), \ +.CONCAT2 (NAME,_update_armap_timestamp) +. bfd_boolean (*_bfd_slurp_armap) PARAMS ((bfd *)); +. bfd_boolean (*_bfd_slurp_extended_name_table) PARAMS ((bfd *)); +. bfd_boolean (*_bfd_construct_extended_name_table) +. PARAMS ((bfd *, char **, bfd_size_type *, const char **)); +. void (*_bfd_truncate_arname) PARAMS ((bfd *, const char *, char *)); +. bfd_boolean (*write_armap) +. PARAMS ((bfd *, unsigned int, struct orl *, unsigned int, int)); +. PTR (*_bfd_read_ar_hdr_fn) PARAMS ((bfd *)); +. bfd * (*openr_next_archived_file) PARAMS ((bfd *, bfd *)); +.#define bfd_get_elt_at_index(b,i) BFD_SEND(b, _bfd_get_elt_at_index, (b,i)) +. bfd * (*_bfd_get_elt_at_index) PARAMS ((bfd *, symindex)); +. int (*_bfd_stat_arch_elt) PARAMS ((bfd *, struct stat *)); +. bfd_boolean (*_bfd_update_armap_timestamp) PARAMS ((bfd *)); +. +. {* Entry points used for symbols. *} +.#define BFD_JUMP_TABLE_SYMBOLS(NAME) \ +.CONCAT2 (NAME,_get_symtab_upper_bound), \ +.CONCAT2 (NAME,_get_symtab), \ +.CONCAT2 (NAME,_make_empty_symbol), \ +.CONCAT2 (NAME,_print_symbol), \ +.CONCAT2 (NAME,_get_symbol_info), \ +.CONCAT2 (NAME,_bfd_is_local_label_name), \ +.CONCAT2 (NAME,_get_lineno), \ +.CONCAT2 (NAME,_find_nearest_line), \ +.CONCAT2 (NAME,_bfd_make_debug_symbol), \ +.CONCAT2 (NAME,_read_minisymbols), \ +.CONCAT2 (NAME,_minisymbol_to_symbol) +. long (*_bfd_get_symtab_upper_bound) PARAMS ((bfd *)); +. long (*_bfd_canonicalize_symtab) PARAMS ((bfd *, +. struct symbol_cache_entry **)); +. struct symbol_cache_entry * +. (*_bfd_make_empty_symbol) PARAMS ((bfd *)); +. void (*_bfd_print_symbol) +. PARAMS ((bfd *, PTR, struct symbol_cache_entry *, bfd_print_symbol_type)); +.#define bfd_print_symbol(b,p,s,e) BFD_SEND(b, _bfd_print_symbol, (b,p,s,e)) +. void (*_bfd_get_symbol_info) +. PARAMS ((bfd *, struct symbol_cache_entry *, symbol_info *)); +.#define bfd_get_symbol_info(b,p,e) BFD_SEND(b, _bfd_get_symbol_info, (b,p,e)) +. bfd_boolean (*_bfd_is_local_label_name) PARAMS ((bfd *, const char *)); +. +. alent * (*_get_lineno) PARAMS ((bfd *, struct symbol_cache_entry *)); +. bfd_boolean (*_bfd_find_nearest_line) +. PARAMS ((bfd *, struct sec *, struct symbol_cache_entry **, bfd_vma, +. const char **, const char **, unsigned int *)); +. {* Back-door to allow format-aware applications to create debug symbols +. while using BFD for everything else. Currently used by the assembler +. when creating COFF files. *} +. asymbol * (*_bfd_make_debug_symbol) +. PARAMS ((bfd *, void *, unsigned long size)); +.#define bfd_read_minisymbols(b, d, m, s) \ +. BFD_SEND (b, _read_minisymbols, (b, d, m, s)) +. long (*_read_minisymbols) +. PARAMS ((bfd *, bfd_boolean, PTR *, unsigned int *)); +.#define bfd_minisymbol_to_symbol(b, d, m, f) \ +. BFD_SEND (b, _minisymbol_to_symbol, (b, d, m, f)) +. asymbol * (*_minisymbol_to_symbol) +. PARAMS ((bfd *, bfd_boolean, const PTR, asymbol *)); +. +. {* Routines for relocs. *} +.#define BFD_JUMP_TABLE_RELOCS(NAME) \ +.CONCAT2 (NAME,_get_reloc_upper_bound), \ +.CONCAT2 (NAME,_canonicalize_reloc), \ +.CONCAT2 (NAME,_bfd_reloc_type_lookup) +. long (*_get_reloc_upper_bound) PARAMS ((bfd *, sec_ptr)); +. long (*_bfd_canonicalize_reloc) +. PARAMS ((bfd *, sec_ptr, arelent **, struct symbol_cache_entry **)); +. {* See documentation on reloc types. *} +. reloc_howto_type * +. (*reloc_type_lookup) PARAMS ((bfd *, bfd_reloc_code_real_type)); +. +. {* Routines used when writing an object file. *} +.#define BFD_JUMP_TABLE_WRITE(NAME) \ +.CONCAT2 (NAME,_set_arch_mach), \ +.CONCAT2 (NAME,_set_section_contents) +. bfd_boolean (*_bfd_set_arch_mach) +. PARAMS ((bfd *, enum bfd_architecture, unsigned long)); +. bfd_boolean (*_bfd_set_section_contents) +. PARAMS ((bfd *, sec_ptr, PTR, file_ptr, bfd_size_type)); +. +. {* Routines used by the linker. *} +.#define BFD_JUMP_TABLE_LINK(NAME) \ +.CONCAT2 (NAME,_sizeof_headers), \ +.CONCAT2 (NAME,_bfd_get_relocated_section_contents), \ +.CONCAT2 (NAME,_bfd_relax_section), \ +.CONCAT2 (NAME,_bfd_link_hash_table_create), \ +.CONCAT2 (NAME,_bfd_link_hash_table_free), \ +.CONCAT2 (NAME,_bfd_link_add_symbols), \ +.CONCAT2 (NAME,_bfd_link_just_syms), \ +.CONCAT2 (NAME,_bfd_final_link), \ +.CONCAT2 (NAME,_bfd_link_split_section), \ +.CONCAT2 (NAME,_bfd_gc_sections), \ +.CONCAT2 (NAME,_bfd_merge_sections), \ +.CONCAT2 (NAME,_bfd_discard_group) +. int (*_bfd_sizeof_headers) PARAMS ((bfd *, bfd_boolean)); +. bfd_byte * (*_bfd_get_relocated_section_contents) +. PARAMS ((bfd *, struct bfd_link_info *, struct bfd_link_order *, +. bfd_byte *, bfd_boolean, struct symbol_cache_entry **)); +. +. bfd_boolean (*_bfd_relax_section) +. PARAMS ((bfd *, struct sec *, struct bfd_link_info *, bfd_boolean *)); +. +. {* Create a hash table for the linker. Different backends store +. different information in this table. *} +. struct bfd_link_hash_table * +. (*_bfd_link_hash_table_create) PARAMS ((bfd *)); +. +. {* Release the memory associated with the linker hash table. *} +. void (*_bfd_link_hash_table_free) +. PARAMS ((struct bfd_link_hash_table *)); +. +. {* Add symbols from this object file into the hash table. *} +. bfd_boolean (*_bfd_link_add_symbols) +. PARAMS ((bfd *, struct bfd_link_info *)); +. +. {* Indicate that we are only retrieving symbol values from this section. *} +. void (*_bfd_link_just_syms) +. PARAMS ((asection *, struct bfd_link_info *)); +. +. {* Do a link based on the link_order structures attached to each +. section of the BFD. *} +. bfd_boolean (*_bfd_final_link) PARAMS ((bfd *, struct bfd_link_info *)); +. +. {* Should this section be split up into smaller pieces during linking. *} +. bfd_boolean (*_bfd_link_split_section) PARAMS ((bfd *, struct sec *)); +. +. {* Remove sections that are not referenced from the output. *} +. bfd_boolean (*_bfd_gc_sections) PARAMS ((bfd *, struct bfd_link_info *)); +. +. {* Attempt to merge SEC_MERGE sections. *} +. bfd_boolean (*_bfd_merge_sections) PARAMS ((bfd *, struct bfd_link_info *)); +. +. {* Discard members of a group. *} +. bfd_boolean (*_bfd_discard_group) PARAMS ((bfd *, struct sec *)); +. +. {* Routines to handle dynamic symbols and relocs. *} +.#define BFD_JUMP_TABLE_DYNAMIC(NAME) \ +.CONCAT2 (NAME,_get_dynamic_symtab_upper_bound), \ +.CONCAT2 (NAME,_canonicalize_dynamic_symtab), \ +.CONCAT2 (NAME,_get_dynamic_reloc_upper_bound), \ +.CONCAT2 (NAME,_canonicalize_dynamic_reloc) +. {* Get the amount of memory required to hold the dynamic symbols. *} +. long (*_bfd_get_dynamic_symtab_upper_bound) PARAMS ((bfd *)); +. {* Read in the dynamic symbols. *} +. long (*_bfd_canonicalize_dynamic_symtab) +. PARAMS ((bfd *, struct symbol_cache_entry **)); +. {* Get the amount of memory required to hold the dynamic relocs. *} +. long (*_bfd_get_dynamic_reloc_upper_bound) PARAMS ((bfd *)); +. {* Read in the dynamic relocs. *} +. long (*_bfd_canonicalize_dynamic_reloc) +. PARAMS ((bfd *, arelent **, struct symbol_cache_entry **)); +. + +A pointer to an alternative bfd_target in case the current one is not +satisfactory. This can happen when the target cpu supports both big +and little endian code, and target chosen by the linker has the wrong +endianness. The function open_output() in ld/ldlang.c uses this field +to find an alternative output format that is suitable. + +. {* Opposite endian version of this target. *} +. const struct bfd_target * alternative_target; +. + +. {* Data for use by back-end routines, which isn't +. generic enough to belong in this structure. *} +. PTR backend_data; +. +.} bfd_target; +. +*/ + +/* All known xvecs (even those that don't compile on all systems). + Alphabetized for easy reference. + They are listed a second time below, since + we can't intermix extern's and initializers. */ +extern const bfd_target a29kcoff_big_vec; +extern const bfd_target a_out_adobe_vec; +extern const bfd_target aix5coff64_vec; +extern const bfd_target aout0_big_vec; +extern const bfd_target aout_arm_big_vec; +extern const bfd_target aout_arm_little_vec; +extern const bfd_target aout_mips_big_vec; +extern const bfd_target aout_mips_little_vec; +extern const bfd_target apollocoff_vec; +extern const bfd_target arm_epoc_pe_big_vec; +extern const bfd_target arm_epoc_pe_little_vec; +extern const bfd_target arm_epoc_pei_big_vec; +extern const bfd_target arm_epoc_pei_little_vec; +extern const bfd_target armcoff_big_vec; +extern const bfd_target armcoff_little_vec; +extern const bfd_target armnetbsd_vec; +extern const bfd_target armpe_big_vec; +extern const bfd_target armpe_little_vec; +extern const bfd_target armpei_big_vec; +extern const bfd_target armpei_little_vec; +extern const bfd_target b_out_vec_big_host; +extern const bfd_target b_out_vec_little_host; +extern const bfd_target bfd_efi_app_ia32_vec; +extern const bfd_target bfd_efi_app_ia64_vec; +extern const bfd_target bfd_elf32_avr_vec; +extern const bfd_target bfd_elf32_big_generic_vec; +extern const bfd_target bfd_elf32_bigarc_vec; +extern const bfd_target bfd_elf32_bigarm_oabi_vec; +extern const bfd_target bfd_elf32_bigarm_vec; +extern const bfd_target bfd_elf32_bigmips_vec; +extern const bfd_target bfd_elf32_cris_vec; +extern const bfd_target bfd_elf32_d10v_vec; +extern const bfd_target bfd_elf32_d30v_vec; +extern const bfd_target bfd_elf32_dlx_big_vec; +extern const bfd_target bfd_elf32_fr30_vec; +extern const bfd_target bfd_elf32_frv_vec; +extern const bfd_target bfd_elf32_h8300_vec; +extern const bfd_target bfd_elf32_hppa_linux_vec; +extern const bfd_target bfd_elf32_hppa_vec; +extern const bfd_target bfd_elf32_i370_vec; +extern const bfd_target bfd_elf32_i386_freebsd_vec; +extern const bfd_target bfd_elf32_i386_vec; +extern const bfd_target bfd_elf32_i860_little_vec; +extern const bfd_target bfd_elf32_i860_vec; +extern const bfd_target bfd_elf32_i960_vec; +extern const bfd_target bfd_elf32_ia64_big_vec; +extern const bfd_target bfd_elf32_ia64_hpux_big_vec; +extern const bfd_target bfd_elf32_ip2k_vec; +extern const bfd_target bfd_elf32_iq2000_vec; +extern const bfd_target bfd_elf32_little_generic_vec; +extern const bfd_target bfd_elf32_littlearc_vec; +extern const bfd_target bfd_elf32_littlearm_oabi_vec; +extern const bfd_target bfd_elf32_littlearm_vec; +extern const bfd_target bfd_elf32_littlemips_vec; +extern const bfd_target bfd_elf32_m32r_vec; +extern const bfd_target bfd_elf32_m68hc11_vec; +extern const bfd_target bfd_elf32_m68hc12_vec; +extern const bfd_target bfd_elf32_m68k_vec; +extern const bfd_target bfd_elf32_m88k_vec; +extern const bfd_target bfd_elf32_mcore_big_vec; +extern const bfd_target bfd_elf32_mcore_little_vec; +extern const bfd_target bfd_elf32_mn10200_vec; +extern const bfd_target bfd_elf32_mn10300_vec; +extern const bfd_target bfd_elf32_msp430_vec; +extern const bfd_target bfd_elf32_nbigmips_vec; +extern const bfd_target bfd_elf32_nlittlemips_vec; +extern const bfd_target bfd_elf32_ntradbigmips_vec; +extern const bfd_target bfd_elf32_ntradlittlemips_vec; +extern const bfd_target bfd_elf32_openrisc_vec; +extern const bfd_target bfd_elf32_or32_big_vec; +extern const bfd_target bfd_elf32_pj_vec; +extern const bfd_target bfd_elf32_pjl_vec; +extern const bfd_target bfd_elf32_powerpc_vec; +extern const bfd_target bfd_elf32_powerpcle_vec; +extern const bfd_target bfd_elf32_s390_vec; +extern const bfd_target bfd_elf32_sh64_vec; +extern const bfd_target bfd_elf32_sh64l_vec; +extern const bfd_target bfd_elf32_sh64lin_vec; +extern const bfd_target bfd_elf32_sh64blin_vec; +extern const bfd_target bfd_elf32_sh64lnbsd_vec; +extern const bfd_target bfd_elf32_sh64nbsd_vec; +extern const bfd_target bfd_elf32_sh_vec; +extern const bfd_target bfd_elf32_shblin_vec; +extern const bfd_target bfd_elf32_shl_vec; +extern const bfd_target bfd_elf32_shlin_vec; +extern const bfd_target bfd_elf32_shlnbsd_vec; +extern const bfd_target bfd_elf32_shnbsd_vec; +extern const bfd_target bfd_elf32_sparc_vec; +extern const bfd_target bfd_elf32_tradbigmips_vec; +extern const bfd_target bfd_elf32_tradlittlemips_vec; +extern const bfd_target bfd_elf32_us_cris_vec; +extern const bfd_target bfd_elf32_v850_vec; +extern const bfd_target bfd_elf32_vax_vec; +extern const bfd_target bfd_elf32_xstormy16_vec; +extern const bfd_target bfd_elf32_xtensa_be_vec; +extern const bfd_target bfd_elf32_xtensa_le_vec; +extern const bfd_target bfd_elf64_alpha_freebsd_vec; +extern const bfd_target bfd_elf64_alpha_vec; +extern const bfd_target bfd_elf64_big_generic_vec; +extern const bfd_target bfd_elf64_bigmips_vec; +extern const bfd_target bfd_elf64_hppa_linux_vec; +extern const bfd_target bfd_elf64_hppa_vec; +extern const bfd_target bfd_elf64_ia64_aix_big_vec; +extern const bfd_target bfd_elf64_ia64_aix_little_vec; +extern const bfd_target bfd_elf64_ia64_big_vec; +extern const bfd_target bfd_elf64_ia64_hpux_big_vec; +extern const bfd_target bfd_elf64_ia64_little_vec; +extern const bfd_target bfd_elf64_little_generic_vec; +extern const bfd_target bfd_elf64_littlemips_vec; +extern const bfd_target bfd_elf64_mmix_vec; +extern const bfd_target bfd_elf64_powerpc_vec; +extern const bfd_target bfd_elf64_powerpcle_vec; +extern const bfd_target bfd_elf64_s390_vec; +extern const bfd_target bfd_elf64_sh64_vec; +extern const bfd_target bfd_elf64_sh64l_vec; +extern const bfd_target bfd_elf64_sh64lin_vec; +extern const bfd_target bfd_elf64_sh64blin_vec; +extern const bfd_target bfd_elf64_sh64lnbsd_vec; +extern const bfd_target bfd_elf64_sh64nbsd_vec; +extern const bfd_target bfd_elf64_sparc_vec; +extern const bfd_target bfd_elf64_tradbigmips_vec; +extern const bfd_target bfd_elf64_tradlittlemips_vec; +extern const bfd_target bfd_elf64_x86_64_vec; +extern const bfd_target bfd_mmo_vec; +extern const bfd_target bfd_powerpc_pe_vec; +extern const bfd_target bfd_powerpc_pei_vec; +extern const bfd_target bfd_powerpcle_pe_vec; +extern const bfd_target bfd_powerpcle_pei_vec; +extern const bfd_target cris_aout_vec; +extern const bfd_target demo_64_vec; +extern const bfd_target ecoff_big_vec; +extern const bfd_target ecoff_biglittle_vec; +extern const bfd_target ecoff_little_vec; +extern const bfd_target ecoffalpha_little_vec; +extern const bfd_target go32coff_vec; +extern const bfd_target go32stubbedcoff_vec; +extern const bfd_target h8300coff_vec; +extern const bfd_target h8500coff_vec; +extern const bfd_target host_aout_vec; +extern const bfd_target hp300bsd_vec; +extern const bfd_target hp300hpux_vec; +extern const bfd_target i386aout_vec; +extern const bfd_target i386bsd_vec; +extern const bfd_target i386coff_vec; +extern const bfd_target i386dynix_vec; +extern const bfd_target i386freebsd_vec; +extern const bfd_target i386linux_vec; +extern const bfd_target i386lynx_aout_vec; +extern const bfd_target i386lynx_coff_vec; +extern const bfd_target i386mach3_vec; +extern const bfd_target i386msdos_vec; +extern const bfd_target i386netbsd_vec; +extern const bfd_target i386os9k_vec; +extern const bfd_target i386pe_vec; +extern const bfd_target i386pei_vec; +extern const bfd_target i860coff_vec; +extern const bfd_target icoff_big_vec; +extern const bfd_target icoff_little_vec; +extern const bfd_target ieee_vec; +extern const bfd_target m68k4knetbsd_vec; +extern const bfd_target m68kaux_coff_vec; +extern const bfd_target m68kcoff_vec; +extern const bfd_target m68kcoffun_vec; +extern const bfd_target m68klinux_vec; +extern const bfd_target m68klynx_aout_vec; +extern const bfd_target m68klynx_coff_vec; +extern const bfd_target m68knetbsd_vec; +extern const bfd_target m68ksysvcoff_vec; +extern const bfd_target m88kbcs_vec; +extern const bfd_target m88kmach3_vec; +extern const bfd_target mach_o_be_vec; +extern const bfd_target mach_o_le_vec; +extern const bfd_target mach_o_fat_vec; +extern const bfd_target mcore_pe_big_vec; +extern const bfd_target mcore_pe_little_vec; +extern const bfd_target mcore_pei_big_vec; +extern const bfd_target mcore_pei_little_vec; +extern const bfd_target mipslpe_vec; +extern const bfd_target mipslpei_vec; +extern const bfd_target newsos3_vec; +extern const bfd_target nlm32_alpha_vec; +extern const bfd_target nlm32_i386_vec; +extern const bfd_target nlm32_powerpc_vec; +extern const bfd_target nlm32_sparc_vec; +extern const bfd_target oasys_vec; +extern const bfd_target or32coff_big_vec; +extern const bfd_target pc532machaout_vec; +extern const bfd_target pc532netbsd_vec; +extern const bfd_target pdp11_aout_vec; +extern const bfd_target pef_vec; +extern const bfd_target pef_xlib_vec; +extern const bfd_target pmac_xcoff_vec; +extern const bfd_target ppcboot_vec; +extern const bfd_target riscix_vec; +extern const bfd_target rs6000coff64_vec; +extern const bfd_target rs6000coff_vec; +extern const bfd_target shcoff_small_vec; +extern const bfd_target shcoff_vec; +extern const bfd_target shlcoff_small_vec; +extern const bfd_target shlcoff_vec; +extern const bfd_target shlpe_vec; +extern const bfd_target shlpei_vec; +extern const bfd_target som_vec; +extern const bfd_target sparccoff_vec; +extern const bfd_target sparcle_aout_vec; +extern const bfd_target sparclinux_vec; +extern const bfd_target sparclynx_aout_vec; +extern const bfd_target sparclynx_coff_vec; +extern const bfd_target sparcnetbsd_vec; +extern const bfd_target sunos_big_vec; +extern const bfd_target sym_vec; +extern const bfd_target tic30_aout_vec; +extern const bfd_target tic30_coff_vec; +extern const bfd_target tic4x_coff0_beh_vec; +extern const bfd_target tic4x_coff0_vec; +extern const bfd_target tic4x_coff1_beh_vec; +extern const bfd_target tic4x_coff1_vec; +extern const bfd_target tic4x_coff2_beh_vec; +extern const bfd_target tic4x_coff2_vec; +extern const bfd_target tic54x_coff0_beh_vec; +extern const bfd_target tic54x_coff0_vec; +extern const bfd_target tic54x_coff1_beh_vec; +extern const bfd_target tic54x_coff1_vec; +extern const bfd_target tic54x_coff2_beh_vec; +extern const bfd_target tic54x_coff2_vec; +extern const bfd_target tic80coff_vec; +extern const bfd_target vaxbsd_vec; +extern const bfd_target vaxnetbsd_vec; +extern const bfd_target vax1knetbsd_vec; +extern const bfd_target versados_vec; +extern const bfd_target vms_alpha_vec; +extern const bfd_target vms_vax_vec; +extern const bfd_target w65_vec; +extern const bfd_target we32kcoff_vec; +extern const bfd_target z8kcoff_vec; + +/* These are always included. */ +extern const bfd_target srec_vec; +extern const bfd_target symbolsrec_vec; +extern const bfd_target tekhex_vec; +extern const bfd_target binary_vec; +extern const bfd_target ihex_vec; + +/* All of the xvecs for core files. */ +extern const bfd_target aix386_core_vec; +extern const bfd_target cisco_core_big_vec; +extern const bfd_target cisco_core_little_vec; +extern const bfd_target hppabsd_core_vec; +extern const bfd_target hpux_core_vec; +extern const bfd_target irix_core_vec; +extern const bfd_target netbsd_core_vec; +extern const bfd_target osf_core_vec; +extern const bfd_target ptrace_core_vec; +extern const bfd_target sco5_core_vec; +extern const bfd_target trad_core_vec; + +static const bfd_target * const _bfd_target_vector[] = { + +#ifdef SELECT_VECS + + SELECT_VECS, + +#else /* not SELECT_VECS */ + +#ifdef DEFAULT_VECTOR + &DEFAULT_VECTOR, +#endif + /* This list is alphabetized to make it easy to compare + with other vector lists -- the decls above and + the case statement in configure.in. + Vectors that don't compile on all systems, or aren't finished, + should have an entry here with #if 0 around it, to show that + it wasn't omitted by mistake. */ + &a29kcoff_big_vec, + &a_out_adobe_vec, +#ifdef BFD64 + &aix5coff64_vec, +#endif + &aout0_big_vec, +#if 0 + /* We have no way of distinguishing these from other a.out variants. */ + &aout_arm_big_vec, + &aout_arm_little_vec, + /* No one seems to use this. */ + &aout_mips_big_vec, +#endif + &aout_mips_little_vec, +#if 0 + &apollocoff_vec, +#endif + &arm_epoc_pe_big_vec, + &arm_epoc_pe_little_vec, + &arm_epoc_pei_big_vec, + &arm_epoc_pei_little_vec, + &armcoff_big_vec, + &armcoff_little_vec, + &armnetbsd_vec, + &armpe_big_vec, + &armpe_little_vec, + &armpei_big_vec, + &armpei_little_vec, + &b_out_vec_big_host, + &b_out_vec_little_host, + &bfd_efi_app_ia32_vec, +#ifdef BFD64 + &bfd_efi_app_ia64_vec, +#endif + &bfd_elf32_avr_vec, + + /* This, and other vectors, may not be used in any *.mt configuration. + But that does not mean they are unnecessary. If configured with + --enable-targets=all, objdump or gdb should be able to examine + the file even if we don't recognize the machine type. */ + &bfd_elf32_big_generic_vec, + &bfd_elf32_bigarc_vec, + &bfd_elf32_bigarm_oabi_vec, + &bfd_elf32_bigarm_vec, + &bfd_elf32_bigmips_vec, + &bfd_elf32_cris_vec, + &bfd_elf32_d10v_vec, + &bfd_elf32_d30v_vec, + &bfd_elf32_dlx_big_vec, + &bfd_elf32_fr30_vec, + &bfd_elf32_frv_vec, + &bfd_elf32_h8300_vec, + &bfd_elf32_hppa_linux_vec, + &bfd_elf32_hppa_vec, + &bfd_elf32_i370_vec, + &bfd_elf32_i386_freebsd_vec, + &bfd_elf32_i386_vec, + &bfd_elf32_i860_little_vec, + &bfd_elf32_i860_vec, + &bfd_elf32_i960_vec, +#if 0 + &bfd_elf32_ia64_big_vec, +#endif + &bfd_elf32_ia64_hpux_big_vec, + &bfd_elf32_ip2k_vec, + &bfd_elf32_iq2000_vec, + &bfd_elf32_little_generic_vec, + &bfd_elf32_littlearc_vec, + &bfd_elf32_littlearm_oabi_vec, + &bfd_elf32_littlearm_vec, + &bfd_elf32_littlemips_vec, + &bfd_elf32_m32r_vec, + &bfd_elf32_m68hc11_vec, + &bfd_elf32_m68hc12_vec, + &bfd_elf32_m68k_vec, + &bfd_elf32_m88k_vec, + &bfd_elf32_mcore_big_vec, + &bfd_elf32_mcore_little_vec, + &bfd_elf32_mn10200_vec, + &bfd_elf32_mn10300_vec, + &bfd_elf32_msp430_vec, +#ifdef BFD64 + &bfd_elf32_nbigmips_vec, + &bfd_elf32_nlittlemips_vec, + &bfd_elf32_ntradbigmips_vec, + &bfd_elf32_ntradlittlemips_vec, +#endif + &bfd_elf32_openrisc_vec, + &bfd_elf32_or32_big_vec, + &bfd_elf32_pj_vec, + &bfd_elf32_pjl_vec, + &bfd_elf32_powerpc_vec, + &bfd_elf32_powerpcle_vec, + &bfd_elf32_s390_vec, + &bfd_elf32_sh_vec, + &bfd_elf32_shblin_vec, + &bfd_elf32_shl_vec, + &bfd_elf32_shlin_vec, + &bfd_elf32_shlnbsd_vec, + &bfd_elf32_shnbsd_vec, +#ifdef BFD64 + &bfd_elf32_sh64_vec, + &bfd_elf32_sh64l_vec, + &bfd_elf32_sh64lnbsd_vec, + &bfd_elf32_sh64nbsd_vec, + &bfd_elf32_sh64lin_vec, + &bfd_elf32_sh64blin_vec, +#endif + &bfd_elf32_sparc_vec, + &bfd_elf32_tradbigmips_vec, + &bfd_elf32_tradlittlemips_vec, + &bfd_elf32_us_cris_vec, + &bfd_elf32_v850_vec, + &bfd_elf32_vax_vec, + &bfd_elf32_xstormy16_vec, + &bfd_elf32_xtensa_be_vec, + &bfd_elf32_xtensa_le_vec, +#ifdef BFD64 + &bfd_elf64_alpha_freebsd_vec, + &bfd_elf64_alpha_vec, + &bfd_elf64_big_generic_vec, + &bfd_elf64_bigmips_vec, + &bfd_elf64_hppa_linux_vec, + &bfd_elf64_hppa_vec, + &bfd_elf64_ia64_aix_big_vec, + &bfd_elf64_ia64_aix_little_vec, + &bfd_elf64_ia64_big_vec, + &bfd_elf64_ia64_hpux_big_vec, + &bfd_elf64_ia64_little_vec, + &bfd_elf64_little_generic_vec, + &bfd_elf64_littlemips_vec, + &bfd_elf64_mmix_vec, + &bfd_elf64_powerpc_vec, + &bfd_elf64_powerpcle_vec, + &bfd_elf64_s390_vec, + &bfd_elf64_sh64_vec, + &bfd_elf64_sh64l_vec, + &bfd_elf64_sh64lnbsd_vec, + &bfd_elf64_sh64nbsd_vec, + &bfd_elf64_sh64lin_vec, + &bfd_elf64_sh64blin_vec, +#if 0 + &bfd_elf64_sparc_vec, +#endif + &bfd_elf64_tradbigmips_vec, + &bfd_elf64_tradlittlemips_vec, + &bfd_elf64_x86_64_vec, + &bfd_mmo_vec, +#endif + &bfd_powerpc_pe_vec, + &bfd_powerpc_pei_vec, + &bfd_powerpcle_pe_vec, + &bfd_powerpcle_pei_vec, + &cris_aout_vec, +#ifdef BFD64 + &demo_64_vec, /* Only compiled if host has long-long support. */ +#endif + &ecoff_big_vec, + &ecoff_biglittle_vec, + &ecoff_little_vec, +#ifdef BFD64 + &ecoffalpha_little_vec, +#endif + &go32coff_vec, + &go32stubbedcoff_vec, + &h8300coff_vec, + &h8500coff_vec, +#if 0 + /* Since a.out files lack decent magic numbers, no way to recognize + which kind of a.out file it is. */ + &host_aout_vec, + /* Clashes with sunos_big_vec magic no. */ + &hp300bsd_vec, +#endif + &hp300hpux_vec, + &i386aout_vec, + &i386bsd_vec, + &i386coff_vec, +#if 0 + &i386dynix_vec, +#endif + &i386freebsd_vec, +#if 0 + /* Since a.out files lack decent magic numbers, no way to recognize + which kind of a.out file it is. */ + &i386linux_vec, +#endif + &i386lynx_aout_vec, + &i386lynx_coff_vec, +#if 0 + /* No distinguishing features for Mach 3 executables. */ + &i386mach3_vec, +#endif + &i386msdos_vec, + &i386netbsd_vec, + &i386os9k_vec, + &i386pe_vec, + &i386pei_vec, + &i860coff_vec, + &icoff_big_vec, + &icoff_little_vec, + &ieee_vec, +#if 0 + &m68k4knetbsd_vec, + &m68kaux_coff_vec, +#endif + &m68kcoff_vec, + &m68kcoffun_vec, +#if 0 + /* Since a.out files lack decent magic numbers, no way to recognize + which kind of a.out file it is. */ + &m68klinux_vec, +#endif + &m68klynx_aout_vec, + &m68klynx_coff_vec, + &m68knetbsd_vec, + &m68ksysvcoff_vec, + &m88kbcs_vec, + &m88kmach3_vec, + &mach_o_be_vec, + &mach_o_le_vec, + &mach_o_fat_vec, + &mcore_pe_big_vec, + &mcore_pe_little_vec, + &mcore_pei_big_vec, + &mcore_pei_little_vec, + &mipslpe_vec, + &mipslpei_vec, + &newsos3_vec, +#ifdef BFD64 + &nlm32_alpha_vec, +#endif + &nlm32_i386_vec, + &nlm32_powerpc_vec, + &nlm32_sparc_vec, +#if 0 + /* We have no oasys tools anymore, so we can't test any of this + anymore. If you want to test the stuff yourself, go ahead... + steve@cygnus.com + Worse, since there is no magic number for archives, there + can be annoying target mis-matches. */ + &oasys_vec, +#endif + /* Entry for the OpenRISC family. */ + &or32coff_big_vec, + + &pc532machaout_vec, + &pc532netbsd_vec, + &pdp11_aout_vec, + &pef_vec, + &pef_xlib_vec, +#if 0 + /* This has the same magic number as RS/6000. */ + &pmac_xcoff_vec, +#endif + &ppcboot_vec, +#if 0 + /* We have no way of distinguishing these from other a.out variants. */ + &riscix_vec, +#endif +#ifdef BFD64 + &rs6000coff64_vec, +#endif + &rs6000coff_vec, + &shcoff_small_vec, + &shcoff_vec, + &shlcoff_small_vec, + &shlcoff_vec, + &shlpe_vec, + &shlpei_vec, +#if defined (HOST_HPPAHPUX) || defined (HOST_HPPABSD) || defined (HOST_HPPAOSF) + &som_vec, +#endif + &sparccoff_vec, + &sparcle_aout_vec, + &sparclinux_vec, + &sparclynx_aout_vec, + &sparclynx_coff_vec, + &sparcnetbsd_vec, + &sunos_big_vec, + &sym_vec, + &tic30_aout_vec, + &tic30_coff_vec, + &tic54x_coff0_beh_vec, + &tic54x_coff0_vec, + &tic54x_coff1_beh_vec, + &tic54x_coff1_vec, + &tic54x_coff2_beh_vec, + &tic54x_coff2_vec, + &tic80coff_vec, + &vaxbsd_vec, + &vaxnetbsd_vec, + &vax1knetbsd_vec, + &versados_vec, +#ifdef BFD64 + &vms_alpha_vec, +#endif + &vms_vax_vec, + &w65_vec, + &we32kcoff_vec, + &z8kcoff_vec, +#endif /* not SELECT_VECS */ + +/* Always support S-records, for convenience. */ + &srec_vec, + &symbolsrec_vec, +/* And tekhex */ + &tekhex_vec, +/* Likewise for binary output. */ + &binary_vec, +/* Likewise for ihex. */ + &ihex_vec, + +/* Add any required traditional-core-file-handler. */ + +#ifdef AIX386_CORE + &aix386_core_vec, +#endif +#if 0 + /* We don't include cisco_core_*_vec. Although it has a magic number, + the magic number isn't at the beginning of the file, and thus + might spuriously match other kinds of files. */ + &cisco_core_big_vec, + &cisco_core_little_vec, +#endif +#ifdef HPPABSD_CORE + &hppabsd_core_vec, +#endif +#ifdef HPUX_CORE + &hpux_core_vec, +#endif +#ifdef IRIX_CORE + &irix_core_vec, +#endif +#ifdef NETBSD_CORE + &netbsd_core_vec, +#endif +#ifdef OSF_CORE + &osf_core_vec, +#endif +#ifdef PTRACE_CORE + &ptrace_core_vec, +#endif +#ifdef SCO5_CORE + &sco5_core_vec, +#endif +#ifdef TRAD_CORE + &trad_core_vec, +#endif + + NULL /* end of list marker */ +}; +const bfd_target * const *bfd_target_vector = _bfd_target_vector; + +/* bfd_default_vector[0] contains either the address of the default vector, + if there is one, or zero if there isn't. */ + +const bfd_target *bfd_default_vector[] = { +#ifdef DEFAULT_VECTOR + &DEFAULT_VECTOR, +#endif + NULL +}; + +/* bfd_associated_vector[] contains the associated target vectors used + to reduce the ambiguity in bfd_check_format_matches. */ + +static const bfd_target *_bfd_associated_vector[] = { +#ifdef ASSOCIATED_VECS + ASSOCIATED_VECS, +#endif + NULL +}; +const bfd_target * const *bfd_associated_vector = _bfd_associated_vector; + +/* When there is an ambiguous match, bfd_check_format_matches puts the + names of the matching targets in an array. This variable is the maximum + number of entries that the array could possibly need. */ +const size_t _bfd_target_vector_entries = sizeof (_bfd_target_vector)/sizeof (*_bfd_target_vector); + +/* This array maps configuration triplets onto BFD vectors. */ + +struct targmatch +{ + /* The configuration triplet. */ + const char *triplet; + /* The BFD vector. If this is NULL, then the vector is found by + searching forward for the next structure with a non NULL vector + field. */ + const bfd_target *vector; +}; + +/* targmatch.h is built by Makefile out of config.bfd. */ +static const struct targmatch bfd_target_match[] = { +#include "targmatch.h" + { NULL, NULL } +}; + +static const bfd_target *find_target PARAMS ((const char *)); + +/* Find a target vector, given a name or configuration triplet. */ + +static const bfd_target * +find_target (name) + const char *name; +{ + const bfd_target * const *target; + const struct targmatch *match; + + for (target = &bfd_target_vector[0]; *target != NULL; target++) + if (strcmp (name, (*target)->name) == 0) + return *target; + + /* If we couldn't match on the exact name, try matching on the + configuration triplet. FIXME: We should run the triplet through + config.sub first, but that is hard. */ + for (match = &bfd_target_match[0]; match->triplet != NULL; match++) + { + if (fnmatch (match->triplet, name, 0) == 0) + { + while (match->vector == NULL) + ++match; + return match->vector; + break; + } + } + + bfd_set_error (bfd_error_invalid_target); + return NULL; +} + +/* +FUNCTION + bfd_set_default_target + +SYNOPSIS + bfd_boolean bfd_set_default_target (const char *name); + +DESCRIPTION + Set the default target vector to use when recognizing a BFD. + This takes the name of the target, which may be a BFD target + name or a configuration triplet. +*/ + +bfd_boolean +bfd_set_default_target (name) + const char *name; +{ + const bfd_target *target; + + if (bfd_default_vector[0] != NULL + && strcmp (name, bfd_default_vector[0]->name) == 0) + return TRUE; + + target = find_target (name); + if (target == NULL) + return FALSE; + + bfd_default_vector[0] = target; + return TRUE; +} + +/* +FUNCTION + bfd_find_target + +SYNOPSIS + const bfd_target *bfd_find_target (const char *target_name, bfd *abfd); + +DESCRIPTION + Return a pointer to the transfer vector for the object target + named @var{target_name}. If @var{target_name} is <>, choose the + one in the environment variable <>; if that is null or not + defined, then choose the first entry in the target list. + Passing in the string "default" or setting the environment + variable to "default" will cause the first entry in the target + list to be returned, and "target_defaulted" will be set in the + BFD. This causes <> to loop over all the + targets to find the one that matches the file being read. +*/ + +const bfd_target * +bfd_find_target (target_name, abfd) + const char *target_name; + bfd *abfd; +{ + const char *targname; + const bfd_target *target; + + if (target_name != NULL) + targname = target_name; + else + targname = getenv ("GNUTARGET"); + + /* This is safe; the vector cannot be null. */ + if (targname == NULL || strcmp (targname, "default") == 0) + { + abfd->target_defaulted = TRUE; + if (bfd_default_vector[0] != NULL) + abfd->xvec = bfd_default_vector[0]; + else + abfd->xvec = bfd_target_vector[0]; + return abfd->xvec; + } + + abfd->target_defaulted = FALSE; + + target = find_target (targname); + if (target == NULL) + return NULL; + + abfd->xvec = target; + return target; +} + +/* +FUNCTION + bfd_target_list + +SYNOPSIS + const char ** bfd_target_list (void); + +DESCRIPTION + Return a freshly malloced NULL-terminated + vector of the names of all the valid BFD targets. Do not + modify the names. + +*/ + +const char ** +bfd_target_list () +{ + int vec_length= 0; + bfd_size_type amt; +#if defined (HOST_HPPAHPUX) && ! defined (__STDC__) + /* The native compiler on the HP9000/700 has a bug which causes it + to loop endlessly when compiling this file. This avoids it. */ + volatile +#endif + const bfd_target * const *target; + const char **name_list, **name_ptr; + + for (target = &bfd_target_vector[0]; *target != NULL; target++) + vec_length++; + + amt = (vec_length + 1) * sizeof (char **); + name_ptr = name_list = (const char **) bfd_malloc (amt); + + if (name_list == NULL) + return NULL; + + for (target = &bfd_target_vector[0]; *target != NULL; target++) + if (target == &bfd_target_vector[0] + || *target != bfd_target_vector[0]) + *name_ptr++ = (*target)->name; + + *name_ptr = NULL; + return name_list; +} + +/* +FUNCTION + bfd_seach_for_target + +SYNOPSIS + const bfd_target * bfd_search_for_target (int (* search_func) + (const bfd_target *, void *), + void *); + +DESCRIPTION + Return a pointer to the first transfer vector in the list of + transfer vectors maintained by BFD that produces a non-zero + result when passed to the function @var{search_func}. The + parameter @var{data} is passed, unexamined, to the search + function. +*/ + +const bfd_target * +bfd_search_for_target (search_func, data) + int (* search_func) PARAMS ((const bfd_target * target, void * data)); + void * data; +{ + const bfd_target * const * target; + + for (target = bfd_target_vector; * target != NULL; target ++) + if (search_func (* target, data)) + return * target; + + return NULL; +} diff --git a/contrib/binutils-2.14/bfd/targmatch.sed b/contrib/binutils-2.14/bfd/targmatch.sed new file mode 100644 index 0000000000..2716876547 --- /dev/null +++ b/contrib/binutils-2.14/bfd/targmatch.sed @@ -0,0 +1,33 @@ +1,/START OF targmatch.h/ d +/END OF targmatch.h/,$ d +/^[ ]*case/,/^[ ]*esac/ d +s/^#if/KEEP #if/ +s/^#endif/KEEP #endif/ +s/^[ ]*#.*$// +s/^KEEP #/#/ +s/[ ]*\\$// +t lab1 + :lab1 +s/[| ][| ]*\([^|() ][^|() ]*\)[ ]*|/{ "\1", NULL },/g +s/[| ][| ]*\([^|() ][^|() ]*\)[ ]*)/{ "\1",/g +t lab2 +s/^[ ]*targ_defvec=\([^ ]*\)/#if !defined (SELECT_VECS) || defined (HAVE_\1)/ +t lab3 +s/.*=.*// +s/;;// +b + :lab2 +H +d + :lab3 +G +s/\n/%EOL%/g +s/\(defined (HAVE_\)\([^)]*\)\(.*\)/\1\2\3\ +\&\2 },\ +#endif/ +s/%EOL%/\ +/g +p +s/.*//g +s/\n//g +h diff --git a/contrib/binutils-2.14/bfd/tekhex.c b/contrib/binutils-2.14/bfd/tekhex.c new file mode 100644 index 0000000000..77b471a2d7 --- /dev/null +++ b/contrib/binutils-2.14/bfd/tekhex.c @@ -0,0 +1,1068 @@ +/* BFD backend for Extended Tektronix Hex Format objects. + Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + Written by Steve Chamberlain of 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* +SUBSECTION + Tektronix Hex Format handling + +DESCRIPTION + + Tek Hex records can hold symbols and data, but not + relocations. Their main application is communication with + devices like PROM programmers and ICE equipment. + + It seems that the sections are descibed as being really big, + the example I have says that the text section is 0..ffffffff. + BFD would barf with this, many apps would try to alloc 4GB to + read in the file. + + Tex Hex may contain many sections, but the data which comes in + has no tag saying which section it belongs to, so we create + one section for each block of data, called "blknnnn" which we + stick all the data into. + + TekHex may come out of order and there is no header, so an + initial scan is required to discover the minimum and maximum + addresses used to create the vma and size of the sections we + create. + We read in the data into pages of CHUNK_MASK+1 size and read + them out from that whenever we need to. + + Any number of sections may be created for output, we save them + up and output them when it's time to close the bfd. + + A TekHex record looks like: +EXAMPLE + % + +DESCRIPTION + Where + o length + is the number of bytes in the record not including the % sign. + o type + is one of: + 3) symbol record + 6) data record + 8) termination record + +The data can come out of order, and may be discontigous. This is a +serial protocol, so big files are unlikely, so we keep a list of 8k chunks +*/ + +#include "bfd.h" +#include "sysdep.h" +#include "libbfd.h" +#include "libiberty.h" + +typedef struct + { + bfd_vma low; + bfd_vma high; + } addr_range_type; + +typedef struct tekhex_symbol_struct + { + + asymbol symbol; + struct tekhex_symbol_struct *prev; + + } tekhex_symbol_type; + +static const char digs[] = "0123456789ABCDEF"; + +static char sum_block[256]; + +#define NOT_HEX 20 +#define NIBBLE(x) hex_value(x) +#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1])) +#define TOHEX(d,x) \ +(d)[1] = digs[(x) & 0xf]; \ +(d)[0] = digs[((x)>>4)&0xf]; +#define ISHEX(x) hex_p(x) + +static void tekhex_init PARAMS ((void)); +static bfd_vma getvalue PARAMS ((char **)); +static void tekhex_print_symbol + PARAMS ((bfd *, PTR, asymbol *, bfd_print_symbol_type)); +static void tekhex_get_symbol_info PARAMS ((bfd *, asymbol *, symbol_info *)); +static asymbol *tekhex_make_empty_symbol PARAMS ((bfd *)); +static int tekhex_sizeof_headers PARAMS ((bfd *, bfd_boolean)); +static bfd_boolean tekhex_write_object_contents PARAMS ((bfd *)); +static void out PARAMS ((bfd *, int, char *, char *)); +static void writesym PARAMS ((char **, const char *)); +static void writevalue PARAMS ((char **, bfd_vma)); +static bfd_boolean tekhex_set_section_contents + PARAMS ((bfd*, sec_ptr, PTR, file_ptr, bfd_size_type)); +static bfd_boolean tekhex_set_arch_mach + PARAMS ((bfd *, enum bfd_architecture, unsigned long)); +static bfd_boolean tekhex_get_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type)); +static void move_section_contents + PARAMS ((bfd *, asection *, PTR, file_ptr, bfd_size_type, bfd_boolean)); +static const bfd_target *tekhex_object_p PARAMS ((bfd *)); +static bfd_boolean tekhex_mkobject PARAMS ((bfd *)); +static long tekhex_get_symtab_upper_bound PARAMS ((bfd *)); +static long tekhex_get_symtab PARAMS ((bfd *, asymbol **)); +static void pass_over PARAMS ((bfd *, void (*) (bfd*, int, char *))); +static void first_phase PARAMS ((bfd *, int, char *)); +static void insert_byte PARAMS ((bfd *, int, bfd_vma)); +static struct data_struct *find_chunk PARAMS ((bfd *, bfd_vma)); +static unsigned int getsym PARAMS ((char *, char **)); + +/* +Here's an example +%3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 +%1B3709T_SEGMENT1108FFFFFFFF +%2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 +%373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 +%373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 +%373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 +%373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 +%373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 +%373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 +%373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 +%2734D9T_SEGMENT8Bvoid$t15$151035_main10 +%2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 +%2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 +%07 8 10 10 + +explanation: +%3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 + ^ ^^ ^ ^-data + | || +------ 4 char integer 0x8000 + | |+-------- checksum + | +--------- type 6 (data record) + +----------- length 3a chars + <---------------------- 3a (58 chars) -------------------> + +%1B3709T_SEGMENT1108FFFFFFFF + ^ ^^ ^- 8 character integer 0xffffffff + | |+- 1 character integer 0 + | +-- type 1 symbol (section definition) + +------------ 9 char symbol T_SEGMENT + +%2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 +%373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 +%373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 +%373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 +%373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 +%373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 +%373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 +%373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 +%2734D9T_SEGMENT8Bvoid$t15$151035_main10 +%2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 +%2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 +%0781010 + +Turns into +sac@thepub$ ./objdump -dx -m m68k f + +f: file format tekhex +-----x--- 9/55728 -134219416 Sep 29 15:13 1995 f +architecture: UNKNOWN!, flags 0x00000010: +HAS_SYMS +start address 0x00000000 +SECTION 0 [D00000000] : size 00020000 vma 00000000 align 2**0 + ALLOC, LOAD +SECTION 1 [D00008000] : size 00002001 vma 00008000 align 2**0 + +SECTION 2 [T_SEGMENT] : size ffffffff vma 00000000 align 2**0 + +SYMBOL TABLE: +00000000 g T_SEGMENT gcc_compiled$ +00000000 g T_SEGMENT hello$c +00000000 g T_SEGMENT int$t1$r1$$21474 +00000000 g T_SEGMENT char$t2$r2$0$127 +00000000 g T_SEGMENT long$int$t3$r1$$ +00000000 g T_SEGMENT unsigned$int$t4$ +00000000 g T_SEGMENT long$unsigned$in +00000000 g T_SEGMENT short$int$t6$r1$ +00000000 g T_SEGMENT long$long$int$t7 +00000000 g T_SEGMENT short$unsigned$i +00000000 g T_SEGMENT long$long$unsign +00000000 g T_SEGMENT signed$char$t10$ +00000000 g T_SEGMENT unsigned$char$t1 +00000000 g T_SEGMENT float$t12$r1$4$0 +00000000 g T_SEGMENT double$t13$r1$8$ +00000000 g T_SEGMENT long$double$t14$ +00000000 g T_SEGMENT void$t15$15 +00000000 g T_SEGMENT _main +00000000 g T_SEGMENT $ +00000000 g T_SEGMENT $ +00000000 g T_SEGMENT $ +00000010 g T_SEGMENT $ +00000000 g T_SEGMENT main$F1 +fcffffff g T_SEGMENT i$1 +00000000 g T_SEGMENT $ +00000010 g T_SEGMENT $ + +RELOCATION RECORDS FOR [D00000000]: (none) + +RELOCATION RECORDS FOR [D00008000]: (none) + +RELOCATION RECORDS FOR [T_SEGMENT]: (none) + +Disassembly of section D00000000: +... +00008000 ($+)7ff0 linkw fp,#-4 +00008004 ($+)7ff4 nop +00008006 ($+)7ff6 movel #99,d0 +00008008 ($+)7ff8 cmpl fp@(-4),d0 +0000800c ($+)7ffc blts 00008014 ($+)8004 +0000800e ($+)7ffe addql #1,fp@(-4) +00008012 ($+)8002 bras 00008006 ($+)7ff6 +00008014 ($+)8004 unlk fp +00008016 ($+)8006 rts +... + +*/ + +static void +tekhex_init () +{ + unsigned int i; + static bfd_boolean inited = FALSE; + int val; + + if (! inited) + { + inited = TRUE; + hex_init (); + val = 0; + for (i = 0; i < 10; i++) + { + sum_block[i + '0'] = val++; + } + for (i = 'A'; i <= 'Z'; i++) + { + sum_block[i] = val++; + } + sum_block['$'] = val++; + sum_block['%'] = val++; + sum_block['.'] = val++; + sum_block['_'] = val++; + for (i = 'a'; i <= 'z'; i++) + { + sum_block[i] = val++; + } + } +} + +/* The maximum number of bytes on a line is FF */ +#define MAXCHUNK 0xff +/* The number of bytes we fit onto a line on output */ +#define CHUNK 21 + +/* We cannot output our tekhexords as we see them, we have to glue them + together, this is done in this structure : */ + +struct tekhex_data_list_struct +{ + unsigned char *data; + bfd_vma where; + bfd_size_type size; + struct tekhex_data_list_struct *next; + +}; +typedef struct tekhex_data_list_struct tekhex_data_list_type; + +#define CHUNK_MASK 0x1fff + +struct data_struct + { + char chunk_data[CHUNK_MASK + 1]; + char chunk_init[CHUNK_MASK + 1]; + bfd_vma vma; + struct data_struct *next; + }; + +typedef struct tekhex_data_struct +{ + tekhex_data_list_type *head; + unsigned int type; + struct tekhex_symbol_struct *symbols; + struct data_struct *data; +} tdata_type; + +#define enda(x) (x->vma + x->size) + +static bfd_vma +getvalue (srcp) + char **srcp; +{ + char *src = *srcp; + bfd_vma value = 0; + unsigned int len = hex_value(*src++); + + if (len == 0) + len = 16; + while (len--) + { + value = value << 4 | hex_value(*src++); + } + *srcp = src; + return value; +} + +static unsigned int +getsym (dstp, srcp) + char *dstp; + char **srcp; +{ + char *src = *srcp; + unsigned int i; + unsigned int len = hex_value(*src++); + + if (len == 0) + len = 16; + for (i = 0; i < len; i++) + dstp[i] = src[i]; + dstp[i] = 0; + *srcp = src + i; + return len; +} + +static struct data_struct * +find_chunk (abfd, vma) + bfd *abfd; + bfd_vma vma; +{ + struct data_struct *d = abfd->tdata.tekhex_data->data; + + vma &= ~CHUNK_MASK; + while (d && (d->vma) != vma) + { + d = d->next; + } + if (!d) + { + /* No chunk for this address, so make one up */ + d = ((struct data_struct *) + bfd_zalloc (abfd, (bfd_size_type) sizeof (struct data_struct))); + + if (!d) + return NULL; + + d->next = abfd->tdata.tekhex_data->data; + d->vma = vma; + abfd->tdata.tekhex_data->data = d; + } + return d; +} + +static void +insert_byte (abfd, value, addr) + bfd *abfd; + int value; + bfd_vma addr; +{ + /* Find the chunk that this byte needs and put it in */ + struct data_struct *d = find_chunk (abfd, addr); + + d->chunk_data[addr & CHUNK_MASK] = value; + d->chunk_init[addr & CHUNK_MASK] = 1; +} + +/* The first pass is to find the names of all the sections, and see + how big the data is */ +static void +first_phase (abfd, type, src) + bfd *abfd; + int type; + char *src; +{ + asection *section = bfd_abs_section_ptr; + unsigned int len; + char sym[17]; /* A symbol can only be 16chars long */ + + switch (type) + { + case '6': + /* Data record - read it and store it */ + { + bfd_vma addr = getvalue (&src); + + while (*src) + { + insert_byte (abfd, HEX (src), addr); + src += 2; + addr++; + } + } + + return; + case '3': + /* Symbol record, read the segment */ + len = getsym (sym, &src); + section = bfd_get_section_by_name (abfd, sym); + if (section == (asection *) NULL) + { + char *n = bfd_alloc (abfd, (bfd_size_type) len + 1); + + if (!n) + abort (); /* FIXME */ + memcpy (n, sym, len + 1); + section = bfd_make_section (abfd, n); + } + while (*src) + { + switch (*src) + { + case '1': /* section range */ + src++; + section->vma = getvalue (&src); + section->_raw_size = getvalue (&src) - section->vma; + section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; + break; + case '0': + case '2': + case '3': + case '4': + case '6': + case '7': + case '8': + /* Symbols, add to section */ + { + bfd_size_type amt = sizeof (tekhex_symbol_type); + tekhex_symbol_type *new = + (tekhex_symbol_type *) bfd_alloc (abfd, amt); + char stype = (*src); + + if (!new) + abort (); /* FIXME */ + new->symbol.the_bfd = abfd; + src++; + abfd->symcount++; + abfd->flags |= HAS_SYMS; + new->prev = abfd->tdata.tekhex_data->symbols; + abfd->tdata.tekhex_data->symbols = new; + len = getsym (sym, &src); + new->symbol.name = bfd_alloc (abfd, (bfd_size_type) len + 1); + if (!new->symbol.name) + abort (); /* FIXME */ + memcpy ((char *) (new->symbol.name), sym, len + 1); + new->symbol.section = section; + if (stype <= '4') + new->symbol.flags = (BSF_GLOBAL | BSF_EXPORT); + else + new->symbol.flags = BSF_LOCAL; + new->symbol.value = getvalue (&src) - section->vma; + } + } + } + } +} + +/* Pass over a tekhex, calling one of the above functions on each + record. */ + +static void +pass_over (abfd, func) + bfd *abfd; + void (*func) PARAMS ((bfd *, int, char *)); +{ + unsigned int chars_on_line; + bfd_boolean eof = FALSE; + + /* To the front of the file */ + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) + abort (); + while (! eof) + { + char buffer[MAXCHUNK]; + char *src = buffer; + char type; + + /* Find first '%' */ + eof = (bfd_boolean) (bfd_bread (src, (bfd_size_type) 1, abfd) != 1); + while (*src != '%' && !eof) + { + eof = (bfd_boolean) (bfd_bread (src, (bfd_size_type) 1, abfd) != 1); + } + if (eof) + break; + src++; + + /* Fetch the type and the length and the checksum */ + if (bfd_bread (src, (bfd_size_type) 5, abfd) != 5) + abort (); /* FIXME */ + + type = src[2]; + + if (!ISHEX (src[0]) || !ISHEX (src[1])) + break; + + chars_on_line = HEX (src) - 5; /* Already read five char */ + + if (bfd_bread (src, (bfd_size_type) chars_on_line, abfd) != chars_on_line) + abort (); /* FIXME */ + src[chars_on_line] = 0; /* put a null at the end */ + + func (abfd, type, src); + } + +} + +static long +tekhex_get_symtab (abfd, table) + bfd *abfd; + asymbol **table; +{ + tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols; + unsigned int c = bfd_get_symcount (abfd); + + table[c] = 0; + while (p) + { + table[--c] = &(p->symbol); + p = p->prev; + } + + return bfd_get_symcount (abfd); +} + +static long +tekhex_get_symtab_upper_bound (abfd) + bfd *abfd; +{ + return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *)); + +} + +static bfd_boolean +tekhex_mkobject (abfd) + bfd *abfd; +{ + tdata_type *tdata; + + tdata = (tdata_type *) bfd_alloc (abfd, (bfd_size_type) sizeof (tdata_type)); + if (!tdata) + return FALSE; + abfd->tdata.tekhex_data = tdata; + tdata->type = 1; + tdata->head = (tekhex_data_list_type *) NULL; + tdata->symbols = (struct tekhex_symbol_struct *) NULL; + tdata->data = (struct data_struct *) NULL; + return TRUE; +} + +/* + Return TRUE if the file looks like it's in TekHex format. Just look + for a percent sign and some hex digits */ + +static const bfd_target * +tekhex_object_p (abfd) + bfd *abfd; +{ + char b[4]; + + tekhex_init (); + + if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 + || bfd_bread (b, (bfd_size_type) 4, abfd) != 4) + return NULL; + + if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) + return (const bfd_target *) NULL; + + tekhex_mkobject (abfd); + + pass_over (abfd, first_phase); + return abfd->xvec; +} + +static void +move_section_contents (abfd, section, locationp, offset, count, get) + bfd *abfd; + asection *section; + PTR locationp; + file_ptr offset; + bfd_size_type count; + bfd_boolean get; +{ + bfd_vma addr; + char *location = (char *) locationp; + bfd_vma prev_number = 1; /* Nothing can have this as a high bit*/ + struct data_struct *d = (struct data_struct *) NULL; + + BFD_ASSERT (offset == 0); + for (addr = section->vma; count != 0; count--, addr++) + { + /* Get high bits of address. */ + bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK; + bfd_vma low_bits = addr & CHUNK_MASK; + + if (chunk_number != prev_number) + { + /* Different chunk, so move pointer */ + d = find_chunk (abfd, chunk_number); + } + + if (get) + { + if (d->chunk_init[low_bits]) + { + *location = d->chunk_data[low_bits]; + } + else + { + *location = 0; + } + } + else + { + d->chunk_data[low_bits] = *location; + d->chunk_init[low_bits] = (*location != 0); + } + + location++; + + } + +} + +static bfd_boolean +tekhex_get_section_contents (abfd, section, locationp, offset, count) + bfd *abfd; + asection *section; + PTR locationp; + file_ptr offset; + bfd_size_type count; +{ + if (section->flags & (SEC_LOAD | SEC_ALLOC)) + { + move_section_contents (abfd, section, locationp, offset, count, TRUE); + return TRUE; + } + else + return FALSE; +} + +static bfd_boolean +tekhex_set_arch_mach (abfd, arch, machine) + bfd *abfd; + enum bfd_architecture arch; + unsigned long machine; +{ + return bfd_default_set_arch_mach (abfd, arch, machine); +} + +/* we have to save up all the Tekhexords for a splurge before output, + */ + +static bfd_boolean +tekhex_set_section_contents (abfd, section, locationp, offset, bytes_to_do) + bfd *abfd; + sec_ptr section; + PTR locationp; + file_ptr offset; + bfd_size_type bytes_to_do; +{ + + if (! abfd->output_has_begun) + { + /* The first time around, allocate enough sections to hold all the chunks */ + asection *s = abfd->sections; + bfd_vma vma; + + for (s = abfd->sections; s; s = s->next) + { + if (s->flags & SEC_LOAD) + { + for (vma = s->vma & ~(bfd_vma) CHUNK_MASK; + vma < s->vma + s->_raw_size; + vma += CHUNK_MASK) + find_chunk (abfd, vma); + } + } + + } + if (section->flags & (SEC_LOAD | SEC_ALLOC)) + { + move_section_contents (abfd, section, locationp, offset, bytes_to_do, + FALSE); + return TRUE; + } + else + return FALSE; + +} + +static void +writevalue (dst, value) + char **dst; + bfd_vma value; +{ + char *p = *dst; + int len; + int shift; + + for (len = 8, shift = 28; shift; shift -= 4, len--) + { + if ((value >> shift) & 0xf) + { + *p++ = len + '0'; + while (len) + { + *p++ = digs[(value >> shift) & 0xf]; + shift -= 4; + len--; + } + *dst = p; + return; + + } + } + *p++ = '1'; + *p++ = '0'; + *dst = p; +} + +static void +writesym (dst, sym) + char **dst; + const char *sym; +{ + char *p = *dst; + int len = (sym ? strlen (sym) : 0); + + if (len >= 16) + { + *p++ = '0'; + len = 16; + } + + else + { + if (len == 0) + { + *p++ = '1'; + sym = "$"; + len = 1; + } + else + { + *p++ = digs[len]; + } + } + + while (len--) + { + *p++ = *sym++; + } + *dst = p; +} + +static void +out (abfd, type, start, end) + bfd *abfd; + int type; + char *start; + char *end; +{ + int sum = 0; + char *s; + char front[6]; + bfd_size_type wrlen; + + front[0] = '%'; + TOHEX (front + 1, end - start + 5); + front[3] = type; + + for (s = start; s < end; s++) + { + sum += sum_block[(unsigned char) *s]; + } + + sum += sum_block[(unsigned char) front[1]]; /* length */ + sum += sum_block[(unsigned char) front[2]]; + sum += sum_block[(unsigned char) front[3]]; /* type */ + TOHEX (front + 4, sum); + if (bfd_bwrite (front, (bfd_size_type) 6, abfd) != 6) + abort (); + end[0] = '\n'; + wrlen = end - start + 1; + if (bfd_bwrite (start, wrlen, abfd) != wrlen) + abort (); +} + +static bfd_boolean +tekhex_write_object_contents (abfd) + bfd *abfd; +{ + int bytes_written; + char buffer[100]; + asymbol **p; + asection *s; + struct data_struct *d; + + tekhex_init (); + + bytes_written = 0; + + /* And the raw data */ + for (d = abfd->tdata.tekhex_data->data; + d != (struct data_struct *) NULL; + d = d->next) + { + int low; + + const int span = 32; + int addr; + + /* Write it in blocks of 32 bytes */ + + for (addr = 0; addr < CHUNK_MASK + 1; addr += span) + { + int need = 0; + + /* Check to see if necessary */ + for (low = 0; !need && low < span; low++) + { + if (d->chunk_init[addr + low]) + need = 1; + } + if (need) + { + char *dst = buffer; + + writevalue (&dst, addr + d->vma); + for (low = 0; low < span; low++) + { + TOHEX (dst, d->chunk_data[addr + low]); + dst += 2; + } + out (abfd, '6', buffer, dst); + } + } + } + /* write all the section headers for the sections */ + for (s = abfd->sections; s != (asection *) NULL; s = s->next) + { + char *dst = buffer; + + writesym (&dst, s->name); + *dst++ = '1'; + writevalue (&dst, s->vma); + writevalue (&dst, s->vma + s->_raw_size); + out (abfd, '3', buffer, dst); + } + + /* And the symbols */ + if (abfd->outsymbols) + { + for (p = abfd->outsymbols; *p; p++) + { + int section_code = bfd_decode_symclass (*p); + + if (section_code != '?') + { /* do not include debug symbols */ + asymbol *sym = *p; + char *dst = buffer; + + writesym (&dst, sym->section->name); + + switch (section_code) + { + case 'A': + *dst++ = '2'; + break; + case 'a': + *dst++ = '6'; + break; + case 'D': + case 'B': + case 'O': + *dst++ = '4'; + break; + case 'd': + case 'b': + case 'o': + *dst++ = '8'; + break; + case 'T': + *dst++ = '3'; + break; + case 't': + *dst++ = '7'; + break; + case 'C': + case 'U': + bfd_set_error (bfd_error_wrong_format); + return FALSE; + } + + writesym (&dst, sym->name); + writevalue (&dst, sym->value + sym->section->vma); + out (abfd, '3', buffer, dst); + } + } + } + + /* And the terminator */ + if (bfd_bwrite ("%0781010\n", (bfd_size_type) 9, abfd) != 9) + abort (); + return TRUE; +} + +static int +tekhex_sizeof_headers (abfd, exec) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_boolean exec ATTRIBUTE_UNUSED; + +{ + return 0; +} + +static asymbol * +tekhex_make_empty_symbol (abfd) + bfd *abfd; +{ + bfd_size_type amt = sizeof (struct tekhex_symbol_struct); + tekhex_symbol_type *new = (tekhex_symbol_type *) bfd_zalloc (abfd, amt); + + if (!new) + return NULL; + new->symbol.the_bfd = abfd; + new->prev = (struct tekhex_symbol_struct *) NULL; + return &(new->symbol); +} + +static void +tekhex_get_symbol_info (ignore_abfd, symbol, ret) + bfd *ignore_abfd ATTRIBUTE_UNUSED; + asymbol *symbol; + symbol_info *ret; +{ + bfd_symbol_info (symbol, ret); +} + +static void +tekhex_print_symbol (abfd, filep, symbol, how) + bfd *abfd; + PTR filep; + asymbol *symbol; + bfd_print_symbol_type how; +{ + FILE *file = (FILE *) filep; + + switch (how) + { + case bfd_print_symbol_name: + fprintf (file, "%s", symbol->name); + break; + case bfd_print_symbol_more: + break; + + case bfd_print_symbol_all: + { + const char *section_name = symbol->section->name; + + bfd_print_symbol_vandf (abfd, (PTR) file, symbol); + + fprintf (file, " %-5s %s", + section_name, + symbol->name); + } + } +} + +#define tekhex_close_and_cleanup _bfd_generic_close_and_cleanup +#define tekhex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info +#define tekhex_new_section_hook _bfd_generic_new_section_hook + +#define tekhex_bfd_is_local_label_name bfd_generic_is_local_label_name +#define tekhex_get_lineno _bfd_nosymbols_get_lineno +#define tekhex_find_nearest_line _bfd_nosymbols_find_nearest_line +#define tekhex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol +#define tekhex_read_minisymbols _bfd_generic_read_minisymbols +#define tekhex_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol + +#define tekhex_bfd_get_relocated_section_contents \ + bfd_generic_get_relocated_section_contents +#define tekhex_bfd_relax_section bfd_generic_relax_section +#define tekhex_bfd_gc_sections bfd_generic_gc_sections +#define tekhex_bfd_merge_sections bfd_generic_merge_sections +#define tekhex_bfd_discard_group bfd_generic_discard_group +#define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create +#define tekhex_bfd_link_hash_table_free _bfd_generic_link_hash_table_free +#define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols +#define tekhex_bfd_link_just_syms _bfd_generic_link_just_syms +#define tekhex_bfd_final_link _bfd_generic_final_link +#define tekhex_bfd_link_split_section _bfd_generic_link_split_section + +#define tekhex_get_section_contents_in_window \ + _bfd_generic_get_section_contents_in_window + +const bfd_target tekhex_vec = +{ + "tekhex", /* name */ + bfd_target_tekhex_flavour, + BFD_ENDIAN_UNKNOWN, /* target byte order */ + BFD_ENDIAN_UNKNOWN, /* target headers byte order */ + (EXEC_P | /* object flags */ + HAS_SYMS | HAS_LINENO | HAS_DEBUG | HAS_RELOC | HAS_LOCALS | + WP_TEXT | D_PAGED), + (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS + | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ + 0, /* leading underscore */ + ' ', /* ar_pad_char */ + 16, /* ar_max_namelen */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* data */ + bfd_getb64, bfd_getb_signed_64, bfd_putb64, + bfd_getb32, bfd_getb_signed_32, bfd_putb32, + bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* hdrs */ + + { + _bfd_dummy_target, + tekhex_object_p, /* bfd_check_format */ + _bfd_dummy_target, + _bfd_dummy_target, + }, + { + bfd_false, + tekhex_mkobject, + _bfd_generic_mkarchive, + bfd_false, + }, + { /* bfd_write_contents */ + bfd_false, + tekhex_write_object_contents, + _bfd_write_archive_contents, + bfd_false, + }, + + BFD_JUMP_TABLE_GENERIC (tekhex), + BFD_JUMP_TABLE_COPY (_bfd_generic), + BFD_JUMP_TABLE_CORE (_bfd_nocore), + BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), + BFD_JUMP_TABLE_SYMBOLS (tekhex), + BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), + BFD_JUMP_TABLE_WRITE (tekhex), + BFD_JUMP_TABLE_LINK (tekhex), + BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), + + NULL, + + (PTR) 0 +}; diff --git a/contrib/binutils-2.14/bfd/version.h b/contrib/binutils-2.14/bfd/version.h new file mode 100644 index 0000000000..2b77c7a7d0 --- /dev/null +++ b/contrib/binutils-2.14/bfd/version.h @@ -0,0 +1,3 @@ +#define BFD_VERSION_DATE 20030612 +#define BFD_VERSION @bfd_version@ +#define BFD_VERSION_STRING @bfd_version_string@ diff --git a/contrib/binutils-2.14/binutils/MAINTAINERS b/contrib/binutils-2.14/binutils/MAINTAINERS new file mode 100644 index 0000000000..351678e885 --- /dev/null +++ b/contrib/binutils-2.14/binutils/MAINTAINERS @@ -0,0 +1,163 @@ + ========= Binutils Maintainers ========= + +This is the list of individuals responsible for maintenance and update +of the GNU Binary Utilities project. This includes the linker (ld), +the assembler (gas), the profiler (gprof), a whole suite of other +programs (binutils) and the libraries that they use (bfd and +opcodes). This project shares a common set of header files with the +GCC and GDB projects (include), so maintainership of those files is +shared amoungst the projects. + +The home page for binutils is: + + http://www.gnu.org/software/binutils/binutils.html + +and patches should be sent to: + + bug-binutils@gnu.org + +with "[Patch]" as part of the subject line. Note - patches to the +top level configure.in and config.sub scripts should be sent to: + + config-patches@gnu.org + +and not to the binutils list. + + --------- Blanket Write Privs --------- + +The following people have permission to check patches into the +repository without obtaining approval first: + + Nick Clifton (head maintainer) + Richard Henderson + Ian Taylor + Jeff Law + Jim Wilson + DJ Delorie + Alan Modra + Michael Meissner + + --------- Maintainers --------- + +Maintainers are individuals who are responsible for, and have +permission to check in changes in, certain subsets of the code. Note +that maintainers still need approval to check in changes outside of +the immediate domain that they maintain. + +If there is no maintainer for a given domain then the responsibility +falls to the head maintainer (above). If there are several +maintainers for a given domain then responsibility falls to the first +maintainer. The first maintainer is free to devolve that +responsibility among the other maintainers. + + ALPHA Richard Henderson + ARM Nick Clifton + ARM Richard Earnshaw + AVR Denis Chertykov + AVR Marek Michalkiewicz + CONFIGURE Ben Elliston + CRIS Hans-Peter Nilsson + DWARF2 Jason Merrill + FR30 Dave Brolley + FRV Dave Brolley + HPPA elf32 Alan Modra + HPPA elf64 Jeff Law [Basic maintainance only] + HPPA Dave Anglin + IA-64 Jim Wilson + IQ2000 Stan Cox + i860 Jason Eckhardt + ix86 Alan Modra + ix86 PE Christopher Faylor + ix86 COFF DJ Delorie + ix86 H.J.Lu + ix86 INTEL MODE Diego Novillo + M68HC11 M68HC12 Stephane Carrez + M68k Ben Elliston + M88k Ben Elliston + MIPS Eric Christopher + MMIX Hans-Peter Nilsson + MN10300 Eric Christopher + MN10300 Alexandre Oliva + PPC Geoff Keating + PPC vector ext Aldy Hernandez + s390, s390x Martin Schwidefsky + SH Jörn Rennecke + SH Alexandre Oliva + SH Kaz Kojima + SPARC Jakub Jelinek + TESTSUITES Ben Elliston + TIC4X Svein Seldal + TIC54X Timothy Wall + VAX Jason R Thorpe + x86_64 Jan Hubicka + x86_64 Andreas Jaeger + Xtensa Bob Wilson + z8k Christian Groessler + + + --------- CGEN Maintainers ------------- + +CGEN is a tool for building, amongst other things, assemblers, +disassemblers and simulators from a single description of a CPU. +It creates files in several of the binutils directories, but it +is mentioned here since there is a single group that maintains +CGEN and the files that it creates. + +If you have CGEN related problems you can send email to; + + cgen@sources.redhat.com + +The current CGEN maintainers are: + + Doug Evans, Ben Elliston, Frank Eigler + + --------- Write After Approval --------- + +Individuals with "write after approval" have the ability to check in +changes, but they must get approval for each change from someone in +one of the above lists (blanket write or maintainers). + +[It's a huge list, folks. You know who you are. If you have the + *ability* to do binutils checkins, you're in this group. Just + remember to get approval before checking anything in.] + + ------------- Obvious Fixes ------------- + +Fixes for obvious mistakes do not need approval, and can be checked in +right away, but the patch should still be sent to the binutils list. +The definition of obvious is a bit hazy, and if you are not sure, then +you should seek approval first. Obvious fixes include fixes for +spelling mistakes, blatantly incorrect code (where the correct code is +also blatantly obvious), and so on. Obvious fixes should always be +small, the larger they are, the more likely it is that they contain +some un-obvious side effect or consequence. + + --------- Branch Checkins --------- + +If a patch is approved for check in to the mainline sources, it can +also be checked into the current release branch. Normally however +only bug fixes should be applied to the branch. New features, new +ports, etc, should be restricted to the mainline. (Otherwise the +burden of maintaining the branch in sync with the mainline becomes too +great). If you are uncertain as to whether a patch is appropriate for +the branch, ask the branch maintainer. This is: + + Daniel Jacobowitz + + -------- Testsuites --------------- + +In general patches to any of the binutils testsuites should be +considered generic and sent to the binutils mailing list for +approval. Patches to target specific tests are the responsibility the +relevent port maintainer(s), and can be approved/checked in by them. +Other testsuite patches need the approval of a blanket-write-priveleges +person. + + -------- Configure patches ---------- + +Patches to the top level configure files (config.sub & config.guess) +are not the domain of the binutils project and they cannot be approved +by the binutils group. Instead they should be submitted to the config +maintainer at: + + config-patches@gnu.org diff --git a/contrib/binutils-2.14/binutils/NEWS b/contrib/binutils-2.14/binutils/NEWS new file mode 100644 index 0000000000..3730a7b926 --- /dev/null +++ b/contrib/binutils-2.14/binutils/NEWS @@ -0,0 +1,249 @@ +-*- text -*- + +* Added --info switch to objcopy and strip. + +* Support for Vitesse IQ2000 added by Red Hat. + +* Added 'S' encoding to strings to allow the display of 8-bit characters. + +* Added --prefix-symbols=, --prefix-sections= and + --prefix-alloc-sections= to objcopy. + +* readelf can handle the extensions to the DWARF2 spec used by the Unified + Parallel C compiler. + +* BFD no longer declares a "boolean" type, to avoid clashes with other + headers that declare the same. Users of BFD should replace boolean, + false and true, with int, 0 and 1, or define their own boolean type. + +* Support for IP2K added by Denis Chertykov. + +Changes in 2.13: + +* Support for the Fujitsu FRV architecture added by Red Hat. Models for FR400 + and FR500 included. + +Changes in version 2.12: + +* Support for Don Knuth's MMIX, by Hans-Peter Nilsson. + +* size: Add --totals to display summary of sizes (Berkeley format only). + +* readelf: Add --wide option to not break section header or segment listing + lines to fit into 80 columns. + +* strings: Add --encoding to display wide character strings. By Markus Kuhn. + +* objcopy: Add --rename-section to change section names. + +* readelf: Support added for DWARF 2.1 extensions. Support added for + displaying the contents of .debug.macinfo sections. + +* New command line switches added to objcopy to allow symbols to be kept as + global symbols, and also to specify files containing lists of such symbols. + by Honda Hiroki. + +* Support for OpenRISC by Johan Rydberg. + +* New command line switch to objcopy --alt-machine-code which creates a binary + with an alternate machine code if one is defined in the architecture + description. Only supported for ELF targets. By Alexandre Oliva. + +* New command line switch to objcopy -B (or --binary-architecture) which sets + the architecture of the output file to the given argument. This option only + makes sense, if the input target is binary. Otherwise it is ignored. + By Stefan Geuken. + +* Support for PDP-11 by Lars Brinkhoff. + +Changes in binutils 2.11: + +* Add support for ARM v5t and v5te architectures and Intel's XScale ARM + extenstions. + +* Add --srec-len and --srec-forceS3 command line switch to objcopy. + By Luciano Gemme. + +* Support for the MIPS32, by Anders Norlander. + +* Support for the i860, by Jason Eckhardt. + +* Support for CRIS (Axis Communications ETRAX series). + +Changes in binutils 2.10: + +* Support for 64-bit ELF on HPPA. + +* New command line switch to objdump --file-start-context which shows the + entire file contents up to the source line first encountered for a given + file. + +* New command line switch to objdump -M (or --disassembler-options) which takes + a parameter which can then be interpreted on a per-target basis by the + disassembler. Used by ARM targets to select register name sets, ISA, APCS or + raw verions. + +* objdump support for -mi386:intel which causes disassembly to be displayed + with intel syntax. + +* New program: readelf. This displays the contents of ELF format files, + regardless of target machine. + +* objcopy now takes --change-section-lma, --change-section-vma, and + --change-section-address options. The old --adjust-section-vma option is + equivalent to --change-section-address. The other --adjust-* options are now + renamed to --change-*, although --adjust-* continues to work. + +* objcopy has a --redefine-sym option that lets you rename symbols. + +* objcopy now takes a -j/--only-section option to copy only the specified + sections. + +* dlltool now supports the IMPORTS command. + +* dlltool now takes --export-all-symbols, --no-export-all-symbols, + --exclude-symbols, and --no-default-excludes options. + +Changes in binutils 2.9: + +* Added windres program, which can be used to manipulate resources in WIN32 + files as used on Windows 95 and Windows NT. + +* The objcopy --gap-fill and --pad-to options operate on the LMA rather than + the VMA of the sections. + +* Added S modifier to ar to not build a symbol table. + +Changes in binutils 2.8: + +* The objdump disassembly format has been changed, and hopefully improved. Use + the new --prefix-addresses option to get the old format. There are also new + --disassemble-zeroes and --no-show-raw-insn options which affect disassembler + output. + +* Formats may now be specified as configuration triplets. For example, + objdump -b i386-pc-linux. The triplets are not passed through config.sub, + so they must be in canonical form. + +* Added new addr2line program. This uses the debugging information to convert + an address into a file name and line number within a program. + +* Added --change-leading-char argument to objcopy. + +* Added --weaken argument to objcopy. + +* objdump --dynamic-reloc now works on ELF executables and shared libraries. + +* Added --adjust-vma option to objdump. + +* Added -C/--demangle option to objdump. + +* Added -p/--preserve-dates option to strip and objcopy. + +Changes in binutils 2.7: + +* Added --enable-shared and --enable-commonbfdlib options to configure. + +* Added --debugging argument to objdump and objcopy. + +* Added --defined-only argument to nm. + +* Added --remove-leading-char argument to objcopy. + +* The objdump --line-numbers option is now meaningful with --reloc. + +* Added --line-numbers option to nm. + +* Added --endian/-EB/-EL option to objdump. + +* Added support for Alpha OpenVMS/AXP. + +Changes in binutils 2.6: + +* Added -N/--strip-symbol and -K/--keep-symbol arguments to strip and objcopy. + +* Added several arguments to objcopy to provide some control over how the new + file is laid out in memory. Also added binary output format to BFD to permit + generating plain binary files. + +* Added --start-address and --stop-address options to objdump. + +* ar and ranlib now work on AIX. The tools are now built by default on AIX. + +Changes in binutils 2.5: + +* Changed objdump -dr to dump the relocs interspersed with the assembly + listing, for a more useful listing of relocateable files. + +* Changed objdump -d/--disassemble to only disassemble SEC_CODE sections. + Added -D/--disassemble-all option to disassemble all sections. + +* Added --size-sort option to nm. + +* strip and objcopy should now be able to handle dynamically linked ELF + executables. + +Changes in binutils 2.4: + +* Support for HP-PA (by Jeff Law), i386 Mach (by David Mackenzie), RS/6000 and + PowerPC (except ar and ranlib; by Ian Taylor). + +* Support for Irix 5. + +* Programs `strip' and `objcopy' will not attempt to write dynamically linked + ELF output files, since BFD currently can't create them properly. + +Changes in binutils 2.3: + +* A new --stabs argument has been added to objdump to dump stabs sections in + ELF and COFF files. + +* A new program, nlmconv, has been added. It can convert object files into + Novell NetWare Loadable Modules. + +* The strings program has been added. + +Changes in binutils 2.2: + +* The 'copy' program has been renamed to 'objcopy', for consistency with + 'objdump', and because 'copy' might more plausibly be used as a synonym for + 'cp'. + +* The new stand-alone program c++filt is a filter that converts encoded + (mangled) C++ assembly-level identifiers to user-level names. (Note: This + may get moved to the gcc distribution.) + +* nm -o on an archive now prefixes each line with the archive name, matching + the output from BSD nm. + +* ar (and ld) can now read (but not write) BSD4.4-style archives. + +* New support for H8500, Z8000, and the Hitach SH. + +* Dis-assembler interface changed to allow sharing with gdb. + +* There is new Elf code, but it is not yet ready for general use. + +* There is the beginnings of a test suite. + +Changes in binutils 2.1: + +* There is now support for writing ECOFF files, so ld and the other utilities + should work on Risc/Ultrix and Irix. Please let us know how well this works. + +* ar now automatically creates a symbol table (a __.SYMDEF member, in the BSD + version), if there are any object files in the archive. So running ranlib is + now redundant (unless the non-standard q command is used). This is required + for Posix.2 conformance. + +* The archive-reading code now reads both BSD-style and SYSV-style archives + independently of the selected target format. This is to encourage people to + switch to SYSV-format, which has a number of advantages. + +* The strip and copy programs now have options to remove debug-symbols only + and/or local symbols only. They now also support long options. + + +Local variables: +fill-column: 79 +End: diff --git a/contrib/binutils-2.14/binutils/README b/contrib/binutils-2.14/binutils/README new file mode 100644 index 0000000000..936f25f85e --- /dev/null +++ b/contrib/binutils-2.14/binutils/README @@ -0,0 +1,216 @@ + README for BINUTILS + +These are the GNU binutils. These are utilities of use when dealing +with binary files, either object files or executables. These tools +consist of the linker (ld), the assembler (gas), and the profiler +(gprof) each of which have their own sub-directory named after them. +There is also a collection of other binary tools, including the +disassembler (objdump) in this directory. These tools make use of a +pair of libraries (bfd and opcodes) and a common set of header files +(include). + +There are README and NEWS files in most of the program sub-directories +which give more information about those specific programs. + + +Unpacking and Installation -- quick overview +============================================ + +When you unpack the binutils archive file, you will get a directory +called something like `binutils-XXX', where XXX is the number of the +release. (Probably 2.13 or higher). This directory contains +various files and sub-directories. Most of the files in the top +directory are for information and for configuration. The actual +source code is in sub-directories. + +To build binutils, you can just do: + + cd binutils-XXX + ./configure [options] + make + make install # copies the programs files into /usr/local/bin + # by default. + +This will configure and build all the libraries as well as the +assembler, the binutils, and the linker. + +If you have GNU make, we recommend building in a different directory: + + mkdir objdir + cd objdir + ../binutils-XXX/configure [options] + make + make install + +This relies on the VPATH feature of GNU make. + +By default, the binutils will be configured to support the system on +which they are built. When doing cross development, use the --target +configure option to specify a different target, eg: + + ./configure --target=foo-elf + +The --enable-targets option adds support for more binary file formats +besides the default. List them as the argument to --enable-targets, +separated by commas. For example: + + ./configure --enable-targets=sun3,rs6000-aix,decstation + +The name 'all' compiles in support for all valid BFD targets: + + ./configure --enable-targets=all + +On 32-bit hosts though, this support will be restricted to 32-bit +target unless the --enable-64-bit-bfd option is also used: + + ./configure --enable-64-bit-bfd --enable-targets=all + +You can also specify the --enable-shared option when you run +configure. This will build the BFD and opcodes libraries as shared +libraries. You can use arguments with the --enable-shared option to +indicate that only certain libraries should be built shared; for +example, --enable-shared=bfd. The only potential shared libraries in +a binutils release are bfd and opcodes. + +The binutils will be linked against the shared libraries. The build +step will attempt to place the correct library in the run-time search +path for the binaries. However, in some cases, after you install the +binaries, you may have to set an environment variable, normally +LD_LIBRARY_PATH, so that the system can find the installed libbfd +shared library. + +To build under openVMS/AXP, see the file makefile.vms in the top level +directory. + + +Native Language Support +======================= + +By default Native Language Support will be enabled for binutils. On +some systems however this support is not present and can lead to error +messages such as "undefined reference to `libintl_gettext'" when +building there tools. If that happens the NLS support can be disabled +by adding the --disable-nls switch to the configure line like this: + + ../binutils-XXX/configure --disable-nls + + +If you don't have ar +==================== + +If your system does not already have an 'ar' program, the normal +binutils build process will not work. In this case, run configure as +usual. Before running make, run this script: + +#!/bin/sh +MAKE_PROG="${MAKE-make}" +MAKE="${MAKE_PROG} AR=true LINK=true" +export MAKE +${MAKE} $* all-libiberty +${MAKE} $* all-intl +${MAKE} $* all-bfd +cd binutils +MAKE="${MAKE_PROG}" +export MAKE +${MAKE} $* ar_DEPENDENCIES= ar_LDADD='../bfd/*.o ../libiberty/*.o `if test -f ../intl/gettext.o; then echo '../intl/*.o'; fi`' ar + +This script will build an ar program in binutils/ar. Move binutils/ar +into a directory on your PATH. After doing this, you can run make as +usual to build the complete binutils distribution. You do not need +the ranlib program in order to build the distribution. + +Porting +======= + +Binutils-2.13 supports many different architectures, but there +are many more not supported, including some that were supported +by earlier versions. We are hoping for volunteers to improve this +situation. + +The major effort in porting binutils to a new host and/or target +architecture involves the BFD library. There is some documentation +in ../bfd/doc. The file ../gdb/doc/gdbint.texinfo (distributed +with gdb-5.x) may also be of help. + +Reporting bugs +============== + +Send bug reports and patches to: + + bug-binutils@gnu.org. + +Always mention the version number you are running; this is printed by +running any of the binutils with the --version option. We appreciate +reports about bugs, but we do not promise to fix them. + +VMS +=== + +This section was written by Klaus K"ampf . It +describes how to build and install the binutils on openVMS (Alpha and +Vax). (The BFD library only supports reading Vax object files.) + +Compiling the release: + +To compile the gnu binary utilities and the gnu assembler, you'll +need DEC C or GNU C for openVMS/Alpha. You'll need *both* compilers +on openVMS/Vax. + +Compiling with either DEC C or GNU C works on openVMS/Alpha only. Some +of the opcodes and binutils files trap a bug in the DEC C optimizer, +so these files must be compiled with /noopt. + +Compiling on openVMS/Vax is a bit complicated, as the bfd library traps +a bug in GNU C and the gnu assembler a bug in (my version of) DEC C. + +I never tried compiling with VAX C. + + +You further need GNU Make Version 3.76 or later. This is available +at ftp.progis.de or any GNU archive site. The makefiles assume that +gmake starts gnu make as a foreign command. + +If you're compiling with DEC C or VAX C, you must run + + $ @setup + +before starting gnu-make. This isn't needed with GNU C. + +On the Alpha you can choose the compiler by editing the toplevel +makefile.vms. Either select CC=cc (for DEC C) or CC=gcc (for GNU C) + + +Installing the release + +Provided that your directory setup conforms to the GNU on openVMS +standard, you already have a concealed device named 'GNU_ROOT'. +In this case, a simple + + $ gmake install + +suffices to copy all programs and libraries to the proper directories. + +Define the programs as foreign commands by adding these lines to your +login.com: + + $ gas :== $GNU_ROOT:[bin]as.exe + $ size :== $GNU_ROOT:[bin]size.exe + $ nm :== $GNU_ROOT:[bin]nm.exe + $ objdump :== $GNU_ROOT:[bin]objdump.exe + $ strings :== $GNU_ROOT:[bin]strings.exe + +If you have a different directory setup, copy the binary utilities +([.binutils]size.exe, [.binutils]nm.exe, [.binutils]objdump.exe, +and [.binutils]strings.exe) and the gnu assembler and preprocessor +([.gas]as.exe and [.gas]gasp.exe]) to a directory of your choice +and define all programs as foreign commands. + + +If you're satisfied with the compilation, you may want to remove +unneeded objects and libraries: + + $ gmake clean + + +If you have any problems or questions about the binutils on VMS, feel +free to mail me at kkaempf@rmi.de. diff --git a/contrib/binutils-2.14/binutils/addr2line.c b/contrib/binutils-2.14/binutils/addr2line.c new file mode 100644 index 0000000000..8ebd87e8ab --- /dev/null +++ b/contrib/binutils-2.14/binutils/addr2line.c @@ -0,0 +1,355 @@ +/* addr2line.c -- convert addresses to line number and function name + Copyright 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Ulrich Lauther + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Derived from objdump.c and nm.c by Ulrich.Lauther@mchp.siemens.de + + Usage: + addr2line [options] addr addr ... + or + addr2line [options] + + both forms write results to stdout, the second form reads addresses + to be converted from stdin. */ + +#include + +#include "bfd.h" +#include "getopt.h" +#include "libiberty.h" +#include "demangle.h" +#include "bucomm.h" +#include "budemang.h" + +static bfd_boolean with_functions; /* -f, show function names. */ +static bfd_boolean do_demangle; /* -C, demangle names. */ +static bfd_boolean base_names; /* -s, strip directory names. */ + +static int naddr; /* Number of addresses to process. */ +static char **addr; /* Hex addresses to process. */ + +static asymbol **syms; /* Symbol table. */ + +static struct option long_options[] = +{ + {"basenames", no_argument, NULL, 's'}, + {"demangle", optional_argument, NULL, 'C'}, + {"exe", required_argument, NULL, 'e'}, + {"functions", no_argument, NULL, 'f'}, + {"target", required_argument, NULL, 'b'}, + {"help", no_argument, NULL, 'H'}, + {"version", no_argument, NULL, 'V'}, + {0, no_argument, 0, 0} +}; + +static void usage PARAMS ((FILE *, int)); +static void slurp_symtab PARAMS ((bfd *)); +static void find_address_in_section PARAMS ((bfd *, asection *, PTR)); +static void translate_addresses PARAMS ((bfd *)); +static void process_file PARAMS ((const char *, const char *)); + +/* Print a usage message to STREAM and exit with STATUS. */ + +static void +usage (stream, status) + FILE *stream; + int status; +{ + fprintf (stream, _("Usage: %s [option(s)] [addr(s)]\n"), program_name); + fprintf (stream, _(" Convert addresses into line number/file name pairs.\n")); + fprintf (stream, _(" If no addresses are specified on the command line, they will be read from stdin\n")); + fprintf (stream, _(" The options are:\n\ + -b --target= Set the binary file format\n\ + -e --exe= Set the input file name (default is a.out)\n\ + -s --basenames Strip directory names\n\ + -f --functions Show function names\n\ + -C --demangle[=style] Demangle function names\n\ + -h --help Display this information\n\ + -v --version Display the program's version\n\ +\n")); + + list_supported_targets (program_name, stream); + if (status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); + exit (status); +} + +/* Read in the symbol table. */ + +static void +slurp_symtab (abfd) + bfd *abfd; +{ + long symcount; + unsigned int size; + + if ((bfd_get_file_flags (abfd) & HAS_SYMS) == 0) + return; + + symcount = bfd_read_minisymbols (abfd, FALSE, (PTR) &syms, &size); + if (symcount == 0) + symcount = bfd_read_minisymbols (abfd, TRUE /* dynamic */, (PTR) &syms, &size); + + if (symcount < 0) + bfd_fatal (bfd_get_filename (abfd)); +} + +/* These global variables are used to pass information between + translate_addresses and find_address_in_section. */ + +static bfd_vma pc; +static const char *filename; +static const char *functionname; +static unsigned int line; +static bfd_boolean found; + +/* Look for an address in a section. This is called via + bfd_map_over_sections. */ + +static void +find_address_in_section (abfd, section, data) + bfd *abfd; + asection *section; + PTR data ATTRIBUTE_UNUSED; +{ + bfd_vma vma; + bfd_size_type size; + + if (found) + return; + + if ((bfd_get_section_flags (abfd, section) & SEC_ALLOC) == 0) + return; + + vma = bfd_get_section_vma (abfd, section); + if (pc < vma) + return; + + size = bfd_get_section_size_before_reloc (section); + if (pc >= vma + size) + return; + + found = bfd_find_nearest_line (abfd, section, syms, pc - vma, + &filename, &functionname, &line); +} + +/* Read hexadecimal addresses from stdin, translate into + file_name:line_number and optionally function name. */ + +static void +translate_addresses (abfd) + bfd *abfd; +{ + int read_stdin = (naddr == 0); + + for (;;) + { + if (read_stdin) + { + char addr_hex[100]; + + if (fgets (addr_hex, sizeof addr_hex, stdin) == NULL) + break; + pc = bfd_scan_vma (addr_hex, NULL, 16); + } + else + { + if (naddr <= 0) + break; + --naddr; + pc = bfd_scan_vma (*addr++, NULL, 16); + } + + found = FALSE; + bfd_map_over_sections (abfd, find_address_in_section, (PTR) NULL); + + if (! found) + { + if (with_functions) + printf ("??\n"); + printf ("??:0\n"); + } + else + { + if (with_functions) + { + const char *name; + char *alloc = NULL; + + name = functionname; + if (name == NULL || *name == '\0') + name = "??"; + else if (do_demangle) + { + alloc = demangle (abfd, name); + name = alloc; + } + + printf ("%s\n", name); + + if (alloc != NULL) + free (alloc); + } + + if (base_names && filename != NULL) + { + char *h; + + h = strrchr (filename, '/'); + if (h != NULL) + filename = h + 1; + } + + printf ("%s:%u\n", filename ? filename : "??", line); + } + + /* fflush() is essential for using this command as a server + child process that reads addresses from a pipe and responds + with line number information, processing one address at a + time. */ + fflush (stdout); + } +} + +/* Process a file. */ + +static void +process_file (file_name, target) + const char *file_name; + const char *target; +{ + bfd *abfd; + char **matching; + + abfd = bfd_openr (file_name, target); + if (abfd == NULL) + bfd_fatal (file_name); + + if (bfd_check_format (abfd, bfd_archive)) + fatal (_("%s: can not get addresses from archive"), file_name); + + if (! bfd_check_format_matches (abfd, bfd_object, &matching)) + { + bfd_nonfatal (bfd_get_filename (abfd)); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } + xexit (1); + } + + slurp_symtab (abfd); + + translate_addresses (abfd); + + if (syms != NULL) + { + free (syms); + syms = NULL; + } + + bfd_close (abfd); +} + +int main PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char **argv; +{ + const char *file_name; + char *target; + int c; + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = *argv; + xmalloc_set_program_name (program_name); + + bfd_init (); + set_default_bfd_target (); + + file_name = NULL; + target = NULL; + while ((c = getopt_long (argc, argv, "b:Ce:sfHhVv", long_options, (int *) 0)) + != EOF) + { + switch (c) + { + case 0: + break; /* We've been given a long option. */ + case 'b': + target = optarg; + break; + case 'C': + do_demangle = TRUE; + if (optarg != NULL) + { + enum demangling_styles style; + + style = cplus_demangle_name_to_style (optarg); + if (style == unknown_demangling) + fatal (_("unknown demangling style `%s'"), + optarg); + + cplus_demangle_set_style (style); + } + break; + case 'e': + file_name = optarg; + break; + case 's': + base_names = TRUE; + break; + case 'f': + with_functions = TRUE; + break; + case 'v': + case 'V': + print_version ("addr2line"); + break; + case 'h': + case 'H': + usage (stdout, 0); + break; + default: + usage (stderr, 1); + break; + } + } + + if (file_name == NULL) + file_name = "a.out"; + + addr = argv + optind; + naddr = argc - optind; + + process_file (file_name, target); + + return 0; +} diff --git a/contrib/binutils-2.14/binutils/ar.c b/contrib/binutils-2.14/binutils/ar.c new file mode 100644 index 0000000000..9a6946eb0d --- /dev/null +++ b/contrib/binutils-2.14/binutils/ar.c @@ -0,0 +1,1438 @@ +/* ar.c - Archive modify and extract. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002 + Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + Bugs: should use getopt the way tar does (complete w/optional -) and + should have long options too. GNU ar used to check file against filesystem + in quick_update and replace operations (would check mtime). Doesn't warn + when name truncated. No way to specify pos_end. Error messages should be + more consistant. */ + +#include "bfd.h" +#include "libiberty.h" +#include "progress.h" +#include "bucomm.h" +#include "aout/ar.h" +#include "libbfd.h" +#include "arsup.h" +#include "filenames.h" +#include "binemul.h" +#include + +#ifdef __GO32___ +#define EXT_NAME_LEN 3 /* bufflen of addition to name if it's MS-DOS */ +#else +#define EXT_NAME_LEN 6 /* ditto for *NIX */ +#endif + +/* We need to open files in binary modes on system where that makes a + difference. */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define BUFSIZE 8192 + +/* Kludge declaration from BFD! This is ugly! FIXME! XXX */ + +struct ar_hdr * + bfd_special_undocumented_glue PARAMS ((bfd * abfd, const char *filename)); + +/* Static declarations */ + +static void +mri_emul PARAMS ((void)); + +static const char * +normalize PARAMS ((const char *, bfd *)); + +static void +remove_output PARAMS ((void)); + +static void +map_over_members PARAMS ((bfd *, void (*)(bfd *), char **, int)); + +static void +print_contents PARAMS ((bfd * member)); + +static void +delete_members PARAMS ((bfd *, char **files_to_delete)); + +#if 0 +static void +do_quick_append PARAMS ((const char *archive_filename, + char **files_to_append)); +#endif + +static void +move_members PARAMS ((bfd *, char **files_to_move)); + +static void +replace_members PARAMS ((bfd *, char **files_to_replace, bfd_boolean quick)); + +static void +print_descr PARAMS ((bfd * abfd)); + +static void +write_archive PARAMS ((bfd *)); + +static void +ranlib_only PARAMS ((const char *archname)); + +static void +ranlib_touch PARAMS ((const char *archname)); + +static void +usage PARAMS ((int)); + +/** Globals and flags */ + +int mri_mode; + +/* This flag distinguishes between ar and ranlib: + 1 means this is 'ranlib'; 0 means this is 'ar'. + -1 means if we should use argv[0] to decide. */ +extern int is_ranlib; + +/* Nonzero means don't warn about creating the archive file if necessary. */ +int silent_create = 0; + +/* Nonzero means describe each action performed. */ +int verbose = 0; + +/* Nonzero means preserve dates of members when extracting them. */ +int preserve_dates = 0; + +/* Nonzero means don't replace existing members whose dates are more recent + than the corresponding files. */ +int newer_only = 0; + +/* Controls the writing of an archive symbol table (in BSD: a __.SYMDEF + member). -1 means we've been explicitly asked to not write a symbol table; + +1 means we've been explictly asked to write it; + 0 is the default. + Traditionally, the default in BSD has been to not write the table. + However, for POSIX.2 compliance the default is now to write a symbol table + if any of the members are object files. */ +int write_armap = 0; + +/* Nonzero means it's the name of an existing member; position new or moved + files with respect to this one. */ +char *posname = NULL; + +/* Sez how to use `posname': pos_before means position before that member. + pos_after means position after that member. pos_end means always at end. + pos_default means default appropriately. For the latter two, `posname' + should also be zero. */ +enum pos + { + pos_default, pos_before, pos_after, pos_end + } postype = pos_default; + +static bfd ** +get_pos_bfd PARAMS ((bfd **, enum pos, const char *)); + +/* For extract/delete only. If COUNTED_NAME_MODE is TRUE, we only + extract the COUNTED_NAME_COUNTER instance of that name. */ +static bfd_boolean counted_name_mode = 0; +static int counted_name_counter = 0; + +/* Whether to truncate names of files stored in the archive. */ +static bfd_boolean ar_truncate = FALSE; + +/* Whether to use a full file name match when searching an archive. + This is convenient for archives created by the Microsoft lib + program. */ +static bfd_boolean full_pathname = FALSE; + +int interactive = 0; + +static void +mri_emul () +{ + interactive = isatty (fileno (stdin)); + yyparse (); +} + +/* If COUNT is 0, then FUNCTION is called once on each entry. If nonzero, + COUNT is the length of the FILES chain; FUNCTION is called on each entry + whose name matches one in FILES. */ + +static void +map_over_members (arch, function, files, count) + bfd *arch; + void (*function) PARAMS ((bfd *)); + char **files; + int count; +{ + bfd *head; + int match_count; + + if (count == 0) + { + for (head = arch->next; head; head = head->next) + { + PROGRESS (1); + function (head); + } + return; + } + + /* This may appear to be a baroque way of accomplishing what we want. + However we have to iterate over the filenames in order to notice where + a filename is requested but does not exist in the archive. Ditto + mapping over each file each time -- we want to hack multiple + references. */ + + for (; count > 0; files++, count--) + { + bfd_boolean found = FALSE; + + match_count = 0; + for (head = arch->next; head; head = head->next) + { + PROGRESS (1); + if (head->filename == NULL) + { + /* Some archive formats don't get the filenames filled in + until the elements are opened. */ + struct stat buf; + bfd_stat_arch_elt (head, &buf); + } + if ((head->filename != NULL) && + (!FILENAME_CMP (normalize (*files, arch), head->filename))) + { + ++match_count; + if (counted_name_mode + && match_count != counted_name_counter) + { + /* Counting, and didn't match on count; go on to the + next one. */ + continue; + } + + found = TRUE; + function (head); + } + } + if (!found) + /* xgettext:c-format */ + fprintf (stderr, _("no entry %s in archive\n"), *files); + } +} + +bfd_boolean operation_alters_arch = FALSE; + +static void +usage (help) + int help; +{ + FILE *s; + + s = help ? stdout : stderr; + + if (! is_ranlib) + { + /* xgettext:c-format */ + fprintf (s, _("Usage: %s [emulation options] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file file...\n"), + program_name); + /* xgettext:c-format */ + fprintf (s, _(" %s -M [ filename)) + filename = bslash; + if (filename == NULL && file[0] != '\0' && file[1] == ':') + filename = file + 1; + } +#endif + if (filename != (char *) NULL) + filename++; + else + filename = file; + + if (ar_truncate + && abfd != NULL + && strlen (filename) > abfd->xvec->ar_max_namelen) + { + char *s; + + /* Space leak. */ + s = (char *) xmalloc (abfd->xvec->ar_max_namelen + 1); + memcpy (s, filename, abfd->xvec->ar_max_namelen); + s[abfd->xvec->ar_max_namelen] = '\0'; + filename = s; + } + + return filename; +} + +/* Remove any output file. This is only called via xatexit. */ + +static const char *output_filename = NULL; +static FILE *output_file = NULL; +static bfd *output_bfd = NULL; + +static void +remove_output () +{ + if (output_filename != NULL) + { + if (output_bfd != NULL && output_bfd->iostream != NULL) + fclose ((FILE *) (output_bfd->iostream)); + if (output_file != NULL) + fclose (output_file); + unlink (output_filename); + } +} + +/* The option parsing should be in its own function. + It will be when I have getopt working. */ + +int main PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char **argv; +{ + char *arg_ptr; + char c; + enum + { + none = 0, delete, replace, print_table, + print_files, extract, move, quick_append + } operation = none; + int arg_index; + char **files; + int file_count; + char *inarch_filename; + int show_version; + int i; + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = argv[0]; + xmalloc_set_program_name (program_name); + + if (is_ranlib < 0) + { + char *temp; + + temp = strrchr (program_name, '/'); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ + char *bslash = strrchr (program_name, '\\'); + if (temp == NULL || (bslash != NULL && bslash > temp)) + temp = bslash; + if (temp == NULL && program_name[0] != '\0' && program_name[1] == ':') + temp = program_name + 1; + } +#endif + if (temp == NULL) + temp = program_name; + else + ++temp; + if (strlen (temp) >= 6 + && FILENAME_CMP (temp + strlen (temp) - 6, "ranlib") == 0) + is_ranlib = 1; + else + is_ranlib = 0; + } + + if (argc > 1 && argv[1][0] == '-') + { + if (strcmp (argv[1], "--help") == 0) + usage (1); + else if (strcmp (argv[1], "--version") == 0) + { + if (is_ranlib) + print_version ("ranlib"); + else + print_version ("ar"); + } + } + + START_PROGRESS (program_name, 0); + + bfd_init (); + set_default_bfd_target (); + + show_version = 0; + + xatexit (remove_output); + + for (i = 1; i < argc; i++) + if (! ar_emul_parse_arg (argv[i])) + break; + argv += (i - 1); + argc -= (i - 1); + + if (is_ranlib) + { + bfd_boolean touch = FALSE; + + if (argc < 2 + || strcmp (argv[1], "--help") == 0 + || strcmp (argv[1], "-h") == 0 + || strcmp (argv[1], "-H") == 0) + usage (0); + if (strcmp (argv[1], "-V") == 0 + || strcmp (argv[1], "-v") == 0 + || strncmp (argv[1], "--v", 3) == 0) + print_version ("ranlib"); + arg_index = 1; + if (strcmp (argv[1], "-t") == 0) + { + ++arg_index; + touch = TRUE; + } + while (arg_index < argc) + { + if (! touch) + ranlib_only (argv[arg_index]); + else + ranlib_touch (argv[arg_index]); + ++arg_index; + } + xexit (0); + } + + if (argc == 2 && strcmp (argv[1], "-M") == 0) + { + mri_emul (); + xexit (0); + } + + if (argc < 2) + usage (0); + + arg_ptr = argv[1]; + + if (*arg_ptr == '-') + ++arg_ptr; /* compatibility */ + + while ((c = *arg_ptr++) != '\0') + { + switch (c) + { + case 'd': + case 'm': + case 'p': + case 'q': + case 'r': + case 't': + case 'x': + if (operation != none) + fatal (_("two different operation options specified")); + switch (c) + { + case 'd': + operation = delete; + operation_alters_arch = TRUE; + break; + case 'm': + operation = move; + operation_alters_arch = TRUE; + break; + case 'p': + operation = print_files; + break; + case 'q': + operation = quick_append; + operation_alters_arch = TRUE; + break; + case 'r': + operation = replace; + operation_alters_arch = TRUE; + break; + case 't': + operation = print_table; + break; + case 'x': + operation = extract; + break; + } + case 'l': + break; + case 'c': + silent_create = 1; + break; + case 'o': + preserve_dates = 1; + break; + case 'V': + show_version = TRUE; + break; + case 's': + write_armap = 1; + break; + case 'S': + write_armap = -1; + break; + case 'u': + newer_only = 1; + break; + case 'v': + verbose = 1; + break; + case 'a': + postype = pos_after; + break; + case 'b': + postype = pos_before; + break; + case 'i': + postype = pos_before; + break; + case 'M': + mri_mode = 1; + break; + case 'N': + counted_name_mode = TRUE; + break; + case 'f': + ar_truncate = TRUE; + break; + case 'P': + full_pathname = TRUE; + break; + default: + /* xgettext:c-format */ + non_fatal (_("illegal option -- %c"), c); + usage (0); + } + } + + if (show_version) + print_version ("ar"); + + if (argc < 3) + usage (0); + + if (mri_mode) + { + mri_emul (); + } + else + { + bfd *arch; + + /* We can't write an armap when using ar q, so just do ar r + instead. */ + if (operation == quick_append && write_armap) + operation = replace; + + if ((operation == none || operation == print_table) + && write_armap == 1) + { + ranlib_only (argv[2]); + xexit (0); + } + + if (operation == none) + fatal (_("no operation specified")); + + if (newer_only && operation != replace) + fatal (_("`u' is only meaningful with the `r' option.")); + + arg_index = 2; + + if (postype != pos_default) + posname = argv[arg_index++]; + + if (counted_name_mode) + { + if (operation != extract && operation != delete) + fatal (_("`N' is only meaningful with the `x' and `d' options.")); + counted_name_counter = atoi (argv[arg_index++]); + if (counted_name_counter <= 0) + fatal (_("Value for `N' must be positive.")); + } + + inarch_filename = argv[arg_index++]; + + files = arg_index < argc ? argv + arg_index : NULL; + file_count = argc - arg_index; + +#if 0 + /* We don't use do_quick_append any more. Too many systems + expect ar to always rebuild the symbol table even when q is + used. */ + + /* We can't do a quick append if we need to construct an + extended name table, because do_quick_append won't be able to + rebuild the name table. Unfortunately, at this point we + don't actually know the maximum name length permitted by this + object file format. So, we guess. FIXME. */ + if (operation == quick_append && ! ar_truncate) + { + char **chk; + + for (chk = files; chk != NULL && *chk != '\0'; chk++) + { + if (strlen (normalize (*chk, (bfd *) NULL)) > 14) + { + operation = replace; + break; + } + } + } + + if (operation == quick_append) + { + /* Note that quick appending to a non-existent archive creates it, + even if there are no files to append. */ + do_quick_append (inarch_filename, files); + xexit (0); + } +#endif + + arch = open_inarch (inarch_filename, + files == NULL ? (char *) NULL : files[0]); + + switch (operation) + { + case print_table: + map_over_members (arch, print_descr, files, file_count); + break; + + case print_files: + map_over_members (arch, print_contents, files, file_count); + break; + + case extract: + map_over_members (arch, extract_file, files, file_count); + break; + + case delete: + if (files != NULL) + delete_members (arch, files); + else + output_filename = NULL; + break; + + case move: + if (files != NULL) + move_members (arch, files); + else + output_filename = NULL; + break; + + case replace: + case quick_append: + if (files != NULL || write_armap > 0) + replace_members (arch, files, operation == quick_append); + else + output_filename = NULL; + break; + + /* Shouldn't happen! */ + default: + /* xgettext:c-format */ + fatal (_("internal error -- this option not implemented")); + } + } + + END_PROGRESS (program_name); + + xexit (0); + return 0; +} + +bfd * +open_inarch (archive_filename, file) + const char *archive_filename; + const char *file; +{ + const char *target; + bfd **last_one; + bfd *next_one; + struct stat sbuf; + bfd *arch; + char **matching; + + bfd_set_error (bfd_error_no_error); + + target = NULL; + + if (stat (archive_filename, &sbuf) != 0) + { +#if !defined(__GO32__) || defined(__DJGPP__) + + /* FIXME: I don't understand why this fragment was ifndef'ed + away for __GO32__; perhaps it was in the days of DJGPP v1.x. + stat() works just fine in v2.x, so I think this should be + removed. For now, I enable it for DJGPP v2. -- EZ. */ + +/* KLUDGE ALERT! Temporary fix until I figger why + stat() is wrong ... think it's buried in GO32's IDT - Jax */ + if (errno != ENOENT) + bfd_fatal (archive_filename); +#endif + + if (!operation_alters_arch) + { + fprintf (stderr, "%s: ", program_name); + perror (archive_filename); + maybequit (); + return NULL; + } + + /* Try to figure out the target to use for the archive from the + first object on the list. */ + if (file != NULL) + { + bfd *obj; + + obj = bfd_openr (file, NULL); + if (obj != NULL) + { + if (bfd_check_format (obj, bfd_object)) + target = bfd_get_target (obj); + (void) bfd_close (obj); + } + } + + /* Create an empty archive. */ + arch = bfd_openw (archive_filename, target); + if (arch == NULL + || ! bfd_set_format (arch, bfd_archive) + || ! bfd_close (arch)) + bfd_fatal (archive_filename); + + /* If we die creating a new archive, don't leave it around. */ + output_filename = archive_filename; + } + + arch = bfd_openr (archive_filename, target); + if (arch == NULL) + { + bloser: + bfd_fatal (archive_filename); + } + + if (! bfd_check_format_matches (arch, bfd_archive, &matching)) + { + bfd_nonfatal (archive_filename); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } + xexit (1); + } + + last_one = &(arch->next); + /* Read all the contents right away, regardless. */ + for (next_one = bfd_openr_next_archived_file (arch, NULL); + next_one; + next_one = bfd_openr_next_archived_file (arch, next_one)) + { + PROGRESS (1); + *last_one = next_one; + last_one = &next_one->next; + } + *last_one = (bfd *) NULL; + if (bfd_get_error () != bfd_error_no_more_archived_files) + goto bloser; + return arch; +} + +static void +print_contents (abfd) + bfd *abfd; +{ + int ncopied = 0; + char *cbuf = xmalloc (BUFSIZE); + struct stat buf; + long size; + if (bfd_stat_arch_elt (abfd, &buf) != 0) + /* xgettext:c-format */ + fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); + + if (verbose) + /* xgettext:c-format */ + printf (_("\n\n\n"), bfd_get_filename (abfd)); + + bfd_seek (abfd, (file_ptr) 0, SEEK_SET); + + size = buf.st_size; + while (ncopied < size) + { + + int nread; + int tocopy = size - ncopied; + if (tocopy > BUFSIZE) + tocopy = BUFSIZE; + + nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd); + if (nread != tocopy) + /* xgettext:c-format */ + fatal (_("%s is not a valid archive"), + bfd_get_filename (bfd_my_archive (abfd))); + fwrite (cbuf, 1, nread, stdout); + ncopied += tocopy; + } + free (cbuf); +} + +/* Extract a member of the archive into its own file. + + We defer opening the new file until after we have read a BUFSIZ chunk of the + old one, since we know we have just read the archive header for the old + one. Since most members are shorter than BUFSIZ, this means we will read + the old header, read the old data, write a new inode for the new file, and + write the new data, and be done. This 'optimization' is what comes from + sitting next to a bare disk and hearing it every time it seeks. -- Gnu + Gilmore */ + +void +extract_file (abfd) + bfd *abfd; +{ + FILE *ostream; + char *cbuf = xmalloc (BUFSIZE); + int nread, tocopy; + long ncopied = 0; + long size; + struct stat buf; + + if (bfd_stat_arch_elt (abfd, &buf) != 0) + /* xgettext:c-format */ + fatal (_("internal stat error on %s"), bfd_get_filename (abfd)); + size = buf.st_size; + + if (size < 0) + /* xgettext:c-format */ + fatal (_("stat returns negative size for %s"), bfd_get_filename (abfd)); + + if (verbose) + printf ("x - %s\n", bfd_get_filename (abfd)); + + bfd_seek (abfd, (file_ptr) 0, SEEK_SET); + + ostream = NULL; + if (size == 0) + { + /* Seems like an abstraction violation, eh? Well it's OK! */ + output_filename = bfd_get_filename (abfd); + + ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); + if (ostream == NULL) + { + perror (bfd_get_filename (abfd)); + xexit (1); + } + + output_file = ostream; + } + else + while (ncopied < size) + { + tocopy = size - ncopied; + if (tocopy > BUFSIZE) + tocopy = BUFSIZE; + + nread = bfd_bread (cbuf, (bfd_size_type) tocopy, abfd); + if (nread != tocopy) + /* xgettext:c-format */ + fatal (_("%s is not a valid archive"), + bfd_get_filename (bfd_my_archive (abfd))); + + /* See comment above; this saves disk arm motion */ + if (ostream == NULL) + { + /* Seems like an abstraction violation, eh? Well it's OK! */ + output_filename = bfd_get_filename (abfd); + + ostream = fopen (bfd_get_filename (abfd), FOPEN_WB); + if (ostream == NULL) + { + perror (bfd_get_filename (abfd)); + xexit (1); + } + + output_file = ostream; + } + fwrite (cbuf, 1, nread, ostream); + ncopied += tocopy; + } + + if (ostream != NULL) + fclose (ostream); + + output_file = NULL; + output_filename = NULL; + + chmod (bfd_get_filename (abfd), buf.st_mode); + + if (preserve_dates) + set_times (bfd_get_filename (abfd), &buf); + + free (cbuf); +} + +#if 0 + +/* We don't use this anymore. Too many systems expect ar to rebuild + the symbol table even when q is used. */ + +/* Just do it quickly; don't worry about dups, armap, or anything like that */ + +static void +do_quick_append (archive_filename, files_to_append) + const char *archive_filename; + char **files_to_append; +{ + FILE *ofile, *ifile; + char *buf = xmalloc (BUFSIZE); + long tocopy, thistime; + bfd *temp; + struct stat sbuf; + bfd_boolean newfile = FALSE; + bfd_set_error (bfd_error_no_error); + + if (stat (archive_filename, &sbuf) != 0) + { + +#if !defined(__GO32__) || defined(__DJGPP__) + + /* FIXME: I don't understand why this fragment was ifndef'ed + away for __GO32__; perhaps it was in the days of DJGPP v1.x. + stat() works just fine in v2.x, so I think this should be + removed. For now, I enable it for DJGPP v2. + + (And yes, I know this is all unused, but somebody, someday, + might wish to resurrect this again... -- EZ. */ + +/* KLUDGE ALERT! Temporary fix until I figger why + stat() is wrong ... think it's buried in GO32's IDT - Jax */ + + if (errno != ENOENT) + bfd_fatal (archive_filename); +#endif + + newfile = TRUE; + } + + ofile = fopen (archive_filename, FOPEN_AUB); + if (ofile == NULL) + { + perror (program_name); + xexit (1); + } + + temp = bfd_openr (archive_filename, NULL); + if (temp == NULL) + { + bfd_fatal (archive_filename); + } + if (!newfile) + { + if (!bfd_check_format (temp, bfd_archive)) + /* xgettext:c-format */ + fatal (_("%s is not an archive"), archive_filename); + } + else + { + fwrite (ARMAG, 1, SARMAG, ofile); + if (!silent_create) + /* xgettext:c-format */ + non_fatal (_("creating %s"), archive_filename); + } + + if (ar_truncate) + temp->flags |= BFD_TRADITIONAL_FORMAT; + + /* assume it's an achive, go straight to the end, sans $200 */ + fseek (ofile, 0, 2); + + for (; files_to_append && *files_to_append; ++files_to_append) + { + struct ar_hdr *hdr = bfd_special_undocumented_glue (temp, *files_to_append); + if (hdr == NULL) + { + bfd_fatal (*files_to_append); + } + + BFD_SEND (temp, _bfd_truncate_arname, (temp, *files_to_append, (char *) hdr)); + + ifile = fopen (*files_to_append, FOPEN_RB); + if (ifile == NULL) + { + bfd_nonfatal (*files_to_append); + } + + if (stat (*files_to_append, &sbuf) != 0) + { + bfd_nonfatal (*files_to_append); + } + + tocopy = sbuf.st_size; + + /* XXX should do error-checking! */ + fwrite (hdr, 1, sizeof (struct ar_hdr), ofile); + + while (tocopy > 0) + { + thistime = tocopy; + if (thistime > BUFSIZE) + thistime = BUFSIZE; + fread (buf, 1, thistime, ifile); + fwrite (buf, 1, thistime, ofile); + tocopy -= thistime; + } + fclose (ifile); + if ((sbuf.st_size % 2) == 1) + putc ('\012', ofile); + } + fclose (ofile); + bfd_close (temp); + free (buf); +} + +#endif /* 0 */ + +static void +write_archive (iarch) + bfd *iarch; +{ + bfd *obfd; + char *old_name, *new_name; + bfd *contents_head = iarch->next; + + old_name = xmalloc (strlen (bfd_get_filename (iarch)) + 1); + strcpy (old_name, bfd_get_filename (iarch)); + new_name = make_tempname (old_name); + + output_filename = new_name; + + obfd = bfd_openw (new_name, bfd_get_target (iarch)); + + if (obfd == NULL) + bfd_fatal (old_name); + + output_bfd = obfd; + + bfd_set_format (obfd, bfd_archive); + + /* Request writing the archive symbol table unless we've + been explicitly requested not to. */ + obfd->has_armap = write_armap >= 0; + + if (ar_truncate) + { + /* This should really use bfd_set_file_flags, but that rejects + archives. */ + obfd->flags |= BFD_TRADITIONAL_FORMAT; + } + + if (!bfd_set_archive_head (obfd, contents_head)) + bfd_fatal (old_name); + + if (!bfd_close (obfd)) + bfd_fatal (old_name); + + output_bfd = NULL; + output_filename = NULL; + + /* We don't care if this fails; we might be creating the archive. */ + bfd_close (iarch); + + if (smart_rename (new_name, old_name, 0) != 0) + xexit (1); +} + +/* Return a pointer to the pointer to the entry which should be rplacd'd + into when altering. DEFAULT_POS should be how to interpret pos_default, + and should be a pos value. */ + +static bfd ** +get_pos_bfd (contents, default_pos, default_posname) + bfd **contents; + enum pos default_pos; + const char *default_posname; +{ + bfd **after_bfd = contents; + enum pos realpos; + const char *realposname; + + if (postype == pos_default) + { + realpos = default_pos; + realposname = default_posname; + } + else + { + realpos = postype; + realposname = posname; + } + + if (realpos == pos_end) + { + while (*after_bfd) + after_bfd = &((*after_bfd)->next); + } + else + { + for (; *after_bfd; after_bfd = &(*after_bfd)->next) + if (FILENAME_CMP ((*after_bfd)->filename, realposname) == 0) + { + if (realpos == pos_after) + after_bfd = &(*after_bfd)->next; + break; + } + } + return after_bfd; +} + +static void +delete_members (arch, files_to_delete) + bfd *arch; + char **files_to_delete; +{ + bfd **current_ptr_ptr; + bfd_boolean found; + bfd_boolean something_changed = FALSE; + int match_count; + + for (; *files_to_delete != NULL; ++files_to_delete) + { + /* In a.out systems, the armap is optional. It's also called + __.SYMDEF. So if the user asked to delete it, we should remember + that fact. This isn't quite right for COFF systems (where + __.SYMDEF might be regular member), but it's very unlikely + to be a problem. FIXME */ + + if (!strcmp (*files_to_delete, "__.SYMDEF")) + { + arch->has_armap = FALSE; + write_armap = -1; + continue; + } + + found = FALSE; + match_count = 0; + current_ptr_ptr = &(arch->next); + while (*current_ptr_ptr) + { + if (FILENAME_CMP (normalize (*files_to_delete, arch), + (*current_ptr_ptr)->filename) == 0) + { + ++match_count; + if (counted_name_mode + && match_count != counted_name_counter) + { + /* Counting, and didn't match on count; go on to the + next one. */ + } + else + { + found = TRUE; + something_changed = TRUE; + if (verbose) + printf ("d - %s\n", + *files_to_delete); + *current_ptr_ptr = ((*current_ptr_ptr)->next); + goto next_file; + } + } + + current_ptr_ptr = &((*current_ptr_ptr)->next); + } + + if (verbose && !found) + { + /* xgettext:c-format */ + printf (_("No member named `%s'\n"), *files_to_delete); + } + next_file: + ; + } + + if (something_changed) + write_archive (arch); + else + output_filename = NULL; +} + + +/* Reposition existing members within an archive */ + +static void +move_members (arch, files_to_move) + bfd *arch; + char **files_to_move; +{ + bfd **after_bfd; /* New entries go after this one */ + bfd **current_ptr_ptr; /* cdr pointer into contents */ + + for (; *files_to_move; ++files_to_move) + { + current_ptr_ptr = &(arch->next); + while (*current_ptr_ptr) + { + bfd *current_ptr = *current_ptr_ptr; + if (FILENAME_CMP (normalize (*files_to_move, arch), + current_ptr->filename) == 0) + { + /* Move this file to the end of the list - first cut from + where it is. */ + bfd *link; + *current_ptr_ptr = current_ptr->next; + + /* Now glue to end */ + after_bfd = get_pos_bfd (&arch->next, pos_end, NULL); + link = *after_bfd; + *after_bfd = current_ptr; + current_ptr->next = link; + + if (verbose) + printf ("m - %s\n", *files_to_move); + + goto next_file; + } + + current_ptr_ptr = &((*current_ptr_ptr)->next); + } + /* xgettext:c-format */ + fatal (_("no entry %s in archive %s!"), *files_to_move, arch->filename); + + next_file:; + } + + write_archive (arch); +} + +/* Ought to default to replacing in place, but this is existing practice! */ + +static void +replace_members (arch, files_to_move, quick) + bfd *arch; + char **files_to_move; + bfd_boolean quick; +{ + bfd_boolean changed = FALSE; + bfd **after_bfd; /* New entries go after this one */ + bfd *current; + bfd **current_ptr; + + while (files_to_move && *files_to_move) + { + if (! quick) + { + current_ptr = &arch->next; + while (*current_ptr) + { + current = *current_ptr; + + /* For compatibility with existing ar programs, we + permit the same file to be added multiple times. */ + if (FILENAME_CMP (normalize (*files_to_move, arch), + normalize (current->filename, arch)) == 0 + && current->arelt_data != NULL) + { + if (newer_only) + { + struct stat fsbuf, asbuf; + + if (stat (*files_to_move, &fsbuf) != 0) + { + if (errno != ENOENT) + bfd_fatal (*files_to_move); + goto next_file; + } + if (bfd_stat_arch_elt (current, &asbuf) != 0) + /* xgettext:c-format */ + fatal (_("internal stat error on %s"), + current->filename); + + if (fsbuf.st_mtime <= asbuf.st_mtime) + goto next_file; + } + + after_bfd = get_pos_bfd (&arch->next, pos_after, + current->filename); + if (ar_emul_replace (after_bfd, *files_to_move, + verbose)) + { + /* Snip out this entry from the chain. */ + *current_ptr = (*current_ptr)->next; + changed = TRUE; + } + + goto next_file; + } + current_ptr = &(current->next); + } + } + + /* Add to the end of the archive. */ + after_bfd = get_pos_bfd (&arch->next, pos_end, NULL); + if (ar_emul_append (after_bfd, *files_to_move, verbose)) + changed = TRUE; + + next_file:; + + files_to_move++; + } + + if (changed) + write_archive (arch); + else + output_filename = NULL; +} + +static void +ranlib_only (archname) + const char *archname; +{ + bfd *arch; + + write_armap = 1; + arch = open_inarch (archname, (char *) NULL); + if (arch == NULL) + xexit (1); + write_archive (arch); +} + +/* Update the timestamp of the symbol map of an archive. */ + +static void +ranlib_touch (archname) + const char *archname; +{ +#ifdef __GO32__ + /* I don't think updating works on go32. */ + ranlib_only (archname); +#else + int f; + bfd *arch; + char **matching; + + f = open (archname, O_RDWR | O_BINARY, 0); + if (f < 0) + { + bfd_set_error (bfd_error_system_call); + bfd_fatal (archname); + } + + arch = bfd_fdopenr (archname, (const char *) NULL, f); + if (arch == NULL) + bfd_fatal (archname); + if (! bfd_check_format_matches (arch, bfd_archive, &matching)) + { + bfd_nonfatal (archname); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } + xexit (1); + } + + if (! bfd_has_map (arch)) + /* xgettext:c-format */ + fatal (_("%s: no archive map to update"), archname); + + bfd_update_armap_timestamp (arch); + + if (! bfd_close (arch)) + bfd_fatal (archname); +#endif +} + +/* Things which are interesting to map over all or some of the files: */ + +static void +print_descr (abfd) + bfd *abfd; +{ + print_arelt_descr (stdout, abfd, verbose); +} diff --git a/contrib/binutils-2.14/binutils/arlex.l b/contrib/binutils-2.14/binutils/arlex.l new file mode 100644 index 0000000000..c1771a5584 --- /dev/null +++ b/contrib/binutils-2.14/binutils/arlex.l @@ -0,0 +1,91 @@ +%{ +/* arlex.l - Strange script language lexer */ + +/* Copyright 1992, 1997, 2000, 2002 Free Software Foundation, Inc. + +This file is part of GNU Binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* Contributed by Steve Chamberlain + sac@cygnus.com + +*/ +#define DONTDECLARE_MALLOC +#include "ansidecl.h" +#include "libiberty.h" +#include "arparse.h" + +#define YY_NO_UNPUT + +extern int yylex PARAMS ((void)); + +int linenumber; +%} + +%a 10000 +%o 25000 + +%% + +"ADDLIB" { return ADDLIB; } +"ADDMOD" { return ADDMOD; } +"CLEAR" { return CLEAR; } +"CREATE" { return CREATE; } +"DELETE" { return DELETE; } +"DIRECTORY" { return DIRECTORY; } +"END" { return END; } +"EXTRACT" { return EXTRACT; } +"FULLDIR" { return FULLDIR; } +"HELP" { return HELP; } +"LIST" { return LIST; } +"OPEN" { return OPEN; } +"REPLACE" { return REPLACE; } +"VERBOSE" { return VERBOSE; } +"SAVE" { return SAVE; } +"addlib" { return ADDLIB; } +"addmod" { return ADDMOD; } +"clear" { return CLEAR; } +"create" { return CREATE; } +"delete" { return DELETE; } +"directory" { return DIRECTORY; } +"end" { return END; } +"extract" { return EXTRACT; } +"fulldir" { return FULLDIR; } +"help" { return HELP; } +"list" { return LIST; } +"open" { return OPEN; } +"replace" { return REPLACE; } +"verbose" { return VERBOSE; } +"save" { return SAVE; } +"+\n" { linenumber ++; } +"(" { return '('; } +")" { return ')'; } +"," { return ','; } +[A-Za-z0-9/\\$:.\-\_]+ { + yylval.name = xstrdup (yytext); + return FILENAME; + } +"*".* { } +";".* { } +" " { } +"\n" { linenumber ++; return NEWLINE; } + +%% +#ifndef yywrap +/* Needed for lex, though not flex. */ +int yywrap() { return 1; } +#endif diff --git a/contrib/binutils-2.14/binutils/arparse.h b/contrib/binutils-2.14/binutils/arparse.h new file mode 100644 index 0000000000..0b9c3fd3ed --- /dev/null +++ b/contrib/binutils-2.14/binutils/arparse.h @@ -0,0 +1,35 @@ +#ifndef BISON_Y_TAB_H +# define BISON_Y_TAB_H + +#ifndef YYSTYPE +typedef union { + char *name; +struct list *list ; + +} yystype; +# define YYSTYPE yystype +# define YYSTYPE_IS_TRIVIAL 1 +#endif +# define NEWLINE 257 +# define VERBOSE 258 +# define FILENAME 259 +# define ADDLIB 260 +# define LIST 261 +# define ADDMOD 262 +# define CLEAR 263 +# define CREATE 264 +# define DELETE 265 +# define DIRECTORY 266 +# define END 267 +# define EXTRACT 268 +# define FULLDIR 269 +# define HELP 270 +# define QUIT 271 +# define REPLACE 272 +# define SAVE 273 +# define OPEN 274 + + +extern YYSTYPE yylval; + +#endif /* not BISON_Y_TAB_H */ diff --git a/contrib/binutils-2.14/binutils/arparse.y b/contrib/binutils-2.14/binutils/arparse.y new file mode 100644 index 0000000000..cf0ece1b92 --- /dev/null +++ b/contrib/binutils-2.14/binutils/arparse.y @@ -0,0 +1,203 @@ +%{ +/* arparse.y - Stange script language parser */ + +/* Copyright 1992, 1993, 1995, 1997, 1999 Free Software Foundation, Inc. + +This file is part of GNU Binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* Contributed by Steve Chamberlain + sac@cygnus.com + +*/ +#define DONTDECLARE_MALLOC +#include "bfd.h" +#include "bucomm.h" +#include "arsup.h" +extern int verbose; +extern int yylex PARAMS ((void)); +static int yyerror PARAMS ((const char *)); +%} + +%union { + char *name; +struct list *list ; + +}; + +%token NEWLINE +%token VERBOSE +%token FILENAME +%token ADDLIB +%token LIST +%token ADDMOD +%token CLEAR +%token CREATE +%token DELETE +%token DIRECTORY +%token END +%token EXTRACT +%token FULLDIR +%token HELP +%token QUIT +%token REPLACE +%token SAVE +%token OPEN + +%type modulelist +%type modulename +%type optional_filename +%% + +start: + { prompt(); } session + ; + +session: + session command_line + | + ; + +command_line: + command NEWLINE { prompt(); } + ; + +command: + open_command + | create_command + | verbose_command + | directory_command + | addlib_command + | clear_command + | addmod_command + | save_command + | extract_command + | replace_command + | delete_command + | list_command + | END { ar_end(); return 0; } + | error + | FILENAME { yyerror("foo"); } + | + ; + + +extract_command: + EXTRACT modulename + { ar_extract($2); } + ; + +replace_command: + REPLACE modulename + { ar_replace($2); } + ; + +clear_command: + CLEAR + { ar_clear(); } + ; + +delete_command: + DELETE modulename + { ar_delete($2); } + ; +addmod_command: + ADDMOD modulename + { ar_addmod($2); } + ; + +list_command: + LIST + { ar_list(); } + ; + +save_command: + SAVE + { ar_save(); } + ; + + + +open_command: + OPEN FILENAME + { ar_open($2,0); } + ; + +create_command: + CREATE FILENAME + { ar_open($2,1); } + ; + + +addlib_command: + ADDLIB FILENAME modulelist + { ar_addlib($2,$3); } + ; +directory_command: + DIRECTORY FILENAME modulelist optional_filename + { ar_directory($2, $3, $4); } + ; + + + +optional_filename: + FILENAME + { $$ = $1; } + | { $$ = 0; } + ; + +modulelist: + '(' modulename ')' + { $$ = $2; } + | + { $$ = 0; } + ; + +modulename: + modulename optcomma FILENAME + { struct list *n = (struct list *) malloc(sizeof(struct list)); + n->next = $1; + n->name = $3; + $$ = n; + } + | { $$ = 0; } + ; + + +optcomma: + ',' + | + ; + + +verbose_command: + VERBOSE + { verbose = !verbose; } + ; + + +%% + +static int +yyerror (x) + const char *x ATTRIBUTE_UNUSED; +{ + extern int linenumber; + + printf (_("Syntax error in archive script, line %d\n"), linenumber + 1); + return 0; +} diff --git a/contrib/binutils-2.14/binutils/arsup.c b/contrib/binutils-2.14/binutils/arsup.c new file mode 100644 index 0000000000..b3e967243a --- /dev/null +++ b/contrib/binutils-2.14/binutils/arsup.c @@ -0,0 +1,496 @@ +/* arsup.c - Archive support for MRI compatibility + Copyright 1992, 1994, 1995, 1996, 1997, 2000, 2002 + Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* Contributed by Steve Chamberlain + sac@cygnus.com + + This file looks after requests from arparse.y, to provide the MRI + style librarian command syntax + 1 word LIST. */ + +#include "bfd.h" +#include "arsup.h" +#include "libiberty.h" +#include "bucomm.h" +#include "filenames.h" + +static void map_over_list + PARAMS ((bfd *, void (*function) (bfd *, bfd *), struct list *)); +static void ar_directory_doer PARAMS ((bfd *, bfd *)); +static void ar_addlib_doer PARAMS ((bfd *, bfd *)); + +extern int verbose; + +static void +map_over_list (arch, function, list) + bfd *arch; + void (*function) PARAMS ((bfd *, bfd *)); + struct list *list; +{ + bfd *head; + + if (list == NULL) + { + bfd *next; + + head = arch->next; + while (head != NULL) + { + next = head->next; + function (head, (bfd *) NULL); + head = next; + } + } + else + { + struct list *ptr; + + /* This may appear to be a baroque way of accomplishing what we + want. however we have to iterate over the filenames in order + to notice where a filename is requested but does not exist in + the archive. Ditto mapping over each file each time -- we + want to hack multiple references. */ + for (ptr = list; ptr; ptr = ptr->next) + { + bfd_boolean found = FALSE; + bfd *prev = arch; + + for (head = arch->next; head; head = head->next) + { + if (head->filename != NULL + && FILENAME_CMP (ptr->name, head->filename) == 0) + { + found = TRUE; + function (head, prev); + } + prev = head; + } + if (! found) + fprintf (stderr, _("No entry %s in archive.\n"), ptr->name); + } + } +} + + +FILE *outfile; + +static void +ar_directory_doer (abfd, ignore) + bfd *abfd; + bfd *ignore ATTRIBUTE_UNUSED; +{ + print_arelt_descr(outfile, abfd, verbose); +} + +void +ar_directory (ar_name, list, output) + char *ar_name; + struct list *list; + char *output; +{ + bfd *arch; + + arch = open_inarch (ar_name, (char *) NULL); + if (output) + { + outfile = fopen(output,"w"); + if (outfile == 0) + { + outfile = stdout; + fprintf (stderr,_("Can't open file %s\n"), output); + output = 0; + } + } + else + outfile = stdout; + + map_over_list (arch, ar_directory_doer, list); + + bfd_close (arch); + + if (output) + fclose (outfile); +} + +void +DEFUN_VOID(prompt) +{ + extern int interactive; + + if (interactive) + { + printf ("AR >"); + fflush (stdout); + } +} + +void +maybequit () +{ + if (! interactive) + xexit (9); +} + + +bfd *obfd; +char *real_name; + +void +ar_open (name, t) + char *name; + int t; +{ + char *tname = (char *) xmalloc (strlen (name) + 10); + const char *bname = lbasename (name); + real_name = name; + + /* Prepend tmp- to the beginning, to avoid file-name clashes after + truncation on filesystems with limited namespaces (DOS). */ + sprintf (tname, "%.*stmp-%s", (int) (bname - name), name, bname); + obfd = bfd_openw (tname, NULL); + + if (!obfd) + { + fprintf (stderr, + _("%s: Can't open output archive %s\n"), + program_name, tname); + + maybequit (); + } + else + { + if (!t) + { + bfd **ptr; + bfd *element; + bfd *ibfd; + + ibfd = bfd_openr (name, NULL); + + if (!ibfd) + { + fprintf (stderr,_("%s: Can't open input archive %s\n"), + program_name, name); + maybequit (); + return; + } + + if (!bfd_check_format(ibfd, bfd_archive)) + { + fprintf (stderr, + _("%s: file %s is not an archive\n"), + program_name, name); + maybequit (); + return; + } + + ptr = &(obfd->archive_head); + element = bfd_openr_next_archived_file (ibfd, NULL); + + while (element) + { + *ptr = element; + ptr = &element->next; + element = bfd_openr_next_archived_file (ibfd, element); + } + } + + bfd_set_format (obfd, bfd_archive); + + obfd->has_armap = 1; + } +} + +static void +ar_addlib_doer (abfd, prev) + bfd *abfd; + bfd *prev; +{ + /* Add this module to the output bfd. */ + if (prev != NULL) + prev->next = abfd->next; + + abfd->next = obfd->archive_head; + obfd->archive_head = abfd; +} + +void +ar_addlib (name, list) + char *name; + struct list *list; +{ + if (obfd == NULL) + { + fprintf (stderr, _("%s: no output archive specified yet\n"), program_name); + maybequit (); + } + else + { + bfd *arch; + + arch = open_inarch (name, (char *) NULL); + if (arch != NULL) + map_over_list (arch, ar_addlib_doer, list); + + /* Don't close the bfd, since it will make the elements disasppear. */ + } +} + +void +ar_addmod (list) + struct list *list; +{ + if (!obfd) + { + fprintf (stderr, _("%s: no open output archive\n"), program_name); + maybequit (); + } + else + { + while (list) + { + bfd *abfd = bfd_openr (list->name, NULL); + + if (!abfd) + { + fprintf (stderr, _("%s: can't open file %s\n"), + program_name, list->name); + maybequit (); + } + else + { + abfd->next = obfd->archive_head; + obfd->archive_head = abfd; + } + list = list->next; + } + } +} + + +void +ar_clear () +{ + if (obfd) + obfd->archive_head = 0; +} + +void +ar_delete (list) + struct list *list; +{ + if (!obfd) + { + fprintf (stderr, _("%s: no open output archive\n"), program_name); + maybequit (); + } + else + { + while (list) + { + /* Find this name in the archive. */ + bfd *member = obfd->archive_head; + bfd **prev = &(obfd->archive_head); + int found = 0; + + while (member) + { + if (FILENAME_CMP(member->filename, list->name) == 0) + { + *prev = member->next; + found = 1; + } + else + prev = &(member->next); + + member = member->next; + } + + if (!found) + { + fprintf (stderr, _("%s: can't find module file %s\n"), + program_name, list->name); + maybequit (); + } + + list = list->next; + } + } +} + +void +ar_save () +{ + if (!obfd) + { + fprintf (stderr, _("%s: no open output archive\n"), program_name); + maybequit (); + } + else + { + char *ofilename = xstrdup (bfd_get_filename (obfd)); + + bfd_close (obfd); + + rename (ofilename, real_name); + obfd = 0; + free (ofilename); + } +} + +void +ar_replace (list) + struct list *list; +{ + if (!obfd) + { + fprintf (stderr, _("%s: no open output archive\n"), program_name); + maybequit (); + } + else + { + while (list) + { + /* Find this name in the archive. */ + bfd *member = obfd->archive_head; + bfd **prev = &(obfd->archive_head); + int found = 0; + + while (member) + { + if (FILENAME_CMP (member->filename, list->name) == 0) + { + /* Found the one to replace. */ + bfd *abfd = bfd_openr (list->name, 0); + + if (!abfd) + { + fprintf (stderr, _("%s: can't open file %s\n"), + program_name, list->name); + maybequit (); + } + else + { + *prev = abfd; + abfd->next = member->next; + found = 1; + } + } + else + { + prev = &(member->next); + } + member = member->next; + } + + if (!found) + { + bfd *abfd = bfd_openr (list->name, 0); + + fprintf (stderr,_("%s: can't find module file %s\n"), + program_name, list->name); + if (!abfd) + { + fprintf (stderr, _("%s: can't open file %s\n"), + program_name, list->name); + maybequit (); + } + else + *prev = abfd; + } + + list = list->next; + } + } +} + +/* And I added this one. */ +void +ar_list () +{ + if (!obfd) + { + fprintf (stderr, _("%s: no open output archive\n"), program_name); + maybequit (); + } + else + { + bfd *abfd; + + outfile = stdout; + verbose =1 ; + printf (_("Current open archive is %s\n"), bfd_get_filename (obfd)); + + for (abfd = obfd->archive_head; + abfd != (bfd *)NULL; + abfd = abfd->next) + ar_directory_doer (abfd, (bfd *) NULL); + } +} + +void +ar_end () +{ + if (obfd) + { + fclose ((FILE *)(obfd->iostream)); + unlink (bfd_get_filename (obfd)); + } +} + +void +ar_extract (list) + struct list *list; +{ + if (!obfd) + { + fprintf (stderr, _("%s: no open archive\n"), program_name); + maybequit (); + } + else + { + while (list) + { + /* Find this name in the archive. */ + bfd *member = obfd->archive_head; + int found = 0; + + while (member && !found) + { + if (FILENAME_CMP (member->filename, list->name) == 0) + { + extract_file (member); + found = 1; + } + + member = member->next; + } + + if (!found) + { + bfd_openr (list->name, 0); + fprintf (stderr, _("%s: can't find module file %s\n"), + program_name, list->name); + } + + list = list->next; + } + } +} diff --git a/contrib/binutils-2.14/binutils/arsup.h b/contrib/binutils-2.14/binutils/arsup.h new file mode 100644 index 0000000000..aeec2589b0 --- /dev/null +++ b/contrib/binutils-2.14/binutils/arsup.h @@ -0,0 +1,61 @@ +/* arsup.h - archive support header file + Copyright 1992, 1993, 1994, 1996 Free Software Foundation, Inc. + +This file is part of GNU Binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +struct list { + char *name; + struct list *next; +}; + +void maybequit PARAMS ((void)); + +void prompt PARAMS ((void)); + +void ar_clear PARAMS ((void)); + +void ar_replace PARAMS ((struct list *)); + +void ar_delete PARAMS ((struct list *)); + +void ar_save PARAMS ((void)); + +void ar_list PARAMS ((void)); + +void ar_open PARAMS ((char *, int)); + +void ar_directory PARAMS ((char *, struct list *, char *)); + +void ar_addmod PARAMS ((struct list *)); + +void ar_addlib PARAMS ((char *, struct list *)); + +void ar_end PARAMS ((void)); + +void ar_extract PARAMS ((struct list *)); + +bfd *open_inarch PARAMS ((const char *archive_filename, const char *)); + +extern int yylex PARAMS ((void)); + +int yyparse PARAMS ((void)); + +/* Functions from ar.c */ + +void extract_file PARAMS ((bfd * abfd)); + +extern int interactive; diff --git a/contrib/binutils-2.14/binutils/binemul.c b/contrib/binutils-2.14/binutils/binemul.c new file mode 100644 index 0000000000..67aaba8623 --- /dev/null +++ b/contrib/binutils-2.14/binutils/binemul.c @@ -0,0 +1,165 @@ +/* Binutils emulation layer. + Copyright 2002 Free Software Foundation, Inc. + Written by Tom Rix, Redhat. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "binemul.h" + +extern bin_emulation_xfer_type bin_dummy_emulation; + +void +ar_emul_usage (fp) + FILE *fp; +{ + if (bin_dummy_emulation.ar_usage) + bin_dummy_emulation.ar_usage (fp); +} + +void +ar_emul_default_usage (fp) + FILE *fp; +{ + AR_EMUL_USAGE_PRINT_OPTION_HEADER (fp); + /* xgettext:c-format */ + fprintf (fp, _(" No emulation specific options\n")); +} + +bfd_boolean +ar_emul_append (after_bfd, file_name, verbose) + bfd **after_bfd; + char *file_name; + bfd_boolean verbose; +{ + if (bin_dummy_emulation.ar_append) + return bin_dummy_emulation.ar_append (after_bfd, file_name, verbose); + + return FALSE; +} + +bfd_boolean +ar_emul_default_append (after_bfd, file_name, verbose) + bfd **after_bfd; + char *file_name; + bfd_boolean verbose; +{ + bfd *temp; + + temp = *after_bfd; + *after_bfd = bfd_openr (file_name, NULL); + + AR_EMUL_ELEMENT_CHECK (*after_bfd, file_name); + AR_EMUL_APPEND_PRINT_VERBOSE (verbose, file_name); + + (*after_bfd)->next = temp; + + return TRUE; +} + +bfd_boolean +ar_emul_replace (after_bfd, file_name, verbose) + bfd **after_bfd; + char *file_name; + bfd_boolean verbose; +{ + if (bin_dummy_emulation.ar_replace) + return bin_dummy_emulation.ar_replace (after_bfd, file_name, verbose); + + return FALSE; +} + +bfd_boolean +ar_emul_default_replace (after_bfd, file_name, verbose) + bfd **after_bfd; + char *file_name; + bfd_boolean verbose; +{ + bfd *temp; + + temp = *after_bfd; + *after_bfd = bfd_openr (file_name, NULL); + + AR_EMUL_ELEMENT_CHECK (*after_bfd, file_name); + AR_EMUL_REPLACE_PRINT_VERBOSE (verbose, file_name); + + (*after_bfd)->next = temp; + + return TRUE; +} + +bfd_boolean +ar_emul_create (abfd_out, archive_file_name, file_name) + bfd **abfd_out; + char *archive_file_name; + char *file_name; +{ + if (bin_dummy_emulation.ar_create) + return bin_dummy_emulation.ar_create (abfd_out, archive_file_name, + file_name); + + return FALSE; +} + +bfd_boolean +ar_emul_default_create (abfd_out, archive_file_name, file_name) + bfd **abfd_out; + char *archive_file_name; + char *file_name; +{ + char *target = NULL; + + /* Try to figure out the target to use for the archive from the + first object on the list. */ + if (file_name != NULL) + { + bfd *obj; + + obj = bfd_openr (file_name, NULL); + if (obj != NULL) + { + if (bfd_check_format (obj, bfd_object)) + target = bfd_get_target (obj); + (void) bfd_close (obj); + } + } + + /* Create an empty archive. */ + *abfd_out = bfd_openw (archive_file_name, target); + if (*abfd_out == NULL + || ! bfd_set_format (*abfd_out, bfd_archive) + || ! bfd_close (*abfd_out)) + bfd_fatal (archive_file_name); + + return TRUE; +} + +bfd_boolean +ar_emul_parse_arg (arg) + char *arg; +{ + if (bin_dummy_emulation.ar_parse_arg) + return bin_dummy_emulation.ar_parse_arg (arg); + + return FALSE; +} + +bfd_boolean +ar_emul_default_parse_arg (arg) + char *arg ATTRIBUTE_UNUSED; +{ + return FALSE; +} diff --git a/contrib/binutils-2.14/binutils/binemul.h b/contrib/binutils-2.14/binutils/binemul.h new file mode 100644 index 0000000000..f8afae518b --- /dev/null +++ b/contrib/binutils-2.14/binutils/binemul.h @@ -0,0 +1,74 @@ +/* Binutils emulation layer. + Copyright 2002 Free Software Foundation, Inc. + Written by Tom Rix, Redhat. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef BINEMUL_H +#define BINEMUL_H + +#include "bfd.h" +#include "bucomm.h" + +extern void ar_emul_usage + PARAMS ((FILE *)); +extern void ar_emul_default_usage + PARAMS ((FILE *)); +extern bfd_boolean ar_emul_append + PARAMS ((bfd **, char *, bfd_boolean)); +extern bfd_boolean ar_emul_default_append + PARAMS ((bfd **, char *, bfd_boolean)); +extern bfd_boolean ar_emul_replace + PARAMS ((bfd **, char *, bfd_boolean)); +extern bfd_boolean ar_emul_default_replace + PARAMS ((bfd **, char *, bfd_boolean)); +extern bfd_boolean ar_emul_create + PARAMS ((bfd **, char *, char *)); +extern bfd_boolean ar_emul_default_create + PARAMS ((bfd **, char *, char *)); +extern bfd_boolean ar_emul_parse_arg + PARAMS ((char *)); +extern bfd_boolean ar_emul_default_parse_arg + PARAMS ((char *)); + +/* Macros for common output. */ + +#define AR_EMUL_USAGE_PRINT_OPTION_HEADER(fp) \ + /* xgettext:c-format */ \ + fprintf (fp, _(" emulation options: \n")) + +#define AR_EMUL_ELEMENT_CHECK(abfd, file_name) \ + do { if ((abfd) == (bfd *) NULL) bfd_fatal (file_name); } while (0) + +#define AR_EMUL_APPEND_PRINT_VERBOSE(verbose, file_name) \ + do { if (verbose) printf ("a - %s\n", file_name); } while (0) + +#define AR_EMUL_REPLACE_PRINT_VERBOSE(verbose, file_name) \ + do { if (verbose) printf ("r - %s\n", file_name); } while (0) + +typedef struct bin_emulation_xfer_struct +{ + /* Print out the extra options. */ + void (* ar_usage) PARAMS ((FILE *fp)); + bfd_boolean (* ar_append) PARAMS ((bfd **, char *, bfd_boolean)); + bfd_boolean (* ar_replace) PARAMS ((bfd **, char *, bfd_boolean)); + bfd_boolean (* ar_create) PARAMS ((bfd **, char *, char *)); + bfd_boolean (* ar_parse_arg) PARAMS ((char *)); +} +bin_emulation_xfer_type; + +#endif diff --git a/contrib/binutils-2.14/binutils/bucomm.c b/contrib/binutils-2.14/binutils/bucomm.c new file mode 100644 index 0000000000..237f934fe8 --- /dev/null +++ b/contrib/binutils-2.14/binutils/bucomm.c @@ -0,0 +1,470 @@ +/* bucomm.c -- Bin Utils COMmon code. + Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* We might put this in a library someday so it could be dynamically + loaded, but for now it's not necessary. */ + +#include "bfd.h" +#include "bfdver.h" +#include "libiberty.h" +#include "bucomm.h" +#include "filenames.h" +#include "libbfd.h" + +#include +#include /* ctime, maybe time_t */ + +#ifndef HAVE_TIME_T_IN_TIME_H +#ifndef HAVE_TIME_T_IN_TYPES_H +typedef long time_t; +#endif +#endif + +static const char * endian_string PARAMS ((enum bfd_endian)); +static int display_target_list PARAMS ((void)); +static int display_info_table PARAMS ((int, int)); +static int display_target_tables PARAMS ((void)); + +/* Error reporting. */ + +char *program_name; + +void +bfd_nonfatal (string) + const char *string; +{ + const char *errmsg = bfd_errmsg (bfd_get_error ()); + + if (string) + fprintf (stderr, "%s: %s: %s\n", program_name, string, errmsg); + else + fprintf (stderr, "%s: %s\n", program_name, errmsg); +} + +void +bfd_fatal (string) + const char *string; +{ + bfd_nonfatal (string); + xexit (1); +} + +void +report (format, args) + const char * format; + va_list args; +{ + fprintf (stderr, "%s: ", program_name); + vfprintf (stderr, format, args); + putc ('\n', stderr); +} + +void +fatal VPARAMS ((const char *format, ...)) +{ + VA_OPEN (args, format); + VA_FIXEDARG (args, const char *, format); + + report (format, args); + VA_CLOSE (args); + xexit (1); +} + +void +non_fatal VPARAMS ((const char *format, ...)) +{ + VA_OPEN (args, format); + VA_FIXEDARG (args, const char *, format); + + report (format, args); + VA_CLOSE (args); +} + +/* Set the default BFD target based on the configured target. Doing + this permits the binutils to be configured for a particular target, + and linked against a shared BFD library which was configured for a + different target. */ + +void +set_default_bfd_target () +{ + /* The macro TARGET is defined by Makefile. */ + const char *target = TARGET; + + if (! bfd_set_default_target (target)) + fatal (_("can't set BFD default target to `%s': %s"), + target, bfd_errmsg (bfd_get_error ())); +} + +/* After a FALSE return from bfd_check_format_matches with + bfd_get_error () == bfd_error_file_ambiguously_recognized, print + the possible matching targets. */ + +void +list_matching_formats (p) + char **p; +{ + fprintf (stderr, _("%s: Matching formats:"), program_name); + while (*p) + fprintf (stderr, " %s", *p++); + fputc ('\n', stderr); +} + +/* List the supported targets. */ + +void +list_supported_targets (name, f) + const char *name; + FILE *f; +{ + int t; + const char **targ_names = bfd_target_list (); + + if (name == NULL) + fprintf (f, _("Supported targets:")); + else + fprintf (f, _("%s: supported targets:"), name); + + for (t = 0; targ_names[t] != NULL; t++) + fprintf (f, " %s", targ_names[t]); + fprintf (f, "\n"); + free (targ_names); +} + +/* List the supported architectures. */ + +void +list_supported_architectures (name, f) + const char *name; + FILE *f; +{ + const char **arch; + + if (name == NULL) + fprintf (f, _("Supported architectures:")); + else + fprintf (f, _("%s: supported architectures:"), name); + + for (arch = bfd_arch_list (); *arch; arch++) + fprintf (f, " %s", *arch); + fprintf (f, "\n"); +} + +/* The length of the longest architecture name + 1. */ +#define LONGEST_ARCH sizeof ("powerpc:common") + +static const char * +endian_string (endian) + enum bfd_endian endian; +{ + switch (endian) + { + case BFD_ENDIAN_BIG: return "big endian"; + case BFD_ENDIAN_LITTLE: return "little endian"; + default: return "endianness unknown"; + } +} + +/* List the targets that BFD is configured to support, each followed + by its endianness and the architectures it supports. */ + +static int +display_target_list () +{ + char *dummy_name; + int t; + int ret = 1; + + dummy_name = make_temp_file (NULL); + for (t = 0; bfd_target_vector[t]; t++) + { + const bfd_target *p = bfd_target_vector[t]; + bfd *abfd = bfd_openw (dummy_name, p->name); + int a; + + printf ("%s\n (header %s, data %s)\n", p->name, + endian_string (p->header_byteorder), + endian_string (p->byteorder)); + + if (abfd == NULL) + { + bfd_nonfatal (dummy_name); + ret = 0; + continue; + } + + if (! bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + { + bfd_nonfatal (p->name); + ret = 0; + } + bfd_close_all_done (abfd); + continue; + } + + for (a = (int) bfd_arch_obscure + 1; a < (int) bfd_arch_last; a++) + if (bfd_set_arch_mach (abfd, (enum bfd_architecture) a, 0)) + printf (" %s\n", + bfd_printable_arch_mach ((enum bfd_architecture) a, 0)); + bfd_close_all_done (abfd); + } + unlink (dummy_name); + free (dummy_name); + + return ret; +} + +/* Print a table showing which architectures are supported for entries + FIRST through LAST-1 of bfd_target_vector (targets across, + architectures down). */ + +static int +display_info_table (first, last) + int first; + int last; +{ + int t; + int a; + int ret = 1; + char *dummy_name; + + /* Print heading of target names. */ + printf ("\n%*s", (int) LONGEST_ARCH, " "); + for (t = first; t < last && bfd_target_vector[t]; t++) + printf ("%s ", bfd_target_vector[t]->name); + putchar ('\n'); + + dummy_name = make_temp_file (NULL); + for (a = (int) bfd_arch_obscure + 1; a < (int) bfd_arch_last; a++) + if (strcmp (bfd_printable_arch_mach (a, 0), "UNKNOWN!") != 0) + { + printf ("%*s ", (int) LONGEST_ARCH - 1, + bfd_printable_arch_mach (a, 0)); + for (t = first; t < last && bfd_target_vector[t]; t++) + { + const bfd_target *p = bfd_target_vector[t]; + bfd_boolean ok = TRUE; + bfd *abfd = bfd_openw (dummy_name, p->name); + + if (abfd == NULL) + { + bfd_nonfatal (p->name); + ret = 0; + ok = FALSE; + } + + if (ok) + { + if (! bfd_set_format (abfd, bfd_object)) + { + if (bfd_get_error () != bfd_error_invalid_operation) + { + bfd_nonfatal (p->name); + ret = 0; + } + ok = FALSE; + } + } + + if (ok) + { + if (! bfd_set_arch_mach (abfd, a, 0)) + ok = FALSE; + } + + if (ok) + printf ("%s ", p->name); + else + { + int l = strlen (p->name); + while (l--) + putchar ('-'); + putchar (' '); + } + if (abfd != NULL) + bfd_close_all_done (abfd); + } + putchar ('\n'); + } + unlink (dummy_name); + free (dummy_name); + + return ret; +} + +/* Print tables of all the target-architecture combinations that + BFD has been configured to support. */ + +static int +display_target_tables () +{ + int t; + int columns; + int ret = 1; + char *colum; + + columns = 0; + colum = getenv ("COLUMNS"); + if (colum != NULL) + columns = atoi (colum); + if (columns == 0) + columns = 80; + + t = 0; + while (bfd_target_vector[t] != NULL) + { + int oldt = t, wid; + + wid = LONGEST_ARCH + strlen (bfd_target_vector[t]->name) + 1; + ++t; + while (wid < columns && bfd_target_vector[t] != NULL) + { + int newwid; + + newwid = wid + strlen (bfd_target_vector[t]->name) + 1; + if (newwid >= columns) + break; + wid = newwid; + ++t; + } + if (! display_info_table (oldt, t)) + ret = 0; + } + + return ret; +} + +int +display_info () +{ + printf (_("BFD header file version %s\n"), BFD_VERSION_STRING); + if (! display_target_list () || ! display_target_tables ()) + return 1; + else + return 0; +} + +/* Display the archive header for an element as if it were an ls -l listing: + + Mode User\tGroup\tSize\tDate Name */ + +void +print_arelt_descr (file, abfd, verbose) + FILE *file; + bfd *abfd; + bfd_boolean verbose; +{ + struct stat buf; + + if (verbose) + { + if (bfd_stat_arch_elt (abfd, &buf) == 0) + { + char modebuf[11]; + char timebuf[40]; + time_t when = buf.st_mtime; + const char *ctime_result = (const char *) ctime (&when); + + /* POSIX format: skip weekday and seconds from ctime output. */ + sprintf (timebuf, "%.12s %.4s", ctime_result + 4, ctime_result + 20); + + mode_string (buf.st_mode, modebuf); + modebuf[10] = '\0'; + /* POSIX 1003.2/D11 says to skip first character (entry type). */ + fprintf (file, "%s %ld/%ld %6ld %s ", modebuf + 1, + (long) buf.st_uid, (long) buf.st_gid, + (long) buf.st_size, timebuf); + } + } + + fprintf (file, "%s\n", bfd_get_filename (abfd)); +} + +/* Return the name of a temporary file in the same directory as FILENAME. */ + +char * +make_tempname (filename) + char *filename; +{ + static char template[] = "stXXXXXX"; + char *tmpname; + char *slash = strrchr (filename, '/'); + +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + { + /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */ + char *bslash = strrchr (filename, '\\'); + if (slash == NULL || (bslash != NULL && bslash > slash)) + slash = bslash; + if (slash == NULL && filename[0] != '\0' && filename[1] == ':') + slash = filename + 1; + } +#endif + + if (slash != (char *) NULL) + { + char c; + + c = *slash; + *slash = 0; + tmpname = xmalloc (strlen (filename) + sizeof (template) + 2); + strcpy (tmpname, filename); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + /* If tmpname is "X:", appending a slash will make it a root + directory on drive X, which is NOT the same as the current + directory on drive X. */ + if (tmpname[1] == ':' && tmpname[2] == '\0') + strcat (tmpname, "."); +#endif + strcat (tmpname, "/"); + strcat (tmpname, template); + mktemp (tmpname); + *slash = c; + } + else + { + tmpname = xmalloc (sizeof (template)); + strcpy (tmpname, template); + mktemp (tmpname); + } + return tmpname; +} + +/* Parse a string into a VMA, with a fatal error if it can't be + parsed. */ + +bfd_vma +parse_vma (s, arg) + const char *s; + const char *arg; +{ + bfd_vma ret; + const char *end; + + ret = bfd_scan_vma (s, &end, 0); + + if (*end != '\0') + fatal (_("%s: bad number: %s"), arg, s); + + return ret; +} diff --git a/contrib/binutils-2.14/binutils/bucomm.h b/contrib/binutils-2.14/binutils/bucomm.h new file mode 100644 index 0000000000..2598d13386 --- /dev/null +++ b/contrib/binutils-2.14/binutils/bucomm.h @@ -0,0 +1,214 @@ +/* bucomm.h -- binutils common include file. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2002, 2003 Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _BUCOMM_H +#define _BUCOMM_H + +#include "ansidecl.h" +#include +#include + +#include "config.h" +#include "bin-bugs.h" + +#ifdef ANSI_PROTOTYPES +#include +#else +#include +#endif + +#ifdef USE_BINARY_FOPEN +#include "fopen-bin.h" +#else +#include "fopen-same.h" +#endif + +#include +#ifndef errno +extern int errno; +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#else +extern char *strchr (); +extern char *strrchr (); +#endif +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#else +#ifdef HAVE_SYS_FILE_H +#include +#endif +#endif + +#ifdef NEED_DECLARATION_STRSTR +extern char *strstr (); +#endif + +#ifdef HAVE_SBRK +#ifdef NEED_DECLARATION_SBRK +extern char *sbrk (); +#endif +#endif + +#ifdef NEED_DECLARATION_GETENV +extern char *getenv (); +#endif + +#ifdef NEED_DECLARATION_ENVIRON +extern char **environ; +#endif + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif + +#ifndef O_RDWR +#define O_RDWR 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#if defined(__GNUC__) && !defined(C_ALLOCA) +# undef alloca +# define alloca __builtin_alloca +#else +# if defined(HAVE_ALLOCA_H) && !defined(C_ALLOCA) +# include +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +# if !defined (__STDC__) && !defined (__hpux) +char *alloca (); +# else +void *alloca (); +# endif /* __STDC__, __hpux */ +# endif /* alloca */ +# endif /* HAVE_ALLOCA_H */ +#endif + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef ENABLE_NLS +# include +# define _(String) gettext (String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define textdomain(Domainname) while (0) /* nothing */ +# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */ +# define _(String) (String) +# define N_(String) (String) +#endif + +/* bucomm.c */ +void bfd_nonfatal + PARAMS ((const char *)); + +void bfd_fatal + PARAMS ((const char *)) ATTRIBUTE_NORETURN; + +void report + PARAMS ((const char *, va_list)); + +void fatal + PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN; + +void non_fatal + PARAMS ((const char *, ...)) ATTRIBUTE_PRINTF_1; + +void set_default_bfd_target + PARAMS ((void)); + +void list_matching_formats + PARAMS ((char **)); + +void list_supported_targets + PARAMS ((const char *, FILE *)); + +void list_supported_architectures + PARAMS ((const char *, FILE *)); + +int display_info + PARAMS ((void)); + +void print_arelt_descr + PARAMS ((FILE *, bfd *, bfd_boolean)); + +char *make_tempname + PARAMS ((char *)); + +bfd_vma parse_vma + PARAMS ((const char *, const char *)); + +extern char *program_name; + +/* filemode.c */ +void mode_string + PARAMS ((unsigned long, char *)); + +/* version.c */ +extern void print_version + PARAMS ((const char *)); + +/* rename.c */ +extern void set_times + PARAMS ((const char *, const struct stat *)); + +extern int smart_rename + PARAMS ((const char *, const char *, int)); + +/* libiberty. */ +PTR xmalloc + PARAMS ((size_t)); + +PTR xrealloc + PARAMS ((PTR, size_t)); + +#endif /* _BUCOMM_H */ diff --git a/contrib/binutils-2.14/binutils/budbg.h b/contrib/binutils-2.14/binutils/budbg.h new file mode 100644 index 0000000000..dc68703890 --- /dev/null +++ b/contrib/binutils-2.14/binutils/budbg.h @@ -0,0 +1,65 @@ +/* budbg.c -- Interfaces to the generic debugging information routines. + Copyright 1995, 1996, 2002 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef BUDBG_H +#define BUDBG_H + +#include + +/* Routine used to read generic debugging information. */ + +extern PTR read_debugging_info + PARAMS ((bfd *, asymbol **, long)); + +/* Routine used to print generic debugging information. */ + +extern bfd_boolean print_debugging_info + PARAMS ((FILE *, PTR)); + +/* Routines used to read and write stabs information. */ + +extern PTR start_stab + PARAMS ((PTR, bfd *, bfd_boolean, asymbol **, long)); + +extern bfd_boolean finish_stab + PARAMS ((PTR, PTR)); + +extern bfd_boolean parse_stab + PARAMS ((PTR, PTR, int, int, bfd_vma, const char *)); + +extern bfd_boolean write_stabs_in_sections_debugging_info + PARAMS ((bfd *, PTR, bfd_byte **, bfd_size_type *, bfd_byte **, + bfd_size_type *)); + +/* Routines used to read and write IEEE debugging information. */ + +extern bfd_boolean parse_ieee + PARAMS ((PTR, bfd *, const bfd_byte *, bfd_size_type)); + +extern bfd_boolean write_ieee_debugging_info + PARAMS ((bfd *, PTR)); + +/* Routine used to read COFF debugging information. */ + +extern bfd_boolean parse_coff + PARAMS ((bfd *, asymbol **, long, PTR)); + +#endif diff --git a/contrib/binutils-2.14/binutils/budemang.c b/contrib/binutils-2.14/binutils/budemang.c new file mode 100644 index 0000000000..3f8d385c5e --- /dev/null +++ b/contrib/binutils-2.14/binutils/budemang.c @@ -0,0 +1,77 @@ +/* demangle.c -- A wrapper calling libiberty cplus_demangle + Copyright 2002 Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "config.h" +#include +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif +#include "bfd.h" +#include "libiberty.h" +#include "demangle.h" +#include "budemang.h" + +/* Wrapper around cplus_demangle. Strips leading underscores and + other such chars that would otherwise confuse the demangler. */ + +char * +demangle (abfd, name) + bfd *abfd; + const char *name; +{ + char *res; + const char *p; + + if (abfd != NULL && bfd_get_symbol_leading_char (abfd) == name[0]) + ++name; + + /* This is a hack for better error reporting on XCOFF, PowerPC64-ELF + or the MS PE format. These formats have a number of leading '.'s + on at least some symbols, so we remove all dots to avoid + confusing the demangler. */ + p = name; + while (*p == '.') + ++p; + + res = cplus_demangle (p, DMGL_ANSI | DMGL_PARAMS); + if (res) + { + size_t dots = p - name; + + /* Now put back any stripped dots. */ + if (dots != 0) + { + size_t len = strlen (res) + 1; + char *add_dots = xmalloc (len + dots); + + memcpy (add_dots, name, dots); + memcpy (add_dots + dots, res, len); + free (res); + res = add_dots; + } + return res; + } + + return xstrdup (name); +} diff --git a/contrib/binutils-2.14/binutils/budemang.h b/contrib/binutils-2.14/binutils/budemang.h new file mode 100644 index 0000000000..60a3c2d733 --- /dev/null +++ b/contrib/binutils-2.14/binutils/budemang.h @@ -0,0 +1,25 @@ +/* demangle.h -- A wrapper calling libiberty cplus_demangle + Copyright 2002 Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ +#ifndef BUDEMANG_H +#define BUDEMANG_H + +char *demangle PARAMS ((bfd *, const char *)); + +#endif diff --git a/contrib/binutils-2.14/binutils/debug.c b/contrib/binutils-2.14/binutils/debug.c new file mode 100644 index 0000000000..3d7d48e2bb --- /dev/null +++ b/contrib/binutils-2.14/binutils/debug.c @@ -0,0 +1,3555 @@ +/* debug.c -- Handle generic debugging information. + Copyright 1995, 1996, 1997, 1998, 2000, 2002, 2003 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file implements a generic debugging format. We may eventually + have readers which convert different formats into this generic + format, and writers which write it out. The initial impetus for + this was writing a convertor from stabs to HP IEEE-695 debugging + format. */ + +#include +#include + +#include "bfd.h" +#include "bucomm.h" +#include "libiberty.h" +#include "debug.h" + +/* Global information we keep for debugging. A pointer to this + structure is the debugging handle passed to all the routines. */ + +struct debug_handle +{ + /* A linked list of compilation units. */ + struct debug_unit *units; + /* The current compilation unit. */ + struct debug_unit *current_unit; + /* The current source file. */ + struct debug_file *current_file; + /* The current function. */ + struct debug_function *current_function; + /* The current block. */ + struct debug_block *current_block; + /* The current line number information for the current unit. */ + struct debug_lineno *current_lineno; + /* Mark. This is used by debug_write. */ + unsigned int mark; + /* A struct/class ID used by debug_write. */ + unsigned int class_id; + /* The base for class_id for this call to debug_write. */ + unsigned int base_id; + /* The current line number in debug_write. */ + struct debug_lineno *current_write_lineno; + unsigned int current_write_lineno_index; + /* A list of classes which have assigned ID's during debug_write. + This is linked through the next_id field of debug_class_type. */ + struct debug_class_id *id_list; + /* A list used to avoid recursion during debug_type_samep. */ + struct debug_type_compare_list *compare_list; +}; + +/* Information we keep for a single compilation unit. */ + +struct debug_unit +{ + /* The next compilation unit. */ + struct debug_unit *next; + /* A list of files included in this compilation unit. The first + file is always the main one, and that is where the main file name + is stored. */ + struct debug_file *files; + /* Line number information for this compilation unit. This is not + stored by function, because assembler code may have line number + information without function information. */ + struct debug_lineno *linenos; +}; + +/* Information kept for a single source file. */ + +struct debug_file +{ + /* The next source file in this compilation unit. */ + struct debug_file *next; + /* The name of the source file. */ + const char *filename; + /* Global functions, variables, types, etc. */ + struct debug_namespace *globals; +}; + +/* A type. */ + +struct debug_type +{ + /* Kind of type. */ + enum debug_type_kind kind; + /* Size of type (0 if not known). */ + unsigned int size; + /* Type which is a pointer to this type. */ + debug_type pointer; + /* Tagged union with additional information about the type. */ + union + { + /* DEBUG_KIND_INDIRECT. */ + struct debug_indirect_type *kindirect; + /* DEBUG_KIND_INT. */ + /* Whether the integer is unsigned. */ + bfd_boolean kint; + /* DEBUG_KIND_STRUCT, DEBUG_KIND_UNION, DEBUG_KIND_CLASS, + DEBUG_KIND_UNION_CLASS. */ + struct debug_class_type *kclass; + /* DEBUG_KIND_ENUM. */ + struct debug_enum_type *kenum; + /* DEBUG_KIND_POINTER. */ + struct debug_type *kpointer; + /* DEBUG_KIND_FUNCTION. */ + struct debug_function_type *kfunction; + /* DEBUG_KIND_REFERENCE. */ + struct debug_type *kreference; + /* DEBUG_KIND_RANGE. */ + struct debug_range_type *krange; + /* DEBUG_KIND_ARRAY. */ + struct debug_array_type *karray; + /* DEBUG_KIND_SET. */ + struct debug_set_type *kset; + /* DEBUG_KIND_OFFSET. */ + struct debug_offset_type *koffset; + /* DEBUG_KIND_METHOD. */ + struct debug_method_type *kmethod; + /* DEBUG_KIND_CONST. */ + struct debug_type *kconst; + /* DEBUG_KIND_VOLATILE. */ + struct debug_type *kvolatile; + /* DEBUG_KIND_NAMED, DEBUG_KIND_TAGGED. */ + struct debug_named_type *knamed; + } u; +}; + +/* Information kept for an indirect type. */ + +struct debug_indirect_type +{ + /* Slot where the final type will appear. */ + debug_type *slot; + /* Tag. */ + const char *tag; +}; + +/* Information kept for a struct, union, or class. */ + +struct debug_class_type +{ + /* NULL terminated array of fields. */ + debug_field *fields; + /* A mark field which indicates whether the struct has already been + printed. */ + unsigned int mark; + /* This is used to uniquely identify unnamed structs when printing. */ + unsigned int id; + /* The remaining fields are only used for DEBUG_KIND_CLASS and + DEBUG_KIND_UNION_CLASS. */ + /* NULL terminated array of base classes. */ + debug_baseclass *baseclasses; + /* NULL terminated array of methods. */ + debug_method *methods; + /* The type of the class providing the virtual function table for + this class. This may point to the type itself. */ + debug_type vptrbase; +}; + +/* Information kept for an enum. */ + +struct debug_enum_type +{ + /* NULL terminated array of names. */ + const char **names; + /* Array of corresponding values. */ + bfd_signed_vma *values; +}; + +/* Information kept for a function. FIXME: We should be able to + record the parameter types. */ + +struct debug_function_type +{ + /* Return type. */ + debug_type return_type; + /* NULL terminated array of argument types. */ + debug_type *arg_types; + /* Whether the function takes a variable number of arguments. */ + bfd_boolean varargs; +}; + +/* Information kept for a range. */ + +struct debug_range_type +{ + /* Range base type. */ + debug_type type; + /* Lower bound. */ + bfd_signed_vma lower; + /* Upper bound. */ + bfd_signed_vma upper; +}; + +/* Information kept for an array. */ + +struct debug_array_type +{ + /* Element type. */ + debug_type element_type; + /* Range type. */ + debug_type range_type; + /* Lower bound. */ + bfd_signed_vma lower; + /* Upper bound. */ + bfd_signed_vma upper; + /* Whether this array is really a string. */ + bfd_boolean stringp; +}; + +/* Information kept for a set. */ + +struct debug_set_type +{ + /* Base type. */ + debug_type type; + /* Whether this set is really a bitstring. */ + bfd_boolean bitstringp; +}; + +/* Information kept for an offset type (a based pointer). */ + +struct debug_offset_type +{ + /* The type the pointer is an offset from. */ + debug_type base_type; + /* The type the pointer points to. */ + debug_type target_type; +}; + +/* Information kept for a method type. */ + +struct debug_method_type +{ + /* The return type. */ + debug_type return_type; + /* The object type which this method is for. */ + debug_type domain_type; + /* A NULL terminated array of argument types. */ + debug_type *arg_types; + /* Whether the method takes a variable number of arguments. */ + bfd_boolean varargs; +}; + +/* Information kept for a named type. */ + +struct debug_named_type +{ + /* Name. */ + struct debug_name *name; + /* Real type. */ + debug_type type; +}; + +/* A field in a struct or union. */ + +struct debug_field +{ + /* Name of the field. */ + const char *name; + /* Type of the field. */ + struct debug_type *type; + /* Visibility of the field. */ + enum debug_visibility visibility; + /* Whether this is a static member. */ + bfd_boolean static_member; + union + { + /* If static_member is false. */ + struct + { + /* Bit position of the field in the struct. */ + unsigned int bitpos; + /* Size of the field in bits. */ + unsigned int bitsize; + } f; + /* If static_member is true. */ + struct + { + const char *physname; + } s; + } u; +}; + +/* A base class for an object. */ + +struct debug_baseclass +{ + /* Type of the base class. */ + struct debug_type *type; + /* Bit position of the base class in the object. */ + unsigned int bitpos; + /* Whether the base class is virtual. */ + bfd_boolean virtual; + /* Visibility of the base class. */ + enum debug_visibility visibility; +}; + +/* A method of an object. */ + +struct debug_method +{ + /* The name of the method. */ + const char *name; + /* A NULL terminated array of different types of variants. */ + struct debug_method_variant **variants; +}; + +/* The variants of a method function of an object. These indicate + which method to run. */ + +struct debug_method_variant +{ + /* The physical name of the function. */ + const char *physname; + /* The type of the function. */ + struct debug_type *type; + /* The visibility of the function. */ + enum debug_visibility visibility; + /* Whether the function is const. */ + bfd_boolean constp; + /* Whether the function is volatile. */ + bfd_boolean volatilep; + /* The offset to the function in the virtual function table. */ + bfd_vma voffset; + /* If voffset is VOFFSET_STATIC_METHOD, this is a static method. */ +#define VOFFSET_STATIC_METHOD ((bfd_vma) -1) + /* Context of a virtual method function. */ + struct debug_type *context; +}; + +/* A variable. This is the information we keep for a variable object. + This has no name; a name is associated with a variable in a + debug_name structure. */ + +struct debug_variable +{ + /* Kind of variable. */ + enum debug_var_kind kind; + /* Type. */ + debug_type type; + /* Value. The interpretation of the value depends upon kind. */ + bfd_vma val; +}; + +/* A function. This has no name; a name is associated with a function + in a debug_name structure. */ + +struct debug_function +{ + /* Return type. */ + debug_type return_type; + /* Parameter information. */ + struct debug_parameter *parameters; + /* Block information. The first structure on the list is the main + block of the function, and describes function local variables. */ + struct debug_block *blocks; +}; + +/* A function parameter. */ + +struct debug_parameter +{ + /* Next parameter. */ + struct debug_parameter *next; + /* Name. */ + const char *name; + /* Type. */ + debug_type type; + /* Kind. */ + enum debug_parm_kind kind; + /* Value (meaning depends upon kind). */ + bfd_vma val; +}; + +/* A typed constant. */ + +struct debug_typed_constant +{ + /* Type. */ + debug_type type; + /* Value. FIXME: We may eventually need to support non-integral + values. */ + bfd_vma val; +}; + +/* Information about a block within a function. */ + +struct debug_block +{ + /* Next block with the same parent. */ + struct debug_block *next; + /* Parent block. */ + struct debug_block *parent; + /* List of child blocks. */ + struct debug_block *children; + /* Start address of the block. */ + bfd_vma start; + /* End address of the block. */ + bfd_vma end; + /* Local variables. */ + struct debug_namespace *locals; +}; + +/* Line number information we keep for a compilation unit. FIXME: + This structure is easy to create, but can be very space + inefficient. */ + +struct debug_lineno +{ + /* More line number information for this block. */ + struct debug_lineno *next; + /* Source file. */ + struct debug_file *file; + /* Line numbers, terminated by a -1 or the end of the array. */ +#define DEBUG_LINENO_COUNT 10 + unsigned long linenos[DEBUG_LINENO_COUNT]; + /* Addresses for the line numbers. */ + bfd_vma addrs[DEBUG_LINENO_COUNT]; +}; + +/* A namespace. This is a mapping from names to objects. FIXME: This + should be implemented as a hash table. */ + +struct debug_namespace +{ + /* List of items in this namespace. */ + struct debug_name *list; + /* Pointer to where the next item in this namespace should go. */ + struct debug_name **tail; +}; + +/* Kinds of objects that appear in a namespace. */ + +enum debug_object_kind +{ + /* A type. */ + DEBUG_OBJECT_TYPE, + /* A tagged type (really a different sort of namespace). */ + DEBUG_OBJECT_TAG, + /* A variable. */ + DEBUG_OBJECT_VARIABLE, + /* A function. */ + DEBUG_OBJECT_FUNCTION, + /* An integer constant. */ + DEBUG_OBJECT_INT_CONSTANT, + /* A floating point constant. */ + DEBUG_OBJECT_FLOAT_CONSTANT, + /* A typed constant. */ + DEBUG_OBJECT_TYPED_CONSTANT +}; + +/* Linkage of an object that appears in a namespace. */ + +enum debug_object_linkage +{ + /* Local variable. */ + DEBUG_LINKAGE_AUTOMATIC, + /* Static--either file static or function static, depending upon the + namespace is. */ + DEBUG_LINKAGE_STATIC, + /* Global. */ + DEBUG_LINKAGE_GLOBAL, + /* No linkage. */ + DEBUG_LINKAGE_NONE +}; + +/* A name in a namespace. */ + +struct debug_name +{ + /* Next name in this namespace. */ + struct debug_name *next; + /* Name. */ + const char *name; + /* Mark. This is used by debug_write. */ + unsigned int mark; + /* Kind of object. */ + enum debug_object_kind kind; + /* Linkage of object. */ + enum debug_object_linkage linkage; + /* Tagged union with additional information about the object. */ + union + { + /* DEBUG_OBJECT_TYPE. */ + struct debug_type *type; + /* DEBUG_OBJECT_TAG. */ + struct debug_type *tag; + /* DEBUG_OBJECT_VARIABLE. */ + struct debug_variable *variable; + /* DEBUG_OBJECT_FUNCTION. */ + struct debug_function *function; + /* DEBUG_OBJECT_INT_CONSTANT. */ + bfd_vma int_constant; + /* DEBUG_OBJECT_FLOAT_CONSTANT. */ + double float_constant; + /* DEBUG_OBJECT_TYPED_CONSTANT. */ + struct debug_typed_constant *typed_constant; + } u; +}; + +/* During debug_write, a linked list of these structures is used to + keep track of ID numbers that have been assigned to classes. */ + +struct debug_class_id +{ + /* Next ID number. */ + struct debug_class_id *next; + /* The type with the ID. */ + struct debug_type *type; + /* The tag; NULL if no tag. */ + const char *tag; +}; + +/* During debug_type_samep, a linked list of these structures is kept + on the stack to avoid infinite recursion. */ + +struct debug_type_compare_list +{ + /* Next type on list. */ + struct debug_type_compare_list *next; + /* The types we are comparing. */ + struct debug_type *t1; + struct debug_type *t2; +}; + +/* During debug_get_real_type, a linked list of these structures is + kept on the stack to avoid infinite recursion. */ + +struct debug_type_real_list +{ + /* Next type on list. */ + struct debug_type_real_list *next; + /* The type we are checking. */ + struct debug_type *t; +}; + +/* Local functions. */ + +static void debug_error + PARAMS ((const char *)); +static struct debug_name *debug_add_to_namespace + PARAMS ((struct debug_handle *, struct debug_namespace **, const char *, + enum debug_object_kind, enum debug_object_linkage)); +static struct debug_name *debug_add_to_current_namespace + PARAMS ((struct debug_handle *, const char *, enum debug_object_kind, + enum debug_object_linkage)); +static struct debug_type *debug_make_type + PARAMS ((struct debug_handle *, enum debug_type_kind, unsigned int)); +static struct debug_type *debug_get_real_type + PARAMS ((PTR, debug_type, struct debug_type_real_list *)); +static bfd_boolean debug_write_name + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + struct debug_name *)); +static bfd_boolean debug_write_type + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + struct debug_type *, struct debug_name *)); +static bfd_boolean debug_write_class_type + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + struct debug_type *, const char *)); +static bfd_boolean debug_write_function + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + const char *, enum debug_object_linkage, struct debug_function *)); +static bfd_boolean debug_write_block + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + struct debug_block *)); +static bfd_boolean debug_write_linenos + PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR, + bfd_vma)); +static bfd_boolean debug_set_class_id + PARAMS ((struct debug_handle *, const char *, struct debug_type *)); +static bfd_boolean debug_type_samep + PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *)); +static bfd_boolean debug_class_type_samep + PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *)); + +/* Issue an error message. */ + +static void +debug_error (message) + const char *message; +{ + fprintf (stderr, "%s\n", message); +} + +/* Add an object to a namespace. */ + +static struct debug_name * +debug_add_to_namespace (info, nsp, name, kind, linkage) + struct debug_handle *info ATTRIBUTE_UNUSED; + struct debug_namespace **nsp; + const char *name; + enum debug_object_kind kind; + enum debug_object_linkage linkage; +{ + struct debug_name *n; + struct debug_namespace *ns; + + n = (struct debug_name *) xmalloc (sizeof *n); + memset (n, 0, sizeof *n); + + n->name = name; + n->kind = kind; + n->linkage = linkage; + + ns = *nsp; + if (ns == NULL) + { + ns = (struct debug_namespace *) xmalloc (sizeof *ns); + memset (ns, 0, sizeof *ns); + + ns->tail = &ns->list; + + *nsp = ns; + } + + *ns->tail = n; + ns->tail = &n->next; + + return n; +} + +/* Add an object to the current namespace. */ + +static struct debug_name * +debug_add_to_current_namespace (info, name, kind, linkage) + struct debug_handle *info; + const char *name; + enum debug_object_kind kind; + enum debug_object_linkage linkage; +{ + struct debug_namespace **nsp; + + if (info->current_unit == NULL + || info->current_file == NULL) + { + debug_error (_("debug_add_to_current_namespace: no current file")); + return NULL; + } + + if (info->current_block != NULL) + nsp = &info->current_block->locals; + else + nsp = &info->current_file->globals; + + return debug_add_to_namespace (info, nsp, name, kind, linkage); +} + +/* Return a handle for debugging information. */ + +PTR +debug_init () +{ + struct debug_handle *ret; + + ret = (struct debug_handle *) xmalloc (sizeof *ret); + memset (ret, 0, sizeof *ret); + return (PTR) ret; +} + +/* Set the source filename. This implicitly starts a new compilation + unit. */ + +bfd_boolean +debug_set_filename (handle, name) + PTR handle; + const char *name; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_file *nfile; + struct debug_unit *nunit; + + if (name == NULL) + name = ""; + + nfile = (struct debug_file *) xmalloc (sizeof *nfile); + memset (nfile, 0, sizeof *nfile); + + nfile->filename = name; + + nunit = (struct debug_unit *) xmalloc (sizeof *nunit); + memset (nunit, 0, sizeof *nunit); + + nunit->files = nfile; + info->current_file = nfile; + + if (info->current_unit != NULL) + info->current_unit->next = nunit; + else + { + assert (info->units == NULL); + info->units = nunit; + } + + info->current_unit = nunit; + + info->current_function = NULL; + info->current_block = NULL; + info->current_lineno = NULL; + + return TRUE; +} + +/* Change source files to the given file name. This is used for + include files in a single compilation unit. */ + +bfd_boolean +debug_start_source (handle, name) + PTR handle; + const char *name; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_file *f, **pf; + + if (name == NULL) + name = ""; + + if (info->current_unit == NULL) + { + debug_error (_("debug_start_source: no debug_set_filename call")); + return FALSE; + } + + for (f = info->current_unit->files; f != NULL; f = f->next) + { + if (f->filename[0] == name[0] + && f->filename[1] == name[1] + && strcmp (f->filename, name) == 0) + { + info->current_file = f; + return TRUE; + } + } + + f = (struct debug_file *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->filename = name; + + for (pf = &info->current_file->next; + *pf != NULL; + pf = &(*pf)->next) + ; + *pf = f; + + info->current_file = f; + + return TRUE; +} + +/* Record a function definition. This implicitly starts a function + block. The debug_type argument is the type of the return value. + The boolean indicates whether the function is globally visible. + The bfd_vma is the address of the start of the function. Currently + the parameter types are specified by calls to + debug_record_parameter. FIXME: There is no way to specify nested + functions. */ + +bfd_boolean +debug_record_function (handle, name, return_type, global, addr) + PTR handle; + const char *name; + debug_type return_type; + bfd_boolean global; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_function *f; + struct debug_block *b; + struct debug_name *n; + + if (name == NULL) + name = ""; + if (return_type == NULL) + return FALSE; + + if (info->current_unit == NULL) + { + debug_error (_("debug_record_function: no debug_set_filename call")); + return FALSE; + } + + f = (struct debug_function *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->return_type = return_type; + + b = (struct debug_block *) xmalloc (sizeof *b); + memset (b, 0, sizeof *b); + + b->start = addr; + b->end = (bfd_vma) -1; + + f->blocks = b; + + info->current_function = f; + info->current_block = b; + + /* FIXME: If we could handle nested functions, this would be the + place: we would want to use a different namespace. */ + n = debug_add_to_namespace (info, + &info->current_file->globals, + name, + DEBUG_OBJECT_FUNCTION, + (global + ? DEBUG_LINKAGE_GLOBAL + : DEBUG_LINKAGE_STATIC)); + if (n == NULL) + return FALSE; + + n->u.function = f; + + return TRUE; +} + +/* Record a parameter for the current function. */ + +bfd_boolean +debug_record_parameter (handle, name, type, kind, val) + PTR handle; + const char *name; + debug_type type; + enum debug_parm_kind kind; + bfd_vma val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_parameter *p, **pp; + + if (name == NULL || type == NULL) + return FALSE; + + if (info->current_unit == NULL + || info->current_function == NULL) + { + debug_error (_("debug_record_parameter: no current function")); + return FALSE; + } + + p = (struct debug_parameter *) xmalloc (sizeof *p); + memset (p, 0, sizeof *p); + + p->name = name; + p->type = type; + p->kind = kind; + p->val = val; + + for (pp = &info->current_function->parameters; + *pp != NULL; + pp = &(*pp)->next) + ; + *pp = p; + + return TRUE; +} + +/* End a function. FIXME: This should handle function nesting. */ + +bfd_boolean +debug_end_function (handle, addr) + PTR handle; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + if (info->current_unit == NULL + || info->current_block == NULL + || info->current_function == NULL) + { + debug_error (_("debug_end_function: no current function")); + return FALSE; + } + + if (info->current_block->parent != NULL) + { + debug_error (_("debug_end_function: some blocks were not closed")); + return FALSE; + } + + info->current_block->end = addr; + + info->current_function = NULL; + info->current_block = NULL; + + return TRUE; +} + +/* Start a block in a function. All local information will be + recorded in this block, until the matching call to debug_end_block. + debug_start_block and debug_end_block may be nested. The bfd_vma + argument is the address at which this block starts. */ + +bfd_boolean +debug_start_block (handle, addr) + PTR handle; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_block *b, **pb; + + /* We must always have a current block: debug_record_function sets + one up. */ + if (info->current_unit == NULL + || info->current_block == NULL) + { + debug_error (_("debug_start_block: no current block")); + return FALSE; + } + + b = (struct debug_block *) xmalloc (sizeof *b); + memset (b, 0, sizeof *b); + + b->parent = info->current_block; + b->start = addr; + b->end = (bfd_vma) -1; + + /* This new block is a child of the current block. */ + for (pb = &info->current_block->children; + *pb != NULL; + pb = &(*pb)->next) + ; + *pb = b; + + info->current_block = b; + + return TRUE; +} + +/* Finish a block in a function. This matches the call to + debug_start_block. The argument is the address at which this block + ends. */ + +bfd_boolean +debug_end_block (handle, addr) + PTR handle; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_block *parent; + + if (info->current_unit == NULL + || info->current_block == NULL) + { + debug_error (_("debug_end_block: no current block")); + return FALSE; + } + + parent = info->current_block->parent; + if (parent == NULL) + { + debug_error (_("debug_end_block: attempt to close top level block")); + return FALSE; + } + + info->current_block->end = addr; + + info->current_block = parent; + + return TRUE; +} + +/* Associate a line number in the current source file and function + with a given address. */ + +bfd_boolean +debug_record_line (handle, lineno, addr) + PTR handle; + unsigned long lineno; + bfd_vma addr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_lineno *l; + unsigned int i; + + if (info->current_unit == NULL) + { + debug_error (_("debug_record_line: no current unit")); + return FALSE; + } + + l = info->current_lineno; + if (l != NULL && l->file == info->current_file) + { + for (i = 0; i < DEBUG_LINENO_COUNT; i++) + { + if (l->linenos[i] == (unsigned long) -1) + { + l->linenos[i] = lineno; + l->addrs[i] = addr; + return TRUE; + } + } + } + + /* If we get here, then either 1) there is no current_lineno + structure, which means this is the first line number in this + compilation unit, 2) the current_lineno structure is for a + different file, or 3) the current_lineno structure is full. + Regardless, we want to allocate a new debug_lineno structure, put + it in the right place, and make it the new current_lineno + structure. */ + + l = (struct debug_lineno *) xmalloc (sizeof *l); + memset (l, 0, sizeof *l); + + l->file = info->current_file; + l->linenos[0] = lineno; + l->addrs[0] = addr; + for (i = 1; i < DEBUG_LINENO_COUNT; i++) + l->linenos[i] = (unsigned long) -1; + + if (info->current_lineno != NULL) + info->current_lineno->next = l; + else + info->current_unit->linenos = l; + + info->current_lineno = l; + + return TRUE; +} + +/* Start a named common block. This is a block of variables that may + move in memory. */ + +bfd_boolean +debug_start_common_block (handle, name) + PTR handle ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; +{ + /* FIXME */ + debug_error (_("debug_start_common_block: not implemented")); + return FALSE; +} + +/* End a named common block. */ + +bfd_boolean +debug_end_common_block (handle, name) + PTR handle ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; +{ + /* FIXME */ + debug_error (_("debug_end_common_block: not implemented")); + return FALSE; +} + +/* Record a named integer constant. */ + +bfd_boolean +debug_record_int_const (handle, name, val) + PTR handle; + const char *name; + bfd_vma val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_name *n; + + if (name == NULL) + return FALSE; + + n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_INT_CONSTANT, + DEBUG_LINKAGE_NONE); + if (n == NULL) + return FALSE; + + n->u.int_constant = val; + + return TRUE; +} + +/* Record a named floating point constant. */ + +bfd_boolean +debug_record_float_const (handle, name, val) + PTR handle; + const char *name; + double val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_name *n; + + if (name == NULL) + return FALSE; + + n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_FLOAT_CONSTANT, + DEBUG_LINKAGE_NONE); + if (n == NULL) + return FALSE; + + n->u.float_constant = val; + + return TRUE; +} + +/* Record a typed constant with an integral value. */ + +bfd_boolean +debug_record_typed_const (handle, name, type, val) + PTR handle; + const char *name; + debug_type type; + bfd_vma val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_name *n; + struct debug_typed_constant *tc; + + if (name == NULL || type == NULL) + return FALSE; + + n = debug_add_to_current_namespace (info, name, DEBUG_OBJECT_TYPED_CONSTANT, + DEBUG_LINKAGE_NONE); + if (n == NULL) + return FALSE; + + tc = (struct debug_typed_constant *) xmalloc (sizeof *tc); + memset (tc, 0, sizeof *tc); + + tc->type = type; + tc->val = val; + + n->u.typed_constant = tc; + + return TRUE; +} + +/* Record a label. */ + +bfd_boolean +debug_record_label (handle, name, type, addr) + PTR handle ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; + debug_type type ATTRIBUTE_UNUSED; + bfd_vma addr ATTRIBUTE_UNUSED; +{ + /* FIXME. */ + debug_error (_("debug_record_label: not implemented")); + return FALSE; +} + +/* Record a variable. */ + +bfd_boolean +debug_record_variable (handle, name, type, kind, val) + PTR handle; + const char *name; + debug_type type; + enum debug_var_kind kind; + bfd_vma val; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_namespace **nsp; + enum debug_object_linkage linkage; + struct debug_name *n; + struct debug_variable *v; + + if (name == NULL || type == NULL) + return FALSE; + + if (info->current_unit == NULL + || info->current_file == NULL) + { + debug_error (_("debug_record_variable: no current file")); + return FALSE; + } + + if (kind == DEBUG_GLOBAL || kind == DEBUG_STATIC) + { + nsp = &info->current_file->globals; + if (kind == DEBUG_GLOBAL) + linkage = DEBUG_LINKAGE_GLOBAL; + else + linkage = DEBUG_LINKAGE_STATIC; + } + else + { + if (info->current_block == NULL) + nsp = &info->current_file->globals; + else + nsp = &info->current_block->locals; + linkage = DEBUG_LINKAGE_AUTOMATIC; + } + + n = debug_add_to_namespace (info, nsp, name, DEBUG_OBJECT_VARIABLE, linkage); + if (n == NULL) + return FALSE; + + v = (struct debug_variable *) xmalloc (sizeof *v); + memset (v, 0, sizeof *v); + + v->kind = kind; + v->type = type; + v->val = val; + + n->u.variable = v; + + return TRUE; +} + +/* Make a type with a given kind and size. */ + +static struct debug_type * +debug_make_type (info, kind, size) + struct debug_handle *info ATTRIBUTE_UNUSED; + enum debug_type_kind kind; + unsigned int size; +{ + struct debug_type *t; + + t = (struct debug_type *) xmalloc (sizeof *t); + memset (t, 0, sizeof *t); + + t->kind = kind; + t->size = size; + + return t; +} + +/* Make an indirect type which may be used as a placeholder for a type + which is referenced before it is defined. */ + +debug_type +debug_make_indirect_type (handle, slot, tag) + PTR handle; + debug_type *slot; + const char *tag; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_indirect_type *i; + + t = debug_make_type (info, DEBUG_KIND_INDIRECT, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + i = (struct debug_indirect_type *) xmalloc (sizeof *i); + memset (i, 0, sizeof *i); + + i->slot = slot; + i->tag = tag; + + t->u.kindirect = i; + + return t; +} + +/* Make a void type. There is only one of these. */ + +debug_type +debug_make_void_type (handle) + PTR handle; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + return debug_make_type (info, DEBUG_KIND_VOID, 0); +} + +/* Make an integer type of a given size. The boolean argument is true + if the integer is unsigned. */ + +debug_type +debug_make_int_type (handle, size, unsignedp) + PTR handle; + unsigned int size; + bfd_boolean unsignedp; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + t = debug_make_type (info, DEBUG_KIND_INT, size); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kint = unsignedp; + + return t; +} + +/* Make a floating point type of a given size. FIXME: On some + platforms, like an Alpha, you probably need to be able to specify + the format. */ + +debug_type +debug_make_float_type (handle, size) + PTR handle; + unsigned int size; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + return debug_make_type (info, DEBUG_KIND_FLOAT, size); +} + +/* Make a boolean type of a given size. */ + +debug_type +debug_make_bool_type (handle, size) + PTR handle; + unsigned int size; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + return debug_make_type (info, DEBUG_KIND_BOOL, size); +} + +/* Make a complex type of a given size. */ + +debug_type +debug_make_complex_type (handle, size) + PTR handle; + unsigned int size; +{ + struct debug_handle *info = (struct debug_handle *) handle; + + return debug_make_type (info, DEBUG_KIND_COMPLEX, size); +} + +/* Make a structure type. The second argument is true for a struct, + false for a union. The third argument is the size of the struct. + The fourth argument is a NULL terminated array of fields. */ + +debug_type +debug_make_struct_type (handle, structp, size, fields) + PTR handle; + bfd_boolean structp; + bfd_vma size; + debug_field *fields; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_class_type *c; + + t = debug_make_type (info, + structp ? DEBUG_KIND_STRUCT : DEBUG_KIND_UNION, + size); + if (t == NULL) + return DEBUG_TYPE_NULL; + + c = (struct debug_class_type *) xmalloc (sizeof *c); + memset (c, 0, sizeof *c); + + c->fields = fields; + + t->u.kclass = c; + + return t; +} + +/* Make an object type. The first three arguments after the handle + are the same as for debug_make_struct_type. The next arguments are + a NULL terminated array of base classes, a NULL terminated array of + methods, the type of the object holding the virtual function table + if it is not this object, and a boolean which is true if this + object has its own virtual function table. */ + +debug_type +debug_make_object_type (handle, structp, size, fields, baseclasses, + methods, vptrbase, ownvptr) + PTR handle; + bfd_boolean structp; + bfd_vma size; + debug_field *fields; + debug_baseclass *baseclasses; + debug_method *methods; + debug_type vptrbase; + bfd_boolean ownvptr; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_class_type *c; + + t = debug_make_type (info, + structp ? DEBUG_KIND_CLASS : DEBUG_KIND_UNION_CLASS, + size); + if (t == NULL) + return DEBUG_TYPE_NULL; + + c = (struct debug_class_type *) xmalloc (sizeof *c); + memset (c, 0, sizeof *c); + + c->fields = fields; + c->baseclasses = baseclasses; + c->methods = methods; + if (ownvptr) + c->vptrbase = t; + else + c->vptrbase = vptrbase; + + t->u.kclass = c; + + return t; +} + +/* Make an enumeration type. The arguments are a null terminated + array of strings, and an array of corresponding values. */ + +debug_type +debug_make_enum_type (handle, names, values) + PTR handle; + const char **names; + bfd_signed_vma *values; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_enum_type *e; + + t = debug_make_type (info, DEBUG_KIND_ENUM, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + e = (struct debug_enum_type *) xmalloc (sizeof *e); + memset (e, 0, sizeof *e); + + e->names = names; + e->values = values; + + t->u.kenum = e; + + return t; +} + +/* Make a pointer to a given type. */ + +debug_type +debug_make_pointer_type (handle, type) + PTR handle; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + if (type->pointer != DEBUG_TYPE_NULL) + return type->pointer; + + t = debug_make_type (info, DEBUG_KIND_POINTER, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kpointer = type; + + type->pointer = t; + + return t; +} + +/* Make a function returning a given type. FIXME: We should be able + to record the parameter types. */ + +debug_type +debug_make_function_type (handle, type, arg_types, varargs) + PTR handle; + debug_type type; + debug_type *arg_types; + bfd_boolean varargs; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_function_type *f; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_FUNCTION, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + f = (struct debug_function_type *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->return_type = type; + f->arg_types = arg_types; + f->varargs = varargs; + + t->u.kfunction = f; + + return t; +} + +/* Make a reference to a given type. */ + +debug_type +debug_make_reference_type (handle, type) + PTR handle; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_REFERENCE, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kreference = type; + + return t; +} + +/* Make a range of a given type from a lower to an upper bound. */ + +debug_type +debug_make_range_type (handle, type, lower, upper) + PTR handle; + debug_type type; + bfd_signed_vma lower; + bfd_signed_vma upper; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_range_type *r; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_RANGE, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + r = (struct debug_range_type *) xmalloc (sizeof *r); + memset (r, 0, sizeof *r); + + r->type = type; + r->lower = lower; + r->upper = upper; + + t->u.krange = r; + + return t; +} + +/* Make an array type. The second argument is the type of an element + of the array. The third argument is the type of a range of the + array. The fourth and fifth argument are the lower and upper + bounds, respectively. The sixth argument is true if this array is + actually a string, as in C. */ + +debug_type +debug_make_array_type (handle, element_type, range_type, lower, upper, + stringp) + PTR handle; + debug_type element_type; + debug_type range_type; + bfd_signed_vma lower; + bfd_signed_vma upper; + bfd_boolean stringp; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_array_type *a; + + if (element_type == NULL || range_type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_ARRAY, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + a = (struct debug_array_type *) xmalloc (sizeof *a); + memset (a, 0, sizeof *a); + + a->element_type = element_type; + a->range_type = range_type; + a->lower = lower; + a->upper = upper; + a->stringp = stringp; + + t->u.karray = a; + + return t; +} + +/* Make a set of a given type. For example, a Pascal set type. The + boolean argument is true if this set is actually a bitstring, as in + CHILL. */ + +debug_type +debug_make_set_type (handle, type, bitstringp) + PTR handle; + debug_type type; + bfd_boolean bitstringp; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_set_type *s; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_SET, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + s = (struct debug_set_type *) xmalloc (sizeof *s); + memset (s, 0, sizeof *s); + + s->type = type; + s->bitstringp = bitstringp; + + t->u.kset = s; + + return t; +} + +/* Make a type for a pointer which is relative to an object. The + second argument is the type of the object to which the pointer is + relative. The third argument is the type that the pointer points + to. */ + +debug_type +debug_make_offset_type (handle, base_type, target_type) + PTR handle; + debug_type base_type; + debug_type target_type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_offset_type *o; + + if (base_type == NULL || target_type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_OFFSET, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + o = (struct debug_offset_type *) xmalloc (sizeof *o); + memset (o, 0, sizeof *o); + + o->base_type = base_type; + o->target_type = target_type; + + t->u.koffset = o; + + return t; +} + +/* Make a type for a method function. The second argument is the + return type, the third argument is the domain, and the fourth + argument is a NULL terminated array of argument types. */ + +debug_type +debug_make_method_type (handle, return_type, domain_type, arg_types, varargs) + PTR handle; + debug_type return_type; + debug_type domain_type; + debug_type *arg_types; + bfd_boolean varargs; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_method_type *m; + + if (return_type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_METHOD, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + m = (struct debug_method_type *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->return_type = return_type; + m->domain_type = domain_type; + m->arg_types = arg_types; + m->varargs = varargs; + + t->u.kmethod = m; + + return t; +} + +/* Make a const qualified version of a given type. */ + +debug_type +debug_make_const_type (handle, type) + PTR handle; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_CONST, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kconst = type; + + return t; +} + +/* Make a volatile qualified version of a given type. */ + +debug_type +debug_make_volatile_type (handle, type) + PTR handle; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (type == NULL) + return DEBUG_TYPE_NULL; + + t = debug_make_type (info, DEBUG_KIND_VOLATILE, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + t->u.kvolatile = type; + + return t; +} + +/* Make an undefined tagged type. For example, a struct which has + been mentioned, but not defined. */ + +debug_type +debug_make_undefined_tagged_type (handle, name, kind) + PTR handle; + const char *name; + enum debug_type_kind kind; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + + if (name == NULL) + return DEBUG_TYPE_NULL; + + switch (kind) + { + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + case DEBUG_KIND_ENUM: + break; + + default: + debug_error (_("debug_make_undefined_type: unsupported kind")); + return DEBUG_TYPE_NULL; + } + + t = debug_make_type (info, kind, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + return debug_tag_type (handle, name, t); +} + +/* Make a base class for an object. The second argument is the base + class type. The third argument is the bit position of this base + class in the object (always 0 unless doing multiple inheritance). + The fourth argument is whether this is a virtual class. The fifth + argument is the visibility of the base class. */ + +debug_baseclass +debug_make_baseclass (handle, type, bitpos, virtual, visibility) + PTR handle ATTRIBUTE_UNUSED; + debug_type type; + bfd_vma bitpos; + bfd_boolean virtual; + enum debug_visibility visibility; +{ + struct debug_baseclass *b; + + b = (struct debug_baseclass *) xmalloc (sizeof *b); + memset (b, 0, sizeof *b); + + b->type = type; + b->bitpos = bitpos; + b->virtual = virtual; + b->visibility = visibility; + + return b; +} + +/* Make a field for a struct. The second argument is the name. The + third argument is the type of the field. The fourth argument is + the bit position of the field. The fifth argument is the size of + the field (it may be zero). The sixth argument is the visibility + of the field. */ + +debug_field +debug_make_field (handle, name, type, bitpos, bitsize, visibility) + PTR handle ATTRIBUTE_UNUSED; + const char *name; + debug_type type; + bfd_vma bitpos; + bfd_vma bitsize; + enum debug_visibility visibility; +{ + struct debug_field *f; + + f = (struct debug_field *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->name = name; + f->type = type; + f->static_member = FALSE; + f->u.f.bitpos = bitpos; + f->u.f.bitsize = bitsize; + f->visibility = visibility; + + return f; +} + +/* Make a static member of an object. The second argument is the + name. The third argument is the type of the member. The fourth + argument is the physical name of the member (i.e., the name as a + global variable). The fifth argument is the visibility of the + member. */ + +debug_field +debug_make_static_member (handle, name, type, physname, visibility) + PTR handle ATTRIBUTE_UNUSED; + const char *name; + debug_type type; + const char *physname; + enum debug_visibility visibility; +{ + struct debug_field *f; + + f = (struct debug_field *) xmalloc (sizeof *f); + memset (f, 0, sizeof *f); + + f->name = name; + f->type = type; + f->static_member = TRUE; + f->u.s.physname = physname; + f->visibility = visibility; + + return f; +} + +/* Make a method. The second argument is the name, and the third + argument is a NULL terminated array of method variants. */ + +debug_method +debug_make_method (handle, name, variants) + PTR handle ATTRIBUTE_UNUSED; + const char *name; + debug_method_variant *variants; +{ + struct debug_method *m; + + m = (struct debug_method *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->name = name; + m->variants = variants; + + return m; +} + +/* Make a method argument. The second argument is the real name of + the function. The third argument is the type of the function. The + fourth argument is the visibility. The fifth argument is whether + this is a const function. The sixth argument is whether this is a + volatile function. The seventh argument is the offset in the + virtual function table, if any. The eighth argument is the virtual + function context. FIXME: Are the const and volatile arguments + necessary? Could we just use debug_make_const_type? */ + +debug_method_variant +debug_make_method_variant (handle, physname, type, visibility, constp, + volatilep, voffset, context) + PTR handle ATTRIBUTE_UNUSED; + const char *physname; + debug_type type; + enum debug_visibility visibility; + bfd_boolean constp; + bfd_boolean volatilep; + bfd_vma voffset; + debug_type context; +{ + struct debug_method_variant *m; + + m = (struct debug_method_variant *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->physname = physname; + m->type = type; + m->visibility = visibility; + m->constp = constp; + m->volatilep = volatilep; + m->voffset = voffset; + m->context = context; + + return m; +} + +/* Make a static method argument. The arguments are the same as for + debug_make_method_variant, except that the last two are omitted + since a static method can not also be virtual. */ + +debug_method_variant +debug_make_static_method_variant (handle, physname, type, visibility, + constp, volatilep) + PTR handle ATTRIBUTE_UNUSED; + const char *physname; + debug_type type; + enum debug_visibility visibility; + bfd_boolean constp; + bfd_boolean volatilep; +{ + struct debug_method_variant *m; + + m = (struct debug_method_variant *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->physname = physname; + m->type = type; + m->visibility = visibility; + m->constp = constp; + m->volatilep = volatilep; + m->voffset = VOFFSET_STATIC_METHOD; + + return m; +} + +/* Name a type. */ + +debug_type +debug_name_type (handle, name, type) + PTR handle; + const char *name; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_named_type *n; + struct debug_name *nm; + + if (name == NULL || type == NULL) + return DEBUG_TYPE_NULL; + + if (info->current_unit == NULL + || info->current_file == NULL) + { + debug_error (_("debug_name_type: no current file")); + return DEBUG_TYPE_NULL; + } + + t = debug_make_type (info, DEBUG_KIND_NAMED, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + n = (struct debug_named_type *) xmalloc (sizeof *n); + memset (n, 0, sizeof *n); + + n->type = type; + + t->u.knamed = n; + + /* We always add the name to the global namespace. This is probably + wrong in some cases, but it seems to be right for stabs. FIXME. */ + + nm = debug_add_to_namespace (info, &info->current_file->globals, name, + DEBUG_OBJECT_TYPE, DEBUG_LINKAGE_NONE); + if (nm == NULL) + return DEBUG_TYPE_NULL; + + nm->u.type = t; + + n->name = nm; + + return t; +} + +/* Tag a type. */ + +debug_type +debug_tag_type (handle, name, type) + PTR handle; + const char *name; + debug_type type; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_type *t; + struct debug_named_type *n; + struct debug_name *nm; + + if (name == NULL || type == NULL) + return DEBUG_TYPE_NULL; + + if (info->current_file == NULL) + { + debug_error (_("debug_tag_type: no current file")); + return DEBUG_TYPE_NULL; + } + + if (type->kind == DEBUG_KIND_TAGGED) + { + if (strcmp (type->u.knamed->name->name, name) == 0) + return type; + debug_error (_("debug_tag_type: extra tag attempted")); + return DEBUG_TYPE_NULL; + } + + t = debug_make_type (info, DEBUG_KIND_TAGGED, 0); + if (t == NULL) + return DEBUG_TYPE_NULL; + + n = (struct debug_named_type *) xmalloc (sizeof *n); + memset (n, 0, sizeof *n); + + n->type = type; + + t->u.knamed = n; + + /* We keep a global namespace of tags for each compilation unit. I + don't know if that is the right thing to do. */ + + nm = debug_add_to_namespace (info, &info->current_file->globals, name, + DEBUG_OBJECT_TAG, DEBUG_LINKAGE_NONE); + if (nm == NULL) + return DEBUG_TYPE_NULL; + + nm->u.tag = t; + + n->name = nm; + + return t; +} + +/* Record the size of a given type. */ + +bfd_boolean +debug_record_type_size (handle, type, size) + PTR handle ATTRIBUTE_UNUSED; + debug_type type; + unsigned int size; +{ + if (type->size != 0 && type->size != size) + fprintf (stderr, _("Warning: changing type size from %d to %d\n"), + type->size, size); + + type->size = size; + + return TRUE; +} + +/* Find a named type. */ + +debug_type +debug_find_named_type (handle, name) + PTR handle; + const char *name; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_block *b; + struct debug_file *f; + + /* We only search the current compilation unit. I don't know if + this is right or not. */ + + if (info->current_unit == NULL) + { + debug_error (_("debug_find_named_type: no current compilation unit")); + return DEBUG_TYPE_NULL; + } + + for (b = info->current_block; b != NULL; b = b->parent) + { + if (b->locals != NULL) + { + struct debug_name *n; + + for (n = b->locals->list; n != NULL; n = n->next) + { + if (n->kind == DEBUG_OBJECT_TYPE + && n->name[0] == name[0] + && strcmp (n->name, name) == 0) + return n->u.type; + } + } + } + + for (f = info->current_unit->files; f != NULL; f = f->next) + { + if (f->globals != NULL) + { + struct debug_name *n; + + for (n = f->globals->list; n != NULL; n = n->next) + { + if (n->kind == DEBUG_OBJECT_TYPE + && n->name[0] == name[0] + && strcmp (n->name, name) == 0) + return n->u.type; + } + } + } + + return DEBUG_TYPE_NULL; +} + +/* Find a tagged type. */ + +debug_type +debug_find_tagged_type (handle, name, kind) + PTR handle; + const char *name; + enum debug_type_kind kind; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_unit *u; + + /* We search the globals of all the compilation units. I don't know + if this is correct or not. It would be easy to change. */ + + for (u = info->units; u != NULL; u = u->next) + { + struct debug_file *f; + + for (f = u->files; f != NULL; f = f->next) + { + struct debug_name *n; + + if (f->globals != NULL) + { + for (n = f->globals->list; n != NULL; n = n->next) + { + if (n->kind == DEBUG_OBJECT_TAG + && (kind == DEBUG_KIND_ILLEGAL + || n->u.tag->kind == kind) + && n->name[0] == name[0] + && strcmp (n->name, name) == 0) + return n->u.tag; + } + } + } + } + + return DEBUG_TYPE_NULL; +} + +/* Get a base type. We build a linked list on the stack to avoid + crashing if the type is defined circularly. */ + +static struct debug_type * +debug_get_real_type (handle, type, list) + PTR handle; + debug_type type; + struct debug_type_real_list *list; +{ + struct debug_type_real_list *l; + struct debug_type_real_list rl; + + switch (type->kind) + { + default: + return type; + + case DEBUG_KIND_INDIRECT: + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + break; + } + + for (l = list; l != NULL; l = l->next) + { + if (l->t == type || l == l->next) + { + fprintf (stderr, + _("debug_get_real_type: circular debug information for %s\n"), + debug_get_type_name (handle, type)); + return NULL; + } + } + + rl.next = list; + rl.t = type; + + switch (type->kind) + { + /* The default case is just here to avoid warnings. */ + default: + case DEBUG_KIND_INDIRECT: + if (*type->u.kindirect->slot != NULL) + return debug_get_real_type (handle, *type->u.kindirect->slot, &rl); + return type; + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + return debug_get_real_type (handle, type->u.knamed->type, &rl); + } + /*NOTREACHED*/ +} + +/* Get the kind of a type. */ + +enum debug_type_kind +debug_get_type_kind (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return DEBUG_KIND_ILLEGAL; + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return DEBUG_KIND_ILLEGAL; + return type->kind; +} + +/* Get the name of a type. */ + +const char * +debug_get_type_name (handle, type) + PTR handle; + debug_type type; +{ + if (type->kind == DEBUG_KIND_INDIRECT) + { + if (*type->u.kindirect->slot != NULL) + return debug_get_type_name (handle, *type->u.kindirect->slot); + return type->u.kindirect->tag; + } + if (type->kind == DEBUG_KIND_NAMED + || type->kind == DEBUG_KIND_TAGGED) + return type->u.knamed->name->name; + return NULL; +} + +/* Get the size of a type. */ + +bfd_vma +debug_get_type_size (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return 0; + + /* We don't call debug_get_real_type, because somebody might have + called debug_record_type_size on a named or indirect type. */ + + if (type->size != 0) + return type->size; + + switch (type->kind) + { + default: + return 0; + case DEBUG_KIND_INDIRECT: + if (*type->u.kindirect->slot != NULL) + return debug_get_type_size (handle, *type->u.kindirect->slot); + return 0; + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + return debug_get_type_size (handle, type->u.knamed->type); + } + /*NOTREACHED*/ +} + +/* Get the return type of a function or method type. */ + +debug_type +debug_get_return_type (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return DEBUG_TYPE_NULL; + + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return DEBUG_TYPE_NULL; + + switch (type->kind) + { + default: + return DEBUG_TYPE_NULL; + case DEBUG_KIND_FUNCTION: + return type->u.kfunction->return_type; + case DEBUG_KIND_METHOD: + return type->u.kmethod->return_type; + } + /*NOTREACHED*/ +} + +/* Get the parameter types of a function or method type (except that + we don't currently store the parameter types of a function). */ + +const debug_type * +debug_get_parameter_types (handle, type, pvarargs) + PTR handle; + debug_type type; + bfd_boolean *pvarargs; +{ + if (type == NULL) + return NULL; + + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return NULL; + + switch (type->kind) + { + default: + return NULL; + case DEBUG_KIND_FUNCTION: + *pvarargs = type->u.kfunction->varargs; + return type->u.kfunction->arg_types; + case DEBUG_KIND_METHOD: + *pvarargs = type->u.kmethod->varargs; + return type->u.kmethod->arg_types; + } + /*NOTREACHED*/ +} + +/* Get the target type of a type. */ + +debug_type +debug_get_target_type (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return NULL; + + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return NULL; + + switch (type->kind) + { + default: + return NULL; + case DEBUG_KIND_POINTER: + return type->u.kpointer; + case DEBUG_KIND_REFERENCE: + return type->u.kreference; + case DEBUG_KIND_CONST: + return type->u.kconst; + case DEBUG_KIND_VOLATILE: + return type->u.kvolatile; + } + /*NOTREACHED*/ +} + +/* Get the NULL terminated array of fields for a struct, union, or + class. */ + +const debug_field * +debug_get_fields (handle, type) + PTR handle; + debug_type type; +{ + if (type == NULL) + return NULL; + + type = debug_get_real_type (handle, type, NULL); + if (type == NULL) + return NULL; + + switch (type->kind) + { + default: + return NULL; + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + return type->u.kclass->fields; + } + /*NOTREACHED*/ +} + +/* Get the type of a field. */ + +debug_type +debug_get_field_type (handle, field) + PTR handle ATTRIBUTE_UNUSED; + debug_field field; +{ + if (field == NULL) + return NULL; + return field->type; +} + +/* Get the name of a field. */ + +const char * +debug_get_field_name (handle, field) + PTR handle ATTRIBUTE_UNUSED; + debug_field field; +{ + if (field == NULL) + return NULL; + return field->name; +} + +/* Get the bit position of a field. */ + +bfd_vma +debug_get_field_bitpos (handle, field) + PTR handle ATTRIBUTE_UNUSED; + debug_field field; +{ + if (field == NULL || field->static_member) + return (bfd_vma) -1; + return field->u.f.bitpos; +} + +/* Get the bit size of a field. */ + +bfd_vma +debug_get_field_bitsize (handle, field) + PTR handle ATTRIBUTE_UNUSED; + debug_field field; +{ + if (field == NULL || field->static_member) + return (bfd_vma) -1; + return field->u.f.bitsize; +} + +/* Get the visibility of a field. */ + +enum debug_visibility +debug_get_field_visibility (handle, field) + PTR handle ATTRIBUTE_UNUSED; + debug_field field; +{ + if (field == NULL) + return DEBUG_VISIBILITY_IGNORE; + return field->visibility; +} + +/* Get the physical name of a field. */ + +const char * +debug_get_field_physname (handle, field) + PTR handle ATTRIBUTE_UNUSED; + debug_field field; +{ + if (field == NULL || ! field->static_member) + return NULL; + return field->u.s.physname; +} + +/* Write out the debugging information. This is given a handle to + debugging information, and a set of function pointers to call. */ + +bfd_boolean +debug_write (handle, fns, fhandle) + PTR handle; + const struct debug_write_fns *fns; + PTR fhandle; +{ + struct debug_handle *info = (struct debug_handle *) handle; + struct debug_unit *u; + + /* We use a mark to tell whether we have already written out a + particular name. We use an integer, so that we don't have to + clear the mark fields if we happen to write out the same + information more than once. */ + ++info->mark; + + /* The base_id field holds an ID value which will never be used, so + that we can tell whether we have assigned an ID during this call + to debug_write. */ + info->base_id = info->class_id; + + /* We keep a linked list of classes for which was have assigned ID's + during this call to debug_write. */ + info->id_list = NULL; + + for (u = info->units; u != NULL; u = u->next) + { + struct debug_file *f; + bfd_boolean first_file; + + info->current_write_lineno = u->linenos; + info->current_write_lineno_index = 0; + + if (! (*fns->start_compilation_unit) (fhandle, u->files->filename)) + return FALSE; + + first_file = TRUE; + for (f = u->files; f != NULL; f = f->next) + { + struct debug_name *n; + + if (first_file) + first_file = FALSE; + else if (! (*fns->start_source) (fhandle, f->filename)) + return FALSE; + + if (f->globals != NULL) + for (n = f->globals->list; n != NULL; n = n->next) + if (! debug_write_name (info, fns, fhandle, n)) + return FALSE; + } + + /* Output any line number information which hasn't already been + handled. */ + if (! debug_write_linenos (info, fns, fhandle, (bfd_vma) -1)) + return FALSE; + } + + return TRUE; +} + +/* Write out an element in a namespace. */ + +static bfd_boolean +debug_write_name (info, fns, fhandle, n) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + struct debug_name *n; +{ + switch (n->kind) + { + case DEBUG_OBJECT_TYPE: + if (! debug_write_type (info, fns, fhandle, n->u.type, n) + || ! (*fns->typdef) (fhandle, n->name)) + return FALSE; + return TRUE; + case DEBUG_OBJECT_TAG: + if (! debug_write_type (info, fns, fhandle, n->u.tag, n)) + return FALSE; + return (*fns->tag) (fhandle, n->name); + case DEBUG_OBJECT_VARIABLE: + if (! debug_write_type (info, fns, fhandle, n->u.variable->type, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->variable) (fhandle, n->name, n->u.variable->kind, + n->u.variable->val); + case DEBUG_OBJECT_FUNCTION: + return debug_write_function (info, fns, fhandle, n->name, + n->linkage, n->u.function); + case DEBUG_OBJECT_INT_CONSTANT: + return (*fns->int_constant) (fhandle, n->name, n->u.int_constant); + case DEBUG_OBJECT_FLOAT_CONSTANT: + return (*fns->float_constant) (fhandle, n->name, n->u.float_constant); + case DEBUG_OBJECT_TYPED_CONSTANT: + if (! debug_write_type (info, fns, fhandle, n->u.typed_constant->type, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->typed_constant) (fhandle, n->name, + n->u.typed_constant->val); + default: + abort (); + return FALSE; + } + /*NOTREACHED*/ +} + +/* Write out a type. If the type is DEBUG_KIND_NAMED or + DEBUG_KIND_TAGGED, then the name argument is the name for which we + are about to call typedef or tag. If the type is anything else, + then the name argument is a tag from a DEBUG_KIND_TAGGED type which + points to this one. */ + +static bfd_boolean +debug_write_type (info, fns, fhandle, type, name) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + struct debug_type *type; + struct debug_name *name; +{ + unsigned int i; + int is; + const char *tag = NULL; + + /* If we have a name for this type, just output it. We only output + typedef names after they have been defined. We output type tags + whenever we are not actually defining them. */ + if ((type->kind == DEBUG_KIND_NAMED + || type->kind == DEBUG_KIND_TAGGED) + && (type->u.knamed->name->mark == info->mark + || (type->kind == DEBUG_KIND_TAGGED + && type->u.knamed->name != name))) + { + if (type->kind == DEBUG_KIND_NAMED) + return (*fns->typedef_type) (fhandle, type->u.knamed->name->name); + else + { + struct debug_type *real; + unsigned int id; + + real = debug_get_real_type ((PTR) info, type, NULL); + if (real == NULL) + return (*fns->empty_type) (fhandle); + id = 0; + if ((real->kind == DEBUG_KIND_STRUCT + || real->kind == DEBUG_KIND_UNION + || real->kind == DEBUG_KIND_CLASS + || real->kind == DEBUG_KIND_UNION_CLASS) + && real->u.kclass != NULL) + { + if (real->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, + type->u.knamed->name->name, + real)) + return FALSE; + } + id = real->u.kclass->id; + } + + return (*fns->tag_type) (fhandle, type->u.knamed->name->name, id, + real->kind); + } + } + + /* Mark the name after we have already looked for a known name, so + that we don't just define a type in terms of itself. We need to + mark the name here so that a struct containing a pointer to + itself will work. */ + if (name != NULL) + name->mark = info->mark; + + if (name != NULL + && type->kind != DEBUG_KIND_NAMED + && type->kind != DEBUG_KIND_TAGGED) + { + assert (name->kind == DEBUG_OBJECT_TAG); + tag = name->name; + } + + switch (type->kind) + { + case DEBUG_KIND_ILLEGAL: + debug_error (_("debug_write_type: illegal type encountered")); + return FALSE; + case DEBUG_KIND_INDIRECT: + if (*type->u.kindirect->slot == DEBUG_TYPE_NULL) + return (*fns->empty_type) (fhandle); + return debug_write_type (info, fns, fhandle, *type->u.kindirect->slot, + name); + case DEBUG_KIND_VOID: + return (*fns->void_type) (fhandle); + case DEBUG_KIND_INT: + return (*fns->int_type) (fhandle, type->size, type->u.kint); + case DEBUG_KIND_FLOAT: + return (*fns->float_type) (fhandle, type->size); + case DEBUG_KIND_COMPLEX: + return (*fns->complex_type) (fhandle, type->size); + case DEBUG_KIND_BOOL: + return (*fns->bool_type) (fhandle, type->size); + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + if (type->u.kclass != NULL) + { + if (type->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, tag, type)) + return FALSE; + } + + if (info->mark == type->u.kclass->mark) + { + /* We are currently outputting this struct, or we have + already output it. I don't know if this can happen, + but it can happen for a class. */ + assert (type->u.kclass->id > info->base_id); + return (*fns->tag_type) (fhandle, tag, type->u.kclass->id, + type->kind); + } + type->u.kclass->mark = info->mark; + } + + if (! (*fns->start_struct_type) (fhandle, tag, + (type->u.kclass != NULL + ? type->u.kclass->id + : 0), + type->kind == DEBUG_KIND_STRUCT, + type->size)) + return FALSE; + if (type->u.kclass != NULL + && type->u.kclass->fields != NULL) + { + for (i = 0; type->u.kclass->fields[i] != NULL; i++) + { + struct debug_field *f; + + f = type->u.kclass->fields[i]; + if (! debug_write_type (info, fns, fhandle, f->type, + (struct debug_name *) NULL) + || ! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, + f->u.f.bitsize, f->visibility)) + return FALSE; + } + } + return (*fns->end_struct_type) (fhandle); + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + return debug_write_class_type (info, fns, fhandle, type, tag); + case DEBUG_KIND_ENUM: + if (type->u.kenum == NULL) + return (*fns->enum_type) (fhandle, tag, (const char **) NULL, + (bfd_signed_vma *) NULL); + return (*fns->enum_type) (fhandle, tag, type->u.kenum->names, + type->u.kenum->values); + case DEBUG_KIND_POINTER: + if (! debug_write_type (info, fns, fhandle, type->u.kpointer, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->pointer_type) (fhandle); + case DEBUG_KIND_FUNCTION: + if (! debug_write_type (info, fns, fhandle, + type->u.kfunction->return_type, + (struct debug_name *) NULL)) + return FALSE; + if (type->u.kfunction->arg_types == NULL) + is = -1; + else + { + for (is = 0; type->u.kfunction->arg_types[is] != NULL; is++) + if (! debug_write_type (info, fns, fhandle, + type->u.kfunction->arg_types[is], + (struct debug_name *) NULL)) + return FALSE; + } + return (*fns->function_type) (fhandle, is, + type->u.kfunction->varargs); + case DEBUG_KIND_REFERENCE: + if (! debug_write_type (info, fns, fhandle, type->u.kreference, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->reference_type) (fhandle); + case DEBUG_KIND_RANGE: + if (! debug_write_type (info, fns, fhandle, type->u.krange->type, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->range_type) (fhandle, type->u.krange->lower, + type->u.krange->upper); + case DEBUG_KIND_ARRAY: + if (! debug_write_type (info, fns, fhandle, type->u.karray->element_type, + (struct debug_name *) NULL) + || ! debug_write_type (info, fns, fhandle, + type->u.karray->range_type, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->array_type) (fhandle, type->u.karray->lower, + type->u.karray->upper, + type->u.karray->stringp); + case DEBUG_KIND_SET: + if (! debug_write_type (info, fns, fhandle, type->u.kset->type, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->set_type) (fhandle, type->u.kset->bitstringp); + case DEBUG_KIND_OFFSET: + if (! debug_write_type (info, fns, fhandle, type->u.koffset->base_type, + (struct debug_name *) NULL) + || ! debug_write_type (info, fns, fhandle, + type->u.koffset->target_type, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->offset_type) (fhandle); + case DEBUG_KIND_METHOD: + if (! debug_write_type (info, fns, fhandle, + type->u.kmethod->return_type, + (struct debug_name *) NULL)) + return FALSE; + if (type->u.kmethod->arg_types == NULL) + is = -1; + else + { + for (is = 0; type->u.kmethod->arg_types[is] != NULL; is++) + if (! debug_write_type (info, fns, fhandle, + type->u.kmethod->arg_types[is], + (struct debug_name *) NULL)) + return FALSE; + } + if (type->u.kmethod->domain_type != NULL) + { + if (! debug_write_type (info, fns, fhandle, + type->u.kmethod->domain_type, + (struct debug_name *) NULL)) + return FALSE; + } + return (*fns->method_type) (fhandle, + type->u.kmethod->domain_type != NULL, + is, + type->u.kmethod->varargs); + case DEBUG_KIND_CONST: + if (! debug_write_type (info, fns, fhandle, type->u.kconst, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->const_type) (fhandle); + case DEBUG_KIND_VOLATILE: + if (! debug_write_type (info, fns, fhandle, type->u.kvolatile, + (struct debug_name *) NULL)) + return FALSE; + return (*fns->volatile_type) (fhandle); + case DEBUG_KIND_NAMED: + return debug_write_type (info, fns, fhandle, type->u.knamed->type, + (struct debug_name *) NULL); + case DEBUG_KIND_TAGGED: + return debug_write_type (info, fns, fhandle, type->u.knamed->type, + type->u.knamed->name); + default: + abort (); + return FALSE; + } +} + +/* Write out a class type. */ + +static bfd_boolean +debug_write_class_type (info, fns, fhandle, type, tag) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + struct debug_type *type; + const char *tag; +{ + unsigned int i; + unsigned int id; + struct debug_type *vptrbase; + + if (type->u.kclass == NULL) + { + id = 0; + vptrbase = NULL; + } + else + { + if (type->u.kclass->id <= info->base_id) + { + if (! debug_set_class_id (info, tag, type)) + return FALSE; + } + + if (info->mark == type->u.kclass->mark) + { + /* We are currently outputting this class, or we have + already output it. This can happen when there are + methods for an anonymous class. */ + assert (type->u.kclass->id > info->base_id); + return (*fns->tag_type) (fhandle, tag, type->u.kclass->id, + type->kind); + } + type->u.kclass->mark = info->mark; + id = type->u.kclass->id; + + vptrbase = type->u.kclass->vptrbase; + if (vptrbase != NULL && vptrbase != type) + { + if (! debug_write_type (info, fns, fhandle, vptrbase, + (struct debug_name *) NULL)) + return FALSE; + } + } + + if (! (*fns->start_class_type) (fhandle, tag, id, + type->kind == DEBUG_KIND_CLASS, + type->size, + vptrbase != NULL, + vptrbase == type)) + return FALSE; + + if (type->u.kclass != NULL) + { + if (type->u.kclass->fields != NULL) + { + for (i = 0; type->u.kclass->fields[i] != NULL; i++) + { + struct debug_field *f; + + f = type->u.kclass->fields[i]; + if (! debug_write_type (info, fns, fhandle, f->type, + (struct debug_name *) NULL)) + return FALSE; + if (f->static_member) + { + if (! (*fns->class_static_member) (fhandle, f->name, + f->u.s.physname, + f->visibility)) + return FALSE; + } + else + { + if (! (*fns->struct_field) (fhandle, f->name, f->u.f.bitpos, + f->u.f.bitsize, f->visibility)) + return FALSE; + } + } + } + + if (type->u.kclass->baseclasses != NULL) + { + for (i = 0; type->u.kclass->baseclasses[i] != NULL; i++) + { + struct debug_baseclass *b; + + b = type->u.kclass->baseclasses[i]; + if (! debug_write_type (info, fns, fhandle, b->type, + (struct debug_name *) NULL)) + return FALSE; + if (! (*fns->class_baseclass) (fhandle, b->bitpos, b->virtual, + b->visibility)) + return FALSE; + } + } + + if (type->u.kclass->methods != NULL) + { + for (i = 0; type->u.kclass->methods[i] != NULL; i++) + { + struct debug_method *m; + unsigned int j; + + m = type->u.kclass->methods[i]; + if (! (*fns->class_start_method) (fhandle, m->name)) + return FALSE; + for (j = 0; m->variants[j] != NULL; j++) + { + struct debug_method_variant *v; + + v = m->variants[j]; + if (v->context != NULL) + { + if (! debug_write_type (info, fns, fhandle, v->context, + (struct debug_name *) NULL)) + return FALSE; + } + if (! debug_write_type (info, fns, fhandle, v->type, + (struct debug_name *) NULL)) + return FALSE; + if (v->voffset != VOFFSET_STATIC_METHOD) + { + if (! (*fns->class_method_variant) (fhandle, v->physname, + v->visibility, + v->constp, + v->volatilep, + v->voffset, + v->context != NULL)) + return FALSE; + } + else + { + if (! (*fns->class_static_method_variant) (fhandle, + v->physname, + v->visibility, + v->constp, + v->volatilep)) + return FALSE; + } + } + if (! (*fns->class_end_method) (fhandle)) + return FALSE; + } + } + } + + return (*fns->end_class_type) (fhandle); +} + +/* Write out information for a function. */ + +static bfd_boolean +debug_write_function (info, fns, fhandle, name, linkage, function) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + const char *name; + enum debug_object_linkage linkage; + struct debug_function *function; +{ + struct debug_parameter *p; + struct debug_block *b; + + if (! debug_write_linenos (info, fns, fhandle, function->blocks->start)) + return FALSE; + + if (! debug_write_type (info, fns, fhandle, function->return_type, + (struct debug_name *) NULL)) + return FALSE; + + if (! (*fns->start_function) (fhandle, name, + linkage == DEBUG_LINKAGE_GLOBAL)) + return FALSE; + + for (p = function->parameters; p != NULL; p = p->next) + { + if (! debug_write_type (info, fns, fhandle, p->type, + (struct debug_name *) NULL) + || ! (*fns->function_parameter) (fhandle, p->name, p->kind, p->val)) + return FALSE; + } + + for (b = function->blocks; b != NULL; b = b->next) + { + if (! debug_write_block (info, fns, fhandle, b)) + return FALSE; + } + + return (*fns->end_function) (fhandle); +} + +/* Write out information for a block. */ + +static bfd_boolean +debug_write_block (info, fns, fhandle, block) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + struct debug_block *block; +{ + struct debug_name *n; + struct debug_block *b; + + if (! debug_write_linenos (info, fns, fhandle, block->start)) + return FALSE; + + /* I can't see any point to writing out a block with no local + variables, so we don't bother, except for the top level block. */ + if (block->locals != NULL || block->parent == NULL) + { + if (! (*fns->start_block) (fhandle, block->start)) + return FALSE; + } + + if (block->locals != NULL) + { + for (n = block->locals->list; n != NULL; n = n->next) + { + if (! debug_write_name (info, fns, fhandle, n)) + return FALSE; + } + } + + for (b = block->children; b != NULL; b = b->next) + { + if (! debug_write_block (info, fns, fhandle, b)) + return FALSE; + } + + if (! debug_write_linenos (info, fns, fhandle, block->end)) + return FALSE; + + if (block->locals != NULL || block->parent == NULL) + { + if (! (*fns->end_block) (fhandle, block->end)) + return FALSE; + } + + return TRUE; +} + +/* Write out line number information up to ADDRESS. */ + +static bfd_boolean +debug_write_linenos (info, fns, fhandle, address) + struct debug_handle *info; + const struct debug_write_fns *fns; + PTR fhandle; + bfd_vma address; +{ + while (info->current_write_lineno != NULL) + { + struct debug_lineno *l; + + l = info->current_write_lineno; + + while (info->current_write_lineno_index < DEBUG_LINENO_COUNT) + { + if (l->linenos[info->current_write_lineno_index] + == (unsigned long) -1) + break; + + if (l->addrs[info->current_write_lineno_index] >= address) + return TRUE; + + if (! (*fns->lineno) (fhandle, l->file->filename, + l->linenos[info->current_write_lineno_index], + l->addrs[info->current_write_lineno_index])) + return FALSE; + + ++info->current_write_lineno_index; + } + + info->current_write_lineno = l->next; + info->current_write_lineno_index = 0; + } + + return TRUE; +} + +/* Get the ID number for a class. If during the same call to + debug_write we find a struct with the same definition with the same + name, we use the same ID. This type of things happens because the + same struct will be defined by multiple compilation units. */ + +static bfd_boolean +debug_set_class_id (info, tag, type) + struct debug_handle *info; + const char *tag; + struct debug_type *type; +{ + struct debug_class_type *c; + struct debug_class_id *l; + + assert (type->kind == DEBUG_KIND_STRUCT + || type->kind == DEBUG_KIND_UNION + || type->kind == DEBUG_KIND_CLASS + || type->kind == DEBUG_KIND_UNION_CLASS); + + c = type->u.kclass; + + if (c->id > info->base_id) + return TRUE; + + for (l = info->id_list; l != NULL; l = l->next) + { + if (l->type->kind != type->kind) + continue; + + if (tag == NULL) + { + if (l->tag != NULL) + continue; + } + else + { + if (l->tag == NULL + || l->tag[0] != tag[0] + || strcmp (l->tag, tag) != 0) + continue; + } + + if (debug_type_samep (info, l->type, type)) + { + c->id = l->type->u.kclass->id; + return TRUE; + } + } + + /* There are no identical types. Use a new ID, and add it to the + list. */ + ++info->class_id; + c->id = info->class_id; + + l = (struct debug_class_id *) xmalloc (sizeof *l); + memset (l, 0, sizeof *l); + + l->type = type; + l->tag = tag; + + l->next = info->id_list; + info->id_list = l; + + return TRUE; +} + +/* See if two types are the same. At this point, we don't care about + tags and the like. */ + +static bfd_boolean +debug_type_samep (info, t1, t2) + struct debug_handle *info; + struct debug_type *t1; + struct debug_type *t2; +{ + struct debug_type_compare_list *l; + struct debug_type_compare_list top; + bfd_boolean ret; + + if (t1 == NULL) + return t2 == NULL; + if (t2 == NULL) + return FALSE; + + while (t1->kind == DEBUG_KIND_INDIRECT) + { + t1 = *t1->u.kindirect->slot; + if (t1 == NULL) + return FALSE; + } + while (t2->kind == DEBUG_KIND_INDIRECT) + { + t2 = *t2->u.kindirect->slot; + if (t2 == NULL) + return FALSE; + } + + if (t1 == t2) + return TRUE; + + /* As a special case, permit a typedef to match a tag, since C++ + debugging output will sometimes add a typedef where C debugging + output will not. */ + if (t1->kind == DEBUG_KIND_NAMED + && t2->kind == DEBUG_KIND_TAGGED) + return debug_type_samep (info, t1->u.knamed->type, t2); + else if (t1->kind == DEBUG_KIND_TAGGED + && t2->kind == DEBUG_KIND_NAMED) + return debug_type_samep (info, t1, t2->u.knamed->type); + + if (t1->kind != t2->kind + || t1->size != t2->size) + return FALSE; + + /* Get rid of the trivial cases first. */ + switch (t1->kind) + { + default: + break; + case DEBUG_KIND_VOID: + case DEBUG_KIND_FLOAT: + case DEBUG_KIND_COMPLEX: + case DEBUG_KIND_BOOL: + return TRUE; + case DEBUG_KIND_INT: + return t1->u.kint == t2->u.kint; + } + + /* We have to avoid an infinite recursion. We do this by keeping a + list of types which we are comparing. We just keep the list on + the stack. If we encounter a pair of types we are currently + comparing, we just assume that they are equal. */ + for (l = info->compare_list; l != NULL; l = l->next) + { + if (l->t1 == t1 && l->t2 == t2) + return TRUE; + } + + top.t1 = t1; + top.t2 = t2; + top.next = info->compare_list; + info->compare_list = ⊤ + + switch (t1->kind) + { + default: + abort (); + ret = FALSE; + break; + + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_UNION: + case DEBUG_KIND_CLASS: + case DEBUG_KIND_UNION_CLASS: + if (t1->u.kclass == NULL) + ret = t2->u.kclass == NULL; + else if (t2->u.kclass == NULL) + ret = FALSE; + else if (t1->u.kclass->id > info->base_id + && t1->u.kclass->id == t2->u.kclass->id) + ret = TRUE; + else + ret = debug_class_type_samep (info, t1, t2); + break; + + case DEBUG_KIND_ENUM: + if (t1->u.kenum == NULL) + ret = t2->u.kenum == NULL; + else if (t2->u.kenum == NULL) + ret = FALSE; + else + { + const char **pn1, **pn2; + bfd_signed_vma *pv1, *pv2; + + pn1 = t1->u.kenum->names; + pn2 = t2->u.kenum->names; + pv1 = t1->u.kenum->values; + pv2 = t2->u.kenum->values; + while (*pn1 != NULL && *pn2 != NULL) + { + if (**pn1 != **pn2 + || *pv1 != *pv2 + || strcmp (*pn1, *pn2) != 0) + break; + ++pn1; + ++pn2; + ++pv1; + ++pv2; + } + ret = *pn1 == NULL && *pn2 == NULL; + } + break; + + case DEBUG_KIND_POINTER: + ret = debug_type_samep (info, t1->u.kpointer, t2->u.kpointer); + break; + + case DEBUG_KIND_FUNCTION: + if (t1->u.kfunction->varargs != t2->u.kfunction->varargs + || ! debug_type_samep (info, t1->u.kfunction->return_type, + t2->u.kfunction->return_type) + || ((t1->u.kfunction->arg_types == NULL) + != (t2->u.kfunction->arg_types == NULL))) + ret = FALSE; + else if (t1->u.kfunction->arg_types == NULL) + ret = TRUE; + else + { + struct debug_type **a1, **a2; + + a1 = t1->u.kfunction->arg_types; + a2 = t2->u.kfunction->arg_types; + while (*a1 != NULL && *a2 != NULL) + { + if (! debug_type_samep (info, *a1, *a2)) + break; + ++a1; + ++a2; + } + ret = *a1 == NULL && *a2 == NULL; + } + break; + + case DEBUG_KIND_REFERENCE: + ret = debug_type_samep (info, t1->u.kreference, t2->u.kreference); + break; + + case DEBUG_KIND_RANGE: + ret = (t1->u.krange->lower == t2->u.krange->lower + && t1->u.krange->upper == t2->u.krange->upper + && debug_type_samep (info, t1->u.krange->type, + t2->u.krange->type)); + + case DEBUG_KIND_ARRAY: + ret = (t1->u.karray->lower == t2->u.karray->lower + && t1->u.karray->upper == t2->u.karray->upper + && t1->u.karray->stringp == t2->u.karray->stringp + && debug_type_samep (info, t1->u.karray->element_type, + t2->u.karray->element_type)); + break; + + case DEBUG_KIND_SET: + ret = (t1->u.kset->bitstringp == t2->u.kset->bitstringp + && debug_type_samep (info, t1->u.kset->type, t2->u.kset->type)); + break; + + case DEBUG_KIND_OFFSET: + ret = (debug_type_samep (info, t1->u.koffset->base_type, + t2->u.koffset->base_type) + && debug_type_samep (info, t1->u.koffset->target_type, + t2->u.koffset->target_type)); + break; + + case DEBUG_KIND_METHOD: + if (t1->u.kmethod->varargs != t2->u.kmethod->varargs + || ! debug_type_samep (info, t1->u.kmethod->return_type, + t2->u.kmethod->return_type) + || ! debug_type_samep (info, t1->u.kmethod->domain_type, + t2->u.kmethod->domain_type) + || ((t1->u.kmethod->arg_types == NULL) + != (t2->u.kmethod->arg_types == NULL))) + ret = FALSE; + else if (t1->u.kmethod->arg_types == NULL) + ret = TRUE; + else + { + struct debug_type **a1, **a2; + + a1 = t1->u.kmethod->arg_types; + a2 = t2->u.kmethod->arg_types; + while (*a1 != NULL && *a2 != NULL) + { + if (! debug_type_samep (info, *a1, *a2)) + break; + ++a1; + ++a2; + } + ret = *a1 == NULL && *a2 == NULL; + } + break; + + case DEBUG_KIND_CONST: + ret = debug_type_samep (info, t1->u.kconst, t2->u.kconst); + break; + + case DEBUG_KIND_VOLATILE: + ret = debug_type_samep (info, t1->u.kvolatile, t2->u.kvolatile); + break; + + case DEBUG_KIND_NAMED: + case DEBUG_KIND_TAGGED: + ret = (strcmp (t1->u.knamed->name->name, t2->u.knamed->name->name) == 0 + && debug_type_samep (info, t1->u.knamed->type, + t2->u.knamed->type)); + break; + } + + info->compare_list = top.next; + + return ret; +} + +/* See if two classes are the same. This is a subroutine of + debug_type_samep. */ + +static bfd_boolean +debug_class_type_samep (info, t1, t2) + struct debug_handle *info; + struct debug_type *t1; + struct debug_type *t2; +{ + struct debug_class_type *c1, *c2; + + c1 = t1->u.kclass; + c2 = t2->u.kclass; + + if ((c1->fields == NULL) != (c2->fields == NULL) + || (c1->baseclasses == NULL) != (c2->baseclasses == NULL) + || (c1->methods == NULL) != (c2->methods == NULL) + || (c1->vptrbase == NULL) != (c2->vptrbase == NULL)) + return FALSE; + + if (c1->fields != NULL) + { + struct debug_field **pf1, **pf2; + + for (pf1 = c1->fields, pf2 = c2->fields; + *pf1 != NULL && *pf2 != NULL; + pf1++, pf2++) + { + struct debug_field *f1, *f2; + + f1 = *pf1; + f2 = *pf2; + if (f1->name[0] != f2->name[0] + || f1->visibility != f2->visibility + || f1->static_member != f2->static_member) + return FALSE; + if (f1->static_member) + { + if (strcmp (f1->u.s.physname, f2->u.s.physname) != 0) + return FALSE; + } + else + { + if (f1->u.f.bitpos != f2->u.f.bitpos + || f1->u.f.bitsize != f2->u.f.bitsize) + return FALSE; + } + /* We do the checks which require function calls last. We + don't require that the types of fields have the same + names, since that sometimes fails in the presence of + typedefs and we really don't care. */ + if (strcmp (f1->name, f2->name) != 0 + || ! debug_type_samep (info, + debug_get_real_type ((PTR) info, + f1->type, NULL), + debug_get_real_type ((PTR) info, + f2->type, NULL))) + return FALSE; + } + if (*pf1 != NULL || *pf2 != NULL) + return FALSE; + } + + if (c1->vptrbase != NULL) + { + if (! debug_type_samep (info, c1->vptrbase, c2->vptrbase)) + return FALSE; + } + + if (c1->baseclasses != NULL) + { + struct debug_baseclass **pb1, **pb2; + + for (pb1 = c1->baseclasses, pb2 = c2->baseclasses; + *pb1 != NULL && *pb2 != NULL; + ++pb1, ++pb2) + { + struct debug_baseclass *b1, *b2; + + b1 = *pb1; + b2 = *pb2; + if (b1->bitpos != b2->bitpos + || b1->virtual != b2->virtual + || b1->visibility != b2->visibility + || ! debug_type_samep (info, b1->type, b2->type)) + return FALSE; + } + if (*pb1 != NULL || *pb2 != NULL) + return FALSE; + } + + if (c1->methods != NULL) + { + struct debug_method **pm1, **pm2; + + for (pm1 = c1->methods, pm2 = c2->methods; + *pm1 != NULL && *pm2 != NULL; + ++pm1, ++pm2) + { + struct debug_method *m1, *m2; + + m1 = *pm1; + m2 = *pm2; + if (m1->name[0] != m2->name[0] + || strcmp (m1->name, m2->name) != 0 + || (m1->variants == NULL) != (m2->variants == NULL)) + return FALSE; + if (m1->variants == NULL) + { + struct debug_method_variant **pv1, **pv2; + + for (pv1 = m1->variants, pv2 = m2->variants; + *pv1 != NULL && *pv2 != NULL; + ++pv1, ++pv2) + { + struct debug_method_variant *v1, *v2; + + v1 = *pv1; + v2 = *pv2; + if (v1->physname[0] != v2->physname[0] + || v1->visibility != v2->visibility + || v1->constp != v2->constp + || v1->volatilep != v2->volatilep + || v1->voffset != v2->voffset + || (v1->context == NULL) != (v2->context == NULL) + || strcmp (v1->physname, v2->physname) != 0 + || ! debug_type_samep (info, v1->type, v2->type)) + return FALSE; + if (v1->context != NULL) + { + if (! debug_type_samep (info, v1->context, + v2->context)) + return FALSE; + } + } + if (*pv1 != NULL || *pv2 != NULL) + return FALSE; + } + } + if (*pm1 != NULL || *pm2 != NULL) + return FALSE; + } + + return TRUE; +} diff --git a/contrib/binutils-2.14/binutils/debug.h b/contrib/binutils-2.14/binutils/debug.h new file mode 100644 index 0000000000..d53210e5b7 --- /dev/null +++ b/contrib/binutils-2.14/binutils/debug.h @@ -0,0 +1,801 @@ +/* debug.h -- Describe generic debugging information. + Copyright 1995, 1996, 2002 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef DEBUG_H +#define DEBUG_H + +/* This header file describes a generic debugging information format. + We may eventually have readers which convert different formats into + this generic format, and writers which write it out. The initial + impetus for this was writing a convertor from stabs to HP IEEE-695 + debugging format. */ + +/* Different kinds of types. */ + +enum debug_type_kind +{ + /* Not used. */ + DEBUG_KIND_ILLEGAL, + /* Indirect via a pointer. */ + DEBUG_KIND_INDIRECT, + /* Void. */ + DEBUG_KIND_VOID, + /* Integer. */ + DEBUG_KIND_INT, + /* Floating point. */ + DEBUG_KIND_FLOAT, + /* Complex. */ + DEBUG_KIND_COMPLEX, + /* Boolean. */ + DEBUG_KIND_BOOL, + /* Struct. */ + DEBUG_KIND_STRUCT, + /* Union. */ + DEBUG_KIND_UNION, + /* Class. */ + DEBUG_KIND_CLASS, + /* Union class (can this really happen?). */ + DEBUG_KIND_UNION_CLASS, + /* Enumeration type. */ + DEBUG_KIND_ENUM, + /* Pointer. */ + DEBUG_KIND_POINTER, + /* Function. */ + DEBUG_KIND_FUNCTION, + /* Reference. */ + DEBUG_KIND_REFERENCE, + /* Range. */ + DEBUG_KIND_RANGE, + /* Array. */ + DEBUG_KIND_ARRAY, + /* Set. */ + DEBUG_KIND_SET, + /* Based pointer. */ + DEBUG_KIND_OFFSET, + /* Method. */ + DEBUG_KIND_METHOD, + /* Const qualified type. */ + DEBUG_KIND_CONST, + /* Volatile qualified type. */ + DEBUG_KIND_VOLATILE, + /* Named type. */ + DEBUG_KIND_NAMED, + /* Tagged type. */ + DEBUG_KIND_TAGGED +}; + +/* Different kinds of variables. */ + +enum debug_var_kind +{ + /* Not used. */ + DEBUG_VAR_ILLEGAL, + /* A global variable. */ + DEBUG_GLOBAL, + /* A static variable. */ + DEBUG_STATIC, + /* A local static variable. */ + DEBUG_LOCAL_STATIC, + /* A local variable. */ + DEBUG_LOCAL, + /* A register variable. */ + DEBUG_REGISTER +}; + +/* Different kinds of function parameters. */ + +enum debug_parm_kind +{ + /* Not used. */ + DEBUG_PARM_ILLEGAL, + /* A stack based parameter. */ + DEBUG_PARM_STACK, + /* A register parameter. */ + DEBUG_PARM_REG, + /* A stack based reference parameter. */ + DEBUG_PARM_REFERENCE, + /* A register reference parameter. */ + DEBUG_PARM_REF_REG +}; + +/* Different kinds of visibility. */ + +enum debug_visibility +{ + /* A public field (e.g., a field in a C struct). */ + DEBUG_VISIBILITY_PUBLIC, + /* A protected field. */ + DEBUG_VISIBILITY_PROTECTED, + /* A private field. */ + DEBUG_VISIBILITY_PRIVATE, + /* A field which should be ignored. */ + DEBUG_VISIBILITY_IGNORE +}; + +/* A type. */ + +typedef struct debug_type *debug_type; + +#define DEBUG_TYPE_NULL ((debug_type) NULL) + +/* A field in a struct or union. */ + +typedef struct debug_field *debug_field; + +#define DEBUG_FIELD_NULL ((debug_field) NULL) + +/* A base class for an object. */ + +typedef struct debug_baseclass *debug_baseclass; + +#define DEBUG_BASECLASS_NULL ((debug_baseclass) NULL) + +/* A method of an object. */ + +typedef struct debug_method *debug_method; + +#define DEBUG_METHOD_NULL ((debug_method) NULL) + +/* The arguments to a method function of an object. These indicate + which method to run. */ + +typedef struct debug_method_variant *debug_method_variant; + +#define DEBUG_METHOD_VARIANT_NULL ((debug_method_variant) NULL) + +/* This structure is passed to debug_write. It holds function + pointers that debug_write will call based on the accumulated + debugging information. */ + +struct debug_write_fns +{ + /* This is called at the start of each new compilation unit with the + name of the main file in the new unit. */ + bfd_boolean (*start_compilation_unit) PARAMS ((PTR, const char *)); + + /* This is called at the start of each source file within a + compilation unit, before outputting any global information for + that file. The argument is the name of the file. */ + bfd_boolean (*start_source) PARAMS ((PTR, const char *)); + + /* Each writer must keep a stack of types. */ + + /* Push an empty type onto the type stack. This type can appear if + there is a reference to a type which is never defined. */ + bfd_boolean (*empty_type) PARAMS ((PTR)); + + /* Push a void type onto the type stack. */ + bfd_boolean (*void_type) PARAMS ((PTR)); + + /* Push an integer type onto the type stack, given the size and + whether it is unsigned. */ + bfd_boolean (*int_type) PARAMS ((PTR, unsigned int, bfd_boolean)); + + /* Push a floating type onto the type stack, given the size. */ + bfd_boolean (*float_type) PARAMS ((PTR, unsigned int)); + + /* Push a complex type onto the type stack, given the size. */ + bfd_boolean (*complex_type) PARAMS ((PTR, unsigned int)); + + /* Push a bfd_boolean type onto the type stack, given the size. */ + bfd_boolean (*bool_type) PARAMS ((PTR, unsigned int)); + + /* Push an enum type onto the type stack, given the tag, a NULL + terminated array of names and the associated values. If there is + no tag, the tag argument will be NULL. If this is an undefined + enum, the names and values arguments will be NULL. */ + bfd_boolean (*enum_type) + PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); + + /* Pop the top type on the type stack, and push a pointer to that + type onto the type stack. */ + bfd_boolean (*pointer_type) PARAMS ((PTR)); + + /* Push a function type onto the type stack. The second argument + indicates the number of argument types that have been pushed onto + the stack. If the number of argument types is passed as -1, then + the argument types of the function are unknown, and no types have + been pushed onto the stack. The third argument is TRUE if the + function takes a variable number of arguments. The return type + of the function is pushed onto the type stack below the argument + types, if any. */ + bfd_boolean (*function_type) PARAMS ((PTR, int, bfd_boolean)); + + /* Pop the top type on the type stack, and push a reference to that + type onto the type stack. */ + bfd_boolean (*reference_type) PARAMS ((PTR)); + + /* Pop the top type on the type stack, and push a range of that type + with the given lower and upper bounds onto the type stack. */ + bfd_boolean (*range_type) PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); + + /* Push an array type onto the type stack. The top type on the type + stack is the range, and the next type on the type stack is the + element type. These should be popped before the array type is + pushed. The arguments are the lower bound, the upper bound, and + whether the array is a string. */ + bfd_boolean (*array_type) + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, bfd_boolean)); + + /* Pop the top type on the type stack, and push a set of that type + onto the type stack. The argument indicates whether this set is + a bitstring. */ + bfd_boolean (*set_type) PARAMS ((PTR, bfd_boolean)); + + /* Push an offset type onto the type stack. The top type on the + type stack is the target type, and the next type on the type + stack is the base type. These should be popped before the offset + type is pushed. */ + bfd_boolean (*offset_type) PARAMS ((PTR)); + + /* Push a method type onto the type stack. If the second argument + is TRUE, the top type on the stack is the class to which the + method belongs; otherwise, the class must be determined by the + class to which the method is attached. The third argument is the + number of argument types; these are pushed onto the type stack in + reverse order (the first type popped is the last argument to the + method). A value of -1 for the third argument means that no + argument information is available. The fourth argument is TRUE + if the function takes a variable number of arguments. The next + type on the type stack below the domain and the argument types is + the return type of the method. All these types must be popped, + and then the method type must be pushed. */ + bfd_boolean (*method_type) PARAMS ((PTR, bfd_boolean, int, bfd_boolean)); + + /* Pop the top type off the type stack, and push a const qualified + version of that type onto the type stack. */ + bfd_boolean (*const_type) PARAMS ((PTR)); + + /* Pop the top type off the type stack, and push a volatile + qualified version of that type onto the type stack. */ + bfd_boolean (*volatile_type) PARAMS ((PTR)); + + /* Start building a struct. This is followed by calls to the + struct_field function, and finished by a call to the + end_struct_type function. The second argument is the tag; this + will be NULL if there isn't one. If the second argument is NULL, + the third argument is a constant identifying this struct for use + with tag_type. The fourth argument is TRUE for a struct, FALSE + for a union. The fifth argument is the size. If this is an + undefined struct or union, the size will be 0 and struct_field + will not be called before end_struct_type is called. */ + bfd_boolean (*start_struct_type) + PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int)); + + /* Add a field to the struct type currently being built. The type + of the field should be popped off the type stack. The arguments + are the name, the bit position, the bit size (may be zero if the + field is not packed), and the visibility. */ + bfd_boolean (*struct_field) + PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); + + /* Finish building a struct, and push it onto the type stack. */ + bfd_boolean (*end_struct_type) PARAMS ((PTR)); + + /* Start building a class. This is followed by calls to several + functions: struct_field, class_static_member, class_baseclass, + class_start_method, class_method_variant, + class_static_method_variant, and class_end_method. The class is + finished by a call to end_class_type. The first five arguments + are the same as for start_struct_type. The sixth argument is + TRUE if there is a virtual function table; if there is, the + seventh argument is TRUE if the virtual function table can be + found in the type itself, and is FALSE if the type of the object + holding the virtual function table should be popped from the type + stack. */ + bfd_boolean (*start_class_type) + PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int, + bfd_boolean, bfd_boolean)); + + /* Add a static member to the class currently being built. The + arguments are the field name, the physical name, and the + visibility. The type must be popped off the type stack. */ + bfd_boolean (*class_static_member) + PARAMS ((PTR, const char *, const char *, enum debug_visibility)); + + /* Add a baseclass to the class currently being built. The type of + the baseclass must be popped off the type stack. The arguments + are the bit position, whether the class is virtual, and the + visibility. */ + bfd_boolean (*class_baseclass) + PARAMS ((PTR, bfd_vma, bfd_boolean, enum debug_visibility)); + + /* Start adding a method to the class currently being built. This + is followed by calls to class_method_variant and + class_static_method_variant to describe different variants of the + method which take different arguments. The method is finished + with a call to class_end_method. The argument is the method + name. */ + bfd_boolean (*class_start_method) PARAMS ((PTR, const char *)); + + /* Describe a variant to the class method currently being built. + The type of the variant must be popped off the type stack. The + second argument is the physical name of the function. The + following arguments are the visibility, whether the variant is + const, whether the variant is volatile, the offset in the virtual + function table, and whether the context is on the type stack + (below the variant type). */ + bfd_boolean (*class_method_variant) + PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, + bfd_boolean, bfd_vma, bfd_boolean)); + + /* Describe a static variant to the class method currently being + built. The arguments are the same as for class_method_variant, + except that the last two arguments are omitted. The type of the + variant must be popped off the type stack. */ + bfd_boolean (*class_static_method_variant) + PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, + bfd_boolean)); + + /* Finish describing a class method. */ + bfd_boolean (*class_end_method) PARAMS ((PTR)); + + /* Finish describing a class, and push it onto the type stack. */ + bfd_boolean (*end_class_type) PARAMS ((PTR)); + + /* Push a type on the stack which was given a name by an earlier + call to typdef. */ + bfd_boolean (*typedef_type) PARAMS ((PTR, const char *)); + + /* Push a tagged type on the stack which was defined earlier. If + the second argument is not NULL, the type was defined by a call + to tag. If the second argument is NULL, the type was defined by + a call to start_struct_type or start_class_type with a tag of + NULL and the number of the third argument. Either way, the + fourth argument is the tag kind. Note that this may be called + for a struct (class) being defined, in between the call to + start_struct_type (start_class_type) and the call to + end_struct_type (end_class_type). */ + bfd_boolean (*tag_type) + PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); + + /* Pop the type stack, and typedef it to the given name. */ + bfd_boolean (*typdef) PARAMS ((PTR, const char *)); + + /* Pop the type stack, and declare it as a tagged struct or union or + enum or whatever. The tag passed down here is redundant, since + was also passed when enum_type, start_struct_type, or + start_class_type was called. */ + bfd_boolean (*tag) PARAMS ((PTR, const char *)); + + /* This is called to record a named integer constant. */ + bfd_boolean (*int_constant) PARAMS ((PTR, const char *, bfd_vma)); + + /* This is called to record a named floating point constant. */ + bfd_boolean (*float_constant) PARAMS ((PTR, const char *, double)); + + /* This is called to record a typed integer constant. The type is + popped off the type stack. */ + bfd_boolean (*typed_constant) PARAMS ((PTR, const char *, bfd_vma)); + + /* This is called to record a variable. The type is popped off the + type stack. */ + bfd_boolean (*variable) + PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); + + /* Start writing out a function. The return type must be popped off + the stack. The bfd_boolean is TRUE if the function is global. This + is followed by calls to function_parameter, followed by block + information. */ + bfd_boolean (*start_function) PARAMS ((PTR, const char *, bfd_boolean)); + + /* Record a function parameter for the current function. The type + must be popped off the stack. */ + bfd_boolean (*function_parameter) + PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); + + /* Start writing out a block. There is at least one top level block + per function. Blocks may be nested. The argument is the + starting address of the block. */ + bfd_boolean (*start_block) PARAMS ((PTR, bfd_vma)); + + /* Finish writing out a block. The argument is the ending address + of the block. */ + bfd_boolean (*end_block) PARAMS ((PTR, bfd_vma)); + + /* Finish writing out a function. */ + bfd_boolean (*end_function) PARAMS ((PTR)); + + /* Record line number information for the current compilation unit. */ + bfd_boolean (*lineno) PARAMS ((PTR, const char *, unsigned long, bfd_vma)); +}; + +/* Exported functions. */ + +/* The first argument to most of these functions is a handle. This + handle is returned by the debug_init function. The purpose of the + handle is to permit the debugging routines to not use static + variables, and hence to be reentrant. This would be useful for a + program which wanted to handle two executables simultaneously. */ + +/* Return a debugging handle. */ + +extern PTR debug_init PARAMS ((void)); + +/* Set the source filename. This implicitly starts a new compilation + unit. */ + +extern bfd_boolean debug_set_filename PARAMS ((PTR, const char *)); + +/* Change source files to the given file name. This is used for + include files in a single compilation unit. */ + +extern bfd_boolean debug_start_source PARAMS ((PTR, const char *)); + +/* Record a function definition. This implicitly starts a function + block. The debug_type argument is the type of the return value. + The bfd_boolean indicates whether the function is globally visible. + The bfd_vma is the address of the start of the function. Currently + the parameter types are specified by calls to + debug_record_parameter. */ + +extern bfd_boolean debug_record_function + PARAMS ((PTR, const char *, debug_type, bfd_boolean, bfd_vma)); + +/* Record a parameter for the current function. */ + +extern bfd_boolean debug_record_parameter + PARAMS ((PTR, const char *, debug_type, enum debug_parm_kind, bfd_vma)); + +/* End a function definition. The argument is the address where the + function ends. */ + +extern bfd_boolean debug_end_function PARAMS ((PTR, bfd_vma)); + +/* Start a block in a function. All local information will be + recorded in this block, until the matching call to debug_end_block. + debug_start_block and debug_end_block may be nested. The argument + is the address at which this block starts. */ + +extern bfd_boolean debug_start_block PARAMS ((PTR, bfd_vma)); + +/* Finish a block in a function. This matches the call to + debug_start_block. The argument is the address at which this block + ends. */ + +extern bfd_boolean debug_end_block PARAMS ((PTR, bfd_vma)); + +/* Associate a line number in the current source file with a given + address. */ + +extern bfd_boolean debug_record_line PARAMS ((PTR, unsigned long, bfd_vma)); + +/* Start a named common block. This is a block of variables that may + move in memory. */ + +extern bfd_boolean debug_start_common_block PARAMS ((PTR, const char *)); + +/* End a named common block. */ + +extern bfd_boolean debug_end_common_block PARAMS ((PTR, const char *)); + +/* Record a named integer constant. */ + +extern bfd_boolean debug_record_int_const + PARAMS ((PTR, const char *, bfd_vma)); + +/* Record a named floating point constant. */ + +extern bfd_boolean debug_record_float_const + PARAMS ((PTR, const char *, double)); + +/* Record a typed constant with an integral value. */ + +extern bfd_boolean debug_record_typed_const + PARAMS ((PTR, const char *, debug_type, bfd_vma)); + +/* Record a label. */ + +extern bfd_boolean debug_record_label + PARAMS ((PTR, const char *, debug_type, bfd_vma)); + +/* Record a variable. */ + +extern bfd_boolean debug_record_variable + PARAMS ((PTR, const char *, debug_type, enum debug_var_kind, bfd_vma)); + +/* Make an indirect type. The first argument is a pointer to the + location where the real type will be placed. The second argument + is the type tag, if there is one; this may be NULL; the only + purpose of this argument is so that debug_get_type_name can return + something useful. This function may be used when a type is + referenced before it is defined. */ + +extern debug_type debug_make_indirect_type + PARAMS ((PTR, debug_type *, const char *)); + +/* Make a void type. */ + +extern debug_type debug_make_void_type PARAMS ((PTR)); + +/* Make an integer type of a given size. The bfd_boolean argument is TRUE + if the integer is unsigned. */ + +extern debug_type debug_make_int_type + PARAMS ((PTR, unsigned int, bfd_boolean)); + +/* Make a floating point type of a given size. FIXME: On some + platforms, like an Alpha, you probably need to be able to specify + the format. */ + +extern debug_type debug_make_float_type PARAMS ((PTR, unsigned int)); + +/* Make a boolean type of a given size. */ + +extern debug_type debug_make_bool_type PARAMS ((PTR, unsigned int)); + +/* Make a complex type of a given size. */ + +extern debug_type debug_make_complex_type PARAMS ((PTR, unsigned int)); + +/* Make a structure type. The second argument is TRUE for a struct, + FALSE for a union. The third argument is the size of the struct. + The fourth argument is a NULL terminated array of fields. */ + +extern debug_type debug_make_struct_type + PARAMS ((PTR, bfd_boolean, bfd_vma, debug_field *)); + +/* Make an object type. The first three arguments after the handle + are the same as for debug_make_struct_type. The next arguments are + a NULL terminated array of base classes, a NULL terminated array of + methods, the type of the object holding the virtual function table + if it is not this object, and a bfd_boolean which is TRUE if this + object has its own virtual function table. */ + +extern debug_type debug_make_object_type + PARAMS ((PTR, bfd_boolean, bfd_vma, debug_field *, debug_baseclass *, + debug_method *, debug_type, bfd_boolean)); + +/* Make an enumeration type. The arguments are a null terminated + array of strings, and an array of corresponding values. */ + +extern debug_type debug_make_enum_type + PARAMS ((PTR, const char **, bfd_signed_vma *)); + +/* Make a pointer to a given type. */ + +extern debug_type debug_make_pointer_type + PARAMS ((PTR, debug_type)); + +/* Make a function type. The second argument is the return type. The + third argument is a NULL terminated array of argument types. The + fourth argument is TRUE if the function takes a variable number of + arguments. If the third argument is NULL, then the argument types + are unknown. */ + +extern debug_type debug_make_function_type + PARAMS ((PTR, debug_type, debug_type *, bfd_boolean)); + +/* Make a reference to a given type. */ + +extern debug_type debug_make_reference_type PARAMS ((PTR, debug_type)); + +/* Make a range of a given type from a lower to an upper bound. */ + +extern debug_type debug_make_range_type + PARAMS ((PTR, debug_type, bfd_signed_vma, bfd_signed_vma)); + +/* Make an array type. The second argument is the type of an element + of the array. The third argument is the type of a range of the + array. The fourth and fifth argument are the lower and upper + bounds, respectively (if the bounds are not known, lower should be + 0 and upper should be -1). The sixth argument is TRUE if this + array is actually a string, as in C. */ + +extern debug_type debug_make_array_type + PARAMS ((PTR, debug_type, debug_type, bfd_signed_vma, bfd_signed_vma, + bfd_boolean)); + +/* Make a set of a given type. For example, a Pascal set type. The + bfd_boolean argument is TRUE if this set is actually a bitstring, as in + CHILL. */ + +extern debug_type debug_make_set_type PARAMS ((PTR, debug_type, bfd_boolean)); + +/* Make a type for a pointer which is relative to an object. The + second argument is the type of the object to which the pointer is + relative. The third argument is the type that the pointer points + to. */ + +extern debug_type debug_make_offset_type + PARAMS ((PTR, debug_type, debug_type)); + +/* Make a type for a method function. The second argument is the + return type. The third argument is the domain. The fourth + argument is a NULL terminated array of argument types. The fifth + argument is TRUE if the function takes a variable number of + arguments, in which case the array of argument types indicates the + types of the first arguments. The domain and the argument array + may be NULL, in which case this is a stub method and that + information is not available. Stabs debugging uses this, and gets + the argument types from the mangled name. */ + +extern debug_type debug_make_method_type + PARAMS ((PTR, debug_type, debug_type, debug_type *, bfd_boolean)); + +/* Make a const qualified version of a given type. */ + +extern debug_type debug_make_const_type PARAMS ((PTR, debug_type)); + +/* Make a volatile qualified version of a given type. */ + +extern debug_type debug_make_volatile_type PARAMS ((PTR, debug_type)); + +/* Make an undefined tagged type. For example, a struct which has + been mentioned, but not defined. */ + +extern debug_type debug_make_undefined_tagged_type + PARAMS ((PTR, const char *, enum debug_type_kind)); + +/* Make a base class for an object. The second argument is the base + class type. The third argument is the bit position of this base + class in the object. The fourth argument is whether this is a + virtual class. The fifth argument is the visibility of the base + class. */ + +extern debug_baseclass debug_make_baseclass + PARAMS ((PTR, debug_type, bfd_vma, bfd_boolean, enum debug_visibility)); + +/* Make a field for a struct. The second argument is the name. The + third argument is the type of the field. The fourth argument is + the bit position of the field. The fifth argument is the size of + the field (it may be zero). The sixth argument is the visibility + of the field. */ + +extern debug_field debug_make_field + PARAMS ((PTR, const char *, debug_type, bfd_vma, bfd_vma, + enum debug_visibility)); + +/* Make a static member of an object. The second argument is the + name. The third argument is the type of the member. The fourth + argument is the physical name of the member (i.e., the name as a + global variable). The fifth argument is the visibility of the + member. */ + +extern debug_field debug_make_static_member + PARAMS ((PTR, const char *, debug_type, const char *, + enum debug_visibility)); + +/* Make a method. The second argument is the name, and the third + argument is a NULL terminated array of method variants. Each + method variant is a method with this name but with different + argument types. */ + +extern debug_method debug_make_method + PARAMS ((PTR, const char *, debug_method_variant *)); + +/* Make a method variant. The second argument is the physical name of + the function. The third argument is the type of the function, + probably constructed by debug_make_method_type. The fourth + argument is the visibility. The fifth argument is whether this is + a const function. The sixth argument is whether this is a volatile + function. The seventh argument is the index in the virtual + function table, if any. The eighth argument is the virtual + function context. */ + +extern debug_method_variant debug_make_method_variant + PARAMS ((PTR, const char *, debug_type, enum debug_visibility, bfd_boolean, + bfd_boolean, bfd_vma, debug_type)); + +/* Make a static method argument. The arguments are the same as for + debug_make_method_variant, except that the last two are omitted + since a static method can not also be virtual. */ + +extern debug_method_variant debug_make_static_method_variant + PARAMS ((PTR, const char *, debug_type, enum debug_visibility, bfd_boolean, + bfd_boolean)); + +/* Name a type. This returns a new type with an attached name. */ + +extern debug_type debug_name_type PARAMS ((PTR, const char *, debug_type)); + +/* Give a tag to a type, such as a struct or union. This returns a + new type with an attached tag. */ + +extern debug_type debug_tag_type PARAMS ((PTR, const char *, debug_type)); + +/* Record the size of a given type. */ + +extern bfd_boolean debug_record_type_size + PARAMS ((PTR, debug_type, unsigned int)); + +/* Find a named type. */ + +extern debug_type debug_find_named_type PARAMS ((PTR, const char *)); + +/* Find a tagged type. */ + +extern debug_type debug_find_tagged_type + PARAMS ((PTR, const char *, enum debug_type_kind)); + +/* Get the kind of a type. */ + +extern enum debug_type_kind debug_get_type_kind PARAMS ((PTR, debug_type)); + +/* Get the name of a type. */ + +extern const char *debug_get_type_name PARAMS ((PTR, debug_type)); + +/* Get the size of a type. */ + +extern bfd_vma debug_get_type_size PARAMS ((PTR, debug_type)); + +/* Get the return type of a function or method type. */ + +extern debug_type debug_get_return_type PARAMS ((PTR, debug_type)); + +/* Get the NULL terminated array of parameter types for a function or + method type (actually, parameter types are not currently stored for + function types). This may be used to determine whether a method + type is a stub method or not. The last argument points to a + bfd_boolean which is set to TRUE if the function takes a variable + number of arguments. */ + +extern const debug_type *debug_get_parameter_types + PARAMS ((PTR, debug_type, bfd_boolean *)); + +/* Get the target type of a pointer or reference or const or volatile + type. */ + +extern debug_type debug_get_target_type PARAMS ((PTR, debug_type)); + +/* Get the NULL terminated array of fields for a struct, union, or + class. */ + +extern const debug_field *debug_get_fields PARAMS ((PTR, debug_type)); + +/* Get the type of a field. */ + +extern debug_type debug_get_field_type PARAMS ((PTR, debug_field)); + +/* Get the name of a field. */ + +extern const char *debug_get_field_name PARAMS ((PTR, debug_field)); + +/* Get the bit position of a field within the containing structure. + If the field is a static member, this will return (bfd_vma) -1. */ + +extern bfd_vma debug_get_field_bitpos PARAMS ((PTR, debug_field)); + +/* Get the bit size of a field. If the field is a static member, this + will return (bfd_vma) -1. */ + +extern bfd_vma debug_get_field_bitsize PARAMS ((PTR, debug_field)); + +/* Get the visibility of a field. */ + +extern enum debug_visibility debug_get_field_visibility + PARAMS ((PTR, debug_field)); + +/* Get the physical name of a field, if it is a static member. If the + field is not a static member, this will return NULL. */ + +extern const char *debug_get_field_physname PARAMS ((PTR, debug_field)); + +/* Write out the recorded debugging information. This takes a set of + function pointers which are called to do the actual writing. The + first PTR is the debugging handle. The second PTR is a handle + which is passed to the functions. */ + +extern bfd_boolean debug_write + PARAMS ((PTR, const struct debug_write_fns *, PTR)); + +#endif /* DEBUG_H */ diff --git a/contrib/binutils-2.14/binutils/doc/addr2line.1 b/contrib/binutils-2.14/binutils/doc/addr2line.1 new file mode 100644 index 0000000000..69f97c8fb6 --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/addr2line.1 @@ -0,0 +1,230 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "ADDR2LINE 1" +.TH ADDR2LINE 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +addr2line \- convert addresses into file names and line numbers. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +addr2line [\fB\-b\fR \fIbfdname\fR|\fB\-\-target=\fR\fIbfdname\fR] + [\fB\-C\fR|\fB\-\-demangle\fR[=\fIstyle\fR]] + [\fB\-e\fR \fIfilename\fR|\fB\-\-exe=\fR\fIfilename\fR] + [\fB\-f\fR|\fB\-\-functions\fR] [\fB\-s\fR|\fB\-\-basename\fR] + [\fB\-H\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR] + [addr addr ...] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBaddr2line\fR translates program addresses into file names and line +numbers. Given an address and an executable, it uses the debugging +information in the executable to figure out which file name and line +number are associated with a given address. +.PP +The executable to use is specified with the \fB\-e\fR option. The +default is the file \fIa.out\fR. +.PP +\&\fBaddr2line\fR has two modes of operation. +.PP +In the first, hexadecimal addresses are specified on the command line, +and \fBaddr2line\fR displays the file name and line number for each +address. +.PP +In the second, \fBaddr2line\fR reads hexadecimal addresses from +standard input, and prints the file name and line number for each +address on standard output. In this mode, \fBaddr2line\fR may be used +in a pipe to convert dynamically chosen addresses. +.PP +The format of the output is \fB\s-1FILENAME:LINENO\s0\fR. The file name and +line number for each address is printed on a separate line. If the +\&\fB\-f\fR option is used, then each \fB\s-1FILENAME:LINENO\s0\fR line is +preceded by a \fB\s-1FUNCTIONNAME\s0\fR line which is the name of the function +containing the address. +.PP +If the file name or function name can not be determined, +\&\fBaddr2line\fR will print two question marks in their place. If the +line number can not be determined, \fBaddr2line\fR will print 0. +.SH "OPTIONS" +.IX Header "OPTIONS" +The long and short forms of options, shown here as alternatives, are +equivalent. +.IP "\fB\-b\fR \fIbfdname\fR" 4 +.IX Item "-b bfdname" +.PD 0 +.IP "\fB\-\-target=\fR\fIbfdname\fR" 4 +.IX Item "--target=bfdname" +.PD +Specify that the object-code format for the object files is +\&\fIbfdname\fR. +.IP "\fB\-C\fR" 4 +.IX Item "-C" +.PD 0 +.IP "\fB\-\-demangle[=\fR\fIstyle\fR\fB]\fR" 4 +.IX Item "--demangle[=style]" +.PD +Decode (\fIdemangle\fR) low-level symbol names into user-level names. +Besides removing any initial underscore prepended by the system, this +makes \*(C+ function names readable. Different compilers have different +mangling styles. The optional demangling style argument can be used to +choose an appropriate demangling style for your compiler. +.IP "\fB\-e\fR \fIfilename\fR" 4 +.IX Item "-e filename" +.PD 0 +.IP "\fB\-\-exe=\fR\fIfilename\fR" 4 +.IX Item "--exe=filename" +.PD +Specify the name of the executable for which addresses should be +translated. The default file is \fIa.out\fR. +.IP "\fB\-f\fR" 4 +.IX Item "-f" +.PD 0 +.IP "\fB\-\-functions\fR" 4 +.IX Item "--functions" +.PD +Display function names as well as file and line number information. +.IP "\fB\-s\fR" 4 +.IX Item "-s" +.PD 0 +.IP "\fB\-\-basenames\fR" 4 +.IX Item "--basenames" +.PD +Display only the base of each file name. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/ar.1 b/contrib/binutils-2.14/binutils/doc/ar.1 new file mode 100644 index 0000000000..d937a0efc2 --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/ar.1 @@ -0,0 +1,377 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "AR 1" +.TH AR 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +ar \- create, modify, and extract from archives +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +ar [\fB\-X32_64\fR] [\fB\-\fR]\fIp\fR[\fImod\fR [\fIrelpos\fR] [\fIcount\fR]] \fIarchive\fR [\fImember\fR...] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \s-1GNU\s0 \fBar\fR program creates, modifies, and extracts from +archives. An \fIarchive\fR is a single file holding a collection of +other files in a structure that makes it possible to retrieve +the original individual files (called \fImembers\fR of the archive). +.PP +The original files' contents, mode (permissions), timestamp, owner, and +group are preserved in the archive, and can be restored on +extraction. +.PP +\&\s-1GNU\s0 \fBar\fR can maintain archives whose members have names of any +length; however, depending on how \fBar\fR is configured on your +system, a limit on member-name length may be imposed for compatibility +with archive formats maintained with other tools. If it exists, the +limit is often 15 characters (typical of formats related to a.out) or 16 +characters (typical of formats related to coff). +.PP +\&\fBar\fR is considered a binary utility because archives of this sort +are most often used as \fIlibraries\fR holding commonly needed +subroutines. +.PP +\&\fBar\fR creates an index to the symbols defined in relocatable +object modules in the archive when you specify the modifier \fBs\fR. +Once created, this index is updated in the archive whenever \fBar\fR +makes a change to its contents (save for the \fBq\fR update operation). +An archive with such an index speeds up linking to the library, and +allows routines in the library to call each other without regard to +their placement in the archive. +.PP +You may use \fBnm \-s\fR or \fBnm \-\-print\-armap\fR to list this index +table. If an archive lacks the table, another form of \fBar\fR called +\&\fBranlib\fR can be used to add just the table. +.PP +\&\s-1GNU\s0 \fBar\fR is designed to be compatible with two different +facilities. You can control its activity using command-line options, +like the different varieties of \fBar\fR on Unix systems; or, if you +specify the single command-line option \fB\-M\fR, you can control it +with a script supplied via standard input, like the \s-1MRI\s0 ``librarian'' +program. +.SH "OPTIONS" +.IX Header "OPTIONS" +\&\s-1GNU\s0 \fBar\fR allows you to mix the operation code \fIp\fR and modifier +flags \fImod\fR in any order, within the first command-line argument. +.PP +If you wish, you may begin the first command-line argument with a +dash. +.PP +The \fIp\fR keyletter specifies what operation to execute; it may be +any of the following, but you must specify only one of them: +.IP "\fBd\fR" 4 +.IX Item "d" +\&\fIDelete\fR modules from the archive. Specify the names of modules to +be deleted as \fImember\fR...; the archive is untouched if you +specify no files to delete. +.Sp +If you specify the \fBv\fR modifier, \fBar\fR lists each module +as it is deleted. +.IP "\fBm\fR" 4 +.IX Item "m" +Use this operation to \fImove\fR members in an archive. +.Sp +The ordering of members in an archive can make a difference in how +programs are linked using the library, if a symbol is defined in more +than one member. +.Sp +If no modifiers are used with \f(CW\*(C`m\*(C'\fR, any members you name in the +\&\fImember\fR arguments are moved to the \fIend\fR of the archive; +you can use the \fBa\fR, \fBb\fR, or \fBi\fR modifiers to move them to a +specified place instead. +.IP "\fBp\fR" 4 +.IX Item "p" +\&\fIPrint\fR the specified members of the archive, to the standard +output file. If the \fBv\fR modifier is specified, show the member +name before copying its contents to standard output. +.Sp +If you specify no \fImember\fR arguments, all the files in the archive are +printed. +.IP "\fBq\fR" 4 +.IX Item "q" +\&\fIQuick append\fR; Historically, add the files \fImember\fR... to the end of +\&\fIarchive\fR, without checking for replacement. +.Sp +The modifiers \fBa\fR, \fBb\fR, and \fBi\fR do \fInot\fR affect this +operation; new members are always placed at the end of the archive. +.Sp +The modifier \fBv\fR makes \fBar\fR list each file as it is appended. +.Sp +Since the point of this operation is speed, the archive's symbol table +index is not updated, even if it already existed; you can use \fBar s\fR or +\&\fBranlib\fR explicitly to update the symbol table index. +.Sp +However, too many different systems assume quick append rebuilds the +index, so \s-1GNU\s0 \fBar\fR implements \fBq\fR as a synonym for \fBr\fR. +.IP "\fBr\fR" 4 +.IX Item "r" +Insert the files \fImember\fR... into \fIarchive\fR (with +\&\fIreplacement\fR). This operation differs from \fBq\fR in that any +previously existing members are deleted if their names match those being +added. +.Sp +If one of the files named in \fImember\fR... does not exist, \fBar\fR +displays an error message, and leaves undisturbed any existing members +of the archive matching that name. +.Sp +By default, new members are added at the end of the file; but you may +use one of the modifiers \fBa\fR, \fBb\fR, or \fBi\fR to request +placement relative to some existing member. +.Sp +The modifier \fBv\fR used with this operation elicits a line of +output for each file inserted, along with one of the letters \fBa\fR or +\&\fBr\fR to indicate whether the file was appended (no old member +deleted) or replaced. +.IP "\fBt\fR" 4 +.IX Item "t" +Display a \fItable\fR listing the contents of \fIarchive\fR, or those +of the files listed in \fImember\fR... that are present in the +archive. Normally only the member name is shown; if you also want to +see the modes (permissions), timestamp, owner, group, and size, you can +request that by also specifying the \fBv\fR modifier. +.Sp +If you do not specify a \fImember\fR, all files in the archive +are listed. +.Sp +If there is more than one file with the same name (say, \fBfie\fR) in +an archive (say \fBb.a\fR), \fBar t b.a fie\fR lists only the +first instance; to see them all, you must ask for a complete +listing\-\-\-in our example, \fBar t b.a\fR. +.IP "\fBx\fR" 4 +.IX Item "x" +\&\fIExtract\fR members (named \fImember\fR) from the archive. You can +use the \fBv\fR modifier with this operation, to request that +\&\fBar\fR list each name as it extracts it. +.Sp +If you do not specify a \fImember\fR, all files in the archive +are extracted. +.PP +A number of modifiers (\fImod\fR) may immediately follow the \fIp\fR +keyletter, to specify variations on an operation's behavior: +.IP "\fBa\fR" 4 +.IX Item "a" +Add new files \fIafter\fR an existing member of the +archive. If you use the modifier \fBa\fR, the name of an existing archive +member must be present as the \fIrelpos\fR argument, before the +\&\fIarchive\fR specification. +.IP "\fBb\fR" 4 +.IX Item "b" +Add new files \fIbefore\fR an existing member of the +archive. If you use the modifier \fBb\fR, the name of an existing archive +member must be present as the \fIrelpos\fR argument, before the +\&\fIarchive\fR specification. (same as \fBi\fR). +.IP "\fBc\fR" 4 +.IX Item "c" +\&\fICreate\fR the archive. The specified \fIarchive\fR is always +created if it did not exist, when you request an update. But a warning is +issued unless you specify in advance that you expect to create it, by +using this modifier. +.IP "\fBf\fR" 4 +.IX Item "f" +Truncate names in the archive. \s-1GNU\s0 \fBar\fR will normally permit file +names of any length. This will cause it to create archives which are +not compatible with the native \fBar\fR program on some systems. If +this is a concern, the \fBf\fR modifier may be used to truncate file +names when putting them in the archive. +.IP "\fBi\fR" 4 +.IX Item "i" +Insert new files \fIbefore\fR an existing member of the +archive. If you use the modifier \fBi\fR, the name of an existing archive +member must be present as the \fIrelpos\fR argument, before the +\&\fIarchive\fR specification. (same as \fBb\fR). +.IP "\fBl\fR" 4 +.IX Item "l" +This modifier is accepted but not used. +.IP "\fBN\fR" 4 +.IX Item "N" +Uses the \fIcount\fR parameter. This is used if there are multiple +entries in the archive with the same name. Extract or delete instance +\&\fIcount\fR of the given name from the archive. +.IP "\fBo\fR" 4 +.IX Item "o" +Preserve the \fIoriginal\fR dates of members when extracting them. If +you do not specify this modifier, files extracted from the archive +are stamped with the time of extraction. +.IP "\fBP\fR" 4 +.IX Item "P" +Use the full path name when matching names in the archive. \s-1GNU\s0 +\&\fBar\fR can not create an archive with a full path name (such archives +are not \s-1POSIX\s0 complaint), but other archive creators can. This option +will cause \s-1GNU\s0 \fBar\fR to match file names using a complete path +name, which can be convenient when extracting a single file from an +archive created by another tool. +.IP "\fBs\fR" 4 +.IX Item "s" +Write an object-file index into the archive, or update an existing one, +even if no other change is made to the archive. You may use this modifier +flag either with any operation, or alone. Running \fBar s\fR on an +archive is equivalent to running \fBranlib\fR on it. +.IP "\fBS\fR" 4 +.IX Item "S" +Do not generate an archive symbol table. This can speed up building a +large library in several steps. The resulting archive can not be used +with the linker. In order to build a symbol table, you must omit the +\&\fBS\fR modifier on the last execution of \fBar\fR, or you must run +\&\fBranlib\fR on the archive. +.IP "\fBu\fR" 4 +.IX Item "u" +Normally, \fBar r\fR... inserts all files +listed into the archive. If you would like to insert \fIonly\fR those +of the files you list that are newer than existing members of the same +names, use this modifier. The \fBu\fR modifier is allowed only for the +operation \fBr\fR (replace). In particular, the combination \fBqu\fR is +not allowed, since checking the timestamps would lose any speed +advantage from the operation \fBq\fR. +.IP "\fBv\fR" 4 +.IX Item "v" +This modifier requests the \fIverbose\fR version of an operation. Many +operations display additional information, such as filenames processed, +when the modifier \fBv\fR is appended. +.IP "\fBV\fR" 4 +.IX Item "V" +This modifier shows the version number of \fBar\fR. +.PP +\&\fBar\fR ignores an initial option spelt \fB\-X32_64\fR, for +compatibility with \s-1AIX\s0. The behaviour produced by this option is the +default for \s-1GNU\s0 \fBar\fR. \fBar\fR does not support any of the other +\&\fB\-X\fR options; in particular, it does not support \fB\-X32\fR +which is the default for \s-1AIX\s0 \fBar\fR. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fInm\fR\|(1), \fIranlib\fR\|(1), and the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/binutils.texi b/contrib/binutils-2.14/binutils/doc/binutils.texi new file mode 100644 index 0000000000..f5f06e3e1e --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/binutils.texi @@ -0,0 +1,3482 @@ +\input texinfo @c -*- Texinfo -*- +@setfilename binutils.info +@c Copyright 2001, 2002, 2003 Free Software Foundation, Inc. + +@include config.texi + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Binutils: (binutils). The GNU binary utilities. +* ar: (binutils)ar. Create, modify, and extract from archives +* nm: (binutils)nm. List symbols from object files +* objcopy: (binutils)objcopy. Copy and translate object files +* objdump: (binutils)objdump. Display information from object files +* ranlib: (binutils)ranlib. Generate index to archive contents +* readelf: (binutils)readelf. Display the contents of ELF format files. +* size: (binutils)size. List section sizes and total size +* strings: (binutils)strings. List printable strings from files +* strip: (binutils)strip. Discard symbols +* c++filt: (binutils)c++filt. Filter to demangle encoded C++ symbols +* cxxfilt: (binutils)c++filt. MS-DOS name for c++filt +* addr2line: (binutils)addr2line. Convert addresses to file and line +* nlmconv: (binutils)nlmconv. Converts object code into an NLM +* windres: (binutils)windres. Manipulate Windows resources +* dlltool: (binutils)dlltool. Create files needed to build and use DLLs +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +@c man begin COPYRIGHT +Copyright @copyright{} 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``GNU Free Documentation License''. + +@c man end +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries a copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +@end ifinfo + +@synindex ky cp +@c +@c This file documents the GNU binary utilities "ar", "ld", "objcopy", +@c "objdump", "nm", "size", "strings", "strip", "readelf" and "ranlib". +@c +@c Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, +@c 2002, 2003 Free Software Foundation, Inc. +@c +@c This text may be freely distributed under the terms of the GNU +@c Free Documentation License. +@c + +@setchapternewpage odd +@settitle @sc{gnu} Binary Utilities +@titlepage +@finalout +@title The @sc{gnu} Binary Utilities +@subtitle Version @value{VERSION} +@sp 1 +@subtitle May 1993 +@author Roland H. Pesch +@author Jeffrey M. Osier +@author Cygnus Support +@page + +@tex +{\parskip=0pt \hfill Cygnus Support\par \hfill +\TeX{}info \texinfoversion\par } +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1991, 92, 93, 94, 95, 96, 97, 1998, 2000, 2001, +2002, 2003 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.1 + or any later version published by the Free Software Foundation; + with no Invariant Sections, with no Front-Cover Texts, and with no + Back-Cover Texts. A copy of the license is included in the + section entitled ``GNU Free Documentation License''. + +@end titlepage + +@node Top +@top Introduction + +@cindex version +This brief manual contains documentation for the @sc{gnu} binary +utilities (collectively version @value{VERSION}): + +@iftex +@table @code +@item ar +Create, modify, and extract from archives + +@item nm +List symbols from object files + +@item objcopy +Copy and translate object files + +@item objdump +Display information from object files + +@item ranlib +Generate index to archive contents + +@item readelf +Display the contents of ELF format files. + +@item size +List file section sizes and total size + +@item strings +List printable strings from files + +@item strip +Discard symbols + +@item c++filt +Demangle encoded C++ symbols (on MS-DOS, this program is named +@code{cxxfilt}) + +@item addr2line +Convert addresses into file names and line numbers + +@item nlmconv +Convert object code into a Netware Loadable Module + +@item windres +Manipulate Windows resources + +@item dlltool +Create the files needed to build and use Dynamic Link Libraries +@end table +@end iftex + +This document is distributed under the terms of the GNU Free +Documentation License. A copy of the license is included in the +section entitled "GNU Free Documentation License". + +@menu +* ar:: Create, modify, and extract from archives +* nm:: List symbols from object files +* objcopy:: Copy and translate object files +* objdump:: Display information from object files +* ranlib:: Generate index to archive contents +* readelf:: Display the contents of ELF format files. +* size:: List section sizes and total size +* strings:: List printable strings from files +* strip:: Discard symbols +* c++filt:: Filter to demangle encoded C++ symbols +* cxxfilt: c++filt. MS-DOS name for c++filt +* addr2line:: Convert addresses to file and line +* nlmconv:: Converts object code into an NLM +* windres:: Manipulate Windows resources +* dlltool:: Create files needed to build and use DLLs +* Selecting The Target System:: How these utilities determine the target. +* Reporting Bugs:: Reporting Bugs +* GNU Free Documentation License:: GNU Free Documentation License +* Index:: Index +@end menu + +@node ar +@chapter ar + +@kindex ar +@cindex archives +@cindex collections of files + +@c man title ar create, modify, and extract from archives + +@smallexample +ar [-]@var{p}[@var{mod} [@var{relpos}] [@var{count}]] @var{archive} [@var{member}@dots{}] +ar -M [ }), and continues executing even after +errors. If you redirect standard input to a script file, no prompts are +issued, and @command{ar} abandons execution (with a nonzero exit code) +on any error. + +The @command{ar} command language is @emph{not} designed to be equivalent +to the command-line options; in fact, it provides somewhat less control +over archives. The only purpose of the command language is to ease the +transition to @sc{gnu} @command{ar} for developers who already have scripts +written for the MRI ``librarian'' program. + +The syntax for the @command{ar} command language is straightforward: +@itemize @bullet +@item +commands are recognized in upper or lower case; for example, @code{LIST} +is the same as @code{list}. In the following descriptions, commands are +shown in upper case for clarity. + +@item +a single command may appear on each line; it is the first word on the +line. + +@item +empty lines are allowed, and have no effect. + +@item +comments are allowed; text after either of the characters @samp{*} +or @samp{;} is ignored. + +@item +Whenever you use a list of names as part of the argument to an @command{ar} +command, you can separate the individual names with either commas or +blanks. Commas are shown in the explanations below, for clarity. + +@item +@samp{+} is used as a line continuation character; if @samp{+} appears +at the end of a line, the text on the following line is considered part +of the current command. +@end itemize + +Here are the commands you can use in @command{ar} scripts, or when using +@command{ar} interactively. Three of them have special significance: + +@code{OPEN} or @code{CREATE} specify a @dfn{current archive}, which is +a temporary file required for most of the other commands. + +@code{SAVE} commits the changes so far specified by the script. Prior +to @code{SAVE}, commands affect only the temporary copy of the current +archive. + +@table @code +@item ADDLIB @var{archive} +@itemx ADDLIB @var{archive} (@var{module}, @var{module}, @dots{} @var{module}) +Add all the contents of @var{archive} (or, if specified, each named +@var{module} from @var{archive}) to the current archive. + +Requires prior use of @code{OPEN} or @code{CREATE}. + +@item ADDMOD @var{member}, @var{member}, @dots{} @var{member} +@c FIXME! w/Replacement?? If so, like "ar r @var{archive} @var{names}" +@c else like "ar q..." +Add each named @var{member} as a module in the current archive. + +Requires prior use of @code{OPEN} or @code{CREATE}. + +@item CLEAR +Discard the contents of the current archive, canceling the effect of +any operations since the last @code{SAVE}. May be executed (with no +effect) even if no current archive is specified. + +@item CREATE @var{archive} +Creates an archive, and makes it the current archive (required for many +other commands). The new archive is created with a temporary name; it +is not actually saved as @var{archive} until you use @code{SAVE}. +You can overwrite existing archives; similarly, the contents of any +existing file named @var{archive} will not be destroyed until @code{SAVE}. + +@item DELETE @var{module}, @var{module}, @dots{} @var{module} +Delete each listed @var{module} from the current archive; equivalent to +@samp{ar -d @var{archive} @var{module} @dots{} @var{module}}. + +Requires prior use of @code{OPEN} or @code{CREATE}. + +@item DIRECTORY @var{archive} (@var{module}, @dots{} @var{module}) +@itemx DIRECTORY @var{archive} (@var{module}, @dots{} @var{module}) @var{outputfile} +List each named @var{module} present in @var{archive}. The separate +command @code{VERBOSE} specifies the form of the output: when verbose +output is off, output is like that of @samp{ar -t @var{archive} +@var{module}@dots{}}. When verbose output is on, the listing is like +@samp{ar -tv @var{archive} @var{module}@dots{}}. + +Output normally goes to the standard output stream; however, if you +specify @var{outputfile} as a final argument, @command{ar} directs the +output to that file. + +@item END +Exit from @command{ar}, with a @code{0} exit code to indicate successful +completion. This command does not save the output file; if you have +changed the current archive since the last @code{SAVE} command, those +changes are lost. + +@item EXTRACT @var{module}, @var{module}, @dots{} @var{module} +Extract each named @var{module} from the current archive, writing them +into the current directory as separate files. Equivalent to @samp{ar -x +@var{archive} @var{module}@dots{}}. + +Requires prior use of @code{OPEN} or @code{CREATE}. + +@ignore +@c FIXME Tokens but no commands??? +@item FULLDIR + +@item HELP +@end ignore + +@item LIST +Display full contents of the current archive, in ``verbose'' style +regardless of the state of @code{VERBOSE}. The effect is like @samp{ar +tv @var{archive}}. (This single command is a @sc{gnu} @command{ar} +enhancement, rather than present for MRI compatibility.) + +Requires prior use of @code{OPEN} or @code{CREATE}. + +@item OPEN @var{archive} +Opens an existing archive for use as the current archive (required for +many other commands). Any changes as the result of subsequent commands +will not actually affect @var{archive} until you next use @code{SAVE}. + +@item REPLACE @var{module}, @var{module}, @dots{} @var{module} +In the current archive, replace each existing @var{module} (named in +the @code{REPLACE} arguments) from files in the current working directory. +To execute this command without errors, both the file, and the module in +the current archive, must exist. + +Requires prior use of @code{OPEN} or @code{CREATE}. + +@item VERBOSE +Toggle an internal flag governing the output from @code{DIRECTORY}. +When the flag is on, @code{DIRECTORY} output matches output from +@samp{ar -tv }@dots{}. + +@item SAVE +Commit your changes to the current archive, and actually save it as a +file with the name specified in the last @code{CREATE} or @code{OPEN} +command. + +Requires prior use of @code{OPEN} or @code{CREATE}. + +@end table + +@iftex +@node ld +@chapter ld +@cindex linker +@kindex ld +The @sc{gnu} linker @command{ld} is now described in a separate manual. +@xref{Top,, Overview,, Using LD: the @sc{gnu} linker}. +@end iftex + +@node nm +@chapter nm +@cindex symbols +@kindex nm + +@c man title nm list symbols from object files + +@smallexample +@c man begin SYNOPSIS nm +nm [@option{-a}|@option{--debug-syms}] [@option{-g}|@option{--extern-only}] + [@option{-B}] [@option{-C}|@option{--demangle}[=@var{style}]] [@option{-D}|@option{--dynamic}] + [@option{-S}|@option{--print-size}] [@option{-s}|@option{--print-armap}] + [@option{-A}|@option{-o}|@option{--print-file-name}] + [@option{-n}|@option{-v}|@option{--numeric-sort}] [@option{-p}|@option{--no-sort}] + [@option{-r}|@option{--reverse-sort}] [@option{--size-sort}] [@option{-u}|@option{--undefined-only}] + [@option{-t} @var{radix}|@option{--radix=}@var{radix}] [@option{-P}|@option{--portability}] + [@option{--target=}@var{bfdname}] [@option{-f}@var{format}|@option{--format=}@var{format}] + [@option{--defined-only}] [@option{-l}|@option{--line-numbers}] [@option{--no-demangle}] + [@option{-V}|@option{--version}] [@option{-X 32_64}] [@option{--help}] [@var{objfile}@dots{}] +@c man end +@end smallexample + +@c man begin DESCRIPTION nm +@sc{gnu} @command{nm} lists the symbols from object files @var{objfile}@dots{}. +If no object files are listed as arguments, @command{nm} assumes the file +@file{a.out}. + +For each symbol, @command{nm} shows: + +@itemize @bullet +@item +The symbol value, in the radix selected by options (see below), or +hexadecimal by default. + +@item +The symbol type. At least the following types are used; others are, as +well, depending on the object file format. If lowercase, the symbol is +local; if uppercase, the symbol is global (external). + +@c Some more detail on exactly what these symbol types are used for +@c would be nice. +@table @code +@item A +The symbol's value is absolute, and will not be changed by further +linking. + +@item B +The symbol is in the uninitialized data section (known as BSS). + +@item C +The symbol is common. Common symbols are uninitialized data. When +linking, multiple common symbols may appear with the same name. If the +symbol is defined anywhere, the common symbols are treated as undefined +references. +@ifclear man +For more details on common symbols, see the discussion of +--warn-common in @ref{Options,,Linker options,ld.info,The GNU linker}. +@end ifclear + +@item D +The symbol is in the initialized data section. + +@item G +The symbol is in an initialized data section for small objects. Some +object file formats permit more efficient access to small data objects, +such as a global int variable as opposed to a large global array. + +@item I +The symbol is an indirect reference to another symbol. This is a @sc{gnu} +extension to the a.out object file format which is rarely used. + +@item N +The symbol is a debugging symbol. + +@item R +The symbol is in a read only data section. + +@item S +The symbol is in an uninitialized data section for small objects. + +@item T +The symbol is in the text (code) section. + +@item U +The symbol is undefined. + +@item V +The symbol is a weak object. When a weak defined symbol is linked with +a normal defined symbol, the normal defined symbol is used with no error. +When a weak undefined symbol is linked and the symbol is not defined, +the value of the weak symbol becomes zero with no error. + +@item W +The symbol is a weak symbol that has not been specifically tagged as a +weak object symbol. When a weak defined symbol is linked with a normal +defined symbol, the normal defined symbol is used with no error. +When a weak undefined symbol is linked and the symbol is not defined, +the value of the weak symbol becomes zero with no error. + +@item - +The symbol is a stabs symbol in an a.out object file. In this case, the +next values printed are the stabs other field, the stabs desc field, and +the stab type. Stabs symbols are used to hold debugging information. +@ifclear man +For more information, see @ref{Top,Stabs,Stabs Overview,stabs.info, The +``stabs'' debug format}. +@end ifclear + +@item ? +The symbol type is unknown, or object file format specific. +@end table + +@item +The symbol name. +@end itemize + +@c man end + +@c man begin OPTIONS nm +The long and short forms of options, shown here as alternatives, are +equivalent. + +@table @env +@item -A +@itemx -o +@itemx --print-file-name +@cindex input file name +@cindex file name +@cindex source file name +Precede each symbol by the name of the input file (or archive member) +in which it was found, rather than identifying the input file once only, +before all of its symbols. + +@item -a +@itemx --debug-syms +@cindex debugging symbols +Display all symbols, even debugger-only symbols; normally these are not +listed. + +@item -B +@cindex @command{nm} format +@cindex @command{nm} compatibility +The same as @option{--format=bsd} (for compatibility with the MIPS @command{nm}). + +@item -C +@itemx --demangle[=@var{style}] +@cindex demangling in nm +Decode (@dfn{demangle}) low-level symbol names into user-level names. +Besides removing any initial underscore prepended by the system, this +makes C++ function names readable. Different compilers have different +mangling styles. The optional demangling style argument can be used to +choose an appropriate demangling style for your compiler. @xref{c++filt}, +for more information on demangling. + +@item --no-demangle +Do not demangle low-level symbol names. This is the default. + +@item -D +@itemx --dynamic +@cindex dynamic symbols +Display the dynamic symbols rather than the normal symbols. This is +only meaningful for dynamic objects, such as certain types of shared +libraries. + +@item -f @var{format} +@itemx --format=@var{format} +@cindex @command{nm} format +@cindex @command{nm} compatibility +Use the output format @var{format}, which can be @code{bsd}, +@code{sysv}, or @code{posix}. The default is @code{bsd}. +Only the first character of @var{format} is significant; it can be +either upper or lower case. + +@item -g +@itemx --extern-only +@cindex external symbols +Display only external symbols. + +@item -l +@itemx --line-numbers +@cindex symbol line numbers +For each symbol, use debugging information to try to find a filename and +line number. For a defined symbol, look for the line number of the +address of the symbol. For an undefined symbol, look for the line +number of a relocation entry which refers to the symbol. If line number +information can be found, print it after the other symbol information. + +@item -n +@itemx -v +@itemx --numeric-sort +Sort symbols numerically by their addresses, rather than alphabetically +by their names. + +@item -p +@itemx --no-sort +@cindex sorting symbols +Do not bother to sort the symbols in any order; print them in the order +encountered. + +@item -P +@itemx --portability +Use the POSIX.2 standard output format instead of the default format. +Equivalent to @samp{-f posix}. + +@item -S +@itemx --print-size +Print size, not the value, of defined symbols for the @code{bsd} output format. + +@item -s +@itemx --print-armap +@cindex symbol index, listing +When listing symbols from archive members, include the index: a mapping +(stored in the archive by @command{ar} or @command{ranlib}) of which modules +contain definitions for which names. + +@item -r +@itemx --reverse-sort +Reverse the order of the sort (whether numeric or alphabetic); let the +last come first. + +@item --size-sort +Sort symbols by size. The size is computed as the difference between +the value of the symbol and the value of the symbol with the next higher +value. If the @code{bsd} output format is used the size of the symbol +is printed, rather than the value, and @samp{-S} must be used in order +both size and value to be printed. + +@item -t @var{radix} +@itemx --radix=@var{radix} +Use @var{radix} as the radix for printing the symbol values. It must be +@samp{d} for decimal, @samp{o} for octal, or @samp{x} for hexadecimal. + +@item --target=@var{bfdname} +@cindex object code format +Specify an object code format other than your system's default format. +@xref{Target Selection}, for more information. + +@item -u +@itemx --undefined-only +@cindex external symbols +@cindex undefined symbols +Display only undefined symbols (those external to each object file). + +@item --defined-only +@cindex external symbols +@cindex undefined symbols +Display only defined symbols for each object file. + +@item -V +@itemx --version +Show the version number of @command{nm} and exit. + +@item -X +This option is ignored for compatibility with the AIX version of +@command{nm}. It takes one parameter which must be the string +@option{32_64}. The default mode of AIX @command{nm} corresponds +to @option{-X 32}, which is not supported by @sc{gnu} @command{nm}. + +@item --help +Show a summary of the options to @command{nm} and exit. +@end table + +@c man end + +@ignore +@c man begin SEEALSO nm +ar(1), objdump(1), ranlib(1), and the Info entries for @file{binutils}. +@c man end +@end ignore + +@node objcopy +@chapter objcopy + +@c man title objcopy copy and translate object files + +@smallexample +@c man begin SYNOPSIS objcopy +objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}] + [@option{-I} @var{bfdname}|@option{--input-target=}@var{bfdname}] + [@option{-O} @var{bfdname}|@option{--output-target=}@var{bfdname}] + [@option{-B} @var{bfdarch}|@option{--binary-architecture=}@var{bfdarch}] + [@option{-S}|@option{--strip-all}] [@option{-g}|@option{--strip-debug}] + [@option{-K} @var{symbolname}|@option{--keep-symbol=}@var{symbolname}] + [@option{-N} @var{symbolname}|@option{--strip-symbol=}@var{symbolname}] + [@option{-G} @var{symbolname}|@option{--keep-global-symbol=}@var{symbolname}] + [@option{-L} @var{symbolname}|@option{--localize-symbol=}@var{symbolname}] + [@option{-W} @var{symbolname}|@option{--weaken-symbol=}@var{symbolname}] + [@option{-x}|@option{--discard-all}] [@option{-X}|@option{--discard-locals}] + [@option{-b} @var{byte}|@option{--byte=}@var{byte}] + [@option{-i} @var{interleave}|@option{--interleave=}@var{interleave}] + [@option{-j} @var{sectionname}|@option{--only-section=}@var{sectionname}] + [@option{-R} @var{sectionname}|@option{--remove-section=}@var{sectionname}] + [@option{-p}|@option{--preserve-dates}] + [@option{--debugging}] + [@option{--gap-fill=}@var{val}] [@option{--pad-to=}@var{address}] + [@option{--set-start=}@var{val}] [@option{--adjust-start=}@var{incr}] + [@option{--change-addresses=}@var{incr}] + [@option{--change-section-address} @var{section}@{=,+,-@}@var{val}] + [@option{--change-section-lma} @var{section}@{=,+,-@}@var{val}] + [@option{--change-section-vma} @var{section}@{=,+,-@}@var{val}] + [@option{--change-warnings}] [@option{--no-change-warnings}] + [@option{--set-section-flags} @var{section}=@var{flags}] + [@option{--add-section} @var{sectionname}=@var{filename}] + [@option{--rename-section} @var{oldname}=@var{newname}[,@var{flags}]] + [@option{--change-leading-char} ] [@option{--remove-leading-char}] + [@option{--srec-len=}@var{ival} ] [@option{--srec-forceS3}] + [@option{--redefine-sym} @var{old}=@var{new} ] + [@option{--weaken}] + [@option{--keep-symbols=}@var{filename}] + [@option{--strip-symbols=}@var{filename}] + [@option{--keep-global-symbols=}@var{filename}] + [@option{--localize-symbols=}@var{filename}] + [@option{--weaken-symbols=}@var{filename}] + [@option{--alt-machine-code=}@var{index}] + [@option{--prefix-symbols=}@var{string}] + [@option{--prefix-sections=}@var{string}] + [@option{--prefix-alloc-sections=}@var{string}] + [@option{-v}|@option{--verbose}] + [@option{-V}|@option{--version}] + [@option{--help}] [@option{--info}] + @var{infile} [@var{outfile}] +@c man end +@end smallexample + +@c man begin DESCRIPTION objcopy +The @sc{gnu} @command{objcopy} utility copies the contents of an object +file to another. @command{objcopy} uses the @sc{gnu} @sc{bfd} Library to +read and write the object files. It can write the destination object +file in a format different from that of the source object file. The +exact behavior of @command{objcopy} is controlled by command-line options. +Note that @command{objcopy} should be able to copy a fully linked file +between any two formats. However, copying a relocatable object file +between any two formats may not work as expected. + +@command{objcopy} creates temporary files to do its translations and +deletes them afterward. @command{objcopy} uses @sc{bfd} to do all its +translation work; it has access to all the formats described in @sc{bfd} +and thus is able to recognize most formats without being told +explicitly. @xref{BFD,,BFD,ld.info,Using LD}. + +@command{objcopy} can be used to generate S-records by using an output +target of @samp{srec} (e.g., use @samp{-O srec}). + +@command{objcopy} can be used to generate a raw binary file by using an +output target of @samp{binary} (e.g., use @option{-O binary}). When +@command{objcopy} generates a raw binary file, it will essentially produce +a memory dump of the contents of the input object file. All symbols and +relocation information will be discarded. The memory dump will start at +the load address of the lowest section copied into the output file. + +When generating an S-record or a raw binary file, it may be helpful to +use @option{-S} to remove sections containing debugging information. In +some cases @option{-R} will be useful to remove sections which contain +information that is not needed by the binary file. + +Note---@command{objcopy} is not able to change the endianness of its input +files. If the input format has an endianness (some formats do not), +@command{objcopy} can only copy the inputs into file formats that have the +same endianness or which have no endianness (e.g., @samp{srec}). + +@c man end + +@c man begin OPTIONS objcopy + +@table @env +@item @var{infile} +@itemx @var{outfile} +The input and output files, respectively. +If you do not specify @var{outfile}, @command{objcopy} creates a +temporary file and destructively renames the result with +the name of @var{infile}. + +@item -I @var{bfdname} +@itemx --input-target=@var{bfdname} +Consider the source file's object format to be @var{bfdname}, rather than +attempting to deduce it. @xref{Target Selection}, for more information. + +@item -O @var{bfdname} +@itemx --output-target=@var{bfdname} +Write the output file using the object format @var{bfdname}. +@xref{Target Selection}, for more information. + +@item -F @var{bfdname} +@itemx --target=@var{bfdname} +Use @var{bfdname} as the object format for both the input and the output +file; i.e., simply transfer data from source to destination with no +translation. @xref{Target Selection}, for more information. + +@item -B @var{bfdarch} +@itemx --binary-architecture=@var{bfdarch} +Useful when transforming a raw binary input file into an object file. +In this case the output architecture can be set to @var{bfdarch}. This +option will be ignored if the input file has a known @var{bfdarch}. You +can access this binary data inside a program by referencing the special +symbols that are created by the conversion process. These symbols are +called _binary_@var{objfile}_start, _binary_@var{objfile}_end and +_binary_@var{objfile}_size. e.g. you can transform a picture file into +an object file and then access it in your code using these symbols. + +@item -j @var{sectionname} +@itemx --only-section=@var{sectionname} +Copy only the named section from the input file to the output file. +This option may be given more than once. Note that using this option +inappropriately may make the output file unusable. + +@item -R @var{sectionname} +@itemx --remove-section=@var{sectionname} +Remove any section named @var{sectionname} from the output file. This +option may be given more than once. Note that using this option +inappropriately may make the output file unusable. + +@item -S +@itemx --strip-all +Do not copy relocation and symbol information from the source file. + +@item -g +@itemx --strip-debug +Do not copy debugging symbols from the source file. + +@item --strip-unneeded +Strip all symbols that are not needed for relocation processing. + +@item -K @var{symbolname} +@itemx --keep-symbol=@var{symbolname} +Copy only symbol @var{symbolname} from the source file. This option may +be given more than once. + +@item -N @var{symbolname} +@itemx --strip-symbol=@var{symbolname} +Do not copy symbol @var{symbolname} from the source file. This option +may be given more than once. + +@item -G @var{symbolname} +@itemx --keep-global-symbol=@var{symbolname} +Keep only symbol @var{symbolname} global. Make all other symbols local +to the file, so that they are not visible externally. This option may +be given more than once. + +@item -L @var{symbolname} +@itemx --localize-symbol=@var{symbolname} +Make symbol @var{symbolname} local to the file, so that it is not +visible externally. This option may be given more than once. + +@item -W @var{symbolname} +@itemx --weaken-symbol=@var{symbolname} +Make symbol @var{symbolname} weak. This option may be given more than once. + +@item -x +@itemx --discard-all +Do not copy non-global symbols from the source file. +@c FIXME any reason to prefer "non-global" to "local" here? + +@item -X +@itemx --discard-locals +Do not copy compiler-generated local symbols. +(These usually start with @samp{L} or @samp{.}.) + +@item -b @var{byte} +@itemx --byte=@var{byte} +Keep only every @var{byte}th byte of the input file (header data is not +affected). @var{byte} can be in the range from 0 to @var{interleave}-1, +where @var{interleave} is given by the @option{-i} or @option{--interleave} +option, or the default of 4. This option is useful for creating files +to program @sc{rom}. It is typically used with an @code{srec} output +target. + +@item -i @var{interleave} +@itemx --interleave=@var{interleave} +Only copy one out of every @var{interleave} bytes. Select which byte to +copy with the @option{-b} or @option{--byte} option. The default is 4. +@command{objcopy} ignores this option if you do not specify either @option{-b} or +@option{--byte}. + +@item -p +@itemx --preserve-dates +Set the access and modification dates of the output file to be the same +as those of the input file. + +@item --debugging +Convert debugging information, if possible. This is not the default +because only certain debugging formats are supported, and the +conversion process can be time consuming. + +@item --gap-fill @var{val} +Fill gaps between sections with @var{val}. This operation applies to +the @emph{load address} (LMA) of the sections. It is done by increasing +the size of the section with the lower address, and filling in the extra +space created with @var{val}. + +@item --pad-to @var{address} +Pad the output file up to the load address @var{address}. This is +done by increasing the size of the last section. The extra space is +filled in with the value specified by @option{--gap-fill} (default zero). + +@item --set-start @var{val} +Set the start address of the new file to @var{val}. Not all object file +formats support setting the start address. + +@item --change-start @var{incr} +@itemx --adjust-start @var{incr} +@cindex changing start address +Change the start address by adding @var{incr}. Not all object file +formats support setting the start address. + +@item --change-addresses @var{incr} +@itemx --adjust-vma @var{incr} +@cindex changing object addresses +Change the VMA and LMA addresses of all sections, as well as the start +address, by adding @var{incr}. Some object file formats do not permit +section addresses to be changed arbitrarily. Note that this does not +relocate the sections; if the program expects sections to be loaded at a +certain address, and this option is used to change the sections such +that they are loaded at a different address, the program may fail. + +@item --change-section-address @var{section}@{=,+,-@}@var{val} +@itemx --adjust-section-vma @var{section}@{=,+,-@}@var{val} +@cindex changing section address +Set or change both the VMA address and the LMA address of the named +@var{section}. If @samp{=} is used, the section address is set to +@var{val}. Otherwise, @var{val} is added to or subtracted from the +section address. See the comments under @option{--change-addresses}, +above. If @var{section} does not exist in the input file, a warning will +be issued, unless @option{--no-change-warnings} is used. + +@item --change-section-lma @var{section}@{=,+,-@}@var{val} +@cindex changing section LMA +Set or change the LMA address of the named @var{section}. The LMA +address is the address where the section will be loaded into memory at +program load time. Normally this is the same as the VMA address, which +is the address of the section at program run time, but on some systems, +especially those where a program is held in ROM, the two can be +different. If @samp{=} is used, the section address is set to +@var{val}. Otherwise, @var{val} is added to or subtracted from the +section address. See the comments under @option{--change-addresses}, +above. If @var{section} does not exist in the input file, a warning +will be issued, unless @option{--no-change-warnings} is used. + +@item --change-section-vma @var{section}@{=,+,-@}@var{val} +@cindex changing section VMA +Set or change the VMA address of the named @var{section}. The VMA +address is the address where the section will be located once the +program has started executing. Normally this is the same as the LMA +address, which is the address where the section will be loaded into +memory, but on some systems, especially those where a program is held in +ROM, the two can be different. If @samp{=} is used, the section address +is set to @var{val}. Otherwise, @var{val} is added to or subtracted +from the section address. See the comments under +@option{--change-addresses}, above. If @var{section} does not exist in +the input file, a warning will be issued, unless +@option{--no-change-warnings} is used. + +@item --change-warnings +@itemx --adjust-warnings +If @option{--change-section-address} or @option{--change-section-lma} or +@option{--change-section-vma} is used, and the named section does not +exist, issue a warning. This is the default. + +@item --no-change-warnings +@itemx --no-adjust-warnings +Do not issue a warning if @option{--change-section-address} or +@option{--adjust-section-lma} or @option{--adjust-section-vma} is used, even +if the named section does not exist. + +@item --set-section-flags @var{section}=@var{flags} +Set the flags for the named section. The @var{flags} argument is a +comma separated string of flag names. The recognized names are +@samp{alloc}, @samp{contents}, @samp{load}, @samp{noload}, +@samp{readonly}, @samp{code}, @samp{data}, @samp{rom}, @samp{share}, and +@samp{debug}. You can set the @samp{contents} flag for a section which +does not have contents, but it is not meaningful to clear the +@samp{contents} flag of a section which does have contents--just remove +the section instead. Not all flags are meaningful for all object file +formats. + +@item --add-section @var{sectionname}=@var{filename} +Add a new section named @var{sectionname} while copying the file. The +contents of the new section are taken from the file @var{filename}. The +size of the section will be the size of the file. This option only +works on file formats which can support sections with arbitrary names. + +@item --rename-section @var{oldname}=@var{newname}[,@var{flags}] +Rename a section from @var{oldname} to @var{newname}, optionally +changing the section's flags to @var{flags} in the process. This has +the advantage over usng a linker script to perform the rename in that +the output stays as an object file and does not become a linked +executable. + +This option is particularly helpful when the input format is binary, +since this will always create a section called .data. If for example, +you wanted instead to create a section called .rodata containing binary +data you could use the following command line to achieve it: + +@smallexample + objcopy -I binary -O -B \ + --rename-section .data=.rodata,alloc,load,readonly,data,contents \ + +@end smallexample + +@item --change-leading-char +Some object file formats use special characters at the start of +symbols. The most common such character is underscore, which compilers +often add before every symbol. This option tells @command{objcopy} to +change the leading character of every symbol when it converts between +object file formats. If the object file formats use the same leading +character, this option has no effect. Otherwise, it will add a +character, or remove a character, or change a character, as +appropriate. + +@item --remove-leading-char +If the first character of a global symbol is a special symbol leading +character used by the object file format, remove the character. The +most common symbol leading character is underscore. This option will +remove a leading underscore from all global symbols. This can be useful +if you want to link together objects of different file formats with +different conventions for symbol names. This is different from +@option{--change-leading-char} because it always changes the symbol name +when appropriate, regardless of the object file format of the output +file. + +@item --srec-len=@var{ival} +Meaningful only for srec output. Set the maximum length of the Srecords +being produced to @var{ival}. This length covers both address, data and +crc fields. + +@item --srec-forceS3 +Meaningful only for srec output. Avoid generation of S1/S2 records, +creating S3-only record format. + +@item --redefine-sym @var{old}=@var{new} +Change the name of a symbol @var{old}, to @var{new}. This can be useful +when one is trying link two things together for which you have no +source, and there are name collisions. + +@item --weaken +Change all global symbols in the file to be weak. This can be useful +when building an object which will be linked against other objects using +the @option{-R} option to the linker. This option is only effective when +using an object file format which supports weak symbols. + +@item --keep-symbols=@var{filename} +Apply @option{--keep-symbol} option to each symbol listed in the file +@var{filename}. @var{filename} is simply a flat file, with one symbol +name per line. Line comments may be introduced by the hash character. +This option may be given more than once. + +@item --strip-symbols=@var{filename} +Apply @option{--strip-symbol} option to each symbol listed in the file +@var{filename}. @var{filename} is simply a flat file, with one symbol +name per line. Line comments may be introduced by the hash character. +This option may be given more than once. + +@item --keep-global-symbols=@var{filename} +Apply @option{--keep-global-symbol} option to each symbol listed in the +file @var{filename}. @var{filename} is simply a flat file, with one +symbol name per line. Line comments may be introduced by the hash +character. This option may be given more than once. + +@item --localize-symbols=@var{filename} +Apply @option{--localize-symbol} option to each symbol listed in the file +@var{filename}. @var{filename} is simply a flat file, with one symbol +name per line. Line comments may be introduced by the hash character. +This option may be given more than once. + +@item --weaken-symbols=@var{filename} +Apply @option{--weaken-symbol} option to each symbol listed in the file +@var{filename}. @var{filename} is simply a flat file, with one symbol +name per line. Line comments may be introduced by the hash character. +This option may be given more than once. + +@item --alt-machine-code=@var{index} +If the output architecture has alternate machine codes, use the +@var{index}th code instead of the default one. This is useful in case +a machine is assigned an official code and the tool-chain adopts the +new code, but other applications still depend on the original code +being used. + +@item --prefix-symbols=@var{string} +Prefix all symbols in the output file with @var{string}. + +@item --prefix-sections=@var{string} +Prefix all section names in the output file with @var{string}. + +@item --prefix-alloc-sections=@var{string} +Prefix all the names of all allocated sections in the output file with +@var{string}. + +@item -V +@itemx --version +Show the version number of @command{objcopy}. + +@item -v +@itemx --verbose +Verbose output: list all object files modified. In the case of +archives, @samp{objcopy -V} lists all members of the archive. + +@item --help +Show a summary of the options to @command{objcopy}. + +@item --info +Display a list showing all architectures and object formats available. +@end table + +@c man end + +@ignore +@c man begin SEEALSO objcopy +ld(1), objdump(1), and the Info entries for @file{binutils}. +@c man end +@end ignore + +@node objdump +@chapter objdump + +@cindex object file information +@kindex objdump + +@c man title objdump display information from object files. + +@smallexample +@c man begin SYNOPSIS objdump +objdump [@option{-a}|@option{--archive-headers}] + [@option{-b} @var{bfdname}|@option{--target=@var{bfdname}}] + [@option{-C}|@option{--demangle}[=@var{style}] ] + [@option{-d}|@option{--disassemble}] + [@option{-D}|@option{--disassemble-all}] + [@option{-z}|@option{--disassemble-zeroes}] + [@option{-EB}|@option{-EL}|@option{--endian=}@{big | little @}] + [@option{-f}|@option{--file-headers}] + [@option{--file-start-context}] + [@option{-g}|@option{--debugging}] + [@option{-h}|@option{--section-headers}|@option{--headers}] + [@option{-i}|@option{--info}] + [@option{-j} @var{section}|@option{--section=}@var{section}] + [@option{-l}|@option{--line-numbers}] + [@option{-S}|@option{--source}] + [@option{-m} @var{machine}|@option{--architecture=}@var{machine}] + [@option{-M} @var{options}|@option{--disassembler-options=}@var{options}] + [@option{-p}|@option{--private-headers}] + [@option{-r}|@option{--reloc}] + [@option{-R}|@option{--dynamic-reloc}] + [@option{-s}|@option{--full-contents}] + [@option{-G}|@option{--stabs}] + [@option{-t}|@option{--syms}] + [@option{-T}|@option{--dynamic-syms}] + [@option{-x}|@option{--all-headers}] + [@option{-w}|@option{--wide}] + [@option{--start-address=}@var{address}] + [@option{--stop-address=}@var{address}] + [@option{--prefix-addresses}] + [@option{--[no-]show-raw-insn}] + [@option{--adjust-vma=}@var{offset}] + [@option{-V}|@option{--version}] + [@option{-H}|@option{--help}] + @var{objfile}@dots{} +@c man end +@end smallexample + +@c man begin DESCRIPTION objdump + +@command{objdump} displays information about one or more object files. +The options control what particular information to display. This +information is mostly useful to programmers who are working on the +compilation tools, as opposed to programmers who just want their +program to compile and work. + +@var{objfile}@dots{} are the object files to be examined. When you +specify archives, @command{objdump} shows information on each of the member +object files. + +@c man end + +@c man begin OPTIONS objdump + +The long and short forms of options, shown here as alternatives, are +equivalent. At least one option from the list +@option{-a,-d,-D,-f,-g,-G,-h,-H,-p,-r,-R,-S,-t,-T,-V,-x} must be given. + +@table @env +@item -a +@itemx --archive-header +@cindex archive headers +If any of the @var{objfile} files are archives, display the archive +header information (in a format similar to @samp{ls -l}). Besides the +information you could list with @samp{ar tv}, @samp{objdump -a} shows +the object file format of each archive member. + +@item --adjust-vma=@var{offset} +@cindex section addresses in objdump +@cindex VMA in objdump +When dumping information, first add @var{offset} to all the section +addresses. This is useful if the section addresses do not correspond to +the symbol table, which can happen when putting sections at particular +addresses when using a format which can not represent section addresses, +such as a.out. + +@item -b @var{bfdname} +@itemx --target=@var{bfdname} +@cindex object code format +Specify that the object-code format for the object files is +@var{bfdname}. This option may not be necessary; @var{objdump} can +automatically recognize many formats. + +For example, +@example +objdump -b oasys -m vax -h fu.o +@end example +@noindent +displays summary information from the section headers (@option{-h}) of +@file{fu.o}, which is explicitly identified (@option{-m}) as a VAX object +file in the format produced by Oasys compilers. You can list the +formats available with the @option{-i} option. +@xref{Target Selection}, for more information. + +@item -C +@itemx --demangle[=@var{style}] +@cindex demangling in objdump +Decode (@dfn{demangle}) low-level symbol names into user-level names. +Besides removing any initial underscore prepended by the system, this +makes C++ function names readable. Different compilers have different +mangling styles. The optional demangling style argument can be used to +choose an appropriate demangling style for your compiler. @xref{c++filt}, +for more information on demangling. + +@item -g +@itemx --debugging +Display debugging information. This attempts to parse debugging +information stored in the file and print it out using a C like syntax. +Only certain types of debugging information have been implemented. +Some other types are supported by @command{readelf -w}. +@xref{readelf}. + +@item -d +@itemx --disassemble +@cindex disassembling object code +@cindex machine instructions +Display the assembler mnemonics for the machine instructions from +@var{objfile}. This option only disassembles those sections which are +expected to contain instructions. + +@item -D +@itemx --disassemble-all +Like @option{-d}, but disassemble the contents of all sections, not just +those expected to contain instructions. + +@item --prefix-addresses +When disassembling, print the complete address on each line. This is +the older disassembly format. + +@item -EB +@itemx -EL +@itemx --endian=@{big|little@} +@cindex endianness +@cindex disassembly endianness +Specify the endianness of the object files. This only affects +disassembly. This can be useful when disassembling a file format which +does not describe endianness information, such as S-records. + +@item -f +@itemx --file-headers +@cindex object file header +Display summary information from the overall header of +each of the @var{objfile} files. + +@item --file-start-context +@cindex source code context +Specify that when displaying interlisted source code/disassembly +(assumes @option{-S}) from a file that has not yet been displayed, extend the +context to the start of the file. + +@item -h +@itemx --section-headers +@itemx --headers +@cindex section headers +Display summary information from the section headers of the +object file. + +File segments may be relocated to nonstandard addresses, for example by +using the @option{-Ttext}, @option{-Tdata}, or @option{-Tbss} options to +@command{ld}. However, some object file formats, such as a.out, do not +store the starting address of the file segments. In those situations, +although @command{ld} relocates the sections correctly, using @samp{objdump +-h} to list the file section headers cannot show the correct addresses. +Instead, it shows the usual addresses, which are implicit for the +target. + +@item -H +@itemx --help +Print a summary of the options to @command{objdump} and exit. + +@item -i +@itemx --info +@cindex architectures available +@cindex object formats available +Display a list showing all architectures and object formats available +for specification with @option{-b} or @option{-m}. + +@item -j @var{name} +@itemx --section=@var{name} +@cindex section information +Display information only for section @var{name}. + +@item -l +@itemx --line-numbers +@cindex source filenames for object files +Label the display (using debugging information) with the filename and +source line numbers corresponding to the object code or relocs shown. +Only useful with @option{-d}, @option{-D}, or @option{-r}. + +@item -m @var{machine} +@itemx --architecture=@var{machine} +@cindex architecture +@cindex disassembly architecture +Specify the architecture to use when disassembling object files. This +can be useful when disassembling object files which do not describe +architecture information, such as S-records. You can list the available +architectures with the @option{-i} option. + +@item -M @var{options} +@itemx --disassembler-options=@var{options} +Pass target specific information to the disassembler. Only supported on +some targets. + +If the target is an ARM architecture then this switch can be used to +select which register name set is used during disassembler. Specifying +@option{-M reg-name-std} (the default) will select the register names as +used in ARM's instruction set documentation, but with register 13 called +'sp', register 14 called 'lr' and register 15 called 'pc'. Specifying +@option{-M reg-names-apcs} will select the name set used by the ARM +Procedure Call Standard, whilst specifying @option{-M reg-names-raw} will +just use @samp{r} followed by the register number. + +There are also two variants on the APCS register naming scheme enabled +by @option{-M reg-names-atpcs} and @option{-M reg-names-special-atpcs} which +use the ARM/Thumb Procedure Call Standard naming conventions. (Either +with the normal register names or the special register names). + +This option can also be used for ARM architectures to force the +disassembler to interpret all instructions as Thumb instructions by +using the switch @option{--disassembler-options=force-thumb}. This can be +useful when attempting to disassemble thumb code produced by other +compilers. + +For the x86, some of the options duplicate functions of the @option{-m} +switch, but allow finer grained control. Multiple selections from the +following may be specified as a comma separated string. +@option{x86-64}, @option{i386} and @option{i8086} select disassembly for +the given architecture. @option{intel} and @option{att} select between +intel syntax mode and AT&T syntax mode. @option{addr32}, +@option{addr16}, @option{data32} and @option{data16} specify the default +address size and operand size. These four options will be overridden if +@option{x86-64}, @option{i386} or @option{i8086} appear later in the +option string. Lastly, @option{suffix}, when in AT&T mode, +instructs the disassembler to print a mnemonic suffix even when the +suffix could be inferred by the operands. + +For PPC, @option{booke}, @option{booke32} and @option{booke64} select +disassembly of BookE instructions. @option{32} and @option{64} select +PowerPC and PowerPC64 disassembly, respectively. + +For MIPS, this option controls the printing of register names in +disassembled instructions. Multiple selections from the +following may be specified as a comma separated string, and invalid +options are ignored: + +@table @code +@item gpr-names=@var{ABI} +Print GPR (general-purpose register) names as appropriate +for the specified ABI. By default, GPR names are selected according to +the ABI of the binary being disassembled. + +@item fpr-names=@var{ABI} +Print FPR (floating-point register) names as +appropriate for the specified ABI. By default, FPR numbers are printed +rather than names. + +@item cp0-names=@var{ARCH} +Print CP0 (system control coprocessor; coprocessor 0) register names +as appropriate for the CPU or architecture specified by +@var{ARCH}. By default, CP0 register names are selected according to +the architecture and CPU of the binary being disassembled. + +@item hwr-names=@var{ARCH} +Print HWR (hardware register, used by the @code{rdhwr} instruction) names +as appropriate for the CPU or architecture specified by +@var{ARCH}. By default, HWR names are selected according to +the architecture and CPU of the binary being disassembled. + +@item reg-names=@var{ABI} +Print GPR and FPR names as appropriate for the selected ABI. + +@item reg-names=@var{ARCH} +Print CPU-specific register names (CP0 register and HWR names) +as appropriate for the selected CPU or architecture. +@end table + +For any of the options listed above, @var{ABI} or +@var{ARCH} may be specified as @samp{numeric} to have numbers printed +rather than names, for the selected types of registers. +You can list the available values of @var{ABI} and @var{ARCH} using +the @option{--help} option. + +@item -p +@itemx --private-headers +Print information that is specific to the object file format. The exact +information printed depends upon the object file format. For some +object file formats, no additional information is printed. + +@item -r +@itemx --reloc +@cindex relocation entries, in object file +Print the relocation entries of the file. If used with @option{-d} or +@option{-D}, the relocations are printed interspersed with the +disassembly. + +@item -R +@itemx --dynamic-reloc +@cindex dynamic relocation entries, in object file +Print the dynamic relocation entries of the file. This is only +meaningful for dynamic objects, such as certain types of shared +libraries. + +@item -s +@itemx --full-contents +@cindex sections, full contents +@cindex object file sections +Display the full contents of any sections requested. + +@item -S +@itemx --source +@cindex source disassembly +@cindex disassembly, with source +Display source code intermixed with disassembly, if possible. Implies +@option{-d}. + +@item --show-raw-insn +When disassembling instructions, print the instruction in hex as well as +in symbolic form. This is the default except when +@option{--prefix-addresses} is used. + +@item --no-show-raw-insn +When disassembling instructions, do not print the instruction bytes. +This is the default when @option{--prefix-addresses} is used. + +@item -G +@itemx --stabs +@cindex stab +@cindex .stab +@cindex debug symbols +@cindex ELF object file format +Display the full contents of any sections requested. Display the +contents of the .stab and .stab.index and .stab.excl sections from an +ELF file. This is only useful on systems (such as Solaris 2.0) in which +@code{.stab} debugging symbol-table entries are carried in an ELF +section. In most other file formats, debugging symbol-table entries are +interleaved with linkage symbols, and are visible in the @option{--syms} +output. +@ifclear man +For more information on stabs symbols, see @ref{Top,Stabs,Stabs +Overview,stabs.info, The ``stabs'' debug format}. +@end ifclear + +@item --start-address=@var{address} +@cindex start-address +Start displaying data at the specified address. This affects the output +of the @option{-d}, @option{-r} and @option{-s} options. + +@item --stop-address=@var{address} +@cindex stop-address +Stop displaying data at the specified address. This affects the output +of the @option{-d}, @option{-r} and @option{-s} options. + +@item -t +@itemx --syms +@cindex symbol table entries, printing +Print the symbol table entries of the file. +This is similar to the information provided by the @samp{nm} program. + +@item -T +@itemx --dynamic-syms +@cindex dynamic symbol table entries, printing +Print the dynamic symbol table entries of the file. This is only +meaningful for dynamic objects, such as certain types of shared +libraries. This is similar to the information provided by the @samp{nm} +program when given the @option{-D} (@option{--dynamic}) option. + +@item -V +@itemx --version +Print the version number of @command{objdump} and exit. + +@item -x +@itemx --all-headers +@cindex all header information, object file +@cindex header information, all +Display all available header information, including the symbol table and +relocation entries. Using @option{-x} is equivalent to specifying all of +@option{-a -f -h -r -t}. + +@item -w +@itemx --wide +@cindex wide output, printing +Format some lines for output devices that have more than 80 columns. +Also do not truncate symbol names when they are displayed. + +@item -z +@itemx --disassemble-zeroes +Normally the disassembly output will skip blocks of zeroes. This +option directs the disassembler to disassemble those blocks, just like +any other data. +@end table + +@c man end + +@ignore +@c man begin SEEALSO objdump +nm(1), readelf(1), and the Info entries for @file{binutils}. +@c man end +@end ignore + +@node ranlib +@chapter ranlib + +@kindex ranlib +@cindex archive contents +@cindex symbol index + +@c man title ranlib generate index to archive. + +@smallexample +@c man begin SYNOPSIS ranlib +ranlib [@option{-vV}] @var{archive} +@c man end +@end smallexample + +@c man begin DESCRIPTION ranlib + +@command{ranlib} generates an index to the contents of an archive and +stores it in the archive. The index lists each symbol defined by a +member of an archive that is a relocatable object file. + +You may use @samp{nm -s} or @samp{nm --print-armap} to list this index. + +An archive with such an index speeds up linking to the library and +allows routines in the library to call each other without regard to +their placement in the archive. + +The @sc{gnu} @command{ranlib} program is another form of @sc{gnu} @command{ar}; running +@command{ranlib} is completely equivalent to executing @samp{ar -s}. +@xref{ar}. + +@c man end + +@c man begin OPTIONS ranlib + +@table @env +@item -v +@itemx -V +@itemx --version +Show the version number of @command{ranlib}. +@end table + +@c man end + +@ignore +@c man begin SEEALSO ranlib +ar(1), nm(1), and the Info entries for @file{binutils}. +@c man end +@end ignore + +@node size +@chapter size + +@kindex size +@cindex section sizes + +@c man title size list section sizes and total size. + +@smallexample +@c man begin SYNOPSIS size +size [@option{-A}|@option{-B}|@option{--format=}@var{compatibility}] + [@option{--help}] + [@option{-d}|@option{-o}|@option{-x}|@option{--radix=}@var{number}] + [@option{-t}|@option{--totals}] + [@option{--target=}@var{bfdname}] [@option{-V}|@option{--version}] + [@var{objfile}@dots{}] +@c man end +@end smallexample + +@c man begin DESCRIPTION size + +The @sc{gnu} @command{size} utility lists the section sizes---and the total +size---for each of the object or archive files @var{objfile} in its +argument list. By default, one line of output is generated for each +object file or each module in an archive. + +@var{objfile}@dots{} are the object files to be examined. +If none are specified, the file @code{a.out} will be used. + +@c man end + +@c man begin OPTIONS size + +The command line options have the following meanings: + +@table @env +@item -A +@itemx -B +@itemx --format=@var{compatibility} +@cindex @command{size} display format +Using one of these options, you can choose whether the output from @sc{gnu} +@command{size} resembles output from System V @command{size} (using @option{-A}, +or @option{--format=sysv}), or Berkeley @command{size} (using @option{-B}, or +@option{--format=berkeley}). The default is the one-line format similar to +Berkeley's. +@c Bonus for doc-source readers: you can also say --format=strange (or +@c anything else that starts with 's') for sysv, and --format=boring (or +@c anything else that starts with 'b') for Berkeley. + +Here is an example of the Berkeley (default) format of output from +@command{size}: +@smallexample +$ size --format=Berkeley ranlib size +text data bss dec hex filename +294880 81920 11592 388392 5ed28 ranlib +294880 81920 11888 388688 5ee50 size +@end smallexample + +@noindent +This is the same data, but displayed closer to System V conventions: + +@smallexample +$ size --format=SysV ranlib size +ranlib : +section size addr +.text 294880 8192 +.data 81920 303104 +.bss 11592 385024 +Total 388392 + + +size : +section size addr +.text 294880 8192 +.data 81920 303104 +.bss 11888 385024 +Total 388688 +@end smallexample + +@item --help +Show a summary of acceptable arguments and options. + +@item -d +@itemx -o +@itemx -x +@itemx --radix=@var{number} +@cindex @command{size} number format +@cindex radix for section sizes +Using one of these options, you can control whether the size of each +section is given in decimal (@option{-d}, or @option{--radix=10}); octal +(@option{-o}, or @option{--radix=8}); or hexadecimal (@option{-x}, or +@option{--radix=16}). In @option{--radix=@var{number}}, only the three +values (8, 10, 16) are supported. The total size is always given in two +radices; decimal and hexadecimal for @option{-d} or @option{-x} output, or +octal and hexadecimal if you're using @option{-o}. + +@item -t +@itemx --totals +Show totals of all objects listed (Berkeley format listing mode only). + +@item --target=@var{bfdname} +@cindex object code format +Specify that the object-code format for @var{objfile} is +@var{bfdname}. This option may not be necessary; @command{size} can +automatically recognize many formats. +@xref{Target Selection}, for more information. + +@item -V +@itemx --version +Display the version number of @command{size}. +@end table + +@c man end + +@ignore +@c man begin SEEALSO size +ar(1), objdump(1), readelf(1), and the Info entries for @file{binutils}. +@c man end +@end ignore + +@node strings +@chapter strings +@kindex strings +@cindex listings strings +@cindex printing strings +@cindex strings, printing + +@c man title strings print the strings of printable characters in files. + +@smallexample +@c man begin SYNOPSIS strings +strings [@option{-afov}] [@option{-}@var{min-len}] + [@option{-n} @var{min-len}] [@option{--bytes=}@var{min-len}] + [@option{-t} @var{radix}] [@option{--radix=}@var{radix}] + [@option{-e} @var{encoding}] [@option{--encoding=}@var{encoding}] + [@option{-}] [@option{--all}] [@option{--print-file-name}] + [@option{--target=}@var{bfdname}] + [@option{--help}] [@option{--version}] @var{file}@dots{} +@c man end +@end smallexample + +@c man begin DESCRIPTION strings + +For each @var{file} given, @sc{gnu} @command{strings} prints the printable +character sequences that are at least 4 characters long (or the number +given with the options below) and are followed by an unprintable +character. By default, it only prints the strings from the initialized +and loaded sections of object files; for other types of files, it prints +the strings from the whole file. + +@command{strings} is mainly useful for determining the contents of non-text +files. + +@c man end + +@c man begin OPTIONS strings + +@table @env +@item -a +@itemx --all +@itemx - +Do not scan only the initialized and loaded sections of object files; +scan the whole files. + +@item -f +@itemx --print-file-name +Print the name of the file before each string. + +@item --help +Print a summary of the program usage on the standard output and exit. + +@item -@var{min-len} +@itemx -n @var{min-len} +@itemx --bytes=@var{min-len} +Print sequences of characters that are at least @var{min-len} characters +long, instead of the default 4. + +@item -o +Like @samp{-t o}. Some other versions of @command{strings} have @option{-o} +act like @samp{-t d} instead. Since we can not be compatible with both +ways, we simply chose one. + +@item -t @var{radix} +@itemx --radix=@var{radix} +Print the offset within the file before each string. The single +character argument specifies the radix of the offset---@samp{o} for +octal, @samp{x} for hexadecimal, or @samp{d} for decimal. + +@item -e @var{encoding} +@itemx --encoding=@var{encoding} +Select the character encoding of the strings that are to be found. +Possible values for @var{encoding} are: @samp{s} = single-7-bit-byte +characters (ASCII, ISO 8859, etc., default), @samp{S} = +single-8-bit-byte characters, @samp{b} = 16-bit bigendian, @samp{l} = +16-bit littleendian, @samp{B} = 32-bit bigendian, @samp{L} = 32-bit +littleendian. Useful for finding wide character strings. + +@item --target=@var{bfdname} +@cindex object code format +Specify an object code format other than your system's default format. +@xref{Target Selection}, for more information. + +@item -v +@itemx --version +Print the program version number on the standard output and exit. +@end table + +@c man end + +@ignore +@c man begin SEEALSO strings +ar(1), nm(1), objdump(1), ranlib(1), readelf(1) +and the Info entries for @file{binutils}. +@c man end +@end ignore + +@node strip +@chapter strip + +@kindex strip +@cindex removing symbols +@cindex discarding symbols +@cindex symbols, discarding + +@c man title strip Discard symbols from object files. + +@smallexample +@c man begin SYNOPSIS strip +strip [@option{-F} @var{bfdname} |@option{--target=}@var{bfdname} ] + [@option{-I} @var{bfdname} |@option{--input-target=}@var{bfdname} ] + [@option{-O} @var{bfdname} |@option{--output-target=}@var{bfdname} ] + [@option{-s}|@option{--strip-all}] [@option{-S}|@option{-g}|@option{-d}|@option{--strip-debug}] + [@option{-K} @var{symbolname} |@option{--keep-symbol=}@var{symbolname} ] + [@option{-N} @var{symbolname} |@option{--strip-symbol=}@var{symbolname} ] + [@option{-x}|@option{--discard-all} ] [@option{-X} |@option{--discard-locals}] + [@option{-R} @var{sectionname} |@option{--remove-section=}@var{sectionname} ] + [@option{-o} @var{file} ] [@option{-p}|@option{--preserve-dates}] + [@option{-v} |@option{--verbose}] [@option{-V}|@option{--version}] + [@option{--help}] [@option{--info}] + @var{objfile}@dots{} +@c man end +@end smallexample + +@c man begin DESCRIPTION strip + +@sc{gnu} @command{strip} discards all symbols from object files +@var{objfile}. The list of object files may include archives. +At least one object file must be given. + +@command{strip} modifies the files named in its argument, +rather than writing modified copies under different names. + +@c man end + +@c man begin OPTIONS strip + +@table @env +@item -F @var{bfdname} +@itemx --target=@var{bfdname} +Treat the original @var{objfile} as a file with the object +code format @var{bfdname}, and rewrite it in the same format. +@xref{Target Selection}, for more information. + +@item --help +Show a summary of the options to @command{strip} and exit. + +@item --info +Display a list showing all architectures and object formats available. + +@item -I @var{bfdname} +@itemx --input-target=@var{bfdname} +Treat the original @var{objfile} as a file with the object +code format @var{bfdname}. +@xref{Target Selection}, for more information. + +@item -O @var{bfdname} +@itemx --output-target=@var{bfdname} +Replace @var{objfile} with a file in the output format @var{bfdname}. +@xref{Target Selection}, for more information. + +@item -R @var{sectionname} +@itemx --remove-section=@var{sectionname} +Remove any section named @var{sectionname} from the output file. This +option may be given more than once. Note that using this option +inappropriately may make the output file unusable. + +@item -s +@itemx --strip-all +Remove all symbols. + +@item -g +@itemx -S +@itemx -d +@itemx --strip-debug +Remove debugging symbols only. + +@item --strip-unneeded +Remove all symbols that are not needed for relocation processing. + +@item -K @var{symbolname} +@itemx --keep-symbol=@var{symbolname} +Keep only symbol @var{symbolname} from the source file. This option may +be given more than once. + +@item -N @var{symbolname} +@itemx --strip-symbol=@var{symbolname} +Remove symbol @var{symbolname} from the source file. This option may be +given more than once, and may be combined with strip options other than +@option{-K}. + +@item -o @var{file} +Put the stripped output in @var{file}, rather than replacing the +existing file. When this argument is used, only one @var{objfile} +argument may be specified. + +@item -p +@itemx --preserve-dates +Preserve the access and modification dates of the file. + +@item -x +@itemx --discard-all +Remove non-global symbols. + +@item -X +@itemx --discard-locals +Remove compiler-generated local symbols. +(These usually start with @samp{L} or @samp{.}.) + +@item -V +@itemx --version +Show the version number for @command{strip}. + +@item -v +@itemx --verbose +Verbose output: list all object files modified. In the case of +archives, @samp{strip -v} lists all members of the archive. +@end table + +@c man end + +@ignore +@c man begin SEEALSO strip +the Info entries for @file{binutils}. +@c man end +@end ignore + +@node c++filt, addr2line, strip, Top +@chapter c++filt + +@kindex c++filt +@cindex demangling C++ symbols + +@c man title cxxfilt Demangle C++ and Java symbols. + +@smallexample +@c man begin SYNOPSIS cxxfilt +c++filt [@option{-_}|@option{--strip-underscores}] + [@option{-j}|@option{--java}] + [@option{-n}|@option{--no-strip-underscores}] + [@option{-s} @var{format}|@option{--format=}@var{format}] + [@option{--help}] [@option{--version}] [@var{symbol}@dots{}] +@c man end +@end smallexample + +@c man begin DESCRIPTION cxxfilt + +@kindex cxxfilt +The C++ and Java languages provides function overloading, which means +that you can write many functions with the same name (providing each +takes parameters of different types). All C++ and Java function names +are encoded into a low-level assembly label (this process is known as +@dfn{mangling}). The @command{c++filt} +@footnote{MS-DOS does not allow @kbd{+} characters in file names, so on +MS-DOS this program is named @command{cxxfilt}.} +program does the inverse mapping: it decodes (@dfn{demangles}) low-level +names into user-level names so that the linker can keep these overloaded +functions from clashing. + +Every alphanumeric word (consisting of letters, digits, underscores, +dollars, or periods) seen in the input is a potential label. If the +label decodes into a C++ name, the C++ name replaces the low-level +name in the output. + +You can use @command{c++filt} to decipher individual symbols: + +@example +c++filt @var{symbol} +@end example + +If no @var{symbol} arguments are given, @command{c++filt} reads symbol +names from the standard input and writes the demangled names to the +standard output. All results are printed on the standard output. + +@c man end + +@c man begin OPTIONS cxxfilt + +@table @env +@item -_ +@itemx --strip-underscores +On some systems, both the C and C++ compilers put an underscore in front +of every name. For example, the C name @code{foo} gets the low-level +name @code{_foo}. This option removes the initial underscore. Whether +@command{c++filt} removes the underscore by default is target dependent. + +@item -j +@itemx --java +Prints demangled names using Java syntax. The default is to use C++ +syntax. + +@item -n +@itemx --no-strip-underscores +Do not remove the initial underscore. + +@item -s @var{format} +@itemx --format=@var{format} +@command{c++filt} can decode various methods of mangling, used by +different compilers. The argument to this option selects which +method it uses: + +@table @code +@item auto +Automatic selection based on executable (the default method) +@item gnu +the one used by the @sc{gnu} C++ compiler (g++) +@item lucid +the one used by the Lucid compiler (lcc) +@item arm +the one specified by the C++ Annotated Reference Manual +@item hp +the one used by the HP compiler (aCC) +@item edg +the one used by the EDG compiler +@item gnu-v3 +the one used by the @sc{gnu} C++ compiler (g++) with the V3 ABI. +@item java +the one used by the @sc{gnu} Java compiler (gcj) +@item gnat +the one used by the @sc{gnu} Ada compiler (GNAT). +@end table + +@item --help +Print a summary of the options to @command{c++filt} and exit. + +@item --version +Print the version number of @command{c++filt} and exit. +@end table + +@c man end + +@ignore +@c man begin SEEALSO cxxfilt +the Info entries for @file{binutils}. +@c man end +@end ignore + +@quotation +@emph{Warning:} @command{c++filt} is a new utility, and the details of its +user interface are subject to change in future releases. In particular, +a command-line option may be required in the the future to decode a name +passed as an argument on the command line; in other words, + +@example +c++filt @var{symbol} +@end example + +@noindent +may in a future release become + +@example +c++filt @var{option} @var{symbol} +@end example +@end quotation + +@node addr2line +@chapter addr2line + +@kindex addr2line +@cindex address to file name and line number + +@c man title addr2line convert addresses into file names and line numbers. + +@smallexample +@c man begin SYNOPSIS addr2line +addr2line [@option{-b} @var{bfdname}|@option{--target=}@var{bfdname}] + [@option{-C}|@option{--demangle}[=@var{style}]] + [@option{-e} @var{filename}|@option{--exe=}@var{filename}] + [@option{-f}|@option{--functions}] [@option{-s}|@option{--basename}] + [@option{-H}|@option{--help}] [@option{-V}|@option{--version}] + [addr addr @dots{}] +@c man end +@end smallexample + +@c man begin DESCRIPTION addr2line + +@command{addr2line} translates program addresses into file names and line +numbers. Given an address and an executable, it uses the debugging +information in the executable to figure out which file name and line +number are associated with a given address. + +The executable to use is specified with the @option{-e} option. The +default is the file @file{a.out}. + +@command{addr2line} has two modes of operation. + +In the first, hexadecimal addresses are specified on the command line, +and @command{addr2line} displays the file name and line number for each +address. + +In the second, @command{addr2line} reads hexadecimal addresses from +standard input, and prints the file name and line number for each +address on standard output. In this mode, @command{addr2line} may be used +in a pipe to convert dynamically chosen addresses. + +The format of the output is @samp{FILENAME:LINENO}. The file name and +line number for each address is printed on a separate line. If the +@command{-f} option is used, then each @samp{FILENAME:LINENO} line is +preceded by a @samp{FUNCTIONNAME} line which is the name of the function +containing the address. + +If the file name or function name can not be determined, +@command{addr2line} will print two question marks in their place. If the +line number can not be determined, @command{addr2line} will print 0. + +@c man end + +@c man begin OPTIONS addr2line + +The long and short forms of options, shown here as alternatives, are +equivalent. + +@table @env +@item -b @var{bfdname} +@itemx --target=@var{bfdname} +@cindex object code format +Specify that the object-code format for the object files is +@var{bfdname}. + +@item -C +@itemx --demangle[=@var{style}] +@cindex demangling in objdump +Decode (@dfn{demangle}) low-level symbol names into user-level names. +Besides removing any initial underscore prepended by the system, this +makes C++ function names readable. Different compilers have different +mangling styles. The optional demangling style argument can be used to +choose an appropriate demangling style for your compiler. @xref{c++filt}, +for more information on demangling. + +@item -e @var{filename} +@itemx --exe=@var{filename} +Specify the name of the executable for which addresses should be +translated. The default file is @file{a.out}. + +@item -f +@itemx --functions +Display function names as well as file and line number information. + +@item -s +@itemx --basenames +Display only the base of each file name. +@end table + +@c man end + +@ignore +@c man begin SEEALSO addr2line +Info entries for @file{binutils}. +@c man end +@end ignore + +@node nlmconv +@chapter nlmconv + +@command{nlmconv} converts a relocatable object file into a NetWare +Loadable Module. + +@ignore +@command{nlmconv} currently works with @samp{i386} object +files in @code{coff}, @sc{elf}, or @code{a.out} format, and @sc{SPARC} +object files in @sc{elf}, or @code{a.out} format@footnote{ +@command{nlmconv} should work with any @samp{i386} or @sc{sparc} object +format in the Binary File Descriptor library. It has only been tested +with the above formats.}. +@end ignore + +@quotation +@emph{Warning:} @command{nlmconv} is not always built as part of the binary +utilities, since it is only useful for NLM targets. +@end quotation + +@c man title nlmconv converts object code into an NLM. + +@smallexample +@c man begin SYNOPSIS nlmconv +nlmconv [@option{-I} @var{bfdname}|@option{--input-target=}@var{bfdname}] + [@option{-O} @var{bfdname}|@option{--output-target=}@var{bfdname}] + [@option{-T} @var{headerfile}|@option{--header-file=}@var{headerfile}] + [@option{-d}|@option{--debug}] [@option{-l} @var{linker}|@option{--linker=}@var{linker}] + [@option{-h}|@option{--help}] [@option{-V}|@option{--version}] + @var{infile} @var{outfile} +@c man end +@end smallexample + +@c man begin DESCRIPTION nlmconv + +@command{nlmconv} converts the relocatable @samp{i386} object file +@var{infile} into the NetWare Loadable Module @var{outfile}, optionally +reading @var{headerfile} for NLM header information. For instructions +on writing the NLM command file language used in header files, see the +@samp{linkers} section, @samp{NLMLINK} in particular, of the @cite{NLM +Development and Tools Overview}, which is part of the NLM Software +Developer's Kit (``NLM SDK''), available from Novell, Inc. +@command{nlmconv} uses the @sc{gnu} Binary File Descriptor library to read +@var{infile}; +@ifclear man +see @ref{BFD,,BFD,ld.info,Using LD}, for more information. +@end ifclear + +@command{nlmconv} can perform a link step. In other words, you can list +more than one object file for input if you list them in the definitions +file (rather than simply specifying one input file on the command line). +In this case, @command{nlmconv} calls the linker for you. + +@c man end + +@c man begin OPTIONS nlmconv + +@table @env +@item -I @var{bfdname} +@itemx --input-target=@var{bfdname} +Object format of the input file. @command{nlmconv} can usually determine +the format of a given file (so no default is necessary). +@xref{Target Selection}, for more information. + +@item -O @var{bfdname} +@itemx --output-target=@var{bfdname} +Object format of the output file. @command{nlmconv} infers the output +format based on the input format, e.g. for a @samp{i386} input file the +output format is @samp{nlm32-i386}. +@xref{Target Selection}, for more information. + +@item -T @var{headerfile} +@itemx --header-file=@var{headerfile} +Reads @var{headerfile} for NLM header information. For instructions on +writing the NLM command file language used in header files, see@ see the +@samp{linkers} section, of the @cite{NLM Development and Tools +Overview}, which is part of the NLM Software Developer's Kit, available +from Novell, Inc. + +@item -d +@itemx --debug +Displays (on standard error) the linker command line used by @command{nlmconv}. + +@item -l @var{linker} +@itemx --linker=@var{linker} +Use @var{linker} for any linking. @var{linker} can be an absolute or a +relative pathname. + +@item -h +@itemx --help +Prints a usage summary. + +@item -V +@itemx --version +Prints the version number for @command{nlmconv}. +@end table + +@c man end + +@ignore +@c man begin SEEALSO nlmconv +the Info entries for @file{binutils}. +@c man end +@end ignore + +@node windres +@chapter windres + +@command{windres} may be used to manipulate Windows resources. + +@quotation +@emph{Warning:} @command{windres} is not always built as part of the binary +utilities, since it is only useful for Windows targets. +@end quotation + +@c man title windres manipulate Windows resources. + +@smallexample +@c man begin SYNOPSIS windres +windres [options] [input-file] [output-file] +@c man end +@end smallexample + +@c man begin DESCRIPTION windres + +@command{windres} reads resources from an input file and copies them into +an output file. Either file may be in one of three formats: + +@table @code +@item rc +A text format read by the Resource Compiler. + +@item res +A binary format generated by the Resource Compiler. + +@item coff +A COFF object or executable. +@end table + +The exact description of these different formats is available in +documentation from Microsoft. + +When @command{windres} converts from the @code{rc} format to the @code{res} +format, it is acting like the Windows Resource Compiler. When +@command{windres} converts from the @code{res} format to the @code{coff} +format, it is acting like the Windows @code{CVTRES} program. + +When @command{windres} generates an @code{rc} file, the output is similar +but not identical to the format expected for the input. When an input +@code{rc} file refers to an external filename, an output @code{rc} file +will instead include the file contents. + +If the input or output format is not specified, @command{windres} will +guess based on the file name, or, for the input file, the file contents. +A file with an extension of @file{.rc} will be treated as an @code{rc} +file, a file with an extension of @file{.res} will be treated as a +@code{res} file, and a file with an extension of @file{.o} or +@file{.exe} will be treated as a @code{coff} file. + +If no output file is specified, @command{windres} will print the resources +in @code{rc} format to standard output. + +The normal use is for you to write an @code{rc} file, use @command{windres} +to convert it to a COFF object file, and then link the COFF file into +your application. This will make the resources described in the +@code{rc} file available to Windows. + +@c man end + +@c man begin OPTIONS windres + +@table @env +@item -i @var{filename} +@itemx --input @var{filename} +The name of the input file. If this option is not used, then +@command{windres} will use the first non-option argument as the input file +name. If there are no non-option arguments, then @command{windres} will +read from standard input. @command{windres} can not read a COFF file from +standard input. + +@item -o @var{filename} +@itemx --output @var{filename} +The name of the output file. If this option is not used, then +@command{windres} will use the first non-option argument, after any used +for the input file name, as the output file name. If there is no +non-option argument, then @command{windres} will write to standard output. +@command{windres} can not write a COFF file to standard output. Note, +for compatability with @command{rc} the option @option{-fo} is also +accepted, but its use is not recommended. + +@item -J @var{format} +@itemx --input-format @var{format} +The input format to read. @var{format} may be @samp{res}, @samp{rc}, or +@samp{coff}. If no input format is specified, @command{windres} will +guess, as described above. + +@item -O @var{format} +@itemx --output-format @var{format} +The output format to generate. @var{format} may be @samp{res}, +@samp{rc}, or @samp{coff}. If no output format is specified, +@command{windres} will guess, as described above. + +@item -F @var{target} +@itemx --target @var{target} +Specify the BFD format to use for a COFF file as input or output. This +is a BFD target name; you can use the @option{--help} option to see a list +of supported targets. Normally @command{windres} will use the default +format, which is the first one listed by the @option{--help} option. +@ifclear man +@ref{Target Selection}. +@end ifclear + +@item --preprocessor @var{program} +When @command{windres} reads an @code{rc} file, it runs it through the C +preprocessor first. This option may be used to specify the preprocessor +to use, including any leading arguments. The default preprocessor +argument is @code{gcc -E -xc-header -DRC_INVOKED}. + +@item -I @var{directory} +@itemx --include-dir @var{directory} +Specify an include directory to use when reading an @code{rc} file. +@command{windres} will pass this to the preprocessor as an @option{-I} +option. @command{windres} will also search this directory when looking for +files named in the @code{rc} file. If the argument passed to this command +matches any of the supported @var{formats} (as descrived in the @option{-J} +option), it will issue a deprecation warning, and behave just like the +@option{-J} option. New programs should not use this behaviour. If a +directory happens to match a @var{format}, simple prefix it with @samp{./} +to disable the backward compatibility. + +@item -D @var{target} +@itemx --define @var{sym}[=@var{val}] +Specify a @option{-D} option to pass to the preprocessor when reading an +@code{rc} file. + +@item -U @var{target} +@itemx --undefine @var{sym} +Specify a @option{-U} option to pass to the preprocessor when reading an +@code{rc} file. + +@item -r +Ignored for compatibility with rc. + +@item -v +Enable verbose mode. This tells you what the preprocessor is if you +didn't specify one. + +@item -l @var{val} +@item --language @var{val} +Specify the default language to use when reading an @code{rc} file. +@var{val} should be a hexadecimal language code. The low eight bits are +the language, and the high eight bits are the sublanguage. + +@item --use-temp-file +Use a temporary file to instead of using popen to read the output of +the preprocessor. Use this option if the popen implementation is buggy +on the host (eg., certain non-English language versions of Windows 95 and +Windows 98 are known to have buggy popen where the output will instead +go the console). + +@item --no-use-temp-file +Use popen, not a temporary file, to read the output of the preprocessor. +This is the default behaviour. + +@item -h +@item --help +Prints a usage summary. + +@item -V +@item --version +Prints the version number for @command{windres}. + +@item --yydebug +If @command{windres} is compiled with @code{YYDEBUG} defined as @code{1}, +this will turn on parser debugging. +@end table + +@c man end + +@ignore +@c man begin SEEALSO windres +the Info entries for @file{binutils}. +@c man end +@end ignore + +@node dlltool +@chapter Create files needed to build and use DLLs +@cindex DLL +@kindex dlltool + +@command{dlltool} may be used to create the files needed to build and use +dynamic link libraries (DLLs). + +@quotation +@emph{Warning:} @command{dlltool} is not always built as part of the binary +utilities, since it is only useful for those targets which support DLLs. +@end quotation + +@c man title dlltool Create files needed to build and use DLLs. + +@smallexample +@c man begin SYNOPSIS dlltool +dlltool [@option{-d}|@option{--input-def} @var{def-file-name}] + [@option{-b}|@option{--base-file} @var{base-file-name}] + [@option{-e}|@option{--output-exp} @var{exports-file-name}] + [@option{-z}|@option{--output-def} @var{def-file-name}] + [@option{-l}|@option{--output-lib} @var{library-file-name}] + [@option{--export-all-symbols}] [@option{--no-export-all-symbols}] + [@option{--exclude-symbols} @var{list}] + [@option{--no-default-excludes}] + [@option{-S}|@option{--as} @var{path-to-assembler}] [@option{-f}|@option{--as-flags} @var{options}] + [@option{-D}|@option{--dllname} @var{name}] [@option{-m}|@option{--machine} @var{machine}] + [@option{-a}|@option{--add-indirect}] [@option{-U}|@option{--add-underscore}] [@option{-k}|@option{--kill-at}] + [@option{-A}|@option{--add-stdcall-alias}] + [@option{-x}|@option{--no-idata4}] [@option{-c}|@option{--no-idata5}] [@option{-i}|@option{--interwork}] + [@option{-n}|@option{--nodelete}] [@option{-v}|@option{--verbose}] + [@option{-h}|@option{--help}] [@option{-V}|@option{--version}] + [object-file @dots{}] +@c man end +@end smallexample + +@c man begin DESCRIPTION dlltool + +@command{dlltool} reads its inputs, which can come from the @option{-d} and +@option{-b} options as well as object files specified on the command +line. It then processes these inputs and if the @option{-e} option has +been specified it creates a exports file. If the @option{-l} option +has been specified it creates a library file and if the @option{-z} option +has been specified it creates a def file. Any or all of the @option{-e}, +@option{-l} and @option{-z} options can be present in one invocation of +dlltool. + +When creating a DLL, along with the source for the DLL, it is necessary +to have three other files. @command{dlltool} can help with the creation of +these files. + +The first file is a @samp{.def} file which specifies which functions are +exported from the DLL, which functions the DLL imports, and so on. This +is a text file and can be created by hand, or @command{dlltool} can be used +to create it using the @option{-z} option. In this case @command{dlltool} +will scan the object files specified on its command line looking for +those functions which have been specially marked as being exported and +put entries for them in the .def file it creates. + +In order to mark a function as being exported from a DLL, it needs to +have an @option{-export:} entry in the @samp{.drectve} +section of the object file. This can be done in C by using the +asm() operator: + +@smallexample + asm (".section .drectve"); + asm (".ascii \"-export:my_func\""); + + int my_func (void) @{ @dots{} @} +@end smallexample + +The second file needed for DLL creation is an exports file. This file +is linked with the object files that make up the body of the DLL and it +handles the interface between the DLL and the outside world. This is a +binary file and it can be created by giving the @option{-e} option to +@command{dlltool} when it is creating or reading in a .def file. + +The third file needed for DLL creation is the library file that programs +will link with in order to access the functions in the DLL. This file +can be created by giving the @option{-l} option to dlltool when it +is creating or reading in a .def file. + +@command{dlltool} builds the library file by hand, but it builds the +exports file by creating temporary files containing assembler statements +and then assembling these. The @option{-S} command line option can be +used to specify the path to the assembler that dlltool will use, +and the @option{-f} option can be used to pass specific flags to that +assembler. The @option{-n} can be used to prevent dlltool from deleting +these temporary assembler files when it is done, and if @option{-n} is +specified twice then this will prevent dlltool from deleting the +temporary object files it used to build the library. + +Here is an example of creating a DLL from a source file @samp{dll.c} and +also creating a program (from an object file called @samp{program.o}) +that uses that DLL: + +@smallexample + gcc -c dll.c + dlltool -e exports.o -l dll.lib dll.o + gcc dll.o exports.o -o dll.dll + gcc program.o dll.lib -o program +@end smallexample + +@c man end + +@c man begin OPTIONS dlltool + +The command line options have the following meanings: + +@table @env + +@item -d @var{filename} +@itemx --input-def @var{filename} +@cindex input .def file +Specifies the name of a .def file to be read in and processed. + +@item -b @var{filename} +@itemx --base-file @var{filename} +@cindex base files +Specifies the name of a base file to be read in and processed. The +contents of this file will be added to the relocation section in the +exports file generated by dlltool. + +@item -e @var{filename} +@itemx --output-exp @var{filename} +Specifies the name of the export file to be created by dlltool. + +@item -z @var{filename} +@itemx --output-def @var{filename} +Specifies the name of the .def file to be created by dlltool. + +@item -l @var{filename} +@itemx --output-lib @var{filename} +Specifies the name of the library file to be created by dlltool. + +@item --export-all-symbols +Treat all global and weak defined symbols found in the input object +files as symbols to be exported. There is a small list of symbols which +are not exported by default; see the @option{--no-default-excludes} +option. You may add to the list of symbols to not export by using the +@option{--exclude-symbols} option. + +@item --no-export-all-symbols +Only export symbols explicitly listed in an input .def file or in +@samp{.drectve} sections in the input object files. This is the default +behaviour. The @samp{.drectve} sections are created by @samp{dllexport} +attributes in the source code. + +@item --exclude-symbols @var{list} +Do not export the symbols in @var{list}. This is a list of symbol names +separated by comma or colon characters. The symbol names should not +contain a leading underscore. This is only meaningful when +@option{--export-all-symbols} is used. + +@item --no-default-excludes +When @option{--export-all-symbols} is used, it will by default avoid +exporting certain special symbols. The current list of symbols to avoid +exporting is @samp{DllMain@@12}, @samp{DllEntryPoint@@0}, +@samp{impure_ptr}. You may use the @option{--no-default-excludes} option +to go ahead and export these special symbols. This is only meaningful +when @option{--export-all-symbols} is used. + +@item -S @var{path} +@itemx --as @var{path} +Specifies the path, including the filename, of the assembler to be used +to create the exports file. + +@item -f @var{options} +@itemx --as-flags @var{options} +Specifies any specific command line options to be passed to the +assembler when building the exports file. This option will work even if +the @option{-S} option is not used. This option only takes one argument, +and if it occurs more than once on the command line, then later +occurrences will override earlier occurrences. So if it is necessary to +pass multiple options to the assembler they should be enclosed in +double quotes. + +@item -D @var{name} +@itemx --dll-name @var{name} +Specifies the name to be stored in the .def file as the name of the DLL +when the @option{-e} option is used. If this option is not present, then +the filename given to the @option{-e} option will be used as the name of +the DLL. + +@item -m @var{machine} +@itemx -machine @var{machine} +Specifies the type of machine for which the library file should be +built. @command{dlltool} has a built in default type, depending upon how +it was created, but this option can be used to override that. This is +normally only useful when creating DLLs for an ARM processor, when the +contents of the DLL are actually encode using Thumb instructions. + +@item -a +@itemx --add-indirect +Specifies that when @command{dlltool} is creating the exports file it +should add a section which allows the exported functions to be +referenced without using the import library. Whatever the hell that +means! + +@item -U +@itemx --add-underscore +Specifies that when @command{dlltool} is creating the exports file it +should prepend an underscore to the names of the exported functions. + +@item -k +@itemx --kill-at +Specifies that when @command{dlltool} is creating the exports file it +should not append the string @samp{@@ }. These numbers are +called ordinal numbers and they represent another way of accessing the +function in a DLL, other than by name. + +@item -A +@itemx --add-stdcall-alias +Specifies that when @command{dlltool} is creating the exports file it +should add aliases for stdcall symbols without @samp{@@ } +in addition to the symbols with @samp{@@ }. + +@item -x +@itemx --no-idata4 +Specifies that when @command{dlltool} is creating the exports and library +files it should omit the @code{.idata4} section. This is for compatibility +with certain operating systems. + +@item -c +@itemx --no-idata5 +Specifies that when @command{dlltool} is creating the exports and library +files it should omit the @code{.idata5} section. This is for compatibility +with certain operating systems. + +@item -i +@itemx --interwork +Specifies that @command{dlltool} should mark the objects in the library +file and exports file that it produces as supporting interworking +between ARM and Thumb code. + +@item -n +@itemx --nodelete +Makes @command{dlltool} preserve the temporary assembler files it used to +create the exports file. If this option is repeated then dlltool will +also preserve the temporary object files it uses to create the library +file. + +@item -v +@itemx --verbose +Make dlltool describe what it is doing. + +@item -h +@itemx --help +Displays a list of command line options and then exits. + +@item -V +@itemx --version +Displays dlltool's version number and then exits. + +@end table + +@c man end + +@ignore +@c man begin SEEALSO dlltool +the Info entries for @file{binutils}. +@c man end +@end ignore + +@node readelf +@chapter readelf + +@cindex ELF file information +@kindex readelf + +@c man title readelf Displays information about ELF files. + +@smallexample +@c man begin SYNOPSIS readelf +readelf [@option{-a}|@option{--all}] + [@option{-h}|@option{--file-header}] + [@option{-l}|@option{--program-headers}|@option{--segments}] + [@option{-S}|@option{--section-headers}|@option{--sections}] + [@option{-e}|@option{--headers}] + [@option{-s}|@option{--syms}|@option{--symbols}] + [@option{-n}|@option{--notes}] + [@option{-r}|@option{--relocs}] + [@option{-u}|@option{--unwind}] + [@option{-d}|@option{--dynamic}] + [@option{-V}|@option{--version-info}] + [@option{-A}|@option{--arch-specific}] + [@option{-D}|@option{--use-dynamic}] + [@option{-x} |@option{--hex-dump=}] + [@option{-w[liaprmfFso]}| + @option{--debug-dump}[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=frames-interp,=str,=loc]] + [@option{-I}|@option{-histogram}] + [@option{-v}|@option{--version}] + [@option{-W}|@option{--wide}] + [@option{-H}|@option{--help}] + @var{elffile}@dots{} +@c man end +@end smallexample + +@c man begin DESCRIPTION readelf + +@command{readelf} displays information about one or more ELF format object +files. The options control what particular information to display. + +@var{elffile}@dots{} are the object files to be examined. At the +moment, @command{readelf} does not support examining archives, nor does it +support examining 64 bit ELF files. + +@c man end + +@c man begin OPTIONS readelf + +The long and short forms of options, shown here as alternatives, are +equivalent. At least one option besides @samp{-v} or @samp{-H} must be +given. + +@table @env +@item -a +@itemx --all +Equivalent to specifiying @option{--file-header}, +@option{--program-headers}, @option{--sections}, @option{--symbols}, +@option{--relocs}, @option{--dynamic}, @option{--notes} and +@option{--version-info}. + +@item -h +@itemx --file-header +@cindex ELF file header information +Displays the information contained in the ELF header at the start of the +file. + +@item -l +@itemx --program-headers +@itemx --segments +@cindex ELF program header information +@cindex ELF segment information +Displays the information contained in the file's segment headers, if it +has any. + +@item -S +@itemx --sections +@itemx --section-headers +@cindex ELF section information +Displays the information contained in the file's section headers, if it +has any. + +@item -s +@itemx --symbols +@itemx --syms +@cindex ELF symbol table information +Displays the entries in symbol table section of the file, if it has one. + +@item -e +@itemx --headers +Display all the headers in the file. Equivalent to @option{-h -l -S}. + +@item -n +@itemx --notes +@cindex ELF core notes +Displays the contents of the NOTE segment, if it exists. + +@item -r +@itemx --relocs +@cindex ELF reloc information +Displays the contents of the file's relocation section, if it has one. + +@item -u +@itemx --unwind +@cindex unwind information +Displays the contents of the file's unwind section, if it has one. Only +the unwind sections for IA64 ELF files are currently supported. + +@item -u +@itemx --unwind +@cindex unwind information +Displays the contents of the file's unwind section, if it has one. Only +the unwind sections for IA64 ELF files are currently supported. + +@item -d +@itemx --dynamic +@cindex ELF dynamic section information +Displays the contents of the file's dynamic section, if it has one. + +@item -V +@itemx --version-info +@cindex ELF version sections informations +Displays the contents of the version sections in the file, it they +exist. + +@item -A +@itemx --arch-specific +Displays architecture-specific information in the file, if there +is any. + +@item -D +@itemx --use-dynamic +When displaying symbols, this option makes @command{readelf} use the +symbol table in the file's dynamic section, rather than the one in the +symbols section. + +@item -x +@itemx --hex-dump= +Displays the contents of the indicated section as a hexadecimal dump. + +@item -w[liaprmfFso] +@itemx --debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=frames-interp,=str,=loc] +Displays the contents of the debug sections in the file, if any are +present. If one of the optional letters or words follows the switch +then only data found in those specific sections will be dumped. + +@item -I +@itemx --histogram +Display a histogram of bucket list lengths when displaying the contents +of the symbol tables. + +@item -v +@itemx --version +Display the version number of readelf. + +@item -W +@itemx --wide +Don't break output lines to fit into 80 columns. By default +@command{readelf} breaks section header and segment listing lines for +64-bit ELF files, so that they fit into 80 columns. This option causes +@command{readelf} to print each section header resp. each segment one a +single line, which is far more readable on terminals wider than 80 columns. + +@item -H +@itemx --help +Display the command line options understood by @command{readelf}. + +@end table + +@c man end + +@ignore +@c man begin SEEALSO readelf +objdump(1), and the Info entries for @file{binutils}. +@c man end +@end ignore + +@node Selecting The Target System +@chapter Selecting the Target System + +You can specify two aspects of the target system to the @sc{gnu} +binary file utilities, each in several ways: + +@itemize @bullet +@item +the target + +@item +the architecture +@end itemize + +In the following summaries, the lists of ways to specify values are in +order of decreasing precedence. The ways listed first override those +listed later. + +The commands to list valid values only list the values for which the +programs you are running were configured. If they were configured with +@option{--enable-targets=all}, the commands list most of the available +values, but a few are left out; not all targets can be configured in at +once because some of them can only be configured @dfn{native} (on hosts +with the same type as the target system). + +@menu +* Target Selection:: +* Architecture Selection:: +@end menu + +@node Target Selection +@section Target Selection + +A @dfn{target} is an object file format. A given target may be +supported for multiple architectures (@pxref{Architecture Selection}). +A target selection may also have variations for different operating +systems or architectures. + +The command to list valid target values is @samp{objdump -i} +(the first column of output contains the relevant information). + +Some sample values are: @samp{a.out-hp300bsd}, @samp{ecoff-littlemips}, +@samp{a.out-sunos-big}. + +You can also specify a target using a configuration triplet. This is +the same sort of name that is passed to @file{configure} to specify a +target. When you use a configuration triplet as an argument, it must be +fully canonicalized. You can see the canonical version of a triplet by +running the shell script @file{config.sub} which is included with the +sources. + +Some sample configuration triplets are: @samp{m68k-hp-bsd}, +@samp{mips-dec-ultrix}, @samp{sparc-sun-sunos}. + +@subheading @command{objdump} Target + +Ways to specify: + +@enumerate +@item +command line option: @option{-b} or @option{--target} + +@item +environment variable @code{GNUTARGET} + +@item +deduced from the input file +@end enumerate + +@subheading @command{objcopy} and @command{strip} Input Target + +Ways to specify: + +@enumerate +@item +command line options: @option{-I} or @option{--input-target}, or @option{-F} or @option{--target} + +@item +environment variable @code{GNUTARGET} + +@item +deduced from the input file +@end enumerate + +@subheading @command{objcopy} and @command{strip} Output Target + +Ways to specify: + +@enumerate +@item +command line options: @option{-O} or @option{--output-target}, or @option{-F} or @option{--target} + +@item +the input target (see ``@command{objcopy} and @command{strip} Input Target'' above) + +@item +environment variable @code{GNUTARGET} + +@item +deduced from the input file +@end enumerate + +@subheading @command{nm}, @command{size}, and @command{strings} Target + +Ways to specify: + +@enumerate +@item +command line option: @option{--target} + +@item +environment variable @code{GNUTARGET} + +@item +deduced from the input file +@end enumerate + +@node Architecture Selection +@section Architecture Selection + +An @dfn{architecture} is a type of @sc{cpu} on which an object file is +to run. Its name may contain a colon, separating the name of the +processor family from the name of the particular @sc{cpu}. + +The command to list valid architecture values is @samp{objdump -i} (the +second column contains the relevant information). + +Sample values: @samp{m68k:68020}, @samp{mips:3000}, @samp{sparc}. + +@subheading @command{objdump} Architecture + +Ways to specify: + +@enumerate +@item +command line option: @option{-m} or @option{--architecture} + +@item +deduced from the input file +@end enumerate + +@subheading @command{objcopy}, @command{nm}, @command{size}, @command{strings} Architecture + +Ways to specify: + +@enumerate +@item +deduced from the input file +@end enumerate + +@node Reporting Bugs +@chapter Reporting Bugs +@cindex bugs +@cindex reporting bugs + +Your bug reports play an essential role in making the binary utilities +reliable. + +Reporting a bug may help you by bringing a solution to your problem, or +it may not. But in any case the principal function of a bug report is +to help the entire community by making the next version of the binary +utilities work better. Bug reports are your contribution to their +maintenance. + +In order for a bug report to serve its purpose, you must include the +information that enables us to fix the bug. + +@menu +* Bug Criteria:: Have you found a bug? +* Bug Reporting:: How to report bugs +@end menu + +@node Bug Criteria +@section Have You Found a Bug? +@cindex bug criteria + +If you are not sure whether you have found a bug, here are some guidelines: + +@itemize @bullet +@cindex fatal signal +@cindex crash +@item +If a binary utility gets a fatal signal, for any input whatever, that is +a bug. Reliable utilities never crash. + +@cindex error on valid input +@item +If a binary utility produces an error message for valid input, that is a +bug. + +@item +If you are an experienced user of binary utilities, your suggestions for +improvement are welcome in any case. +@end itemize + +@node Bug Reporting +@section How to Report Bugs +@cindex bug reports +@cindex bugs, reporting + +A number of companies and individuals offer support for @sc{gnu} +products. If you obtained the binary utilities from a support +organization, we recommend you contact that organization first. + +You can find contact information for many support companies and +individuals in the file @file{etc/SERVICE} in the @sc{gnu} Emacs +distribution. + +In any event, we also recommend that you send bug reports for the binary +utilities to @samp{bug-binutils@@gnu.org}. + +The fundamental principle of reporting bugs usefully is this: +@strong{report all the facts}. If you are not sure whether to state a +fact or leave it out, state it! + +Often people omit facts because they think they know what causes the +problem and assume that some details do not matter. Thus, you might +assume that the name of a file you use in an example does not matter. +Well, probably it does not, but one cannot be sure. Perhaps the bug is +a stray memory reference which happens to fetch from the location where +that pathname is stored in memory; perhaps, if the pathname were +different, the contents of that location would fool the utility into +doing the right thing despite the bug. Play it safe and give a +specific, complete example. That is the easiest thing for you to do, +and the most helpful. + +Keep in mind that the purpose of a bug report is to enable us to fix the bug if +it is new to us. Therefore, always write your bug reports on the assumption +that the bug has not been reported previously. + +Sometimes people give a few sketchy facts and ask, ``Does this ring a +bell?'' This cannot help us fix a bug, so it is basically useless. We +respond by asking for enough details to enable us to investigate. +You might as well expedite matters by sending them to begin with. + +To enable us to fix the bug, you should include all these things: + +@itemize @bullet +@item +The version of the utility. Each utility announces it if you start it +with the @option{--version} argument. + +Without this, we will not know whether there is any point in looking for +the bug in the current version of the binary utilities. + +@item +Any patches you may have applied to the source, including any patches +made to the @code{BFD} library. + +@item +The type of machine you are using, and the operating system name and +version number. + +@item +What compiler (and its version) was used to compile the utilities---e.g. +``@code{gcc-2.7}''. + +@item +The command arguments you gave the utility to observe the bug. To +guarantee you will not omit something important, list them all. A copy +of the Makefile (or the output from make) is sufficient. + +If we were to try to guess the arguments, we would probably guess wrong +and then we might not encounter the bug. + +@item +A complete input file, or set of input files, that will reproduce the +bug. If the utility is reading an object file or files, then it is +generally most helpful to send the actual object files, uuencoded if +necessary to get them through the mail system. Note that +@samp{bug-binutils@@gnu.org} is a mailing list, so you should avoid +sending very large files to it. Making the files available for +anonymous FTP is OK. + +If the source files were produced exclusively using @sc{gnu} programs +(e.g., @command{gcc}, @command{gas}, and/or the @sc{gnu} @command{ld}), then it +may be OK to send the source files rather than the object files. In +this case, be sure to say exactly what version of @command{gcc}, or +whatever, was used to produce the object files. Also say how +@command{gcc}, or whatever, was configured. + +@item +A description of what behavior you observe that you believe is +incorrect. For example, ``It gets a fatal signal.'' + +Of course, if the bug is that the utility gets a fatal signal, then we +will certainly notice it. But if the bug is incorrect output, we might +not notice unless it is glaringly wrong. You might as well not give us +a chance to make a mistake. + +Even if the problem you experience is a fatal signal, you should still +say so explicitly. Suppose something strange is going on, such as your +copy of the utility is out of synch, or you have encountered a bug in +the C library on your system. (This has happened!) Your copy might +crash and ours would not. If you told us to expect a crash, then when +ours fails to crash, we would know that the bug was not happening for +us. If you had not told us to expect a crash, then we would not be able +to draw any conclusion from our observations. + +@item +If you wish to suggest changes to the source, send us context diffs, as +generated by @command{diff} with the @option{-u}, @option{-c}, or @option{-p} +option. Always send diffs from the old file to the new file. If you +wish to discuss something in the @command{ld} source, refer to it by +context, not by line number. + +The line numbers in our development sources will not match those in your +sources. Your line numbers would convey no useful information to us. +@end itemize + +Here are some things that are not necessary: + +@itemize @bullet +@item +A description of the envelope of the bug. + +Often people who encounter a bug spend a lot of time investigating +which changes to the input file will make the bug go away and which +changes will not affect it. + +This is often time consuming and not very useful, because the way we +will find the bug is by running a single example under the debugger +with breakpoints, not by pure deduction from a series of examples. +We recommend that you save your time for something else. + +Of course, if you can find a simpler example to report @emph{instead} +of the original one, that is a convenience for us. Errors in the +output will be easier to spot, running under the debugger will take +less time, and so on. + +However, simplification is not vital; if you do not want to do this, +report the bug anyway and send us the entire test case you used. + +@item +A patch for the bug. + +A patch for the bug does help us if it is a good one. But do not omit +the necessary information, such as the test case, on the assumption that +a patch is all we need. We might see problems with your patch and decide +to fix the problem another way, or we might not understand it at all. + +Sometimes with programs as complicated as the binary utilities it is +very hard to construct an example that will make the program follow a +certain path through the code. If you do not send us the example, we +will not be able to construct one, so we will not be able to verify that +the bug is fixed. + +And if we cannot understand what bug you are trying to fix, or why your +patch should be an improvement, we will not install it. A test case will +help us to understand. + +@item +A guess about what the bug is or what it depends on. + +Such guesses are usually wrong. Even we cannot guess right about such +things without first using the debugger to find the facts. +@end itemize + +@include fdl.texi + +@node Index +@unnumbered Index + +@printindex cp + +@contents +@bye diff --git a/contrib/binutils-2.14/binutils/doc/nm.1 b/contrib/binutils-2.14/binutils/doc/nm.1 new file mode 100644 index 0000000000..84d2fa7681 --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/nm.1 @@ -0,0 +1,426 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "NM 1" +.TH NM 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +nm \- list symbols from object files +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +nm [\fB\-a\fR|\fB\-\-debug\-syms\fR] [\fB\-g\fR|\fB\-\-extern\-only\fR] + [\fB\-B\fR] [\fB\-C\fR|\fB\-\-demangle\fR[=\fIstyle\fR]] [\fB\-D\fR|\fB\-\-dynamic\fR] + [\fB\-S\fR|\fB\-\-print\-size\fR] [\fB\-s\fR|\fB\-\-print\-armap\fR] + [\fB\-A\fR|\fB\-o\fR|\fB\-\-print\-file\-name\fR] + [\fB\-n\fR|\fB\-v\fR|\fB\-\-numeric\-sort\fR] [\fB\-p\fR|\fB\-\-no\-sort\fR] + [\fB\-r\fR|\fB\-\-reverse\-sort\fR] [\fB\-\-size\-sort\fR] [\fB\-u\fR|\fB\-\-undefined\-only\fR] + [\fB\-t\fR \fIradix\fR|\fB\-\-radix=\fR\fIradix\fR] [\fB\-P\fR|\fB\-\-portability\fR] + [\fB\-\-target=\fR\fIbfdname\fR] [\fB\-f\fR\fIformat\fR|\fB\-\-format=\fR\fIformat\fR] + [\fB\-\-defined\-only\fR] [\fB\-l\fR|\fB\-\-line\-numbers\fR] [\fB\-\-no\-demangle\fR] + [\fB\-V\fR|\fB\-\-version\fR] [\fB\-X 32_64\fR] [\fB\-\-help\fR] [\fIobjfile\fR...] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\s-1GNU\s0 \fBnm\fR lists the symbols from object files \fIobjfile\fR.... +If no object files are listed as arguments, \fBnm\fR assumes the file +\&\fIa.out\fR. +.PP +For each symbol, \fBnm\fR shows: +.IP "\(bu" 4 +The symbol value, in the radix selected by options (see below), or +hexadecimal by default. +.IP "\(bu" 4 +The symbol type. At least the following types are used; others are, as +well, depending on the object file format. If lowercase, the symbol is +local; if uppercase, the symbol is global (external). +.RS 4 +.ie n .IP """A""" 4 +.el .IP "\f(CWA\fR" 4 +.IX Item "A" +The symbol's value is absolute, and will not be changed by further +linking. +.ie n .IP """B""" 4 +.el .IP "\f(CWB\fR" 4 +.IX Item "B" +The symbol is in the uninitialized data section (known as \s-1BSS\s0). +.ie n .IP """C""" 4 +.el .IP "\f(CWC\fR" 4 +.IX Item "C" +The symbol is common. Common symbols are uninitialized data. When +linking, multiple common symbols may appear with the same name. If the +symbol is defined anywhere, the common symbols are treated as undefined +references. +.ie n .IP """D""" 4 +.el .IP "\f(CWD\fR" 4 +.IX Item "D" +The symbol is in the initialized data section. +.ie n .IP """G""" 4 +.el .IP "\f(CWG\fR" 4 +.IX Item "G" +The symbol is in an initialized data section for small objects. Some +object file formats permit more efficient access to small data objects, +such as a global int variable as opposed to a large global array. +.ie n .IP """I""" 4 +.el .IP "\f(CWI\fR" 4 +.IX Item "I" +The symbol is an indirect reference to another symbol. This is a \s-1GNU\s0 +extension to the a.out object file format which is rarely used. +.ie n .IP """N""" 4 +.el .IP "\f(CWN\fR" 4 +.IX Item "N" +The symbol is a debugging symbol. +.ie n .IP """R""" 4 +.el .IP "\f(CWR\fR" 4 +.IX Item "R" +The symbol is in a read only data section. +.ie n .IP """S""" 4 +.el .IP "\f(CWS\fR" 4 +.IX Item "S" +The symbol is in an uninitialized data section for small objects. +.ie n .IP """T""" 4 +.el .IP "\f(CWT\fR" 4 +.IX Item "T" +The symbol is in the text (code) section. +.ie n .IP """U""" 4 +.el .IP "\f(CWU\fR" 4 +.IX Item "U" +The symbol is undefined. +.ie n .IP """V""" 4 +.el .IP "\f(CWV\fR" 4 +.IX Item "V" +The symbol is a weak object. When a weak defined symbol is linked with +a normal defined symbol, the normal defined symbol is used with no error. +When a weak undefined symbol is linked and the symbol is not defined, +the value of the weak symbol becomes zero with no error. +.ie n .IP """W""" 4 +.el .IP "\f(CWW\fR" 4 +.IX Item "W" +The symbol is a weak symbol that has not been specifically tagged as a +weak object symbol. When a weak defined symbol is linked with a normal +defined symbol, the normal defined symbol is used with no error. +When a weak undefined symbol is linked and the symbol is not defined, +the value of the weak symbol becomes zero with no error. +.ie n .IP """\-""" 4 +.el .IP "\f(CW\-\fR" 4 +.IX Item "-" +The symbol is a stabs symbol in an a.out object file. In this case, the +next values printed are the stabs other field, the stabs desc field, and +the stab type. Stabs symbols are used to hold debugging information. +.ie n .IP """?""" 4 +.el .IP "\f(CW?\fR" 4 +.IX Item "?" +The symbol type is unknown, or object file format specific. +.RE +.RS 4 +.RE +.IP "\(bu" 4 +The symbol name. +.SH "OPTIONS" +.IX Header "OPTIONS" +The long and short forms of options, shown here as alternatives, are +equivalent. +.IP "\fB\-A\fR" 4 +.IX Item "-A" +.PD 0 +.IP "\fB\-o\fR" 4 +.IX Item "-o" +.IP "\fB\-\-print\-file\-name\fR" 4 +.IX Item "--print-file-name" +.PD +Precede each symbol by the name of the input file (or archive member) +in which it was found, rather than identifying the input file once only, +before all of its symbols. +.IP "\fB\-a\fR" 4 +.IX Item "-a" +.PD 0 +.IP "\fB\-\-debug\-syms\fR" 4 +.IX Item "--debug-syms" +.PD +Display all symbols, even debugger-only symbols; normally these are not +listed. +.IP "\fB\-B\fR" 4 +.IX Item "-B" +The same as \fB\-\-format=bsd\fR (for compatibility with the \s-1MIPS\s0 \fBnm\fR). +.IP "\fB\-C\fR" 4 +.IX Item "-C" +.PD 0 +.IP "\fB\-\-demangle[=\fR\fIstyle\fR\fB]\fR" 4 +.IX Item "--demangle[=style]" +.PD +Decode (\fIdemangle\fR) low-level symbol names into user-level names. +Besides removing any initial underscore prepended by the system, this +makes \*(C+ function names readable. Different compilers have different +mangling styles. The optional demangling style argument can be used to +choose an appropriate demangling style for your compiler. +.IP "\fB\-\-no\-demangle\fR" 4 +.IX Item "--no-demangle" +Do not demangle low-level symbol names. This is the default. +.IP "\fB\-D\fR" 4 +.IX Item "-D" +.PD 0 +.IP "\fB\-\-dynamic\fR" 4 +.IX Item "--dynamic" +.PD +Display the dynamic symbols rather than the normal symbols. This is +only meaningful for dynamic objects, such as certain types of shared +libraries. +.IP "\fB\-f\fR \fIformat\fR" 4 +.IX Item "-f format" +.PD 0 +.IP "\fB\-\-format=\fR\fIformat\fR" 4 +.IX Item "--format=format" +.PD +Use the output format \fIformat\fR, which can be \f(CW\*(C`bsd\*(C'\fR, +\&\f(CW\*(C`sysv\*(C'\fR, or \f(CW\*(C`posix\*(C'\fR. The default is \f(CW\*(C`bsd\*(C'\fR. +Only the first character of \fIformat\fR is significant; it can be +either upper or lower case. +.IP "\fB\-g\fR" 4 +.IX Item "-g" +.PD 0 +.IP "\fB\-\-extern\-only\fR" 4 +.IX Item "--extern-only" +.PD +Display only external symbols. +.IP "\fB\-l\fR" 4 +.IX Item "-l" +.PD 0 +.IP "\fB\-\-line\-numbers\fR" 4 +.IX Item "--line-numbers" +.PD +For each symbol, use debugging information to try to find a filename and +line number. For a defined symbol, look for the line number of the +address of the symbol. For an undefined symbol, look for the line +number of a relocation entry which refers to the symbol. If line number +information can be found, print it after the other symbol information. +.IP "\fB\-n\fR" 4 +.IX Item "-n" +.PD 0 +.IP "\fB\-v\fR" 4 +.IX Item "-v" +.IP "\fB\-\-numeric\-sort\fR" 4 +.IX Item "--numeric-sort" +.PD +Sort symbols numerically by their addresses, rather than alphabetically +by their names. +.IP "\fB\-p\fR" 4 +.IX Item "-p" +.PD 0 +.IP "\fB\-\-no\-sort\fR" 4 +.IX Item "--no-sort" +.PD +Do not bother to sort the symbols in any order; print them in the order +encountered. +.IP "\fB\-P\fR" 4 +.IX Item "-P" +.PD 0 +.IP "\fB\-\-portability\fR" 4 +.IX Item "--portability" +.PD +Use the \s-1POSIX\s0.2 standard output format instead of the default format. +Equivalent to \fB\-f posix\fR. +.IP "\fB\-S\fR" 4 +.IX Item "-S" +.PD 0 +.IP "\fB\-\-print\-size\fR" 4 +.IX Item "--print-size" +.PD +Print size, not the value, of defined symbols for the \f(CW\*(C`bsd\*(C'\fR output format. +.IP "\fB\-s\fR" 4 +.IX Item "-s" +.PD 0 +.IP "\fB\-\-print\-armap\fR" 4 +.IX Item "--print-armap" +.PD +When listing symbols from archive members, include the index: a mapping +(stored in the archive by \fBar\fR or \fBranlib\fR) of which modules +contain definitions for which names. +.IP "\fB\-r\fR" 4 +.IX Item "-r" +.PD 0 +.IP "\fB\-\-reverse\-sort\fR" 4 +.IX Item "--reverse-sort" +.PD +Reverse the order of the sort (whether numeric or alphabetic); let the +last come first. +.IP "\fB\-\-size\-sort\fR" 4 +.IX Item "--size-sort" +Sort symbols by size. The size is computed as the difference between +the value of the symbol and the value of the symbol with the next higher +value. If the \f(CW\*(C`bsd\*(C'\fR output format is used the size of the symbol +is printed, rather than the value, and \fB\-S\fR must be used in order +both size and value to be printed. +.IP "\fB\-t\fR \fIradix\fR" 4 +.IX Item "-t radix" +.PD 0 +.IP "\fB\-\-radix=\fR\fIradix\fR" 4 +.IX Item "--radix=radix" +.PD +Use \fIradix\fR as the radix for printing the symbol values. It must be +\&\fBd\fR for decimal, \fBo\fR for octal, or \fBx\fR for hexadecimal. +.IP "\fB\-\-target=\fR\fIbfdname\fR" 4 +.IX Item "--target=bfdname" +Specify an object code format other than your system's default format. +.IP "\fB\-u\fR" 4 +.IX Item "-u" +.PD 0 +.IP "\fB\-\-undefined\-only\fR" 4 +.IX Item "--undefined-only" +.PD +Display only undefined symbols (those external to each object file). +.IP "\fB\-\-defined\-only\fR" 4 +.IX Item "--defined-only" +Display only defined symbols for each object file. +.IP "\fB\-V\fR" 4 +.IX Item "-V" +.PD 0 +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.PD +Show the version number of \fBnm\fR and exit. +.IP "\fB\-X\fR" 4 +.IX Item "-X" +This option is ignored for compatibility with the \s-1AIX\s0 version of +\&\fBnm\fR. It takes one parameter which must be the string +\&\fB32_64\fR. The default mode of \s-1AIX\s0 \fBnm\fR corresponds +to \fB\-X 32\fR, which is not supported by \s-1GNU\s0 \fBnm\fR. +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +Show a summary of the options to \fBnm\fR and exit. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIar\fR\|(1), \fIobjdump\fR\|(1), \fIranlib\fR\|(1), and the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/objcopy.1 b/contrib/binutils-2.14/binutils/doc/objcopy.1 new file mode 100644 index 0000000000..36a06b4b7b --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/objcopy.1 @@ -0,0 +1,638 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "OBJCOPY 1" +.TH OBJCOPY 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +objcopy \- copy and translate object files +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +objcopy [\fB\-F\fR \fIbfdname\fR|\fB\-\-target=\fR\fIbfdname\fR] + [\fB\-I\fR \fIbfdname\fR|\fB\-\-input\-target=\fR\fIbfdname\fR] + [\fB\-O\fR \fIbfdname\fR|\fB\-\-output\-target=\fR\fIbfdname\fR] + [\fB\-B\fR \fIbfdarch\fR|\fB\-\-binary\-architecture=\fR\fIbfdarch\fR] + [\fB\-S\fR|\fB\-\-strip\-all\fR] [\fB\-g\fR|\fB\-\-strip\-debug\fR] + [\fB\-K\fR \fIsymbolname\fR|\fB\-\-keep\-symbol=\fR\fIsymbolname\fR] + [\fB\-N\fR \fIsymbolname\fR|\fB\-\-strip\-symbol=\fR\fIsymbolname\fR] + [\fB\-G\fR \fIsymbolname\fR|\fB\-\-keep\-global\-symbol=\fR\fIsymbolname\fR] + [\fB\-L\fR \fIsymbolname\fR|\fB\-\-localize\-symbol=\fR\fIsymbolname\fR] + [\fB\-W\fR \fIsymbolname\fR|\fB\-\-weaken\-symbol=\fR\fIsymbolname\fR] + [\fB\-x\fR|\fB\-\-discard\-all\fR] [\fB\-X\fR|\fB\-\-discard\-locals\fR] + [\fB\-b\fR \fIbyte\fR|\fB\-\-byte=\fR\fIbyte\fR] + [\fB\-i\fR \fIinterleave\fR|\fB\-\-interleave=\fR\fIinterleave\fR] + [\fB\-j\fR \fIsectionname\fR|\fB\-\-only\-section=\fR\fIsectionname\fR] + [\fB\-R\fR \fIsectionname\fR|\fB\-\-remove\-section=\fR\fIsectionname\fR] + [\fB\-p\fR|\fB\-\-preserve\-dates\fR] + [\fB\-\-debugging\fR] + [\fB\-\-gap\-fill=\fR\fIval\fR] [\fB\-\-pad\-to=\fR\fIaddress\fR] + [\fB\-\-set\-start=\fR\fIval\fR] [\fB\-\-adjust\-start=\fR\fIincr\fR] + [\fB\-\-change\-addresses=\fR\fIincr\fR] + [\fB\-\-change\-section\-address\fR \fIsection\fR{=,+,\-}\fIval\fR] + [\fB\-\-change\-section\-lma\fR \fIsection\fR{=,+,\-}\fIval\fR] + [\fB\-\-change\-section\-vma\fR \fIsection\fR{=,+,\-}\fIval\fR] + [\fB\-\-change\-warnings\fR] [\fB\-\-no\-change\-warnings\fR] + [\fB\-\-set\-section\-flags\fR \fIsection\fR=\fIflags\fR] + [\fB\-\-add\-section\fR \fIsectionname\fR=\fIfilename\fR] + [\fB\-\-rename\-section\fR \fIoldname\fR=\fInewname\fR[,\fIflags\fR]] + [\fB\-\-change\-leading\-char\fR ] [\fB\-\-remove\-leading\-char\fR] + [\fB\-\-srec\-len=\fR\fIival\fR ] [\fB\-\-srec\-forceS3\fR] + [\fB\-\-redefine\-sym\fR \fIold\fR=\fInew\fR ] + [\fB\-\-weaken\fR] + [\fB\-\-keep\-symbols=\fR\fIfilename\fR] + [\fB\-\-strip\-symbols=\fR\fIfilename\fR] + [\fB\-\-keep\-global\-symbols=\fR\fIfilename\fR] + [\fB\-\-localize\-symbols=\fR\fIfilename\fR] + [\fB\-\-weaken\-symbols=\fR\fIfilename\fR] + [\fB\-\-alt\-machine\-code=\fR\fIindex\fR] + [\fB\-\-prefix\-symbols=\fR\fIstring\fR] + [\fB\-\-prefix\-sections=\fR\fIstring\fR] + [\fB\-\-prefix\-alloc\-sections=\fR\fIstring\fR] + [\fB\-v\fR|\fB\-\-verbose\fR] + [\fB\-V\fR|\fB\-\-version\fR] + [\fB\-\-help\fR] [\fB\-\-info\fR] + \fIinfile\fR [\fIoutfile\fR] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \s-1GNU\s0 \fBobjcopy\fR utility copies the contents of an object +file to another. \fBobjcopy\fR uses the \s-1GNU\s0 \s-1BFD\s0 Library to +read and write the object files. It can write the destination object +file in a format different from that of the source object file. The +exact behavior of \fBobjcopy\fR is controlled by command-line options. +Note that \fBobjcopy\fR should be able to copy a fully linked file +between any two formats. However, copying a relocatable object file +between any two formats may not work as expected. +.PP +\&\fBobjcopy\fR creates temporary files to do its translations and +deletes them afterward. \fBobjcopy\fR uses \s-1BFD\s0 to do all its +translation work; it has access to all the formats described in \s-1BFD\s0 +and thus is able to recognize most formats without being told +explicitly. +.PP +\&\fBobjcopy\fR can be used to generate S\-records by using an output +target of \fBsrec\fR (e.g., use \fB\-O srec\fR). +.PP +\&\fBobjcopy\fR can be used to generate a raw binary file by using an +output target of \fBbinary\fR (e.g., use \fB\-O binary\fR). When +\&\fBobjcopy\fR generates a raw binary file, it will essentially produce +a memory dump of the contents of the input object file. All symbols and +relocation information will be discarded. The memory dump will start at +the load address of the lowest section copied into the output file. +.PP +When generating an S\-record or a raw binary file, it may be helpful to +use \fB\-S\fR to remove sections containing debugging information. In +some cases \fB\-R\fR will be useful to remove sections which contain +information that is not needed by the binary file. +.PP +Note\-\-\-\fBobjcopy\fR is not able to change the endianness of its input +files. If the input format has an endianness (some formats do not), +\&\fBobjcopy\fR can only copy the inputs into file formats that have the +same endianness or which have no endianness (e.g., \fBsrec\fR). +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\fIinfile\fR" 4 +.IX Item "infile" +.PD 0 +.IP "\fIoutfile\fR" 4 +.IX Item "outfile" +.PD +The input and output files, respectively. +If you do not specify \fIoutfile\fR, \fBobjcopy\fR creates a +temporary file and destructively renames the result with +the name of \fIinfile\fR. +.IP "\fB\-I\fR \fIbfdname\fR" 4 +.IX Item "-I bfdname" +.PD 0 +.IP "\fB\-\-input\-target=\fR\fIbfdname\fR" 4 +.IX Item "--input-target=bfdname" +.PD +Consider the source file's object format to be \fIbfdname\fR, rather than +attempting to deduce it. +.IP "\fB\-O\fR \fIbfdname\fR" 4 +.IX Item "-O bfdname" +.PD 0 +.IP "\fB\-\-output\-target=\fR\fIbfdname\fR" 4 +.IX Item "--output-target=bfdname" +.PD +Write the output file using the object format \fIbfdname\fR. +.IP "\fB\-F\fR \fIbfdname\fR" 4 +.IX Item "-F bfdname" +.PD 0 +.IP "\fB\-\-target=\fR\fIbfdname\fR" 4 +.IX Item "--target=bfdname" +.PD +Use \fIbfdname\fR as the object format for both the input and the output +file; i.e., simply transfer data from source to destination with no +translation. +.IP "\fB\-B\fR \fIbfdarch\fR" 4 +.IX Item "-B bfdarch" +.PD 0 +.IP "\fB\-\-binary\-architecture=\fR\fIbfdarch\fR" 4 +.IX Item "--binary-architecture=bfdarch" +.PD +Useful when transforming a raw binary input file into an object file. +In this case the output architecture can be set to \fIbfdarch\fR. This +option will be ignored if the input file has a known \fIbfdarch\fR. You +can access this binary data inside a program by referencing the special +symbols that are created by the conversion process. These symbols are +called _binary_\fIobjfile\fR_start, _binary_\fIobjfile\fR_end and +_binary_\fIobjfile\fR_size. e.g. you can transform a picture file into +an object file and then access it in your code using these symbols. +.IP "\fB\-j\fR \fIsectionname\fR" 4 +.IX Item "-j sectionname" +.PD 0 +.IP "\fB\-\-only\-section=\fR\fIsectionname\fR" 4 +.IX Item "--only-section=sectionname" +.PD +Copy only the named section from the input file to the output file. +This option may be given more than once. Note that using this option +inappropriately may make the output file unusable. +.IP "\fB\-R\fR \fIsectionname\fR" 4 +.IX Item "-R sectionname" +.PD 0 +.IP "\fB\-\-remove\-section=\fR\fIsectionname\fR" 4 +.IX Item "--remove-section=sectionname" +.PD +Remove any section named \fIsectionname\fR from the output file. This +option may be given more than once. Note that using this option +inappropriately may make the output file unusable. +.IP "\fB\-S\fR" 4 +.IX Item "-S" +.PD 0 +.IP "\fB\-\-strip\-all\fR" 4 +.IX Item "--strip-all" +.PD +Do not copy relocation and symbol information from the source file. +.IP "\fB\-g\fR" 4 +.IX Item "-g" +.PD 0 +.IP "\fB\-\-strip\-debug\fR" 4 +.IX Item "--strip-debug" +.PD +Do not copy debugging symbols from the source file. +.IP "\fB\-\-strip\-unneeded\fR" 4 +.IX Item "--strip-unneeded" +Strip all symbols that are not needed for relocation processing. +.IP "\fB\-K\fR \fIsymbolname\fR" 4 +.IX Item "-K symbolname" +.PD 0 +.IP "\fB\-\-keep\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--keep-symbol=symbolname" +.PD +Copy only symbol \fIsymbolname\fR from the source file. This option may +be given more than once. +.IP "\fB\-N\fR \fIsymbolname\fR" 4 +.IX Item "-N symbolname" +.PD 0 +.IP "\fB\-\-strip\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--strip-symbol=symbolname" +.PD +Do not copy symbol \fIsymbolname\fR from the source file. This option +may be given more than once. +.IP "\fB\-G\fR \fIsymbolname\fR" 4 +.IX Item "-G symbolname" +.PD 0 +.IP "\fB\-\-keep\-global\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--keep-global-symbol=symbolname" +.PD +Keep only symbol \fIsymbolname\fR global. Make all other symbols local +to the file, so that they are not visible externally. This option may +be given more than once. +.IP "\fB\-L\fR \fIsymbolname\fR" 4 +.IX Item "-L symbolname" +.PD 0 +.IP "\fB\-\-localize\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--localize-symbol=symbolname" +.PD +Make symbol \fIsymbolname\fR local to the file, so that it is not +visible externally. This option may be given more than once. +.IP "\fB\-W\fR \fIsymbolname\fR" 4 +.IX Item "-W symbolname" +.PD 0 +.IP "\fB\-\-weaken\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--weaken-symbol=symbolname" +.PD +Make symbol \fIsymbolname\fR weak. This option may be given more than once. +.IP "\fB\-x\fR" 4 +.IX Item "-x" +.PD 0 +.IP "\fB\-\-discard\-all\fR" 4 +.IX Item "--discard-all" +.PD +Do not copy non-global symbols from the source file. +.IP "\fB\-X\fR" 4 +.IX Item "-X" +.PD 0 +.IP "\fB\-\-discard\-locals\fR" 4 +.IX Item "--discard-locals" +.PD +Do not copy compiler-generated local symbols. +(These usually start with \fBL\fR or \fB.\fR.) +.IP "\fB\-b\fR \fIbyte\fR" 4 +.IX Item "-b byte" +.PD 0 +.IP "\fB\-\-byte=\fR\fIbyte\fR" 4 +.IX Item "--byte=byte" +.PD +Keep only every \fIbyte\fRth byte of the input file (header data is not +affected). \fIbyte\fR can be in the range from 0 to \fIinterleave\fR\-1, +where \fIinterleave\fR is given by the \fB\-i\fR or \fB\-\-interleave\fR +option, or the default of 4. This option is useful for creating files +to program \s-1ROM\s0. It is typically used with an \f(CW\*(C`srec\*(C'\fR output +target. +.IP "\fB\-i\fR \fIinterleave\fR" 4 +.IX Item "-i interleave" +.PD 0 +.IP "\fB\-\-interleave=\fR\fIinterleave\fR" 4 +.IX Item "--interleave=interleave" +.PD +Only copy one out of every \fIinterleave\fR bytes. Select which byte to +copy with the \fB\-b\fR or \fB\-\-byte\fR option. The default is 4. +\&\fBobjcopy\fR ignores this option if you do not specify either \fB\-b\fR or +\&\fB\-\-byte\fR. +.IP "\fB\-p\fR" 4 +.IX Item "-p" +.PD 0 +.IP "\fB\-\-preserve\-dates\fR" 4 +.IX Item "--preserve-dates" +.PD +Set the access and modification dates of the output file to be the same +as those of the input file. +.IP "\fB\-\-debugging\fR" 4 +.IX Item "--debugging" +Convert debugging information, if possible. This is not the default +because only certain debugging formats are supported, and the +conversion process can be time consuming. +.IP "\fB\-\-gap\-fill\fR \fIval\fR" 4 +.IX Item "--gap-fill val" +Fill gaps between sections with \fIval\fR. This operation applies to +the \fIload address\fR (\s-1LMA\s0) of the sections. It is done by increasing +the size of the section with the lower address, and filling in the extra +space created with \fIval\fR. +.IP "\fB\-\-pad\-to\fR \fIaddress\fR" 4 +.IX Item "--pad-to address" +Pad the output file up to the load address \fIaddress\fR. This is +done by increasing the size of the last section. The extra space is +filled in with the value specified by \fB\-\-gap\-fill\fR (default zero). +.IP "\fB\-\-set\-start\fR \fIval\fR" 4 +.IX Item "--set-start val" +Set the start address of the new file to \fIval\fR. Not all object file +formats support setting the start address. +.IP "\fB\-\-change\-start\fR \fIincr\fR" 4 +.IX Item "--change-start incr" +.PD 0 +.IP "\fB\-\-adjust\-start\fR \fIincr\fR" 4 +.IX Item "--adjust-start incr" +.PD +Change the start address by adding \fIincr\fR. Not all object file +formats support setting the start address. +.IP "\fB\-\-change\-addresses\fR \fIincr\fR" 4 +.IX Item "--change-addresses incr" +.PD 0 +.IP "\fB\-\-adjust\-vma\fR \fIincr\fR" 4 +.IX Item "--adjust-vma incr" +.PD +Change the \s-1VMA\s0 and \s-1LMA\s0 addresses of all sections, as well as the start +address, by adding \fIincr\fR. Some object file formats do not permit +section addresses to be changed arbitrarily. Note that this does not +relocate the sections; if the program expects sections to be loaded at a +certain address, and this option is used to change the sections such +that they are loaded at a different address, the program may fail. +.IP "\fB\-\-change\-section\-address\fR \fIsection\fR\fB{=,+,\-}\fR\fIval\fR" 4 +.IX Item "--change-section-address section{=,+,-}val" +.PD 0 +.IP "\fB\-\-adjust\-section\-vma\fR \fIsection\fR\fB{=,+,\-}\fR\fIval\fR" 4 +.IX Item "--adjust-section-vma section{=,+,-}val" +.PD +Set or change both the \s-1VMA\s0 address and the \s-1LMA\s0 address of the named +\&\fIsection\fR. If \fB=\fR is used, the section address is set to +\&\fIval\fR. Otherwise, \fIval\fR is added to or subtracted from the +section address. See the comments under \fB\-\-change\-addresses\fR, +above. If \fIsection\fR does not exist in the input file, a warning will +be issued, unless \fB\-\-no\-change\-warnings\fR is used. +.IP "\fB\-\-change\-section\-lma\fR \fIsection\fR\fB{=,+,\-}\fR\fIval\fR" 4 +.IX Item "--change-section-lma section{=,+,-}val" +Set or change the \s-1LMA\s0 address of the named \fIsection\fR. The \s-1LMA\s0 +address is the address where the section will be loaded into memory at +program load time. Normally this is the same as the \s-1VMA\s0 address, which +is the address of the section at program run time, but on some systems, +especially those where a program is held in \s-1ROM\s0, the two can be +different. If \fB=\fR is used, the section address is set to +\&\fIval\fR. Otherwise, \fIval\fR is added to or subtracted from the +section address. See the comments under \fB\-\-change\-addresses\fR, +above. If \fIsection\fR does not exist in the input file, a warning +will be issued, unless \fB\-\-no\-change\-warnings\fR is used. +.IP "\fB\-\-change\-section\-vma\fR \fIsection\fR\fB{=,+,\-}\fR\fIval\fR" 4 +.IX Item "--change-section-vma section{=,+,-}val" +Set or change the \s-1VMA\s0 address of the named \fIsection\fR. The \s-1VMA\s0 +address is the address where the section will be located once the +program has started executing. Normally this is the same as the \s-1LMA\s0 +address, which is the address where the section will be loaded into +memory, but on some systems, especially those where a program is held in +\&\s-1ROM\s0, the two can be different. If \fB=\fR is used, the section address +is set to \fIval\fR. Otherwise, \fIval\fR is added to or subtracted +from the section address. See the comments under +\&\fB\-\-change\-addresses\fR, above. If \fIsection\fR does not exist in +the input file, a warning will be issued, unless +\&\fB\-\-no\-change\-warnings\fR is used. +.IP "\fB\-\-change\-warnings\fR" 4 +.IX Item "--change-warnings" +.PD 0 +.IP "\fB\-\-adjust\-warnings\fR" 4 +.IX Item "--adjust-warnings" +.PD +If \fB\-\-change\-section\-address\fR or \fB\-\-change\-section\-lma\fR or +\&\fB\-\-change\-section\-vma\fR is used, and the named section does not +exist, issue a warning. This is the default. +.IP "\fB\-\-no\-change\-warnings\fR" 4 +.IX Item "--no-change-warnings" +.PD 0 +.IP "\fB\-\-no\-adjust\-warnings\fR" 4 +.IX Item "--no-adjust-warnings" +.PD +Do not issue a warning if \fB\-\-change\-section\-address\fR or +\&\fB\-\-adjust\-section\-lma\fR or \fB\-\-adjust\-section\-vma\fR is used, even +if the named section does not exist. +.IP "\fB\-\-set\-section\-flags\fR \fIsection\fR\fB=\fR\fIflags\fR" 4 +.IX Item "--set-section-flags section=flags" +Set the flags for the named section. The \fIflags\fR argument is a +comma separated string of flag names. The recognized names are +\&\fBalloc\fR, \fBcontents\fR, \fBload\fR, \fBnoload\fR, +\&\fBreadonly\fR, \fBcode\fR, \fBdata\fR, \fBrom\fR, \fBshare\fR, and +\&\fBdebug\fR. You can set the \fBcontents\fR flag for a section which +does not have contents, but it is not meaningful to clear the +\&\fBcontents\fR flag of a section which does have contents\*(--just remove +the section instead. Not all flags are meaningful for all object file +formats. +.IP "\fB\-\-add\-section\fR \fIsectionname\fR\fB=\fR\fIfilename\fR" 4 +.IX Item "--add-section sectionname=filename" +Add a new section named \fIsectionname\fR while copying the file. The +contents of the new section are taken from the file \fIfilename\fR. The +size of the section will be the size of the file. This option only +works on file formats which can support sections with arbitrary names. +.IP "\fB\-\-rename\-section\fR \fIoldname\fR\fB=\fR\fInewname\fR\fB[,\fR\fIflags\fR\fB]\fR" 4 +.IX Item "--rename-section oldname=newname[,flags]" +Rename a section from \fIoldname\fR to \fInewname\fR, optionally +changing the section's flags to \fIflags\fR in the process. This has +the advantage over usng a linker script to perform the rename in that +the output stays as an object file and does not become a linked +executable. +.Sp +This option is particularly helpful when the input format is binary, +since this will always create a section called .data. If for example, +you wanted instead to create a section called .rodata containing binary +data you could use the following command line to achieve it: +.Sp +.Vb 3 +\& objcopy -I binary -O -B \e +\& --rename-section .data=.rodata,alloc,load,readonly,data,contents \e +\& +.Ve +.IP "\fB\-\-change\-leading\-char\fR" 4 +.IX Item "--change-leading-char" +Some object file formats use special characters at the start of +symbols. The most common such character is underscore, which compilers +often add before every symbol. This option tells \fBobjcopy\fR to +change the leading character of every symbol when it converts between +object file formats. If the object file formats use the same leading +character, this option has no effect. Otherwise, it will add a +character, or remove a character, or change a character, as +appropriate. +.IP "\fB\-\-remove\-leading\-char\fR" 4 +.IX Item "--remove-leading-char" +If the first character of a global symbol is a special symbol leading +character used by the object file format, remove the character. The +most common symbol leading character is underscore. This option will +remove a leading underscore from all global symbols. This can be useful +if you want to link together objects of different file formats with +different conventions for symbol names. This is different from +\&\fB\-\-change\-leading\-char\fR because it always changes the symbol name +when appropriate, regardless of the object file format of the output +file. +.IP "\fB\-\-srec\-len=\fR\fIival\fR" 4 +.IX Item "--srec-len=ival" +Meaningful only for srec output. Set the maximum length of the Srecords +being produced to \fIival\fR. This length covers both address, data and +crc fields. +.IP "\fB\-\-srec\-forceS3\fR" 4 +.IX Item "--srec-forceS3" +Meaningful only for srec output. Avoid generation of S1/S2 records, +creating S3\-only record format. +.IP "\fB\-\-redefine\-sym\fR \fIold\fR\fB=\fR\fInew\fR" 4 +.IX Item "--redefine-sym old=new" +Change the name of a symbol \fIold\fR, to \fInew\fR. This can be useful +when one is trying link two things together for which you have no +source, and there are name collisions. +.IP "\fB\-\-weaken\fR" 4 +.IX Item "--weaken" +Change all global symbols in the file to be weak. This can be useful +when building an object which will be linked against other objects using +the \fB\-R\fR option to the linker. This option is only effective when +using an object file format which supports weak symbols. +.IP "\fB\-\-keep\-symbols=\fR\fIfilename\fR" 4 +.IX Item "--keep-symbols=filename" +Apply \fB\-\-keep\-symbol\fR option to each symbol listed in the file +\&\fIfilename\fR. \fIfilename\fR is simply a flat file, with one symbol +name per line. Line comments may be introduced by the hash character. +This option may be given more than once. +.IP "\fB\-\-strip\-symbols=\fR\fIfilename\fR" 4 +.IX Item "--strip-symbols=filename" +Apply \fB\-\-strip\-symbol\fR option to each symbol listed in the file +\&\fIfilename\fR. \fIfilename\fR is simply a flat file, with one symbol +name per line. Line comments may be introduced by the hash character. +This option may be given more than once. +.IP "\fB\-\-keep\-global\-symbols=\fR\fIfilename\fR" 4 +.IX Item "--keep-global-symbols=filename" +Apply \fB\-\-keep\-global\-symbol\fR option to each symbol listed in the +file \fIfilename\fR. \fIfilename\fR is simply a flat file, with one +symbol name per line. Line comments may be introduced by the hash +character. This option may be given more than once. +.IP "\fB\-\-localize\-symbols=\fR\fIfilename\fR" 4 +.IX Item "--localize-symbols=filename" +Apply \fB\-\-localize\-symbol\fR option to each symbol listed in the file +\&\fIfilename\fR. \fIfilename\fR is simply a flat file, with one symbol +name per line. Line comments may be introduced by the hash character. +This option may be given more than once. +.IP "\fB\-\-weaken\-symbols=\fR\fIfilename\fR" 4 +.IX Item "--weaken-symbols=filename" +Apply \fB\-\-weaken\-symbol\fR option to each symbol listed in the file +\&\fIfilename\fR. \fIfilename\fR is simply a flat file, with one symbol +name per line. Line comments may be introduced by the hash character. +This option may be given more than once. +.IP "\fB\-\-alt\-machine\-code=\fR\fIindex\fR" 4 +.IX Item "--alt-machine-code=index" +If the output architecture has alternate machine codes, use the +\&\fIindex\fRth code instead of the default one. This is useful in case +a machine is assigned an official code and the tool-chain adopts the +new code, but other applications still depend on the original code +being used. +.IP "\fB\-\-prefix\-symbols=\fR\fIstring\fR" 4 +.IX Item "--prefix-symbols=string" +Prefix all symbols in the output file with \fIstring\fR. +.IP "\fB\-\-prefix\-sections=\fR\fIstring\fR" 4 +.IX Item "--prefix-sections=string" +Prefix all section names in the output file with \fIstring\fR. +.IP "\fB\-\-prefix\-alloc\-sections=\fR\fIstring\fR" 4 +.IX Item "--prefix-alloc-sections=string" +Prefix all the names of all allocated sections in the output file with +\&\fIstring\fR. +.IP "\fB\-V\fR" 4 +.IX Item "-V" +.PD 0 +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.PD +Show the version number of \fBobjcopy\fR. +.IP "\fB\-v\fR" 4 +.IX Item "-v" +.PD 0 +.IP "\fB\-\-verbose\fR" 4 +.IX Item "--verbose" +.PD +Verbose output: list all object files modified. In the case of +archives, \fBobjcopy \-V\fR lists all members of the archive. +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +Show a summary of the options to \fBobjcopy\fR. +.IP "\fB\-\-info\fR" 4 +.IX Item "--info" +Display a list showing all architectures and object formats available. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIld\fR\|(1), \fIobjdump\fR\|(1), and the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/objdump.1 b/contrib/binutils-2.14/binutils/doc/objdump.1 new file mode 100644 index 0000000000..b881102abf --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/objdump.1 @@ -0,0 +1,580 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "OBJDUMP 1" +.TH OBJDUMP 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +objdump \- display information from object files. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +objdump [\fB\-a\fR|\fB\-\-archive\-headers\fR] + [\fB\-b\fR \fIbfdname\fR|\fB\-\-target=\fR\fIbfdname\fR] + [\fB\-C\fR|\fB\-\-demangle\fR[=\fIstyle\fR] ] + [\fB\-d\fR|\fB\-\-disassemble\fR] + [\fB\-D\fR|\fB\-\-disassemble\-all\fR] + [\fB\-z\fR|\fB\-\-disassemble\-zeroes\fR] + [\fB\-EB\fR|\fB\-EL\fR|\fB\-\-endian=\fR{big | little }] + [\fB\-f\fR|\fB\-\-file\-headers\fR] + [\fB\-\-file\-start\-context\fR] + [\fB\-g\fR|\fB\-\-debugging\fR] + [\fB\-h\fR|\fB\-\-section\-headers\fR|\fB\-\-headers\fR] + [\fB\-i\fR|\fB\-\-info\fR] + [\fB\-j\fR \fIsection\fR|\fB\-\-section=\fR\fIsection\fR] + [\fB\-l\fR|\fB\-\-line\-numbers\fR] + [\fB\-S\fR|\fB\-\-source\fR] + [\fB\-m\fR \fImachine\fR|\fB\-\-architecture=\fR\fImachine\fR] + [\fB\-M\fR \fIoptions\fR|\fB\-\-disassembler\-options=\fR\fIoptions\fR] + [\fB\-p\fR|\fB\-\-private\-headers\fR] + [\fB\-r\fR|\fB\-\-reloc\fR] + [\fB\-R\fR|\fB\-\-dynamic\-reloc\fR] + [\fB\-s\fR|\fB\-\-full\-contents\fR] + [\fB\-G\fR|\fB\-\-stabs\fR] + [\fB\-t\fR|\fB\-\-syms\fR] + [\fB\-T\fR|\fB\-\-dynamic\-syms\fR] + [\fB\-x\fR|\fB\-\-all\-headers\fR] + [\fB\-w\fR|\fB\-\-wide\fR] + [\fB\-\-start\-address=\fR\fIaddress\fR] + [\fB\-\-stop\-address=\fR\fIaddress\fR] + [\fB\-\-prefix\-addresses\fR] + [\fB\-\-[no\-]show\-raw\-insn\fR] + [\fB\-\-adjust\-vma=\fR\fIoffset\fR] + [\fB\-V\fR|\fB\-\-version\fR] + [\fB\-H\fR|\fB\-\-help\fR] + \fIobjfile\fR... +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBobjdump\fR displays information about one or more object files. +The options control what particular information to display. This +information is mostly useful to programmers who are working on the +compilation tools, as opposed to programmers who just want their +program to compile and work. +.PP +\&\fIobjfile\fR... are the object files to be examined. When you +specify archives, \fBobjdump\fR shows information on each of the member +object files. +.SH "OPTIONS" +.IX Header "OPTIONS" +The long and short forms of options, shown here as alternatives, are +equivalent. At least one option from the list +\&\fB\-a,\-d,\-D,\-f,\-g,\-G,\-h,\-H,\-p,\-r,\-R,\-S,\-t,\-T,\-V,\-x\fR must be given. +.IP "\fB\-a\fR" 4 +.IX Item "-a" +.PD 0 +.IP "\fB\-\-archive\-header\fR" 4 +.IX Item "--archive-header" +.PD +If any of the \fIobjfile\fR files are archives, display the archive +header information (in a format similar to \fBls \-l\fR). Besides the +information you could list with \fBar tv\fR, \fBobjdump \-a\fR shows +the object file format of each archive member. +.IP "\fB\-\-adjust\-vma=\fR\fIoffset\fR" 4 +.IX Item "--adjust-vma=offset" +When dumping information, first add \fIoffset\fR to all the section +addresses. This is useful if the section addresses do not correspond to +the symbol table, which can happen when putting sections at particular +addresses when using a format which can not represent section addresses, +such as a.out. +.IP "\fB\-b\fR \fIbfdname\fR" 4 +.IX Item "-b bfdname" +.PD 0 +.IP "\fB\-\-target=\fR\fIbfdname\fR" 4 +.IX Item "--target=bfdname" +.PD +Specify that the object-code format for the object files is +\&\fIbfdname\fR. This option may not be necessary; \fIobjdump\fR can +automatically recognize many formats. +.Sp +For example, +.Sp +.Vb 1 +\& objdump -b oasys -m vax -h fu.o +.Ve +.Sp +displays summary information from the section headers (\fB\-h\fR) of +\&\fIfu.o\fR, which is explicitly identified (\fB\-m\fR) as a \s-1VAX\s0 object +file in the format produced by Oasys compilers. You can list the +formats available with the \fB\-i\fR option. +.IP "\fB\-C\fR" 4 +.IX Item "-C" +.PD 0 +.IP "\fB\-\-demangle[=\fR\fIstyle\fR\fB]\fR" 4 +.IX Item "--demangle[=style]" +.PD +Decode (\fIdemangle\fR) low-level symbol names into user-level names. +Besides removing any initial underscore prepended by the system, this +makes \*(C+ function names readable. Different compilers have different +mangling styles. The optional demangling style argument can be used to +choose an appropriate demangling style for your compiler. +.IP "\fB\-g\fR" 4 +.IX Item "-g" +.PD 0 +.IP "\fB\-\-debugging\fR" 4 +.IX Item "--debugging" +.PD +Display debugging information. This attempts to parse debugging +information stored in the file and print it out using a C like syntax. +Only certain types of debugging information have been implemented. +Some other types are supported by \fBreadelf \-w\fR. +.IP "\fB\-d\fR" 4 +.IX Item "-d" +.PD 0 +.IP "\fB\-\-disassemble\fR" 4 +.IX Item "--disassemble" +.PD +Display the assembler mnemonics for the machine instructions from +\&\fIobjfile\fR. This option only disassembles those sections which are +expected to contain instructions. +.IP "\fB\-D\fR" 4 +.IX Item "-D" +.PD 0 +.IP "\fB\-\-disassemble\-all\fR" 4 +.IX Item "--disassemble-all" +.PD +Like \fB\-d\fR, but disassemble the contents of all sections, not just +those expected to contain instructions. +.IP "\fB\-\-prefix\-addresses\fR" 4 +.IX Item "--prefix-addresses" +When disassembling, print the complete address on each line. This is +the older disassembly format. +.IP "\fB\-EB\fR" 4 +.IX Item "-EB" +.PD 0 +.IP "\fB\-EL\fR" 4 +.IX Item "-EL" +.IP "\fB\-\-endian={big|little}\fR" 4 +.IX Item "--endian={big|little}" +.PD +Specify the endianness of the object files. This only affects +disassembly. This can be useful when disassembling a file format which +does not describe endianness information, such as S\-records. +.IP "\fB\-f\fR" 4 +.IX Item "-f" +.PD 0 +.IP "\fB\-\-file\-headers\fR" 4 +.IX Item "--file-headers" +.PD +Display summary information from the overall header of +each of the \fIobjfile\fR files. +.IP "\fB\-\-file\-start\-context\fR" 4 +.IX Item "--file-start-context" +Specify that when displaying interlisted source code/disassembly +(assumes \fB\-S\fR) from a file that has not yet been displayed, extend the +context to the start of the file. +.IP "\fB\-h\fR" 4 +.IX Item "-h" +.PD 0 +.IP "\fB\-\-section\-headers\fR" 4 +.IX Item "--section-headers" +.IP "\fB\-\-headers\fR" 4 +.IX Item "--headers" +.PD +Display summary information from the section headers of the +object file. +.Sp +File segments may be relocated to nonstandard addresses, for example by +using the \fB\-Ttext\fR, \fB\-Tdata\fR, or \fB\-Tbss\fR options to +\&\fBld\fR. However, some object file formats, such as a.out, do not +store the starting address of the file segments. In those situations, +although \fBld\fR relocates the sections correctly, using \fBobjdump +\&\-h\fR to list the file section headers cannot show the correct addresses. +Instead, it shows the usual addresses, which are implicit for the +target. +.IP "\fB\-H\fR" 4 +.IX Item "-H" +.PD 0 +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +.PD +Print a summary of the options to \fBobjdump\fR and exit. +.IP "\fB\-i\fR" 4 +.IX Item "-i" +.PD 0 +.IP "\fB\-\-info\fR" 4 +.IX Item "--info" +.PD +Display a list showing all architectures and object formats available +for specification with \fB\-b\fR or \fB\-m\fR. +.IP "\fB\-j\fR \fIname\fR" 4 +.IX Item "-j name" +.PD 0 +.IP "\fB\-\-section=\fR\fIname\fR" 4 +.IX Item "--section=name" +.PD +Display information only for section \fIname\fR. +.IP "\fB\-l\fR" 4 +.IX Item "-l" +.PD 0 +.IP "\fB\-\-line\-numbers\fR" 4 +.IX Item "--line-numbers" +.PD +Label the display (using debugging information) with the filename and +source line numbers corresponding to the object code or relocs shown. +Only useful with \fB\-d\fR, \fB\-D\fR, or \fB\-r\fR. +.IP "\fB\-m\fR \fImachine\fR" 4 +.IX Item "-m machine" +.PD 0 +.IP "\fB\-\-architecture=\fR\fImachine\fR" 4 +.IX Item "--architecture=machine" +.PD +Specify the architecture to use when disassembling object files. This +can be useful when disassembling object files which do not describe +architecture information, such as S\-records. You can list the available +architectures with the \fB\-i\fR option. +.IP "\fB\-M\fR \fIoptions\fR" 4 +.IX Item "-M options" +.PD 0 +.IP "\fB\-\-disassembler\-options=\fR\fIoptions\fR" 4 +.IX Item "--disassembler-options=options" +.PD +Pass target specific information to the disassembler. Only supported on +some targets. +.Sp +If the target is an \s-1ARM\s0 architecture then this switch can be used to +select which register name set is used during disassembler. Specifying +\&\fB\-M reg-name-std\fR (the default) will select the register names as +used in \s-1ARM\s0's instruction set documentation, but with register 13 called +\&'sp', register 14 called 'lr' and register 15 called 'pc'. Specifying +\&\fB\-M reg-names-apcs\fR will select the name set used by the \s-1ARM\s0 +Procedure Call Standard, whilst specifying \fB\-M reg-names-raw\fR will +just use \fBr\fR followed by the register number. +.Sp +There are also two variants on the \s-1APCS\s0 register naming scheme enabled +by \fB\-M reg-names-atpcs\fR and \fB\-M reg-names-special-atpcs\fR which +use the ARM/Thumb Procedure Call Standard naming conventions. (Either +with the normal register names or the special register names). +.Sp +This option can also be used for \s-1ARM\s0 architectures to force the +disassembler to interpret all instructions as Thumb instructions by +using the switch \fB\-\-disassembler\-options=force\-thumb\fR. This can be +useful when attempting to disassemble thumb code produced by other +compilers. +.Sp +For the x86, some of the options duplicate functions of the \fB\-m\fR +switch, but allow finer grained control. Multiple selections from the +following may be specified as a comma separated string. +\&\fBx86\-64\fR, \fBi386\fR and \fBi8086\fR select disassembly for +the given architecture. \fBintel\fR and \fBatt\fR select between +intel syntax mode and \s-1AT&T\s0 syntax mode. \fBaddr32\fR, +\&\fBaddr16\fR, \fBdata32\fR and \fBdata16\fR specify the default +address size and operand size. These four options will be overridden if +\&\fBx86\-64\fR, \fBi386\fR or \fBi8086\fR appear later in the +option string. Lastly, \fBsuffix\fR, when in \s-1AT&T\s0 mode, +instructs the disassembler to print a mnemonic suffix even when the +suffix could be inferred by the operands. +.Sp +For \s-1PPC\s0, \fBbooke\fR, \fBbooke32\fR and \fBbooke64\fR select +disassembly of BookE instructions. \fB32\fR and \fB64\fR select +PowerPC and PowerPC64 disassembly, respectively. +.Sp +For \s-1MIPS\s0, this option controls the printing of register names in +disassembled instructions. Multiple selections from the +following may be specified as a comma separated string, and invalid +options are ignored: +.RS 4 +.ie n .IP """gpr\-names=\f(CI\s-1ABI\s0\f(CW""" 4 +.el .IP "\f(CWgpr\-names=\f(CI\s-1ABI\s0\f(CW\fR" 4 +.IX Item "gpr-names=ABI" +Print \s-1GPR\s0 (general\-purpose register) names as appropriate +for the specified \s-1ABI\s0. By default, \s-1GPR\s0 names are selected according to +the \s-1ABI\s0 of the binary being disassembled. +.ie n .IP """fpr\-names=\f(CI\s-1ABI\s0\f(CW""" 4 +.el .IP "\f(CWfpr\-names=\f(CI\s-1ABI\s0\f(CW\fR" 4 +.IX Item "fpr-names=ABI" +Print \s-1FPR\s0 (floating\-point register) names as +appropriate for the specified \s-1ABI\s0. By default, \s-1FPR\s0 numbers are printed +rather than names. +.ie n .IP """cp0\-names=\f(CI\s-1ARCH\s0\f(CW""" 4 +.el .IP "\f(CWcp0\-names=\f(CI\s-1ARCH\s0\f(CW\fR" 4 +.IX Item "cp0-names=ARCH" +Print \s-1CP0\s0 (system control coprocessor; coprocessor 0) register names +as appropriate for the \s-1CPU\s0 or architecture specified by +\&\fI\s-1ARCH\s0\fR. By default, \s-1CP0\s0 register names are selected according to +the architecture and \s-1CPU\s0 of the binary being disassembled. +.ie n .IP """hwr\-names=\f(CI\s-1ARCH\s0\f(CW""" 4 +.el .IP "\f(CWhwr\-names=\f(CI\s-1ARCH\s0\f(CW\fR" 4 +.IX Item "hwr-names=ARCH" +Print \s-1HWR\s0 (hardware register, used by the \f(CW\*(C`rdhwr\*(C'\fR instruction) names +as appropriate for the \s-1CPU\s0 or architecture specified by +\&\fI\s-1ARCH\s0\fR. By default, \s-1HWR\s0 names are selected according to +the architecture and \s-1CPU\s0 of the binary being disassembled. +.ie n .IP """reg\-names=\f(CI\s-1ABI\s0\f(CW""" 4 +.el .IP "\f(CWreg\-names=\f(CI\s-1ABI\s0\f(CW\fR" 4 +.IX Item "reg-names=ABI" +Print \s-1GPR\s0 and \s-1FPR\s0 names as appropriate for the selected \s-1ABI\s0. +.ie n .IP """reg\-names=\f(CI\s-1ARCH\s0\f(CW""" 4 +.el .IP "\f(CWreg\-names=\f(CI\s-1ARCH\s0\f(CW\fR" 4 +.IX Item "reg-names=ARCH" +Print CPU-specific register names (\s-1CP0\s0 register and \s-1HWR\s0 names) +as appropriate for the selected \s-1CPU\s0 or architecture. +.RE +.RS 4 +.Sp +For any of the options listed above, \fI\s-1ABI\s0\fR or +\&\fI\s-1ARCH\s0\fR may be specified as \fBnumeric\fR to have numbers printed +rather than names, for the selected types of registers. +You can list the available values of \fI\s-1ABI\s0\fR and \fI\s-1ARCH\s0\fR using +the \fB\-\-help\fR option. +.RE +.IP "\fB\-p\fR" 4 +.IX Item "-p" +.PD 0 +.IP "\fB\-\-private\-headers\fR" 4 +.IX Item "--private-headers" +.PD +Print information that is specific to the object file format. The exact +information printed depends upon the object file format. For some +object file formats, no additional information is printed. +.IP "\fB\-r\fR" 4 +.IX Item "-r" +.PD 0 +.IP "\fB\-\-reloc\fR" 4 +.IX Item "--reloc" +.PD +Print the relocation entries of the file. If used with \fB\-d\fR or +\&\fB\-D\fR, the relocations are printed interspersed with the +disassembly. +.IP "\fB\-R\fR" 4 +.IX Item "-R" +.PD 0 +.IP "\fB\-\-dynamic\-reloc\fR" 4 +.IX Item "--dynamic-reloc" +.PD +Print the dynamic relocation entries of the file. This is only +meaningful for dynamic objects, such as certain types of shared +libraries. +.IP "\fB\-s\fR" 4 +.IX Item "-s" +.PD 0 +.IP "\fB\-\-full\-contents\fR" 4 +.IX Item "--full-contents" +.PD +Display the full contents of any sections requested. +.IP "\fB\-S\fR" 4 +.IX Item "-S" +.PD 0 +.IP "\fB\-\-source\fR" 4 +.IX Item "--source" +.PD +Display source code intermixed with disassembly, if possible. Implies +\&\fB\-d\fR. +.IP "\fB\-\-show\-raw\-insn\fR" 4 +.IX Item "--show-raw-insn" +When disassembling instructions, print the instruction in hex as well as +in symbolic form. This is the default except when +\&\fB\-\-prefix\-addresses\fR is used. +.IP "\fB\-\-no\-show\-raw\-insn\fR" 4 +.IX Item "--no-show-raw-insn" +When disassembling instructions, do not print the instruction bytes. +This is the default when \fB\-\-prefix\-addresses\fR is used. +.IP "\fB\-G\fR" 4 +.IX Item "-G" +.PD 0 +.IP "\fB\-\-stabs\fR" 4 +.IX Item "--stabs" +.PD +Display the full contents of any sections requested. Display the +contents of the .stab and .stab.index and .stab.excl sections from an +\&\s-1ELF\s0 file. This is only useful on systems (such as Solaris 2.0) in which +\&\f(CW\*(C`.stab\*(C'\fR debugging symbol-table entries are carried in an \s-1ELF\s0 +section. In most other file formats, debugging symbol-table entries are +interleaved with linkage symbols, and are visible in the \fB\-\-syms\fR +output. +.IP "\fB\-\-start\-address=\fR\fIaddress\fR" 4 +.IX Item "--start-address=address" +Start displaying data at the specified address. This affects the output +of the \fB\-d\fR, \fB\-r\fR and \fB\-s\fR options. +.IP "\fB\-\-stop\-address=\fR\fIaddress\fR" 4 +.IX Item "--stop-address=address" +Stop displaying data at the specified address. This affects the output +of the \fB\-d\fR, \fB\-r\fR and \fB\-s\fR options. +.IP "\fB\-t\fR" 4 +.IX Item "-t" +.PD 0 +.IP "\fB\-\-syms\fR" 4 +.IX Item "--syms" +.PD +Print the symbol table entries of the file. +This is similar to the information provided by the \fBnm\fR program. +.IP "\fB\-T\fR" 4 +.IX Item "-T" +.PD 0 +.IP "\fB\-\-dynamic\-syms\fR" 4 +.IX Item "--dynamic-syms" +.PD +Print the dynamic symbol table entries of the file. This is only +meaningful for dynamic objects, such as certain types of shared +libraries. This is similar to the information provided by the \fBnm\fR +program when given the \fB\-D\fR (\fB\-\-dynamic\fR) option. +.IP "\fB\-V\fR" 4 +.IX Item "-V" +.PD 0 +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.PD +Print the version number of \fBobjdump\fR and exit. +.IP "\fB\-x\fR" 4 +.IX Item "-x" +.PD 0 +.IP "\fB\-\-all\-headers\fR" 4 +.IX Item "--all-headers" +.PD +Display all available header information, including the symbol table and +relocation entries. Using \fB\-x\fR is equivalent to specifying all of +\&\fB\-a \-f \-h \-r \-t\fR. +.IP "\fB\-w\fR" 4 +.IX Item "-w" +.PD 0 +.IP "\fB\-\-wide\fR" 4 +.IX Item "--wide" +.PD +Format some lines for output devices that have more than 80 columns. +Also do not truncate symbol names when they are displayed. +.IP "\fB\-z\fR" 4 +.IX Item "-z" +.PD 0 +.IP "\fB\-\-disassemble\-zeroes\fR" 4 +.IX Item "--disassemble-zeroes" +.PD +Normally the disassembly output will skip blocks of zeroes. This +option directs the disassembler to disassemble those blocks, just like +any other data. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fInm\fR\|(1), \fIreadelf\fR\|(1), and the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/ranlib.1 b/contrib/binutils-2.14/binutils/doc/ranlib.1 new file mode 100644 index 0000000000..b471ff5e14 --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/ranlib.1 @@ -0,0 +1,175 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "RANLIB 1" +.TH RANLIB 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +ranlib \- generate index to archive. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +ranlib [\fB\-vV\fR] \fIarchive\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBranlib\fR generates an index to the contents of an archive and +stores it in the archive. The index lists each symbol defined by a +member of an archive that is a relocatable object file. +.PP +You may use \fBnm \-s\fR or \fBnm \-\-print\-armap\fR to list this index. +.PP +An archive with such an index speeds up linking to the library and +allows routines in the library to call each other without regard to +their placement in the archive. +.PP +The \s-1GNU\s0 \fBranlib\fR program is another form of \s-1GNU\s0 \fBar\fR; running +\&\fBranlib\fR is completely equivalent to executing \fBar \-s\fR. +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\fB\-v\fR" 4 +.IX Item "-v" +.PD 0 +.IP "\fB\-V\fR" 4 +.IX Item "-V" +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.PD +Show the version number of \fBranlib\fR. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIar\fR\|(1), \fInm\fR\|(1), and the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/readelf.1 b/contrib/binutils-2.14/binutils/doc/readelf.1 new file mode 100644 index 0000000000..7c678da94a --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/readelf.1 @@ -0,0 +1,348 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "READELF 1" +.TH READELF 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +readelf \- Displays information about ELF files. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +readelf [\fB\-a\fR|\fB\-\-all\fR] + [\fB\-h\fR|\fB\-\-file\-header\fR] + [\fB\-l\fR|\fB\-\-program\-headers\fR|\fB\-\-segments\fR] + [\fB\-S\fR|\fB\-\-section\-headers\fR|\fB\-\-sections\fR] + [\fB\-e\fR|\fB\-\-headers\fR] + [\fB\-s\fR|\fB\-\-syms\fR|\fB\-\-symbols\fR] + [\fB\-n\fR|\fB\-\-notes\fR] + [\fB\-r\fR|\fB\-\-relocs\fR] + [\fB\-u\fR|\fB\-\-unwind\fR] + [\fB\-d\fR|\fB\-\-dynamic\fR] + [\fB\-V\fR|\fB\-\-version\-info\fR] + [\fB\-A\fR|\fB\-\-arch\-specific\fR] + [\fB\-D\fR|\fB\-\-use\-dynamic\fR] + [\fB\-x\fR |\fB\-\-hex\-dump=\fR] + [\fB\-w[liaprmfFso]\fR| + \fB\-\-debug\-dump\fR[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=frames\-interp,=str,=loc]] + [\fB\-I\fR|\fB\-histogram\fR] + [\fB\-v\fR|\fB\-\-version\fR] + [\fB\-W\fR|\fB\-\-wide\fR] + [\fB\-H\fR|\fB\-\-help\fR] + \fIelffile\fR... +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBreadelf\fR displays information about one or more \s-1ELF\s0 format object +files. The options control what particular information to display. +.PP +\&\fIelffile\fR... are the object files to be examined. At the +moment, \fBreadelf\fR does not support examining archives, nor does it +support examining 64 bit \s-1ELF\s0 files. +.SH "OPTIONS" +.IX Header "OPTIONS" +The long and short forms of options, shown here as alternatives, are +equivalent. At least one option besides \fB\-v\fR or \fB\-H\fR must be +given. +.IP "\fB\-a\fR" 4 +.IX Item "-a" +.PD 0 +.IP "\fB\-\-all\fR" 4 +.IX Item "--all" +.PD +Equivalent to specifiying \fB\-\-file\-header\fR, +\&\fB\-\-program\-headers\fR, \fB\-\-sections\fR, \fB\-\-symbols\fR, +\&\fB\-\-relocs\fR, \fB\-\-dynamic\fR, \fB\-\-notes\fR and +\&\fB\-\-version\-info\fR. +.IP "\fB\-h\fR" 4 +.IX Item "-h" +.PD 0 +.IP "\fB\-\-file\-header\fR" 4 +.IX Item "--file-header" +.PD +Displays the information contained in the \s-1ELF\s0 header at the start of the +file. +.IP "\fB\-l\fR" 4 +.IX Item "-l" +.PD 0 +.IP "\fB\-\-program\-headers\fR" 4 +.IX Item "--program-headers" +.IP "\fB\-\-segments\fR" 4 +.IX Item "--segments" +.PD +Displays the information contained in the file's segment headers, if it +has any. +.IP "\fB\-S\fR" 4 +.IX Item "-S" +.PD 0 +.IP "\fB\-\-sections\fR" 4 +.IX Item "--sections" +.IP "\fB\-\-section\-headers\fR" 4 +.IX Item "--section-headers" +.PD +Displays the information contained in the file's section headers, if it +has any. +.IP "\fB\-s\fR" 4 +.IX Item "-s" +.PD 0 +.IP "\fB\-\-symbols\fR" 4 +.IX Item "--symbols" +.IP "\fB\-\-syms\fR" 4 +.IX Item "--syms" +.PD +Displays the entries in symbol table section of the file, if it has one. +.IP "\fB\-e\fR" 4 +.IX Item "-e" +.PD 0 +.IP "\fB\-\-headers\fR" 4 +.IX Item "--headers" +.PD +Display all the headers in the file. Equivalent to \fB\-h \-l \-S\fR. +.IP "\fB\-n\fR" 4 +.IX Item "-n" +.PD 0 +.IP "\fB\-\-notes\fR" 4 +.IX Item "--notes" +.PD +Displays the contents of the \s-1NOTE\s0 segment, if it exists. +.IP "\fB\-r\fR" 4 +.IX Item "-r" +.PD 0 +.IP "\fB\-\-relocs\fR" 4 +.IX Item "--relocs" +.PD +Displays the contents of the file's relocation section, if it has one. +.IP "\fB\-u\fR" 4 +.IX Item "-u" +.PD 0 +.IP "\fB\-\-unwind\fR" 4 +.IX Item "--unwind" +.PD +Displays the contents of the file's unwind section, if it has one. Only +the unwind sections for \s-1IA64\s0 \s-1ELF\s0 files are currently supported. +.IP "\fB\-u\fR" 4 +.IX Item "-u" +.PD 0 +.IP "\fB\-\-unwind\fR" 4 +.IX Item "--unwind" +.PD +Displays the contents of the file's unwind section, if it has one. Only +the unwind sections for \s-1IA64\s0 \s-1ELF\s0 files are currently supported. +.IP "\fB\-d\fR" 4 +.IX Item "-d" +.PD 0 +.IP "\fB\-\-dynamic\fR" 4 +.IX Item "--dynamic" +.PD +Displays the contents of the file's dynamic section, if it has one. +.IP "\fB\-V\fR" 4 +.IX Item "-V" +.PD 0 +.IP "\fB\-\-version\-info\fR" 4 +.IX Item "--version-info" +.PD +Displays the contents of the version sections in the file, it they +exist. +.IP "\fB\-A\fR" 4 +.IX Item "-A" +.PD 0 +.IP "\fB\-\-arch\-specific\fR" 4 +.IX Item "--arch-specific" +.PD +Displays architecture-specific information in the file, if there +is any. +.IP "\fB\-D\fR" 4 +.IX Item "-D" +.PD 0 +.IP "\fB\-\-use\-dynamic\fR" 4 +.IX Item "--use-dynamic" +.PD +When displaying symbols, this option makes \fBreadelf\fR use the +symbol table in the file's dynamic section, rather than the one in the +symbols section. +.IP "\fB\-x \fR" 4 +.IX Item "-x " +.PD 0 +.IP "\fB\-\-hex\-dump=\fR" 4 +.IX Item "--hex-dump=" +.PD +Displays the contents of the indicated section as a hexadecimal dump. +.IP "\fB\-w[liaprmfFso]\fR" 4 +.IX Item "-w[liaprmfFso]" +.PD 0 +.IP "\fB\-\-debug\-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=frames\-interp,=str,=loc]\fR" 4 +.IX Item "--debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=frames-interp,=str,=loc]" +.PD +Displays the contents of the debug sections in the file, if any are +present. If one of the optional letters or words follows the switch +then only data found in those specific sections will be dumped. +.IP "\fB\-I\fR" 4 +.IX Item "-I" +.PD 0 +.IP "\fB\-\-histogram\fR" 4 +.IX Item "--histogram" +.PD +Display a histogram of bucket list lengths when displaying the contents +of the symbol tables. +.IP "\fB\-v\fR" 4 +.IX Item "-v" +.PD 0 +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.PD +Display the version number of readelf. +.IP "\fB\-W\fR" 4 +.IX Item "-W" +.PD 0 +.IP "\fB\-\-wide\fR" 4 +.IX Item "--wide" +.PD +Don't break output lines to fit into 80 columns. By default +\&\fBreadelf\fR breaks section header and segment listing lines for +64\-bit \s-1ELF\s0 files, so that they fit into 80 columns. This option causes +\&\fBreadelf\fR to print each section header resp. each segment one a +single line, which is far more readable on terminals wider than 80 columns. +.IP "\fB\-H\fR" 4 +.IX Item "-H" +.PD 0 +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +.PD +Display the command line options understood by \fBreadelf\fR. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIobjdump\fR\|(1), and the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/size.1 b/contrib/binutils-2.14/binutils/doc/size.1 new file mode 100644 index 0000000000..9b6a4f60a0 --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/size.1 @@ -0,0 +1,250 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "SIZE 1" +.TH SIZE 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +size \- list section sizes and total size. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +size [\fB\-A\fR|\fB\-B\fR|\fB\-\-format=\fR\fIcompatibility\fR] + [\fB\-\-help\fR] + [\fB\-d\fR|\fB\-o\fR|\fB\-x\fR|\fB\-\-radix=\fR\fInumber\fR] + [\fB\-t\fR|\fB\-\-totals\fR] + [\fB\-\-target=\fR\fIbfdname\fR] [\fB\-V\fR|\fB\-\-version\fR] + [\fIobjfile\fR...] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \s-1GNU\s0 \fBsize\fR utility lists the section sizes\-\-\-and the total +size\-\-\-for each of the object or archive files \fIobjfile\fR in its +argument list. By default, one line of output is generated for each +object file or each module in an archive. +.PP +\&\fIobjfile\fR... are the object files to be examined. +If none are specified, the file \f(CW\*(C`a.out\*(C'\fR will be used. +.SH "OPTIONS" +.IX Header "OPTIONS" +The command line options have the following meanings: +.IP "\fB\-A\fR" 4 +.IX Item "-A" +.PD 0 +.IP "\fB\-B\fR" 4 +.IX Item "-B" +.IP "\fB\-\-format=\fR\fIcompatibility\fR" 4 +.IX Item "--format=compatibility" +.PD +Using one of these options, you can choose whether the output from \s-1GNU\s0 +\&\fBsize\fR resembles output from System V \fBsize\fR (using \fB\-A\fR, +or \fB\-\-format=sysv\fR), or Berkeley \fBsize\fR (using \fB\-B\fR, or +\&\fB\-\-format=berkeley\fR). The default is the one-line format similar to +Berkeley's. +.Sp +Here is an example of the Berkeley (default) format of output from +\&\fBsize\fR: +.Sp +.Vb 4 +\& $ size --format=Berkeley ranlib size +\& text data bss dec hex filename +\& 294880 81920 11592 388392 5ed28 ranlib +\& 294880 81920 11888 388688 5ee50 size +.Ve +.Sp +This is the same data, but displayed closer to System V conventions: +.Sp +.Vb 7 +\& $ size --format=SysV ranlib size +\& ranlib : +\& section size addr +\& .text 294880 8192 +\& .data 81920 303104 +\& .bss 11592 385024 +\& Total 388392 +.Ve +.Sp +.Vb 6 +\& size : +\& section size addr +\& .text 294880 8192 +\& .data 81920 303104 +\& .bss 11888 385024 +\& Total 388688 +.Ve +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +Show a summary of acceptable arguments and options. +.IP "\fB\-d\fR" 4 +.IX Item "-d" +.PD 0 +.IP "\fB\-o\fR" 4 +.IX Item "-o" +.IP "\fB\-x\fR" 4 +.IX Item "-x" +.IP "\fB\-\-radix=\fR\fInumber\fR" 4 +.IX Item "--radix=number" +.PD +Using one of these options, you can control whether the size of each +section is given in decimal (\fB\-d\fR, or \fB\-\-radix=10\fR); octal +(\fB\-o\fR, or \fB\-\-radix=8\fR); or hexadecimal (\fB\-x\fR, or +\&\fB\-\-radix=16\fR). In \fB\-\-radix=\fR\fInumber\fR, only the three +values (8, 10, 16) are supported. The total size is always given in two +radices; decimal and hexadecimal for \fB\-d\fR or \fB\-x\fR output, or +octal and hexadecimal if you're using \fB\-o\fR. +.IP "\fB\-t\fR" 4 +.IX Item "-t" +.PD 0 +.IP "\fB\-\-totals\fR" 4 +.IX Item "--totals" +.PD +Show totals of all objects listed (Berkeley format listing mode only). +.IP "\fB\-\-target=\fR\fIbfdname\fR" 4 +.IX Item "--target=bfdname" +Specify that the object-code format for \fIobjfile\fR is +\&\fIbfdname\fR. This option may not be necessary; \fBsize\fR can +automatically recognize many formats. +.IP "\fB\-V\fR" 4 +.IX Item "-V" +.PD 0 +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.PD +Display the version number of \fBsize\fR. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIar\fR\|(1), \fIobjdump\fR\|(1), \fIreadelf\fR\|(1), and the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/strings.1 b/contrib/binutils-2.14/binutils/doc/strings.1 new file mode 100644 index 0000000000..09f2323e94 --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/strings.1 @@ -0,0 +1,236 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "STRINGS 1" +.TH STRINGS 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +strings \- print the strings of printable characters in files. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +strings [\fB\-afov\fR] [\fB\-\fR\fImin-len\fR] + [\fB\-n\fR \fImin-len\fR] [\fB\-\-bytes=\fR\fImin-len\fR] + [\fB\-t\fR \fIradix\fR] [\fB\-\-radix=\fR\fIradix\fR] + [\fB\-e\fR \fIencoding\fR] [\fB\-\-encoding=\fR\fIencoding\fR] + [\fB\-\fR] [\fB\-\-all\fR] [\fB\-\-print\-file\-name\fR] + [\fB\-\-target=\fR\fIbfdname\fR] + [\fB\-\-help\fR] [\fB\-\-version\fR] \fIfile\fR... +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +For each \fIfile\fR given, \s-1GNU\s0 \fBstrings\fR prints the printable +character sequences that are at least 4 characters long (or the number +given with the options below) and are followed by an unprintable +character. By default, it only prints the strings from the initialized +and loaded sections of object files; for other types of files, it prints +the strings from the whole file. +.PP +\&\fBstrings\fR is mainly useful for determining the contents of non-text +files. +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\fB\-a\fR" 4 +.IX Item "-a" +.PD 0 +.IP "\fB\-\-all\fR" 4 +.IX Item "--all" +.IP "\fB\-\fR" 4 +.IX Item "-" +.PD +Do not scan only the initialized and loaded sections of object files; +scan the whole files. +.IP "\fB\-f\fR" 4 +.IX Item "-f" +.PD 0 +.IP "\fB\-\-print\-file\-name\fR" 4 +.IX Item "--print-file-name" +.PD +Print the name of the file before each string. +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +Print a summary of the program usage on the standard output and exit. +.IP "\fB\-\fR\fImin-len\fR" 4 +.IX Item "-min-len" +.PD 0 +.IP "\fB\-n\fR \fImin-len\fR" 4 +.IX Item "-n min-len" +.IP "\fB\-\-bytes=\fR\fImin-len\fR" 4 +.IX Item "--bytes=min-len" +.PD +Print sequences of characters that are at least \fImin-len\fR characters +long, instead of the default 4. +.IP "\fB\-o\fR" 4 +.IX Item "-o" +Like \fB\-t o\fR. Some other versions of \fBstrings\fR have \fB\-o\fR +act like \fB\-t d\fR instead. Since we can not be compatible with both +ways, we simply chose one. +.IP "\fB\-t\fR \fIradix\fR" 4 +.IX Item "-t radix" +.PD 0 +.IP "\fB\-\-radix=\fR\fIradix\fR" 4 +.IX Item "--radix=radix" +.PD +Print the offset within the file before each string. The single +character argument specifies the radix of the offset\-\-\-\fBo\fR for +octal, \fBx\fR for hexadecimal, or \fBd\fR for decimal. +.IP "\fB\-e\fR \fIencoding\fR" 4 +.IX Item "-e encoding" +.PD 0 +.IP "\fB\-\-encoding=\fR\fIencoding\fR" 4 +.IX Item "--encoding=encoding" +.PD +Select the character encoding of the strings that are to be found. +Possible values for \fIencoding\fR are: \fBs\fR = single\-7\-bit\-byte +characters (\s-1ASCII\s0, \s-1ISO\s0 8859, etc., default), \fBS\fR = +single\-8\-bit\-byte characters, \fBb\fR = 16\-bit bigendian, \fBl\fR = +16\-bit littleendian, \fBB\fR = 32\-bit bigendian, \fBL\fR = 32\-bit +littleendian. Useful for finding wide character strings. +.IP "\fB\-\-target=\fR\fIbfdname\fR" 4 +.IX Item "--target=bfdname" +Specify an object code format other than your system's default format. +.IP "\fB\-v\fR" 4 +.IX Item "-v" +.PD 0 +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.PD +Print the program version number on the standard output and exit. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIar\fR\|(1), \fInm\fR\|(1), \fIobjdump\fR\|(1), \fIranlib\fR\|(1), \fIreadelf\fR\|(1) +and the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/doc/strip.1 b/contrib/binutils-2.14/binutils/doc/strip.1 new file mode 100644 index 0000000000..6a612af28e --- /dev/null +++ b/contrib/binutils-2.14/binutils/doc/strip.1 @@ -0,0 +1,289 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "STRIP 1" +.TH STRIP 1 "2003-04-27" "binutils-2.13.90" "GNU Development Tools" +.SH "NAME" +strip \- Discard symbols from object files. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +strip [\fB\-F\fR \fIbfdname\fR |\fB\-\-target=\fR\fIbfdname\fR ] + [\fB\-I\fR \fIbfdname\fR |\fB\-\-input\-target=\fR\fIbfdname\fR ] + [\fB\-O\fR \fIbfdname\fR |\fB\-\-output\-target=\fR\fIbfdname\fR ] + [\fB\-s\fR|\fB\-\-strip\-all\fR] [\fB\-S\fR|\fB\-g\fR|\fB\-d\fR|\fB\-\-strip\-debug\fR] + [\fB\-K\fR \fIsymbolname\fR |\fB\-\-keep\-symbol=\fR\fIsymbolname\fR ] + [\fB\-N\fR \fIsymbolname\fR |\fB\-\-strip\-symbol=\fR\fIsymbolname\fR ] + [\fB\-x\fR|\fB\-\-discard\-all\fR ] [\fB\-X\fR |\fB\-\-discard\-locals\fR] + [\fB\-R\fR \fIsectionname\fR |\fB\-\-remove\-section=\fR\fIsectionname\fR ] + [\fB\-o\fR \fIfile\fR ] [\fB\-p\fR|\fB\-\-preserve\-dates\fR] + [\fB\-v\fR |\fB\-\-verbose\fR] [\fB\-V\fR|\fB\-\-version\fR] + [\fB\-\-help\fR] [\fB\-\-info\fR] + \fIobjfile\fR... +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\s-1GNU\s0 \fBstrip\fR discards all symbols from object files +\&\fIobjfile\fR. The list of object files may include archives. +At least one object file must be given. +.PP +\&\fBstrip\fR modifies the files named in its argument, +rather than writing modified copies under different names. +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\fB\-F\fR \fIbfdname\fR" 4 +.IX Item "-F bfdname" +.PD 0 +.IP "\fB\-\-target=\fR\fIbfdname\fR" 4 +.IX Item "--target=bfdname" +.PD +Treat the original \fIobjfile\fR as a file with the object +code format \fIbfdname\fR, and rewrite it in the same format. +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +Show a summary of the options to \fBstrip\fR and exit. +.IP "\fB\-\-info\fR" 4 +.IX Item "--info" +Display a list showing all architectures and object formats available. +.IP "\fB\-I\fR \fIbfdname\fR" 4 +.IX Item "-I bfdname" +.PD 0 +.IP "\fB\-\-input\-target=\fR\fIbfdname\fR" 4 +.IX Item "--input-target=bfdname" +.PD +Treat the original \fIobjfile\fR as a file with the object +code format \fIbfdname\fR. +.IP "\fB\-O\fR \fIbfdname\fR" 4 +.IX Item "-O bfdname" +.PD 0 +.IP "\fB\-\-output\-target=\fR\fIbfdname\fR" 4 +.IX Item "--output-target=bfdname" +.PD +Replace \fIobjfile\fR with a file in the output format \fIbfdname\fR. +.IP "\fB\-R\fR \fIsectionname\fR" 4 +.IX Item "-R sectionname" +.PD 0 +.IP "\fB\-\-remove\-section=\fR\fIsectionname\fR" 4 +.IX Item "--remove-section=sectionname" +.PD +Remove any section named \fIsectionname\fR from the output file. This +option may be given more than once. Note that using this option +inappropriately may make the output file unusable. +.IP "\fB\-s\fR" 4 +.IX Item "-s" +.PD 0 +.IP "\fB\-\-strip\-all\fR" 4 +.IX Item "--strip-all" +.PD +Remove all symbols. +.IP "\fB\-g\fR" 4 +.IX Item "-g" +.PD 0 +.IP "\fB\-S\fR" 4 +.IX Item "-S" +.IP "\fB\-d\fR" 4 +.IX Item "-d" +.IP "\fB\-\-strip\-debug\fR" 4 +.IX Item "--strip-debug" +.PD +Remove debugging symbols only. +.IP "\fB\-\-strip\-unneeded\fR" 4 +.IX Item "--strip-unneeded" +Remove all symbols that are not needed for relocation processing. +.IP "\fB\-K\fR \fIsymbolname\fR" 4 +.IX Item "-K symbolname" +.PD 0 +.IP "\fB\-\-keep\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--keep-symbol=symbolname" +.PD +Keep only symbol \fIsymbolname\fR from the source file. This option may +be given more than once. +.IP "\fB\-N\fR \fIsymbolname\fR" 4 +.IX Item "-N symbolname" +.PD 0 +.IP "\fB\-\-strip\-symbol=\fR\fIsymbolname\fR" 4 +.IX Item "--strip-symbol=symbolname" +.PD +Remove symbol \fIsymbolname\fR from the source file. This option may be +given more than once, and may be combined with strip options other than +\&\fB\-K\fR. +.IP "\fB\-o\fR \fIfile\fR" 4 +.IX Item "-o file" +Put the stripped output in \fIfile\fR, rather than replacing the +existing file. When this argument is used, only one \fIobjfile\fR +argument may be specified. +.IP "\fB\-p\fR" 4 +.IX Item "-p" +.PD 0 +.IP "\fB\-\-preserve\-dates\fR" 4 +.IX Item "--preserve-dates" +.PD +Preserve the access and modification dates of the file. +.IP "\fB\-x\fR" 4 +.IX Item "-x" +.PD 0 +.IP "\fB\-\-discard\-all\fR" 4 +.IX Item "--discard-all" +.PD +Remove non-global symbols. +.IP "\fB\-X\fR" 4 +.IX Item "-X" +.PD 0 +.IP "\fB\-\-discard\-locals\fR" 4 +.IX Item "--discard-locals" +.PD +Remove compiler-generated local symbols. +(These usually start with \fBL\fR or \fB.\fR.) +.IP "\fB\-V\fR" 4 +.IX Item "-V" +.PD 0 +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.PD +Show the version number for \fBstrip\fR. +.IP "\fB\-v\fR" 4 +.IX Item "-v" +.PD 0 +.IP "\fB\-\-verbose\fR" 4 +.IX Item "--verbose" +.PD +Verbose output: list all object files modified. In the case of +archives, \fBstrip \-v\fR lists all members of the archive. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +the Info entries for \fIbinutils\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/binutils/emul_vanilla.c b/contrib/binutils-2.14/binutils/emul_vanilla.c new file mode 100644 index 0000000000..d6cfebda98 --- /dev/null +++ b/contrib/binutils-2.14/binutils/emul_vanilla.c @@ -0,0 +1,30 @@ +/* Binutils emulation layer. + Copyright (C) 2002 Free Software Foundation, Inc. + Written by Tom Rix, Redhat. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "binemul.h" + +struct bin_emulation_xfer_struct bin_vanilla_emulation = +{ + ar_emul_default_usage, + ar_emul_default_append, + ar_emul_default_replace, + ar_emul_default_create, + ar_emul_default_parse_arg, +}; diff --git a/contrib/binutils-2.14/binutils/filemode.c b/contrib/binutils-2.14/binutils/filemode.c new file mode 100644 index 0000000000..ca00694fb7 --- /dev/null +++ b/contrib/binutils-2.14/binutils/filemode.c @@ -0,0 +1,267 @@ +/* filemode.c -- make a string describing file modes + Copyright 1985, 1990, 1991, 1994, 1995, 1997 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "bfd.h" +#include "bucomm.h" + +static char ftypelet PARAMS ((unsigned long)); +static void setst PARAMS ((unsigned long, char *)); + +/* filemodestring - fill in string STR with an ls-style ASCII + representation of the st_mode field of file stats block STATP. + 10 characters are stored in STR; no terminating null is added. + The characters stored in STR are: + + 0 File type. 'd' for directory, 'c' for character + special, 'b' for block special, 'm' for multiplex, + 'l' for symbolic link, 's' for socket, 'p' for fifo, + '-' for any other file type + + 1 'r' if the owner may read, '-' otherwise. + + 2 'w' if the owner may write, '-' otherwise. + + 3 'x' if the owner may execute, 's' if the file is + set-user-id, '-' otherwise. + 'S' if the file is set-user-id, but the execute + bit isn't set. + + 4 'r' if group members may read, '-' otherwise. + + 5 'w' if group members may write, '-' otherwise. + + 6 'x' if group members may execute, 's' if the file is + set-group-id, '-' otherwise. + 'S' if it is set-group-id but not executable. + + 7 'r' if any user may read, '-' otherwise. + + 8 'w' if any user may write, '-' otherwise. + + 9 'x' if any user may execute, 't' if the file is "sticky" + (will be retained in swap space after execution), '-' + otherwise. + 'T' if the file is sticky but not executable. */ + +#if 0 + +/* This is not used; only mode_string is used. */ + +void +filemodestring (statp, str) + struct stat *statp; + char *str; +{ + mode_string ((unsigned long) statp->st_mode, str); +} + +#endif + +/* Get definitions for the file permission bits. */ + +#ifndef S_IRWXU +#define S_IRWXU 0700 +#endif +#ifndef S_IRUSR +#define S_IRUSR 0400 +#endif +#ifndef S_IWUSR +#define S_IWUSR 0200 +#endif +#ifndef S_IXUSR +#define S_IXUSR 0100 +#endif + +#ifndef S_IRWXG +#define S_IRWXG 0070 +#endif +#ifndef S_IRGRP +#define S_IRGRP 0040 +#endif +#ifndef S_IWGRP +#define S_IWGRP 0020 +#endif +#ifndef S_IXGRP +#define S_IXGRP 0010 +#endif + +#ifndef S_IRWXO +#define S_IRWXO 0007 +#endif +#ifndef S_IROTH +#define S_IROTH 0004 +#endif +#ifndef S_IWOTH +#define S_IWOTH 0002 +#endif +#ifndef S_IXOTH +#define S_IXOTH 0001 +#endif + +/* Like filemodestring, but only the relevant part of the `struct stat' + is given as an argument. */ + +void +mode_string (mode, str) + unsigned long mode; + char *str; +{ + str[0] = ftypelet ((unsigned long) mode); + str[1] = (mode & S_IRUSR) != 0 ? 'r' : '-'; + str[2] = (mode & S_IWUSR) != 0 ? 'w' : '-'; + str[3] = (mode & S_IXUSR) != 0 ? 'x' : '-'; + str[4] = (mode & S_IRGRP) != 0 ? 'r' : '-'; + str[5] = (mode & S_IWGRP) != 0 ? 'w' : '-'; + str[6] = (mode & S_IXGRP) != 0 ? 'x' : '-'; + str[7] = (mode & S_IROTH) != 0 ? 'r' : '-'; + str[8] = (mode & S_IWOTH) != 0 ? 'w' : '-'; + str[9] = (mode & S_IXOTH) != 0 ? 'x' : '-'; + setst ((unsigned long) mode, str); +} + +/* Return a character indicating the type of file described by + file mode BITS: + 'd' for directories + 'b' for block special files + 'c' for character special files + 'm' for multiplexor files + 'l' for symbolic links + 's' for sockets + 'p' for fifos + '-' for any other file type. */ + +#ifndef S_ISDIR +#ifdef S_IFDIR +#define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR) +#else /* ! defined (S_IFDIR) */ +#define S_ISDIR(i) (((i) & 0170000) == 040000) +#endif /* ! defined (S_IFDIR) */ +#endif /* ! defined (S_ISDIR) */ + +#ifndef S_ISBLK +#ifdef S_IFBLK +#define S_ISBLK(i) (((i) & S_IFMT) == S_IFBLK) +#else /* ! defined (S_IFBLK) */ +#define S_ISBLK(i) 0 +#endif /* ! defined (S_IFBLK) */ +#endif /* ! defined (S_ISBLK) */ + +#ifndef S_ISCHR +#ifdef S_IFCHR +#define S_ISCHR(i) (((i) & S_IFMT) == S_IFCHR) +#else /* ! defined (S_IFCHR) */ +#define S_ISCHR(i) 0 +#endif /* ! defined (S_IFCHR) */ +#endif /* ! defined (S_ISCHR) */ + +#ifndef S_ISFIFO +#ifdef S_IFIFO +#define S_ISFIFO(i) (((i) & S_IFMT) == S_IFIFO) +#else /* ! defined (S_IFIFO) */ +#define S_ISFIFO(i) 0 +#endif /* ! defined (S_IFIFO) */ +#endif /* ! defined (S_ISFIFO) */ + +#ifndef S_ISSOCK +#ifdef S_IFSOCK +#define S_ISSOCK(i) (((i) & S_IFMT) == S_IFSOCK) +#else /* ! defined (S_IFSOCK) */ +#define S_ISSOCK(i) 0 +#endif /* ! defined (S_IFSOCK) */ +#endif /* ! defined (S_ISSOCK) */ + +#ifndef S_ISLNK +#ifdef S_IFLNK +#define S_ISLNK(i) (((i) & S_IFMT) == S_IFLNK) +#else /* ! defined (S_IFLNK) */ +#define S_ISLNK(i) 0 +#endif /* ! defined (S_IFLNK) */ +#endif /* ! defined (S_ISLNK) */ + +static char +ftypelet (bits) + unsigned long bits; +{ + if (S_ISDIR (bits)) + return 'd'; + if (S_ISLNK (bits)) + return 'l'; + if (S_ISBLK (bits)) + return 'b'; + if (S_ISCHR (bits)) + return 'c'; + if (S_ISSOCK (bits)) + return 's'; + if (S_ISFIFO (bits)) + return 'p'; + +#ifdef S_IFMT +#ifdef S_IFMPC + if ((bits & S_IFMT) == S_IFMPC + || (bits & S_IFMT) == S_IFMPB) + return 'm'; +#endif +#ifdef S_IFNWK + if ((bits & S_IFMT) == S_IFNWK) + return 'n'; +#endif +#endif + + return '-'; +} + +/* Set the 's' and 't' flags in file attributes string CHARS, + according to the file mode BITS. */ + +static void +setst (bits, chars) + unsigned long bits ATTRIBUTE_UNUSED; + char *chars ATTRIBUTE_UNUSED; +{ +#ifdef S_ISUID + if (bits & S_ISUID) + { + if (chars[3] != 'x') + /* Set-uid, but not executable by owner. */ + chars[3] = 'S'; + else + chars[3] = 's'; + } +#endif +#ifdef S_ISGID + if (bits & S_ISGID) + { + if (chars[6] != 'x') + /* Set-gid, but not executable by group. */ + chars[6] = 'S'; + else + chars[6] = 's'; + } +#endif +#ifdef S_ISVTX + if (bits & S_ISVTX) + { + if (chars[9] != 'x') + /* Sticky, but not executable by others. */ + chars[9] = 'T'; + else + chars[9] = 't'; + } +#endif +} diff --git a/contrib/binutils-2.14/binutils/ieee.c b/contrib/binutils-2.14/binutils/ieee.c new file mode 100644 index 0000000000..c9340cbad1 --- /dev/null +++ b/contrib/binutils-2.14/binutils/ieee.c @@ -0,0 +1,7675 @@ +/* ieee.c -- Read and write IEEE-695 debugging information. + Copyright 1996, 1998, 2000, 2001, 2002 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file reads and writes IEEE-695 debugging information. */ + +#include +#include + +#include "bfd.h" +#include "ieee.h" +#include "bucomm.h" +#include "libiberty.h" +#include "debug.h" +#include "budbg.h" +#include "filenames.h" + +/* This structure holds an entry on the block stack. */ + +struct ieee_block +{ + /* The kind of block. */ + int kind; + /* The source file name, for a BB5 block. */ + const char *filename; + /* The index of the function type, for a BB4 or BB6 block. */ + unsigned int fnindx; + /* TRUE if this function is being skipped. */ + bfd_boolean skip; +}; + +/* This structure is the block stack. */ + +#define BLOCKSTACK_SIZE (16) + +struct ieee_blockstack +{ + /* The stack pointer. */ + struct ieee_block *bsp; + /* The stack. */ + struct ieee_block stack[BLOCKSTACK_SIZE]; +}; + +/* This structure holds information for a variable. */ + +struct ieee_var +{ + /* Start of name. */ + const char *name; + /* Length of name. */ + unsigned long namlen; + /* Type. */ + debug_type type; + /* Slot if we make an indirect type. */ + debug_type *pslot; + /* Kind of variable or function. */ + enum + { + IEEE_UNKNOWN, + IEEE_EXTERNAL, + IEEE_GLOBAL, + IEEE_STATIC, + IEEE_LOCAL, + IEEE_FUNCTION + } kind; +}; + +/* This structure holds all the variables. */ + +struct ieee_vars +{ + /* Number of slots allocated. */ + unsigned int alloc; + /* Variables. */ + struct ieee_var *vars; +}; + +/* This structure holds information for a type. We need this because + we don't want to represent bitfields as real types. */ + +struct ieee_type +{ + /* Type. */ + debug_type type; + /* Slot if this is type is referenced before it is defined. */ + debug_type *pslot; + /* Slots for arguments if we make indirect types for them. */ + debug_type *arg_slots; + /* If this is a bitfield, this is the size in bits. If this is not + a bitfield, this is zero. */ + unsigned long bitsize; +}; + +/* This structure holds all the type information. */ + +struct ieee_types +{ + /* Number of slots allocated. */ + unsigned int alloc; + /* Types. */ + struct ieee_type *types; + /* Builtin types. */ +#define BUILTIN_TYPE_COUNT (60) + debug_type builtins[BUILTIN_TYPE_COUNT]; +}; + +/* This structure holds a linked last of structs with their tag names, + so that we can convert them to C++ classes if necessary. */ + +struct ieee_tag +{ + /* Next tag. */ + struct ieee_tag *next; + /* This tag name. */ + const char *name; + /* The type of the tag. */ + debug_type type; + /* The tagged type is an indirect type pointing at this slot. */ + debug_type slot; + /* This is an array of slots used when a field type is converted + into a indirect type, in case it needs to be later converted into + a reference type. */ + debug_type *fslots; +}; + +/* This structure holds the information we pass around to the parsing + functions. */ + +struct ieee_info +{ + /* The debugging handle. */ + PTR dhandle; + /* The BFD. */ + bfd *abfd; + /* The start of the bytes to be parsed. */ + const bfd_byte *bytes; + /* The end of the bytes to be parsed. */ + const bfd_byte *pend; + /* The block stack. */ + struct ieee_blockstack blockstack; + /* Whether we have seen a BB1 or BB2. */ + bfd_boolean saw_filename; + /* The variables. */ + struct ieee_vars vars; + /* The global variables, after a global typedef block. */ + struct ieee_vars *global_vars; + /* The types. */ + struct ieee_types types; + /* The global types, after a global typedef block. */ + struct ieee_types *global_types; + /* The list of tagged structs. */ + struct ieee_tag *tags; +}; + +/* Basic builtin types, not including the pointers. */ + +enum builtin_types +{ + builtin_unknown = 0, + builtin_void = 1, + builtin_signed_char = 2, + builtin_unsigned_char = 3, + builtin_signed_short_int = 4, + builtin_unsigned_short_int = 5, + builtin_signed_long = 6, + builtin_unsigned_long = 7, + builtin_signed_long_long = 8, + builtin_unsigned_long_long = 9, + builtin_float = 10, + builtin_double = 11, + builtin_long_double = 12, + builtin_long_long_double = 13, + builtin_quoted_string = 14, + builtin_instruction_address = 15, + builtin_int = 16, + builtin_unsigned = 17, + builtin_unsigned_int = 18, + builtin_char = 19, + builtin_long = 20, + builtin_short = 21, + builtin_unsigned_short = 22, + builtin_short_int = 23, + builtin_signed_short = 24, + builtin_bcd_float = 25 +}; + +/* These are the values found in the derivation flags of a 'b' + component record of a 'T' type extension record in a C++ pmisc + record. These are bitmasks. */ + +/* Set for a private base class, clear for a public base class. + Protected base classes are not supported. */ +#define BASEFLAGS_PRIVATE (0x1) +/* Set for a virtual base class. */ +#define BASEFLAGS_VIRTUAL (0x2) +/* Set for a friend class, clear for a base class. */ +#define BASEFLAGS_FRIEND (0x10) + +/* These are the values found in the specs flags of a 'd', 'm', or 'v' + component record of a 'T' type extension record in a C++ pmisc + record. The same flags are used for a 'M' record in a C++ pmisc + record. */ + +/* The lower two bits hold visibility information. */ +#define CXXFLAGS_VISIBILITY (0x3) +/* This value in the lower two bits indicates a public member. */ +#define CXXFLAGS_VISIBILITY_PUBLIC (0x0) +/* This value in the lower two bits indicates a private member. */ +#define CXXFLAGS_VISIBILITY_PRIVATE (0x1) +/* This value in the lower two bits indicates a protected member. */ +#define CXXFLAGS_VISIBILITY_PROTECTED (0x2) +/* Set for a static member. */ +#define CXXFLAGS_STATIC (0x4) +/* Set for a virtual override. */ +#define CXXFLAGS_OVERRIDE (0x8) +/* Set for a friend function. */ +#define CXXFLAGS_FRIEND (0x10) +/* Set for a const function. */ +#define CXXFLAGS_CONST (0x20) +/* Set for a volatile function. */ +#define CXXFLAGS_VOLATILE (0x40) +/* Set for an overloaded function. */ +#define CXXFLAGS_OVERLOADED (0x80) +/* Set for an operator function. */ +#define CXXFLAGS_OPERATOR (0x100) +/* Set for a constructor or destructor. */ +#define CXXFLAGS_CTORDTOR (0x400) +/* Set for a constructor. */ +#define CXXFLAGS_CTOR (0x200) +/* Set for an inline function. */ +#define CXXFLAGS_INLINE (0x800) + +/* Local functions. */ + +static void ieee_error + PARAMS ((struct ieee_info *, const bfd_byte *, const char *)); +static void ieee_eof + PARAMS ((struct ieee_info *)); +static char *savestring + PARAMS ((const char *, unsigned long)); +static bfd_boolean ieee_read_number + PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); +static bfd_boolean ieee_read_optional_number + PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *, bfd_boolean *)); +static bfd_boolean ieee_read_id + PARAMS ((struct ieee_info *, const bfd_byte **, const char **, + unsigned long *)); +static bfd_boolean ieee_read_optional_id + PARAMS ((struct ieee_info *, const bfd_byte **, const char **, + unsigned long *, bfd_boolean *)); +static bfd_boolean ieee_read_expression + PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); +static debug_type ieee_builtin_type + PARAMS ((struct ieee_info *, const bfd_byte *, unsigned int)); +static bfd_boolean ieee_alloc_type + PARAMS ((struct ieee_info *, unsigned int, bfd_boolean)); +static bfd_boolean ieee_read_type_index + PARAMS ((struct ieee_info *, const bfd_byte **, debug_type *)); +static int ieee_regno_to_genreg + PARAMS ((bfd *, int)); +static int ieee_genreg_to_regno + PARAMS ((bfd *, int)); +static bfd_boolean parse_ieee_bb + PARAMS ((struct ieee_info *, const bfd_byte **)); +static bfd_boolean parse_ieee_be + PARAMS ((struct ieee_info *, const bfd_byte **)); +static bfd_boolean parse_ieee_nn + PARAMS ((struct ieee_info *, const bfd_byte **)); +static bfd_boolean parse_ieee_ty + PARAMS ((struct ieee_info *, const bfd_byte **)); +static bfd_boolean parse_ieee_atn + PARAMS ((struct ieee_info *, const bfd_byte **)); +static bfd_boolean ieee_read_cxx_misc + PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); +static bfd_boolean ieee_read_cxx_class + PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); +static bfd_boolean ieee_read_cxx_defaults + PARAMS ((struct ieee_info *, const bfd_byte **, unsigned long)); +static bfd_boolean ieee_read_reference + PARAMS ((struct ieee_info *, const bfd_byte **)); +static bfd_boolean ieee_require_asn + PARAMS ((struct ieee_info *, const bfd_byte **, bfd_vma *)); +static bfd_boolean ieee_require_atn65 + PARAMS ((struct ieee_info *, const bfd_byte **, const char **, + unsigned long *)); + +/* Report an error in the IEEE debugging information. */ + +static void +ieee_error (info, p, s) + struct ieee_info *info; + const bfd_byte *p; + const char *s; +{ + if (p != NULL) + fprintf (stderr, "%s: 0x%lx: %s (0x%x)\n", bfd_get_filename (info->abfd), + (unsigned long) (p - info->bytes), s, *p); + else + fprintf (stderr, "%s: %s\n", bfd_get_filename (info->abfd), s); +} + +/* Report an unexpected EOF in the IEEE debugging information. */ + +static void +ieee_eof (info) + struct ieee_info *info; +{ + ieee_error (info, (const bfd_byte *) NULL, + _("unexpected end of debugging information")); +} + +/* Save a string in memory. */ + +static char * +savestring (start, len) + const char *start; + unsigned long len; +{ + char *ret; + + ret = (char *) xmalloc (len + 1); + memcpy (ret, start, len); + ret[len] = '\0'; + return ret; +} + +/* Read a number which must be present in an IEEE file. */ + +static bfd_boolean +ieee_read_number (info, pp, pv) + struct ieee_info *info; + const bfd_byte **pp; + bfd_vma *pv; +{ + return ieee_read_optional_number (info, pp, pv, (bfd_boolean *) NULL); +} + +/* Read a number in an IEEE file. If ppresent is not NULL, the number + need not be there. */ + +static bfd_boolean +ieee_read_optional_number (info, pp, pv, ppresent) + struct ieee_info *info; + const bfd_byte **pp; + bfd_vma *pv; + bfd_boolean *ppresent; +{ + ieee_record_enum_type b; + + if (*pp >= info->pend) + { + if (ppresent != NULL) + { + *ppresent = FALSE; + return TRUE; + } + ieee_eof (info); + return FALSE; + } + + b = (ieee_record_enum_type) **pp; + ++*pp; + + if (b <= ieee_number_end_enum) + { + *pv = (bfd_vma) b; + if (ppresent != NULL) + *ppresent = TRUE; + return TRUE; + } + + if (b >= ieee_number_repeat_start_enum && b <= ieee_number_repeat_end_enum) + { + unsigned int i; + + i = (int) b - (int) ieee_number_repeat_start_enum; + if (*pp + i - 1 >= info->pend) + { + ieee_eof (info); + return FALSE; + } + + *pv = 0; + for (; i > 0; i--) + { + *pv <<= 8; + *pv += **pp; + ++*pp; + } + + if (ppresent != NULL) + *ppresent = TRUE; + + return TRUE; + } + + if (ppresent != NULL) + { + --*pp; + *ppresent = FALSE; + return TRUE; + } + + ieee_error (info, *pp - 1, _("invalid number")); + return FALSE; +} + +/* Read a required string from an IEEE file. */ + +static bfd_boolean +ieee_read_id (info, pp, pname, pnamlen) + struct ieee_info *info; + const bfd_byte **pp; + const char **pname; + unsigned long *pnamlen; +{ + return ieee_read_optional_id (info, pp, pname, pnamlen, (bfd_boolean *) NULL); +} + +/* Read a string from an IEEE file. If ppresent is not NULL, the + string is optional. */ + +static bfd_boolean +ieee_read_optional_id (info, pp, pname, pnamlen, ppresent) + struct ieee_info *info; + const bfd_byte **pp; + const char **pname; + unsigned long *pnamlen; + bfd_boolean *ppresent; +{ + bfd_byte b; + unsigned long len; + + if (*pp >= info->pend) + { + ieee_eof (info); + return FALSE; + } + + b = **pp; + ++*pp; + + if (b <= 0x7f) + len = b; + else if ((ieee_record_enum_type) b == ieee_extension_length_1_enum) + { + len = **pp; + ++*pp; + } + else if ((ieee_record_enum_type) b == ieee_extension_length_2_enum) + { + len = (**pp << 8) + (*pp)[1]; + *pp += 2; + } + else + { + if (ppresent != NULL) + { + --*pp; + *ppresent = FALSE; + return TRUE; + } + ieee_error (info, *pp - 1, _("invalid string length")); + return FALSE; + } + + if ((unsigned long) (info->pend - *pp) < len) + { + ieee_eof (info); + return FALSE; + } + + *pname = (const char *) *pp; + *pnamlen = len; + *pp += len; + + if (ppresent != NULL) + *ppresent = TRUE; + + return TRUE; +} + +/* Read an expression from an IEEE file. Since this code is only used + to parse debugging information, I haven't bothered to write a full + blown IEEE expression parser. I've only thrown in the things I've + seen in debugging information. This can be easily extended if + necessary. */ + +static bfd_boolean +ieee_read_expression (info, pp, pv) + struct ieee_info *info; + const bfd_byte **pp; + bfd_vma *pv; +{ + const bfd_byte *expr_start; +#define EXPR_STACK_SIZE (10) + bfd_vma expr_stack[EXPR_STACK_SIZE]; + bfd_vma *esp; + + expr_start = *pp; + + esp = expr_stack; + + while (1) + { + const bfd_byte *start; + bfd_vma val; + bfd_boolean present; + ieee_record_enum_type c; + + start = *pp; + + if (! ieee_read_optional_number (info, pp, &val, &present)) + return FALSE; + + if (present) + { + if (esp - expr_stack >= EXPR_STACK_SIZE) + { + ieee_error (info, start, _("expression stack overflow")); + return FALSE; + } + *esp++ = val; + continue; + } + + c = (ieee_record_enum_type) **pp; + + if (c >= ieee_module_beginning_enum) + break; + + ++*pp; + + if (c == ieee_comma) + break; + + switch (c) + { + default: + ieee_error (info, start, _("unsupported IEEE expression operator")); + break; + + case ieee_variable_R_enum: + { + bfd_vma indx; + asection *s; + + if (! ieee_read_number (info, pp, &indx)) + return FALSE; + for (s = info->abfd->sections; s != NULL; s = s->next) + if ((bfd_vma) s->target_index == indx) + break; + if (s == NULL) + { + ieee_error (info, start, _("unknown section")); + return FALSE; + } + + if (esp - expr_stack >= EXPR_STACK_SIZE) + { + ieee_error (info, start, _("expression stack overflow")); + return FALSE; + } + + *esp++ = bfd_get_section_vma (info->abfd, s); + } + break; + + case ieee_function_plus_enum: + case ieee_function_minus_enum: + { + bfd_vma v1, v2; + + if (esp - expr_stack < 2) + { + ieee_error (info, start, _("expression stack underflow")); + return FALSE; + } + + v1 = *--esp; + v2 = *--esp; + *esp++ = v1 + v2; + } + break; + } + } + + if (esp - 1 != expr_stack) + { + ieee_error (info, expr_start, _("expression stack mismatch")); + return FALSE; + } + + *pv = *--esp; + + return TRUE; +} + +/* Return an IEEE builtin type. */ + +static debug_type +ieee_builtin_type (info, p, indx) + struct ieee_info *info; + const bfd_byte *p; + unsigned int indx; +{ + PTR dhandle; + debug_type type; + const char *name; + + if (indx < BUILTIN_TYPE_COUNT + && info->types.builtins[indx] != DEBUG_TYPE_NULL) + return info->types.builtins[indx]; + + dhandle = info->dhandle; + + if (indx >= 32 && indx < 64) + { + type = debug_make_pointer_type (dhandle, + ieee_builtin_type (info, p, indx - 32)); + assert (indx < BUILTIN_TYPE_COUNT); + info->types.builtins[indx] = type; + return type; + } + + switch ((enum builtin_types) indx) + { + default: + ieee_error (info, p, _("unknown builtin type")); + return NULL; + + case builtin_unknown: + type = debug_make_void_type (dhandle); + name = NULL; + break; + + case builtin_void: + type = debug_make_void_type (dhandle); + name = "void"; + break; + + case builtin_signed_char: + type = debug_make_int_type (dhandle, 1, FALSE); + name = "signed char"; + break; + + case builtin_unsigned_char: + type = debug_make_int_type (dhandle, 1, TRUE); + name = "unsigned char"; + break; + + case builtin_signed_short_int: + type = debug_make_int_type (dhandle, 2, FALSE); + name = "signed short int"; + break; + + case builtin_unsigned_short_int: + type = debug_make_int_type (dhandle, 2, TRUE); + name = "unsigned short int"; + break; + + case builtin_signed_long: + type = debug_make_int_type (dhandle, 4, FALSE); + name = "signed long"; + break; + + case builtin_unsigned_long: + type = debug_make_int_type (dhandle, 4, TRUE); + name = "unsigned long"; + break; + + case builtin_signed_long_long: + type = debug_make_int_type (dhandle, 8, FALSE); + name = "signed long long"; + break; + + case builtin_unsigned_long_long: + type = debug_make_int_type (dhandle, 8, TRUE); + name = "unsigned long long"; + break; + + case builtin_float: + type = debug_make_float_type (dhandle, 4); + name = "float"; + break; + + case builtin_double: + type = debug_make_float_type (dhandle, 8); + name = "double"; + break; + + case builtin_long_double: + /* FIXME: The size for this type should depend upon the + processor. */ + type = debug_make_float_type (dhandle, 12); + name = "long double"; + break; + + case builtin_long_long_double: + type = debug_make_float_type (dhandle, 16); + name = "long long double"; + break; + + case builtin_quoted_string: + type = debug_make_array_type (dhandle, + ieee_builtin_type (info, p, + ((unsigned int) + builtin_char)), + ieee_builtin_type (info, p, + ((unsigned int) + builtin_int)), + 0, -1, TRUE); + name = "QUOTED STRING"; + break; + + case builtin_instruction_address: + /* FIXME: This should be a code address. */ + type = debug_make_int_type (dhandle, 4, TRUE); + name = "instruction address"; + break; + + case builtin_int: + /* FIXME: The size for this type should depend upon the + processor. */ + type = debug_make_int_type (dhandle, 4, FALSE); + name = "int"; + break; + + case builtin_unsigned: + /* FIXME: The size for this type should depend upon the + processor. */ + type = debug_make_int_type (dhandle, 4, TRUE); + name = "unsigned"; + break; + + case builtin_unsigned_int: + /* FIXME: The size for this type should depend upon the + processor. */ + type = debug_make_int_type (dhandle, 4, TRUE); + name = "unsigned int"; + break; + + case builtin_char: + type = debug_make_int_type (dhandle, 1, FALSE); + name = "char"; + break; + + case builtin_long: + type = debug_make_int_type (dhandle, 4, FALSE); + name = "long"; + break; + + case builtin_short: + type = debug_make_int_type (dhandle, 2, FALSE); + name = "short"; + break; + + case builtin_unsigned_short: + type = debug_make_int_type (dhandle, 2, TRUE); + name = "unsigned short"; + break; + + case builtin_short_int: + type = debug_make_int_type (dhandle, 2, FALSE); + name = "short int"; + break; + + case builtin_signed_short: + type = debug_make_int_type (dhandle, 2, FALSE); + name = "signed short"; + break; + + case builtin_bcd_float: + ieee_error (info, p, _("BCD float type not supported")); + return DEBUG_TYPE_NULL; + } + + if (name != NULL) + type = debug_name_type (dhandle, name, type); + + assert (indx < BUILTIN_TYPE_COUNT); + + info->types.builtins[indx] = type; + + return type; +} + +/* Allocate more space in the type table. If ref is TRUE, this is a + reference to the type; if it is not already defined, we should set + up an indirect type. */ + +static bfd_boolean +ieee_alloc_type (info, indx, ref) + struct ieee_info *info; + unsigned int indx; + bfd_boolean ref; +{ + unsigned int nalloc; + register struct ieee_type *t; + struct ieee_type *tend; + + if (indx >= info->types.alloc) + { + nalloc = info->types.alloc; + if (nalloc == 0) + nalloc = 4; + while (indx >= nalloc) + nalloc *= 2; + + info->types.types = ((struct ieee_type *) + xrealloc (info->types.types, + nalloc * sizeof *info->types.types)); + + memset (info->types.types + info->types.alloc, 0, + (nalloc - info->types.alloc) * sizeof *info->types.types); + + tend = info->types.types + nalloc; + for (t = info->types.types + info->types.alloc; t < tend; t++) + t->type = DEBUG_TYPE_NULL; + + info->types.alloc = nalloc; + } + + if (ref) + { + t = info->types.types + indx; + if (t->type == NULL) + { + t->pslot = (debug_type *) xmalloc (sizeof *t->pslot); + *t->pslot = DEBUG_TYPE_NULL; + t->type = debug_make_indirect_type (info->dhandle, t->pslot, + (const char *) NULL); + if (t->type == NULL) + return FALSE; + } + } + + return TRUE; +} + +/* Read a type index and return the corresponding type. */ + +static bfd_boolean +ieee_read_type_index (info, pp, ptype) + struct ieee_info *info; + const bfd_byte **pp; + debug_type *ptype; +{ + const bfd_byte *start; + bfd_vma indx; + + start = *pp; + + if (! ieee_read_number (info, pp, &indx)) + return FALSE; + + if (indx < 256) + { + *ptype = ieee_builtin_type (info, start, indx); + if (*ptype == NULL) + return FALSE; + return TRUE; + } + + indx -= 256; + if (! ieee_alloc_type (info, indx, TRUE)) + return FALSE; + + *ptype = info->types.types[indx].type; + + return TRUE; +} + +/* Parse IEEE debugging information for a file. This is passed the + bytes which compose the Debug Information Part of an IEEE file. */ + +bfd_boolean +parse_ieee (dhandle, abfd, bytes, len) + PTR dhandle; + bfd *abfd; + const bfd_byte *bytes; + bfd_size_type len; +{ + struct ieee_info info; + unsigned int i; + const bfd_byte *p, *pend; + + info.dhandle = dhandle; + info.abfd = abfd; + info.bytes = bytes; + info.pend = bytes + len; + info.blockstack.bsp = info.blockstack.stack; + info.saw_filename = FALSE; + info.vars.alloc = 0; + info.vars.vars = NULL; + info.global_vars = NULL; + info.types.alloc = 0; + info.types.types = NULL; + info.global_types = NULL; + info.tags = NULL; + for (i = 0; i < BUILTIN_TYPE_COUNT; i++) + info.types.builtins[i] = DEBUG_TYPE_NULL; + + p = bytes; + pend = info.pend; + while (p < pend) + { + const bfd_byte *record_start; + ieee_record_enum_type c; + + record_start = p; + + c = (ieee_record_enum_type) *p++; + + if (c == ieee_at_record_enum) + c = (ieee_record_enum_type) (((unsigned int) c << 8) | *p++); + + if (c <= ieee_number_repeat_end_enum) + { + ieee_error (&info, record_start, _("unexpected number")); + return FALSE; + } + + switch (c) + { + default: + ieee_error (&info, record_start, _("unexpected record type")); + return FALSE; + + case ieee_bb_record_enum: + if (! parse_ieee_bb (&info, &p)) + return FALSE; + break; + + case ieee_be_record_enum: + if (! parse_ieee_be (&info, &p)) + return FALSE; + break; + + case ieee_nn_record: + if (! parse_ieee_nn (&info, &p)) + return FALSE; + break; + + case ieee_ty_record_enum: + if (! parse_ieee_ty (&info, &p)) + return FALSE; + break; + + case ieee_atn_record_enum: + if (! parse_ieee_atn (&info, &p)) + return FALSE; + break; + } + } + + if (info.blockstack.bsp != info.blockstack.stack) + { + ieee_error (&info, (const bfd_byte *) NULL, + _("blocks left on stack at end")); + return FALSE; + } + + return TRUE; +} + +/* Handle an IEEE BB record. */ + +static bfd_boolean +parse_ieee_bb (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *block_start; + bfd_byte b; + bfd_vma size; + const char *name; + unsigned long namlen; + char *namcopy = NULL; + unsigned int fnindx; + bfd_boolean skip; + + block_start = *pp; + + b = **pp; + ++*pp; + + if (! ieee_read_number (info, pp, &size) + || ! ieee_read_id (info, pp, &name, &namlen)) + return FALSE; + + fnindx = (unsigned int) -1; + skip = FALSE; + + switch (b) + { + case 1: + /* BB1: Type definitions local to a module. */ + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return FALSE; + if (! debug_set_filename (info->dhandle, namcopy)) + return FALSE; + info->saw_filename = TRUE; + + /* Discard any variables or types we may have seen before. */ + if (info->vars.vars != NULL) + free (info->vars.vars); + info->vars.vars = NULL; + info->vars.alloc = 0; + if (info->types.types != NULL) + free (info->types.types); + info->types.types = NULL; + info->types.alloc = 0; + + /* Initialize the types to the global types. */ + if (info->global_types != NULL) + { + info->types.alloc = info->global_types->alloc; + info->types.types = ((struct ieee_type *) + xmalloc (info->types.alloc + * sizeof (*info->types.types))); + memcpy (info->types.types, info->global_types->types, + info->types.alloc * sizeof (*info->types.types)); + } + + break; + + case 2: + /* BB2: Global type definitions. The name is supposed to be + empty, but we don't check. */ + if (! debug_set_filename (info->dhandle, "*global*")) + return FALSE; + info->saw_filename = TRUE; + break; + + case 3: + /* BB3: High level module block begin. We don't have to do + anything here. The name is supposed to be the same as for + the BB1, but we don't check. */ + break; + + case 4: + /* BB4: Global function. */ + { + bfd_vma stackspace, typindx, offset; + debug_type return_type; + + if (! ieee_read_number (info, pp, &stackspace) + || ! ieee_read_number (info, pp, &typindx) + || ! ieee_read_expression (info, pp, &offset)) + return FALSE; + + /* We have no way to record the stack space. FIXME. */ + + if (typindx < 256) + { + return_type = ieee_builtin_type (info, block_start, typindx); + if (return_type == DEBUG_TYPE_NULL) + return FALSE; + } + else + { + typindx -= 256; + if (! ieee_alloc_type (info, typindx, TRUE)) + return FALSE; + fnindx = typindx; + return_type = info->types.types[typindx].type; + if (debug_get_type_kind (info->dhandle, return_type) + == DEBUG_KIND_FUNCTION) + return_type = debug_get_return_type (info->dhandle, + return_type); + } + + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return FALSE; + if (! debug_record_function (info->dhandle, namcopy, return_type, + TRUE, offset)) + return FALSE; + } + break; + + case 5: + /* BB5: File name for source line numbers. */ + { + unsigned int i; + + /* We ignore the date and time. FIXME. */ + for (i = 0; i < 6; i++) + { + bfd_vma ignore; + bfd_boolean present; + + if (! ieee_read_optional_number (info, pp, &ignore, &present)) + return FALSE; + if (! present) + break; + } + + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return FALSE; + if (! debug_start_source (info->dhandle, namcopy)) + return FALSE; + } + break; + + case 6: + /* BB6: Local function or block. */ + { + bfd_vma stackspace, typindx, offset; + + if (! ieee_read_number (info, pp, &stackspace) + || ! ieee_read_number (info, pp, &typindx) + || ! ieee_read_expression (info, pp, &offset)) + return FALSE; + + /* We have no way to record the stack space. FIXME. */ + + if (namlen == 0) + { + if (! debug_start_block (info->dhandle, offset)) + return FALSE; + /* Change b to indicate that this is a block + rather than a function. */ + b = 0x86; + } + else + { + /* The MRI C++ compiler will output a fake function named + __XRYCPP to hold C++ debugging information. We skip + that function. This is not crucial, but it makes + converting from IEEE to other debug formats work + better. */ + if (strncmp (name, "__XRYCPP", namlen) == 0) + skip = TRUE; + else + { + debug_type return_type; + + if (typindx < 256) + { + return_type = ieee_builtin_type (info, block_start, + typindx); + if (return_type == NULL) + return FALSE; + } + else + { + typindx -= 256; + if (! ieee_alloc_type (info, typindx, TRUE)) + return FALSE; + fnindx = typindx; + return_type = info->types.types[typindx].type; + if (debug_get_type_kind (info->dhandle, return_type) + == DEBUG_KIND_FUNCTION) + return_type = debug_get_return_type (info->dhandle, + return_type); + } + + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return FALSE; + if (! debug_record_function (info->dhandle, namcopy, + return_type, FALSE, offset)) + return FALSE; + } + } + } + break; + + case 10: + /* BB10: Assembler module scope. In the normal case, we + completely ignore all this information. FIXME. */ + { + const char *inam, *vstr; + unsigned long inamlen, vstrlen; + bfd_vma tool_type; + bfd_boolean present; + unsigned int i; + + if (! info->saw_filename) + { + namcopy = savestring (name, namlen); + if (namcopy == NULL) + return FALSE; + if (! debug_set_filename (info->dhandle, namcopy)) + return FALSE; + info->saw_filename = TRUE; + } + + if (! ieee_read_id (info, pp, &inam, &inamlen) + || ! ieee_read_number (info, pp, &tool_type) + || ! ieee_read_optional_id (info, pp, &vstr, &vstrlen, &present)) + return FALSE; + for (i = 0; i < 6; i++) + { + bfd_vma ignore; + + if (! ieee_read_optional_number (info, pp, &ignore, &present)) + return FALSE; + if (! present) + break; + } + } + break; + + case 11: + /* BB11: Module section. We completely ignore all this + information. FIXME. */ + { + bfd_vma sectype, secindx, offset, map; + bfd_boolean present; + + if (! ieee_read_number (info, pp, §ype) + || ! ieee_read_number (info, pp, &secindx) + || ! ieee_read_expression (info, pp, &offset) + || ! ieee_read_optional_number (info, pp, &map, &present)) + return FALSE; + } + break; + + default: + ieee_error (info, block_start, _("unknown BB type")); + return FALSE; + } + + + /* Push this block on the block stack. */ + + if (info->blockstack.bsp >= info->blockstack.stack + BLOCKSTACK_SIZE) + { + ieee_error (info, (const bfd_byte *) NULL, _("stack overflow")); + return FALSE; + } + + info->blockstack.bsp->kind = b; + if (b == 5) + info->blockstack.bsp->filename = namcopy; + info->blockstack.bsp->fnindx = fnindx; + info->blockstack.bsp->skip = skip; + ++info->blockstack.bsp; + + return TRUE; +} + +/* Handle an IEEE BE record. */ + +static bfd_boolean +parse_ieee_be (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + bfd_vma offset; + + if (info->blockstack.bsp <= info->blockstack.stack) + { + ieee_error (info, *pp, _("stack underflow")); + return FALSE; + } + --info->blockstack.bsp; + + switch (info->blockstack.bsp->kind) + { + case 2: + /* When we end the global typedefs block, we copy out the the + contents of info->vars. This is because the variable indices + may be reused in the local blocks. However, we need to + preserve them so that we can locate a function returning a + reference variable whose type is named in the global typedef + block. */ + info->global_vars = ((struct ieee_vars *) + xmalloc (sizeof *info->global_vars)); + info->global_vars->alloc = info->vars.alloc; + info->global_vars->vars = ((struct ieee_var *) + xmalloc (info->vars.alloc + * sizeof (*info->vars.vars))); + memcpy (info->global_vars->vars, info->vars.vars, + info->vars.alloc * sizeof (*info->vars.vars)); + + /* We also copy out the non builtin parts of info->types, since + the types are discarded when we start a new block. */ + info->global_types = ((struct ieee_types *) + xmalloc (sizeof *info->global_types)); + info->global_types->alloc = info->types.alloc; + info->global_types->types = ((struct ieee_type *) + xmalloc (info->types.alloc + * sizeof (*info->types.types))); + memcpy (info->global_types->types, info->types.types, + info->types.alloc * sizeof (*info->types.types)); + memset (info->global_types->builtins, 0, + sizeof (info->global_types->builtins)); + + break; + + case 4: + case 6: + if (! ieee_read_expression (info, pp, &offset)) + return FALSE; + if (! info->blockstack.bsp->skip) + { + if (! debug_end_function (info->dhandle, offset + 1)) + return FALSE; + } + break; + + case 0x86: + /* This is BE6 when BB6 started a block rather than a local + function. */ + if (! ieee_read_expression (info, pp, &offset)) + return FALSE; + if (! debug_end_block (info->dhandle, offset + 1)) + return FALSE; + break; + + case 5: + /* When we end a BB5, we look up the stack for the last BB5, if + there is one, so that we can call debug_start_source. */ + if (info->blockstack.bsp > info->blockstack.stack) + { + struct ieee_block *bl; + + bl = info->blockstack.bsp; + do + { + --bl; + if (bl->kind == 5) + { + if (! debug_start_source (info->dhandle, bl->filename)) + return FALSE; + break; + } + } + while (bl != info->blockstack.stack); + } + break; + + case 11: + if (! ieee_read_expression (info, pp, &offset)) + return FALSE; + /* We just ignore the module size. FIXME. */ + break; + + default: + /* Other block types do not have any trailing information. */ + break; + } + + return TRUE; +} + +/* Parse an NN record. */ + +static bfd_boolean +parse_ieee_nn (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *nn_start; + bfd_vma varindx; + const char *name; + unsigned long namlen; + + nn_start = *pp; + + if (! ieee_read_number (info, pp, &varindx) + || ! ieee_read_id (info, pp, &name, &namlen)) + return FALSE; + + if (varindx < 32) + { + ieee_error (info, nn_start, _("illegal variable index")); + return FALSE; + } + varindx -= 32; + + if (varindx >= info->vars.alloc) + { + unsigned int alloc; + + alloc = info->vars.alloc; + if (alloc == 0) + alloc = 4; + while (varindx >= alloc) + alloc *= 2; + info->vars.vars = ((struct ieee_var *) + xrealloc (info->vars.vars, + alloc * sizeof *info->vars.vars)); + memset (info->vars.vars + info->vars.alloc, 0, + (alloc - info->vars.alloc) * sizeof *info->vars.vars); + info->vars.alloc = alloc; + } + + info->vars.vars[varindx].name = name; + info->vars.vars[varindx].namlen = namlen; + + return TRUE; +} + +/* Parse a TY record. */ + +static bfd_boolean +parse_ieee_ty (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *ty_start, *ty_var_start, *ty_code_start; + bfd_vma typeindx, varindx, tc; + PTR dhandle; + bfd_boolean tag, typdef; + debug_type *arg_slots; + unsigned long type_bitsize; + debug_type type; + + ty_start = *pp; + + if (! ieee_read_number (info, pp, &typeindx)) + return FALSE; + + if (typeindx < 256) + { + ieee_error (info, ty_start, _("illegal type index")); + return FALSE; + } + + typeindx -= 256; + if (! ieee_alloc_type (info, typeindx, FALSE)) + return FALSE; + + if (**pp != 0xce) + { + ieee_error (info, *pp, _("unknown TY code")); + return FALSE; + } + ++*pp; + + ty_var_start = *pp; + + if (! ieee_read_number (info, pp, &varindx)) + return FALSE; + + if (varindx < 32) + { + ieee_error (info, ty_var_start, _("illegal variable index")); + return FALSE; + } + varindx -= 32; + + if (varindx >= info->vars.alloc || info->vars.vars[varindx].name == NULL) + { + ieee_error (info, ty_var_start, _("undefined variable in TY")); + return FALSE; + } + + ty_code_start = *pp; + + if (! ieee_read_number (info, pp, &tc)) + return FALSE; + + dhandle = info->dhandle; + + tag = FALSE; + typdef = FALSE; + arg_slots = NULL; + type_bitsize = 0; + switch (tc) + { + default: + ieee_error (info, ty_code_start, _("unknown TY code")); + return FALSE; + + case '!': + /* Unknown type, with size. We treat it as int. FIXME. */ + { + bfd_vma size; + + if (! ieee_read_number (info, pp, &size)) + return FALSE; + type = debug_make_int_type (dhandle, size, FALSE); + } + break; + + case 'A': /* Array. */ + case 'a': /* FORTRAN array in column/row order. FIXME: Not + distinguished from normal array. */ + { + debug_type ele_type; + bfd_vma lower, upper; + + if (! ieee_read_type_index (info, pp, &ele_type) + || ! ieee_read_number (info, pp, &lower) + || ! ieee_read_number (info, pp, &upper)) + return FALSE; + type = debug_make_array_type (dhandle, ele_type, + ieee_builtin_type (info, ty_code_start, + ((unsigned int) + builtin_int)), + (bfd_signed_vma) lower, + (bfd_signed_vma) upper, + FALSE); + } + break; + + case 'E': + /* Simple enumeration. */ + { + bfd_vma size; + unsigned int alloc; + const char **names; + unsigned int c; + bfd_signed_vma *vals; + unsigned int i; + + if (! ieee_read_number (info, pp, &size)) + return FALSE; + /* FIXME: we ignore the enumeration size. */ + + alloc = 10; + names = (const char **) xmalloc (alloc * sizeof *names); + memset (names, 0, alloc * sizeof *names); + c = 0; + while (1) + { + const char *name; + unsigned long namlen; + bfd_boolean present; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return FALSE; + if (! present) + break; + + if (c + 1 >= alloc) + { + alloc += 10; + names = ((const char **) + xrealloc (names, alloc * sizeof *names)); + } + + names[c] = savestring (name, namlen); + if (names[c] == NULL) + return FALSE; + ++c; + } + + names[c] = NULL; + + vals = (bfd_signed_vma *) xmalloc (c * sizeof *vals); + for (i = 0; i < c; i++) + vals[i] = i; + + type = debug_make_enum_type (dhandle, names, vals); + tag = TRUE; + } + break; + + case 'G': + /* Struct with bit fields. */ + { + bfd_vma size; + unsigned int alloc; + debug_field *fields; + unsigned int c; + + if (! ieee_read_number (info, pp, &size)) + return FALSE; + + alloc = 10; + fields = (debug_field *) xmalloc (alloc * sizeof *fields); + c = 0; + while (1) + { + const char *name; + unsigned long namlen; + bfd_boolean present; + debug_type ftype; + bfd_vma bitpos, bitsize; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return FALSE; + if (! present) + break; + if (! ieee_read_type_index (info, pp, &ftype) + || ! ieee_read_number (info, pp, &bitpos) + || ! ieee_read_number (info, pp, &bitsize)) + return FALSE; + + if (c + 1 >= alloc) + { + alloc += 10; + fields = ((debug_field *) + xrealloc (fields, alloc * sizeof *fields)); + } + + fields[c] = debug_make_field (dhandle, savestring (name, namlen), + ftype, bitpos, bitsize, + DEBUG_VISIBILITY_PUBLIC); + if (fields[c] == NULL) + return FALSE; + ++c; + } + + fields[c] = NULL; + + type = debug_make_struct_type (dhandle, TRUE, size, fields); + tag = TRUE; + } + break; + + case 'N': + /* Enumeration. */ + { + unsigned int alloc; + const char **names; + bfd_signed_vma *vals; + unsigned int c; + + alloc = 10; + names = (const char **) xmalloc (alloc * sizeof *names); + vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *names); + c = 0; + while (1) + { + const char *name; + unsigned long namlen; + bfd_boolean present; + bfd_vma val; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return FALSE; + if (! present) + break; + if (! ieee_read_number (info, pp, &val)) + return FALSE; + + /* If the length of the name is zero, then the value is + actually the size of the enum. We ignore this + information. FIXME. */ + if (namlen == 0) + continue; + + if (c + 1 >= alloc) + { + alloc += 10; + names = ((const char **) + xrealloc (names, alloc * sizeof *names)); + vals = ((bfd_signed_vma *) + xrealloc (vals, alloc * sizeof *vals)); + } + + names[c] = savestring (name, namlen); + if (names[c] == NULL) + return FALSE; + vals[c] = (bfd_signed_vma) val; + ++c; + } + + names[c] = NULL; + + type = debug_make_enum_type (dhandle, names, vals); + tag = TRUE; + } + break; + + case 'O': /* Small pointer. We don't distinguish small and large + pointers. FIXME. */ + case 'P': /* Large pointer. */ + { + debug_type t; + + if (! ieee_read_type_index (info, pp, &t)) + return FALSE; + type = debug_make_pointer_type (dhandle, t); + } + break; + + case 'R': + /* Range. */ + { + bfd_vma low, high, signedp, size; + + if (! ieee_read_number (info, pp, &low) + || ! ieee_read_number (info, pp, &high) + || ! ieee_read_number (info, pp, &signedp) + || ! ieee_read_number (info, pp, &size)) + return FALSE; + + type = debug_make_range_type (dhandle, + debug_make_int_type (dhandle, size, + ! signedp), + (bfd_signed_vma) low, + (bfd_signed_vma) high); + } + break; + + case 'S': /* Struct. */ + case 'U': /* Union. */ + { + bfd_vma size; + unsigned int alloc; + debug_field *fields; + unsigned int c; + + if (! ieee_read_number (info, pp, &size)) + return FALSE; + + alloc = 10; + fields = (debug_field *) xmalloc (alloc * sizeof *fields); + c = 0; + while (1) + { + const char *name; + unsigned long namlen; + bfd_boolean present; + bfd_vma tindx; + bfd_vma offset; + debug_type ftype; + bfd_vma bitsize; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return FALSE; + if (! present) + break; + if (! ieee_read_number (info, pp, &tindx) + || ! ieee_read_number (info, pp, &offset)) + return FALSE; + + if (tindx < 256) + { + ftype = ieee_builtin_type (info, ty_code_start, tindx); + bitsize = 0; + offset *= 8; + } + else + { + struct ieee_type *t; + + tindx -= 256; + if (! ieee_alloc_type (info, tindx, TRUE)) + return FALSE; + t = info->types.types + tindx; + ftype = t->type; + bitsize = t->bitsize; + if (bitsize == 0) + offset *= 8; + } + + if (c + 1 >= alloc) + { + alloc += 10; + fields = ((debug_field *) + xrealloc (fields, alloc * sizeof *fields)); + } + + fields[c] = debug_make_field (dhandle, savestring (name, namlen), + ftype, offset, bitsize, + DEBUG_VISIBILITY_PUBLIC); + if (fields[c] == NULL) + return FALSE; + ++c; + } + + fields[c] = NULL; + + type = debug_make_struct_type (dhandle, tc == 'S', size, fields); + tag = TRUE; + } + break; + + case 'T': + /* Typedef. */ + if (! ieee_read_type_index (info, pp, &type)) + return FALSE; + typdef = TRUE; + break; + + case 'X': + /* Procedure. FIXME: This is an extern declaration, which we + have no way of representing. */ + { + bfd_vma attr; + debug_type rtype; + bfd_vma nargs; + bfd_boolean present; + struct ieee_var *pv; + + /* FIXME: We ignore the attribute and the argument names. */ + + if (! ieee_read_number (info, pp, &attr) + || ! ieee_read_type_index (info, pp, &rtype) + || ! ieee_read_number (info, pp, &nargs)) + return FALSE; + do + { + const char *name; + unsigned long namlen; + + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return FALSE; + } + while (present); + + pv = info->vars.vars + varindx; + pv->kind = IEEE_EXTERNAL; + if (pv->namlen > 0 + && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER) + { + /* Set up the return type as an indirect type pointing to + the variable slot, so that we can change it to a + reference later if appropriate. */ + pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot); + *pv->pslot = rtype; + rtype = debug_make_indirect_type (dhandle, pv->pslot, + (const char *) NULL); + } + + type = debug_make_function_type (dhandle, rtype, (debug_type *) NULL, + FALSE); + } + break; + + case 'V': + /* Void. This is not documented, but the MRI compiler emits it. */ + type = debug_make_void_type (dhandle); + break; + + case 'Z': + /* Array with 0 lower bound. */ + { + debug_type etype; + bfd_vma high; + + if (! ieee_read_type_index (info, pp, &etype) + || ! ieee_read_number (info, pp, &high)) + return FALSE; + + type = debug_make_array_type (dhandle, etype, + ieee_builtin_type (info, ty_code_start, + ((unsigned int) + builtin_int)), + 0, (bfd_signed_vma) high, FALSE); + } + break; + + case 'c': /* Complex. */ + case 'd': /* Double complex. */ + { + const char *name; + unsigned long namlen; + + /* FIXME: I don't know what the name means. */ + + if (! ieee_read_id (info, pp, &name, &namlen)) + return FALSE; + + type = debug_make_complex_type (dhandle, tc == 'c' ? 4 : 8); + } + break; + + case 'f': + /* Pascal file name. FIXME. */ + ieee_error (info, ty_code_start, _("Pascal file name not supported")); + return FALSE; + + case 'g': + /* Bitfield type. */ + { + bfd_vma signedp, bitsize, dummy; + const bfd_byte *hold; + bfd_boolean present; + + if (! ieee_read_number (info, pp, &signedp) + || ! ieee_read_number (info, pp, &bitsize)) + return FALSE; + + /* I think the documentation says that there is a type index, + but some actual files do not have one. */ + hold = *pp; + if (! ieee_read_optional_number (info, pp, &dummy, &present)) + return FALSE; + if (! present) + { + /* FIXME: This is just a guess. */ + type = debug_make_int_type (dhandle, 4, + signedp ? FALSE : TRUE); + } + else + { + *pp = hold; + if (! ieee_read_type_index (info, pp, &type)) + return FALSE; + } + type_bitsize = bitsize; + } + break; + + case 'n': + /* Qualifier. */ + { + bfd_vma kind; + debug_type t; + + if (! ieee_read_number (info, pp, &kind) + || ! ieee_read_type_index (info, pp, &t)) + return FALSE; + + switch (kind) + { + default: + ieee_error (info, ty_start, _("unsupported qualifier")); + return FALSE; + + case 1: + type = debug_make_const_type (dhandle, t); + break; + + case 2: + type = debug_make_volatile_type (dhandle, t); + break; + } + } + break; + + case 's': + /* Set. */ + { + bfd_vma size; + debug_type etype; + + if (! ieee_read_number (info, pp, &size) + || ! ieee_read_type_index (info, pp, &etype)) + return FALSE; + + /* FIXME: We ignore the size. */ + + type = debug_make_set_type (dhandle, etype, FALSE); + } + break; + + case 'x': + /* Procedure with compiler dependencies. */ + { + struct ieee_var *pv; + bfd_vma attr, frame_type, push_mask, nargs, level, father; + debug_type rtype; + debug_type *arg_types; + bfd_boolean varargs; + bfd_boolean present; + + /* FIXME: We ignore some of this information. */ + + pv = info->vars.vars + varindx; + + if (! ieee_read_number (info, pp, &attr) + || ! ieee_read_number (info, pp, &frame_type) + || ! ieee_read_number (info, pp, &push_mask) + || ! ieee_read_type_index (info, pp, &rtype) + || ! ieee_read_number (info, pp, &nargs)) + return FALSE; + if (nargs == (bfd_vma) -1) + { + arg_types = NULL; + varargs = FALSE; + } + else + { + unsigned int i; + + arg_types = ((debug_type *) + xmalloc ((nargs + 1) * sizeof *arg_types)); + for (i = 0; i < nargs; i++) + if (! ieee_read_type_index (info, pp, arg_types + i)) + return FALSE; + + /* If the last type is pointer to void, this is really a + varargs function. */ + varargs = FALSE; + if (nargs > 0) + { + debug_type last; + + last = arg_types[nargs - 1]; + if (debug_get_type_kind (dhandle, last) == DEBUG_KIND_POINTER + && (debug_get_type_kind (dhandle, + debug_get_target_type (dhandle, + last)) + == DEBUG_KIND_VOID)) + { + --nargs; + varargs = TRUE; + } + } + + /* If there are any pointer arguments, turn them into + indirect types in case we later need to convert them to + reference types. */ + for (i = 0; i < nargs; i++) + { + if (debug_get_type_kind (dhandle, arg_types[i]) + == DEBUG_KIND_POINTER) + { + if (arg_slots == NULL) + { + arg_slots = ((debug_type *) + xmalloc (nargs * sizeof *arg_slots)); + memset (arg_slots, 0, nargs * sizeof *arg_slots); + } + arg_slots[i] = arg_types[i]; + arg_types[i] = + debug_make_indirect_type (dhandle, + arg_slots + i, + (const char *) NULL); + } + } + + arg_types[nargs] = DEBUG_TYPE_NULL; + } + if (! ieee_read_number (info, pp, &level) + || ! ieee_read_optional_number (info, pp, &father, &present)) + return FALSE; + + /* We can't distinguish between a global function and a static + function. */ + pv->kind = IEEE_FUNCTION; + + if (pv->namlen > 0 + && debug_get_type_kind (dhandle, rtype) == DEBUG_KIND_POINTER) + { + /* Set up the return type as an indirect type pointing to + the variable slot, so that we can change it to a + reference later if appropriate. */ + pv->pslot = (debug_type *) xmalloc (sizeof *pv->pslot); + *pv->pslot = rtype; + rtype = debug_make_indirect_type (dhandle, pv->pslot, + (const char *) NULL); + } + + type = debug_make_function_type (dhandle, rtype, arg_types, varargs); + } + break; + } + + /* Record the type in the table. */ + + if (type == DEBUG_TYPE_NULL) + return FALSE; + + info->vars.vars[varindx].type = type; + + if ((tag || typdef) + && info->vars.vars[varindx].namlen > 0) + { + const char *name; + + name = savestring (info->vars.vars[varindx].name, + info->vars.vars[varindx].namlen); + if (typdef) + type = debug_name_type (dhandle, name, type); + else if (tc == 'E' || tc == 'N') + type = debug_tag_type (dhandle, name, type); + else + { + struct ieee_tag *it; + + /* We must allocate all struct tags as indirect types, so + that if we later see a definition of the tag as a C++ + record we can update the indirect slot and automatically + change all the existing references. */ + it = (struct ieee_tag *) xmalloc (sizeof *it); + memset (it, 0, sizeof *it); + it->next = info->tags; + info->tags = it; + it->name = name; + it->slot = type; + + type = debug_make_indirect_type (dhandle, &it->slot, name); + type = debug_tag_type (dhandle, name, type); + + it->type = type; + } + if (type == NULL) + return FALSE; + } + + info->types.types[typeindx].type = type; + info->types.types[typeindx].arg_slots = arg_slots; + info->types.types[typeindx].bitsize = type_bitsize; + + /* We may have already allocated type as an indirect type pointing + to slot. It does no harm to replace the indirect type with the + real type. Filling in slot as well handles the indirect types + which are already hanging around. */ + if (info->types.types[typeindx].pslot != NULL) + *info->types.types[typeindx].pslot = type; + + return TRUE; +} + +/* Parse an ATN record. */ + +static bfd_boolean +parse_ieee_atn (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *atn_start, *atn_code_start; + bfd_vma varindx; + struct ieee_var *pvar; + debug_type type; + bfd_vma atn_code; + PTR dhandle; + bfd_vma v, v2, v3, v4, v5; + const char *name; + unsigned long namlen; + char *namcopy; + bfd_boolean present; + int blocktype; + + atn_start = *pp; + + if (! ieee_read_number (info, pp, &varindx) + || ! ieee_read_type_index (info, pp, &type)) + return FALSE; + + atn_code_start = *pp; + + if (! ieee_read_number (info, pp, &atn_code)) + return FALSE; + + if (varindx == 0) + { + pvar = NULL; + name = ""; + namlen = 0; + } + else if (varindx < 32) + { + /* The MRI compiler reportedly sometimes emits variable lifetime + information for a register. We just ignore it. */ + if (atn_code == 9) + return ieee_read_number (info, pp, &v); + + ieee_error (info, atn_start, _("illegal variable index")); + return FALSE; + } + else + { + varindx -= 32; + if (varindx >= info->vars.alloc + || info->vars.vars[varindx].name == NULL) + { + /* The MRI compiler or linker sometimes omits the NN record + for a pmisc record. */ + if (atn_code == 62) + { + if (varindx >= info->vars.alloc) + { + unsigned int alloc; + + alloc = info->vars.alloc; + if (alloc == 0) + alloc = 4; + while (varindx >= alloc) + alloc *= 2; + info->vars.vars = ((struct ieee_var *) + xrealloc (info->vars.vars, + (alloc + * sizeof *info->vars.vars))); + memset (info->vars.vars + info->vars.alloc, 0, + ((alloc - info->vars.alloc) + * sizeof *info->vars.vars)); + info->vars.alloc = alloc; + } + + pvar = info->vars.vars + varindx; + pvar->name = ""; + pvar->namlen = 0; + } + else + { + ieee_error (info, atn_start, _("undefined variable in ATN")); + return FALSE; + } + } + + pvar = info->vars.vars + varindx; + + pvar->type = type; + + name = pvar->name; + namlen = pvar->namlen; + } + + dhandle = info->dhandle; + + /* If we are going to call debug_record_variable with a pointer + type, change the type to an indirect type so that we can later + change it to a reference type if we encounter a C++ pmisc 'R' + record. */ + if (pvar != NULL + && type != DEBUG_TYPE_NULL + && debug_get_type_kind (dhandle, type) == DEBUG_KIND_POINTER) + { + switch (atn_code) + { + case 1: + case 2: + case 3: + case 5: + case 8: + case 10: + pvar->pslot = (debug_type *) xmalloc (sizeof *pvar->pslot); + *pvar->pslot = type; + type = debug_make_indirect_type (dhandle, pvar->pslot, + (const char *) NULL); + pvar->type = type; + break; + } + } + + switch (atn_code) + { + default: + ieee_error (info, atn_code_start, _("unknown ATN type")); + return FALSE; + + case 1: + /* Automatic variable. */ + if (! ieee_read_number (info, pp, &v)) + return FALSE; + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (pvar != NULL) + pvar->kind = IEEE_LOCAL; + return debug_record_variable (dhandle, namcopy, type, DEBUG_LOCAL, v); + + case 2: + /* Register variable. */ + if (! ieee_read_number (info, pp, &v)) + return FALSE; + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (pvar != NULL) + pvar->kind = IEEE_LOCAL; + return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, + ieee_regno_to_genreg (info->abfd, v)); + + case 3: + /* Static variable. */ + if (! ieee_require_asn (info, pp, &v)) + return FALSE; + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (info->blockstack.bsp <= info->blockstack.stack) + blocktype = 0; + else + blocktype = info->blockstack.bsp[-1].kind; + if (pvar != NULL) + { + if (blocktype == 4 || blocktype == 6) + pvar->kind = IEEE_LOCAL; + else + pvar->kind = IEEE_STATIC; + } + return debug_record_variable (dhandle, namcopy, type, + (blocktype == 4 || blocktype == 6 + ? DEBUG_LOCAL_STATIC + : DEBUG_STATIC), + v); + + case 4: + /* External function. We don't currently record these. FIXME. */ + if (pvar != NULL) + pvar->kind = IEEE_EXTERNAL; + return TRUE; + + case 5: + /* External variable. We don't currently record these. FIXME. */ + if (pvar != NULL) + pvar->kind = IEEE_EXTERNAL; + return TRUE; + + case 7: + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_number (info, pp, &v2) + || ! ieee_read_optional_number (info, pp, &v3, &present)) + return FALSE; + if (present) + { + if (! ieee_read_optional_number (info, pp, &v4, &present)) + return FALSE; + } + + /* We just ignore the two optional fields in v3 and v4, since + they are not defined. */ + + if (! ieee_require_asn (info, pp, &v3)) + return FALSE; + + /* We have no way to record the column number. FIXME. */ + + return debug_record_line (dhandle, v, v3); + + case 8: + /* Global variable. */ + if (! ieee_require_asn (info, pp, &v)) + return FALSE; + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (pvar != NULL) + pvar->kind = IEEE_GLOBAL; + return debug_record_variable (dhandle, namcopy, type, DEBUG_GLOBAL, v); + + case 9: + /* Variable lifetime information. */ + if (! ieee_read_number (info, pp, &v)) + return FALSE; + + /* We have no way to record this information. FIXME. */ + return TRUE; + + case 10: + /* Locked register. The spec says that there are two required + fields, but at least on occasion the MRI compiler only emits + one. */ + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_optional_number (info, pp, &v2, &present)) + return FALSE; + + /* I think this means a variable that is both in a register and + a frame slot. We ignore the frame slot. FIXME. */ + + namcopy = savestring (name, namlen); + if (type == NULL) + type = debug_make_void_type (dhandle); + if (pvar != NULL) + pvar->kind = IEEE_LOCAL; + return debug_record_variable (dhandle, namcopy, type, DEBUG_REGISTER, v); + + case 11: + /* Reserved for FORTRAN common. */ + ieee_error (info, atn_code_start, _("unsupported ATN11")); + + /* Return TRUE to keep going. */ + return TRUE; + + case 12: + /* Based variable. */ + v3 = 0; + v4 = 0x80; + v5 = 0; + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_number (info, pp, &v2) + || ! ieee_read_optional_number (info, pp, &v3, &present)) + return FALSE; + if (present) + { + if (! ieee_read_optional_number (info, pp, &v4, &present)) + return FALSE; + if (present) + { + if (! ieee_read_optional_number (info, pp, &v5, &present)) + return FALSE; + } + } + + /* We have no way to record this information. FIXME. */ + + ieee_error (info, atn_code_start, _("unsupported ATN12")); + + /* Return TRUE to keep going. */ + return TRUE; + + case 16: + /* Constant. The description of this that I have is ambiguous, + so I'm not going to try to implement it. */ + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_optional_number (info, pp, &v2, &present)) + return FALSE; + if (present) + { + if (! ieee_read_optional_number (info, pp, &v2, &present)) + return FALSE; + if (present) + { + if (! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return FALSE; + } + } + + if ((ieee_record_enum_type) **pp == ieee_e2_first_byte_enum) + { + if (! ieee_require_asn (info, pp, &v3)) + return FALSE; + } + + return TRUE; + + case 19: + /* Static variable from assembler. */ + v2 = 0; + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_optional_number (info, pp, &v2, &present) + || ! ieee_require_asn (info, pp, &v3)) + return FALSE; + namcopy = savestring (name, namlen); + /* We don't really handle this correctly. FIXME. */ + return debug_record_variable (dhandle, namcopy, + debug_make_void_type (dhandle), + v2 != 0 ? DEBUG_GLOBAL : DEBUG_STATIC, + v3); + + case 62: + /* Procedure miscellaneous information. */ + case 63: + /* Variable miscellaneous information. */ + case 64: + /* Module miscellaneous information. */ + if (! ieee_read_number (info, pp, &v) + || ! ieee_read_number (info, pp, &v2) + || ! ieee_read_optional_id (info, pp, &name, &namlen, &present)) + return FALSE; + + if (atn_code == 62 && v == 80) + { + if (present) + { + ieee_error (info, atn_code_start, + _("unexpected string in C++ misc")); + return FALSE; + } + return ieee_read_cxx_misc (info, pp, v2); + } + + /* We just ignore all of this stuff. FIXME. */ + + for (; v2 > 0; --v2) + { + switch ((ieee_record_enum_type) **pp) + { + default: + ieee_error (info, *pp, _("bad misc record")); + return FALSE; + + case ieee_at_record_enum: + if (! ieee_require_atn65 (info, pp, &name, &namlen)) + return FALSE; + break; + + case ieee_e2_first_byte_enum: + if (! ieee_require_asn (info, pp, &v3)) + return FALSE; + break; + } + } + + return TRUE; + } + + /*NOTREACHED*/ +} + +/* Handle C++ debugging miscellaneous records. This is called for + procedure miscellaneous records of type 80. */ + +static bfd_boolean +ieee_read_cxx_misc (info, pp, count) + struct ieee_info *info; + const bfd_byte **pp; + unsigned long count; +{ + const bfd_byte *start; + bfd_vma category; + + start = *pp; + + /* Get the category of C++ misc record. */ + if (! ieee_require_asn (info, pp, &category)) + return FALSE; + --count; + + switch (category) + { + default: + ieee_error (info, start, _("unrecognized C++ misc record")); + return FALSE; + + case 'T': + if (! ieee_read_cxx_class (info, pp, count)) + return FALSE; + break; + + case 'M': + { + bfd_vma flags; + const char *name; + unsigned long namlen; + + /* The IEEE spec indicates that the 'M' record only has a + flags field. The MRI compiler also emits the name of the + function. */ + + if (! ieee_require_asn (info, pp, &flags)) + return FALSE; + if (*pp < info->pend + && (ieee_record_enum_type) **pp == ieee_at_record_enum) + { + if (! ieee_require_atn65 (info, pp, &name, &namlen)) + return FALSE; + } + + /* This is emitted for method functions, but I don't think we + care very much. It might help if it told us useful + information like the class with which this function is + associated, but it doesn't, so it isn't helpful. */ + } + break; + + case 'B': + if (! ieee_read_cxx_defaults (info, pp, count)) + return FALSE; + break; + + case 'z': + { + const char *name, *mangled, *class; + unsigned long namlen, mangledlen, classlen; + bfd_vma control; + + /* Pointer to member. */ + + if (! ieee_require_atn65 (info, pp, &name, &namlen) + || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen) + || ! ieee_require_atn65 (info, pp, &class, &classlen) + || ! ieee_require_asn (info, pp, &control)) + return FALSE; + + /* FIXME: We should now track down name and change its type. */ + } + break; + + case 'R': + if (! ieee_read_reference (info, pp)) + return FALSE; + break; + } + + return TRUE; +} + +/* Read a C++ class definition. This is a pmisc type 80 record of + category 'T'. */ + +static bfd_boolean +ieee_read_cxx_class (info, pp, count) + struct ieee_info *info; + const bfd_byte **pp; + unsigned long count; +{ + const bfd_byte *start; + bfd_vma class; + const char *tag; + unsigned long taglen; + struct ieee_tag *it; + PTR dhandle; + debug_field *fields; + unsigned int field_count, field_alloc; + debug_baseclass *baseclasses; + unsigned int baseclasses_count, baseclasses_alloc; + const debug_field *structfields; + struct ieee_method + { + const char *name; + unsigned long namlen; + debug_method_variant *variants; + unsigned count; + unsigned int alloc; + } *methods; + unsigned int methods_count, methods_alloc; + debug_type vptrbase; + bfd_boolean ownvptr; + debug_method *dmethods; + + start = *pp; + + if (! ieee_require_asn (info, pp, &class)) + return FALSE; + --count; + + if (! ieee_require_atn65 (info, pp, &tag, &taglen)) + return FALSE; + --count; + + /* Find the C struct with this name. */ + for (it = info->tags; it != NULL; it = it->next) + if (it->name[0] == tag[0] + && strncmp (it->name, tag, taglen) == 0 + && strlen (it->name) == taglen) + break; + if (it == NULL) + { + ieee_error (info, start, _("undefined C++ object")); + return FALSE; + } + + dhandle = info->dhandle; + + fields = NULL; + field_count = 0; + field_alloc = 0; + baseclasses = NULL; + baseclasses_count = 0; + baseclasses_alloc = 0; + methods = NULL; + methods_count = 0; + methods_alloc = 0; + vptrbase = DEBUG_TYPE_NULL; + ownvptr = FALSE; + + structfields = debug_get_fields (dhandle, it->type); + + while (count > 0) + { + bfd_vma id; + const bfd_byte *spec_start; + + spec_start = *pp; + + if (! ieee_require_asn (info, pp, &id)) + return FALSE; + --count; + + switch (id) + { + default: + ieee_error (info, spec_start, _("unrecognized C++ object spec")); + return FALSE; + + case 'b': + { + bfd_vma flags, cinline; + const char *basename, *fieldname; + unsigned long baselen, fieldlen; + char *basecopy; + debug_type basetype; + bfd_vma bitpos; + bfd_boolean virtualp; + enum debug_visibility visibility; + debug_baseclass baseclass; + + /* This represents a base or friend class. */ + + if (! ieee_require_asn (info, pp, &flags) + || ! ieee_require_atn65 (info, pp, &basename, &baselen) + || ! ieee_require_asn (info, pp, &cinline) + || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen)) + return FALSE; + count -= 4; + + /* We have no way of recording friend information, so we + just ignore it. */ + if ((flags & BASEFLAGS_FRIEND) != 0) + break; + + /* I assume that either all of the members of the + baseclass are included in the object, starting at the + beginning of the object, or that none of them are + included. */ + + if ((fieldlen == 0) == (cinline == 0)) + { + ieee_error (info, start, _("unsupported C++ object type")); + return FALSE; + } + + basecopy = savestring (basename, baselen); + basetype = debug_find_tagged_type (dhandle, basecopy, + DEBUG_KIND_ILLEGAL); + free (basecopy); + if (basetype == DEBUG_TYPE_NULL) + { + ieee_error (info, start, _("C++ base class not defined")); + return FALSE; + } + + if (fieldlen == 0) + bitpos = 0; + else + { + const debug_field *pf; + + if (structfields == NULL) + { + ieee_error (info, start, _("C++ object has no fields")); + return FALSE; + } + + for (pf = structfields; *pf != DEBUG_FIELD_NULL; pf++) + { + const char *fname; + + fname = debug_get_field_name (dhandle, *pf); + if (fname == NULL) + return FALSE; + if (fname[0] == fieldname[0] + && strncmp (fname, fieldname, fieldlen) == 0 + && strlen (fname) == fieldlen) + break; + } + if (*pf == DEBUG_FIELD_NULL) + { + ieee_error (info, start, + _("C++ base class not found in container")); + return FALSE; + } + + bitpos = debug_get_field_bitpos (dhandle, *pf); + } + + if ((flags & BASEFLAGS_VIRTUAL) != 0) + virtualp = TRUE; + else + virtualp = FALSE; + if ((flags & BASEFLAGS_PRIVATE) != 0) + visibility = DEBUG_VISIBILITY_PRIVATE; + else + visibility = DEBUG_VISIBILITY_PUBLIC; + + baseclass = debug_make_baseclass (dhandle, basetype, bitpos, + virtualp, visibility); + if (baseclass == DEBUG_BASECLASS_NULL) + return FALSE; + + if (baseclasses_count + 1 >= baseclasses_alloc) + { + baseclasses_alloc += 10; + baseclasses = ((debug_baseclass *) + xrealloc (baseclasses, + (baseclasses_alloc + * sizeof *baseclasses))); + } + + baseclasses[baseclasses_count] = baseclass; + ++baseclasses_count; + baseclasses[baseclasses_count] = DEBUG_BASECLASS_NULL; + } + break; + + case 'd': + { + bfd_vma flags; + const char *fieldname, *mangledname; + unsigned long fieldlen, mangledlen; + char *fieldcopy; + bfd_boolean staticp; + debug_type ftype; + const debug_field *pf = NULL; + enum debug_visibility visibility; + debug_field field; + + /* This represents a data member. */ + + if (! ieee_require_asn (info, pp, &flags) + || ! ieee_require_atn65 (info, pp, &fieldname, &fieldlen) + || ! ieee_require_atn65 (info, pp, &mangledname, &mangledlen)) + return FALSE; + count -= 3; + + fieldcopy = savestring (fieldname, fieldlen); + + staticp = (flags & CXXFLAGS_STATIC) != 0 ? TRUE : FALSE; + + if (staticp) + { + struct ieee_var *pv, *pvend; + + /* See if we can find a definition for this variable. */ + pv = info->vars.vars; + pvend = pv + info->vars.alloc; + for (; pv < pvend; pv++) + if (pv->namlen == mangledlen + && strncmp (pv->name, mangledname, mangledlen) == 0) + break; + if (pv < pvend) + ftype = pv->type; + else + { + /* This can happen if the variable is never used. */ + ftype = ieee_builtin_type (info, start, + (unsigned int) builtin_void); + } + } + else + { + unsigned int findx; + + if (structfields == NULL) + { + ieee_error (info, start, _("C++ object has no fields")); + return FALSE; + } + + for (pf = structfields, findx = 0; + *pf != DEBUG_FIELD_NULL; + pf++, findx++) + { + const char *fname; + + fname = debug_get_field_name (dhandle, *pf); + if (fname == NULL) + return FALSE; + if (fname[0] == mangledname[0] + && strncmp (fname, mangledname, mangledlen) == 0 + && strlen (fname) == mangledlen) + break; + } + if (*pf == DEBUG_FIELD_NULL) + { + ieee_error (info, start, + _("C++ data member not found in container")); + return FALSE; + } + + ftype = debug_get_field_type (dhandle, *pf); + + if (debug_get_type_kind (dhandle, ftype) == DEBUG_KIND_POINTER) + { + /* We might need to convert this field into a + reference type later on, so make it an indirect + type. */ + if (it->fslots == NULL) + { + unsigned int fcnt; + const debug_field *pfcnt; + + fcnt = 0; + for (pfcnt = structfields; + *pfcnt != DEBUG_FIELD_NULL; + pfcnt++) + ++fcnt; + it->fslots = ((debug_type *) + xmalloc (fcnt * sizeof *it->fslots)); + memset (it->fslots, 0, + fcnt * sizeof *it->fslots); + } + + if (ftype == DEBUG_TYPE_NULL) + return FALSE; + it->fslots[findx] = ftype; + ftype = debug_make_indirect_type (dhandle, + it->fslots + findx, + (const char *) NULL); + } + } + if (ftype == DEBUG_TYPE_NULL) + return FALSE; + + switch (flags & CXXFLAGS_VISIBILITY) + { + default: + ieee_error (info, start, _("unknown C++ visibility")); + return FALSE; + + case CXXFLAGS_VISIBILITY_PUBLIC: + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + + case CXXFLAGS_VISIBILITY_PRIVATE: + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + + case CXXFLAGS_VISIBILITY_PROTECTED: + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + } + + if (staticp) + { + char *mangledcopy; + + mangledcopy = savestring (mangledname, mangledlen); + + field = debug_make_static_member (dhandle, fieldcopy, + ftype, mangledcopy, + visibility); + } + else + { + bfd_vma bitpos, bitsize; + + bitpos = debug_get_field_bitpos (dhandle, *pf); + bitsize = debug_get_field_bitsize (dhandle, *pf); + if (bitpos == (bfd_vma) -1 || bitsize == (bfd_vma) -1) + { + ieee_error (info, start, _("bad C++ field bit pos or size")); + return FALSE; + } + field = debug_make_field (dhandle, fieldcopy, ftype, bitpos, + bitsize, visibility); + } + + if (field == DEBUG_FIELD_NULL) + return FALSE; + + if (field_count + 1 >= field_alloc) + { + field_alloc += 10; + fields = ((debug_field *) + xrealloc (fields, field_alloc * sizeof *fields)); + } + + fields[field_count] = field; + ++field_count; + fields[field_count] = DEBUG_FIELD_NULL; + } + break; + + case 'm': + case 'v': + { + bfd_vma flags, voffset, control; + const char *name, *mangled; + unsigned long namlen, mangledlen; + struct ieee_var *pv, *pvend; + debug_type type; + enum debug_visibility visibility; + bfd_boolean constp, volatilep; + char *mangledcopy; + debug_method_variant mv; + struct ieee_method *meth; + unsigned int im; + + if (! ieee_require_asn (info, pp, &flags) + || ! ieee_require_atn65 (info, pp, &name, &namlen) + || ! ieee_require_atn65 (info, pp, &mangled, &mangledlen)) + return FALSE; + count -= 3; + if (id != 'v') + voffset = 0; + else + { + if (! ieee_require_asn (info, pp, &voffset)) + return FALSE; + --count; + } + if (! ieee_require_asn (info, pp, &control)) + return FALSE; + --count; + + /* We just ignore the control information. */ + + /* We have no way to represent friend information, so we + just ignore it. */ + if ((flags & CXXFLAGS_FRIEND) != 0) + break; + + /* We should already have seen a type for the function. */ + pv = info->vars.vars; + pvend = pv + info->vars.alloc; + for (; pv < pvend; pv++) + if (pv->namlen == mangledlen + && strncmp (pv->name, mangled, mangledlen) == 0) + break; + + if (pv >= pvend) + { + /* We won't have type information for this function if + it is not included in this file. We don't try to + handle this case. FIXME. */ + type = (debug_make_function_type + (dhandle, + ieee_builtin_type (info, start, + (unsigned int) builtin_void), + (debug_type *) NULL, + FALSE)); + } + else + { + debug_type return_type; + const debug_type *arg_types; + bfd_boolean varargs; + + if (debug_get_type_kind (dhandle, pv->type) + != DEBUG_KIND_FUNCTION) + { + ieee_error (info, start, + _("bad type for C++ method function")); + return FALSE; + } + + return_type = debug_get_return_type (dhandle, pv->type); + arg_types = debug_get_parameter_types (dhandle, pv->type, + &varargs); + if (return_type == DEBUG_TYPE_NULL || arg_types == NULL) + { + ieee_error (info, start, + _("no type information for C++ method function")); + return FALSE; + } + + type = debug_make_method_type (dhandle, return_type, it->type, + (debug_type *) arg_types, + varargs); + } + if (type == DEBUG_TYPE_NULL) + return FALSE; + + switch (flags & CXXFLAGS_VISIBILITY) + { + default: + ieee_error (info, start, _("unknown C++ visibility")); + return FALSE; + + case CXXFLAGS_VISIBILITY_PUBLIC: + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + + case CXXFLAGS_VISIBILITY_PRIVATE: + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + + case CXXFLAGS_VISIBILITY_PROTECTED: + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + } + + constp = (flags & CXXFLAGS_CONST) != 0 ? TRUE : FALSE; + volatilep = (flags & CXXFLAGS_VOLATILE) != 0 ? TRUE : FALSE; + + mangledcopy = savestring (mangled, mangledlen); + + if ((flags & CXXFLAGS_STATIC) != 0) + { + if (id == 'v') + { + ieee_error (info, start, _("C++ static virtual method")); + return FALSE; + } + mv = debug_make_static_method_variant (dhandle, mangledcopy, + type, visibility, + constp, volatilep); + } + else + { + debug_type vcontext; + + if (id != 'v') + vcontext = DEBUG_TYPE_NULL; + else + { + /* FIXME: How can we calculate this correctly? */ + vcontext = it->type; + } + mv = debug_make_method_variant (dhandle, mangledcopy, type, + visibility, constp, + volatilep, voffset, + vcontext); + } + if (mv == DEBUG_METHOD_VARIANT_NULL) + return FALSE; + + for (meth = methods, im = 0; im < methods_count; meth++, im++) + if (meth->namlen == namlen + && strncmp (meth->name, name, namlen) == 0) + break; + if (im >= methods_count) + { + if (methods_count >= methods_alloc) + { + methods_alloc += 10; + methods = ((struct ieee_method *) + xrealloc (methods, + methods_alloc * sizeof *methods)); + } + methods[methods_count].name = name; + methods[methods_count].namlen = namlen; + methods[methods_count].variants = NULL; + methods[methods_count].count = 0; + methods[methods_count].alloc = 0; + meth = methods + methods_count; + ++methods_count; + } + + if (meth->count + 1 >= meth->alloc) + { + meth->alloc += 10; + meth->variants = ((debug_method_variant *) + xrealloc (meth->variants, + (meth->alloc + * sizeof *meth->variants))); + } + + meth->variants[meth->count] = mv; + ++meth->count; + meth->variants[meth->count] = DEBUG_METHOD_VARIANT_NULL; + } + break; + + case 'o': + { + bfd_vma spec; + + /* We have no way to store this information, so we just + ignore it. */ + if (! ieee_require_asn (info, pp, &spec)) + return FALSE; + --count; + if ((spec & 4) != 0) + { + const char *filename; + unsigned long filenamlen; + bfd_vma lineno; + + if (! ieee_require_atn65 (info, pp, &filename, &filenamlen) + || ! ieee_require_asn (info, pp, &lineno)) + return FALSE; + count -= 2; + } + else if ((spec & 8) != 0) + { + const char *mangled; + unsigned long mangledlen; + + if (! ieee_require_atn65 (info, pp, &mangled, &mangledlen)) + return FALSE; + --count; + } + else + { + ieee_error (info, start, + _("unrecognized C++ object overhead spec")); + return FALSE; + } + } + break; + + case 'z': + { + const char *vname, *basename; + unsigned long vnamelen, baselen; + bfd_vma vsize, control; + + /* A virtual table pointer. */ + + if (! ieee_require_atn65 (info, pp, &vname, &vnamelen) + || ! ieee_require_asn (info, pp, &vsize) + || ! ieee_require_atn65 (info, pp, &basename, &baselen) + || ! ieee_require_asn (info, pp, &control)) + return FALSE; + count -= 4; + + /* We just ignore the control number. We don't care what + the virtual table name is. We have no way to store the + virtual table size, and I don't think we care anyhow. */ + + /* FIXME: We can't handle multiple virtual table pointers. */ + + if (baselen == 0) + ownvptr = TRUE; + else + { + char *basecopy; + + basecopy = savestring (basename, baselen); + vptrbase = debug_find_tagged_type (dhandle, basecopy, + DEBUG_KIND_ILLEGAL); + free (basecopy); + if (vptrbase == DEBUG_TYPE_NULL) + { + ieee_error (info, start, _("undefined C++ vtable")); + return FALSE; + } + } + } + break; + } + } + + /* Now that we have seen all the method variants, we can call + debug_make_method for each one. */ + + if (methods_count == 0) + dmethods = NULL; + else + { + unsigned int i; + + dmethods = ((debug_method *) + xmalloc ((methods_count + 1) * sizeof *dmethods)); + for (i = 0; i < methods_count; i++) + { + char *namcopy; + + namcopy = savestring (methods[i].name, methods[i].namlen); + dmethods[i] = debug_make_method (dhandle, namcopy, + methods[i].variants); + if (dmethods[i] == DEBUG_METHOD_NULL) + return FALSE; + } + dmethods[i] = DEBUG_METHOD_NULL; + free (methods); + } + + /* The struct type was created as an indirect type pointing at + it->slot. We update it->slot to automatically update all + references to this struct. */ + it->slot = debug_make_object_type (dhandle, + class != 'u', + debug_get_type_size (dhandle, + it->slot), + fields, baseclasses, dmethods, + vptrbase, ownvptr); + if (it->slot == DEBUG_TYPE_NULL) + return FALSE; + + return TRUE; +} + +/* Read C++ default argument value and reference type information. */ + +static bfd_boolean +ieee_read_cxx_defaults (info, pp, count) + struct ieee_info *info; + const bfd_byte **pp; + unsigned long count; +{ + const bfd_byte *start; + const char *fnname; + unsigned long fnlen; + bfd_vma defcount; + + start = *pp; + + /* Giving the function name before the argument count is an addendum + to the spec. The function name is demangled, though, so this + record must always refer to the current function. */ + + if (info->blockstack.bsp <= info->blockstack.stack + || info->blockstack.bsp[-1].fnindx == (unsigned int) -1) + { + ieee_error (info, start, _("C++ default values not in a function")); + return FALSE; + } + + if (! ieee_require_atn65 (info, pp, &fnname, &fnlen) + || ! ieee_require_asn (info, pp, &defcount)) + return FALSE; + count -= 2; + + while (defcount-- > 0) + { + bfd_vma type, val; + const char *strval; + unsigned long strvallen; + + if (! ieee_require_asn (info, pp, &type)) + return FALSE; + --count; + + switch (type) + { + case 0: + case 4: + break; + + case 1: + case 2: + if (! ieee_require_asn (info, pp, &val)) + return FALSE; + --count; + break; + + case 3: + case 7: + if (! ieee_require_atn65 (info, pp, &strval, &strvallen)) + return FALSE; + --count; + break; + + default: + ieee_error (info, start, _("unrecognized C++ default type")); + return FALSE; + } + + /* We have no way to record the default argument values, so we + just ignore them. FIXME. */ + } + + /* Any remaining arguments are indices of parameters that are really + reference type. */ + if (count > 0) + { + PTR dhandle; + debug_type *arg_slots; + + dhandle = info->dhandle; + arg_slots = info->types.types[info->blockstack.bsp[-1].fnindx].arg_slots; + while (count-- > 0) + { + bfd_vma indx; + debug_type target; + + if (! ieee_require_asn (info, pp, &indx)) + return FALSE; + /* The index is 1 based. */ + --indx; + if (arg_slots == NULL + || arg_slots[indx] == DEBUG_TYPE_NULL + || (debug_get_type_kind (dhandle, arg_slots[indx]) + != DEBUG_KIND_POINTER)) + { + ieee_error (info, start, _("reference parameter is not a pointer")); + return FALSE; + } + + target = debug_get_target_type (dhandle, arg_slots[indx]); + arg_slots[indx] = debug_make_reference_type (dhandle, target); + if (arg_slots[indx] == DEBUG_TYPE_NULL) + return FALSE; + } + } + + return TRUE; +} + +/* Read a C++ reference definition. */ + +static bfd_boolean +ieee_read_reference (info, pp) + struct ieee_info *info; + const bfd_byte **pp; +{ + const bfd_byte *start; + bfd_vma flags; + const char *class, *name; + unsigned long classlen, namlen; + debug_type *pslot; + debug_type target; + + start = *pp; + + if (! ieee_require_asn (info, pp, &flags)) + return FALSE; + + /* Giving the class name before the member name is in an addendum to + the spec. */ + if (flags == 3) + { + if (! ieee_require_atn65 (info, pp, &class, &classlen)) + return FALSE; + } + + if (! ieee_require_atn65 (info, pp, &name, &namlen)) + return FALSE; + + pslot = NULL; + if (flags != 3) + { + int pass; + + /* We search from the last variable indices to the first in + hopes of finding local variables correctly. We search the + local variables on the first pass, and the global variables + on the second. FIXME: This probably won't work in all cases. + On the other hand, I don't know what will. */ + for (pass = 0; pass < 2; pass++) + { + struct ieee_vars *vars; + int i; + struct ieee_var *pv = NULL; + + if (pass == 0) + vars = &info->vars; + else + { + vars = info->global_vars; + if (vars == NULL) + break; + } + + for (i = (int) vars->alloc - 1; i >= 0; i--) + { + bfd_boolean found; + + pv = vars->vars + i; + + if (pv->pslot == NULL + || pv->namlen != namlen + || strncmp (pv->name, name, namlen) != 0) + continue; + + found = FALSE; + switch (flags) + { + default: + ieee_error (info, start, + _("unrecognized C++ reference type")); + return FALSE; + + case 0: + /* Global variable or function. */ + if (pv->kind == IEEE_GLOBAL + || pv->kind == IEEE_EXTERNAL + || pv->kind == IEEE_FUNCTION) + found = TRUE; + break; + + case 1: + /* Global static variable or function. */ + if (pv->kind == IEEE_STATIC + || pv->kind == IEEE_FUNCTION) + found = TRUE; + break; + + case 2: + /* Local variable. */ + if (pv->kind == IEEE_LOCAL) + found = TRUE; + break; + } + + if (found) + break; + } + + if (i >= 0) + { + pslot = pv->pslot; + break; + } + } + } + else + { + struct ieee_tag *it; + + for (it = info->tags; it != NULL; it = it->next) + { + if (it->name[0] == class[0] + && strncmp (it->name, class, classlen) == 0 + && strlen (it->name) == classlen) + { + if (it->fslots != NULL) + { + const debug_field *pf; + unsigned int findx; + + pf = debug_get_fields (info->dhandle, it->type); + if (pf == NULL) + { + ieee_error (info, start, + "C++ reference in class with no fields"); + return FALSE; + } + + for (findx = 0; *pf != DEBUG_FIELD_NULL; pf++, findx++) + { + const char *fname; + + fname = debug_get_field_name (info->dhandle, *pf); + if (fname == NULL) + return FALSE; + if (strncmp (fname, name, namlen) == 0 + && strlen (fname) == namlen) + { + pslot = it->fslots + findx; + break; + } + } + } + + break; + } + } + } + + if (pslot == NULL) + { + ieee_error (info, start, _("C++ reference not found")); + return FALSE; + } + + /* We allocated the type of the object as an indirect type pointing + to *pslot, which we can now update to be a reference type. */ + if (debug_get_type_kind (info->dhandle, *pslot) != DEBUG_KIND_POINTER) + { + ieee_error (info, start, _("C++ reference is not pointer")); + return FALSE; + } + + target = debug_get_target_type (info->dhandle, *pslot); + *pslot = debug_make_reference_type (info->dhandle, target); + if (*pslot == DEBUG_TYPE_NULL) + return FALSE; + + return TRUE; +} + +/* Require an ASN record. */ + +static bfd_boolean +ieee_require_asn (info, pp, pv) + struct ieee_info *info; + const bfd_byte **pp; + bfd_vma *pv; +{ + const bfd_byte *start; + ieee_record_enum_type c; + bfd_vma varindx; + + start = *pp; + + c = (ieee_record_enum_type) **pp; + if (c != ieee_e2_first_byte_enum) + { + ieee_error (info, start, _("missing required ASN")); + return FALSE; + } + ++*pp; + + c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp); + if (c != ieee_asn_record_enum) + { + ieee_error (info, start, _("missing required ASN")); + return FALSE; + } + ++*pp; + + /* Just ignore the variable index. */ + if (! ieee_read_number (info, pp, &varindx)) + return FALSE; + + return ieee_read_expression (info, pp, pv); +} + +/* Require an ATN65 record. */ + +static bfd_boolean +ieee_require_atn65 (info, pp, pname, pnamlen) + struct ieee_info *info; + const bfd_byte **pp; + const char **pname; + unsigned long *pnamlen; +{ + const bfd_byte *start; + ieee_record_enum_type c; + bfd_vma name_indx, type_indx, atn_code; + + start = *pp; + + c = (ieee_record_enum_type) **pp; + if (c != ieee_at_record_enum) + { + ieee_error (info, start, _("missing required ATN65")); + return FALSE; + } + ++*pp; + + c = (ieee_record_enum_type) (((unsigned int) c << 8) | **pp); + if (c != ieee_atn_record_enum) + { + ieee_error (info, start, _("missing required ATN65")); + return FALSE; + } + ++*pp; + + if (! ieee_read_number (info, pp, &name_indx) + || ! ieee_read_number (info, pp, &type_indx) + || ! ieee_read_number (info, pp, &atn_code)) + return FALSE; + + /* Just ignore name_indx. */ + + if (type_indx != 0 || atn_code != 65) + { + ieee_error (info, start, _("bad ATN65 record")); + return FALSE; + } + + return ieee_read_id (info, pp, pname, pnamlen); +} + +/* Convert a register number in IEEE debugging information into a + generic register number. */ + +static int +ieee_regno_to_genreg (abfd, r) + bfd *abfd; + int r; +{ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_m68k: + /* For some reasons stabs adds 2 to the floating point register + numbers. */ + if (r >= 16) + r += 2; + break; + + case bfd_arch_i960: + /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and + 32 to 35 for fp0 to fp3. */ + --r; + break; + + default: + break; + } + + return r; +} + +/* Convert a generic register number to an IEEE specific one. */ + +static int +ieee_genreg_to_regno (abfd, r) + bfd *abfd; + int r; +{ + switch (bfd_get_arch (abfd)) + { + case bfd_arch_m68k: + /* For some reason stabs add 2 to the floating point register + numbers. */ + if (r >= 18) + r -= 2; + break; + + case bfd_arch_i960: + /* Stabs uses 0 to 15 for r0 to r15, 16 to 31 for g0 to g15, and + 32 to 35 for fp0 to fp3. */ + ++r; + break; + + default: + break; + } + + return r; +} + +/* These routines build IEEE debugging information out of the generic + debugging information. */ + +/* We build the IEEE debugging information byte by byte. Rather than + waste time copying data around, we use a linked list of buffers to + hold the data. */ + +#define IEEE_BUFSIZE (490) + +struct ieee_buf +{ + /* Next buffer. */ + struct ieee_buf *next; + /* Number of data bytes in this buffer. */ + unsigned int c; + /* Bytes. */ + bfd_byte buf[IEEE_BUFSIZE]; +}; + +/* A list of buffers. */ + +struct ieee_buflist +{ + /* Head of list. */ + struct ieee_buf *head; + /* Tail--last buffer on list. */ + struct ieee_buf *tail; +}; + +/* In order to generate the BB11 blocks required by the HP emulator, + we keep track of ranges of addresses which correspond to a given + compilation unit. */ + +struct ieee_range +{ + /* Next range. */ + struct ieee_range *next; + /* Low address. */ + bfd_vma low; + /* High address. */ + bfd_vma high; +}; + +/* This structure holds information for a class on the type stack. */ + +struct ieee_type_class +{ + /* The name index in the debugging information. */ + unsigned int indx; + /* The pmisc records for the class. */ + struct ieee_buflist pmiscbuf; + /* The number of pmisc records. */ + unsigned int pmisccount; + /* The name of the class holding the virtual table, if not this + class. */ + const char *vclass; + /* Whether this class holds its own virtual table. */ + bfd_boolean ownvptr; + /* The largest virtual table offset seen so far. */ + bfd_vma voffset; + /* The current method. */ + const char *method; + /* Additional pmisc records used to record fields of reference type. */ + struct ieee_buflist refs; +}; + +/* This is how we store types for the writing routines. Most types + are simply represented by a type index. */ + +struct ieee_write_type +{ + /* Type index. */ + unsigned int indx; + /* The size of the type, if known. */ + unsigned int size; + /* The name of the type, if any. */ + const char *name; + /* If this is a function or method type, we build the type here, and + only add it to the output buffers if we need it. */ + struct ieee_buflist fndef; + /* If this is a struct, this is where the struct definition is + built. */ + struct ieee_buflist strdef; + /* If this is a class, this is where the class information is built. */ + struct ieee_type_class *classdef; + /* Whether the type is unsigned. */ + unsigned int unsignedp : 1; + /* Whether this is a reference type. */ + unsigned int referencep : 1; + /* Whether this is in the local type block. */ + unsigned int localp : 1; + /* Whether this is a duplicate struct definition which we are + ignoring. */ + unsigned int ignorep : 1; +}; + +/* This is the type stack used by the debug writing routines. FIXME: + We could generate more efficient output if we remembered when we + have output a particular type before. */ + +struct ieee_type_stack +{ + /* Next entry on stack. */ + struct ieee_type_stack *next; + /* Type information. */ + struct ieee_write_type type; +}; + +/* This is a list of associations between a name and some types. + These are used for typedefs and tags. */ + +struct ieee_name_type +{ + /* Next type for this name. */ + struct ieee_name_type *next; + /* ID number. For a typedef, this is the index of the type to which + this name is typedefed. */ + unsigned int id; + /* Type. */ + struct ieee_write_type type; + /* If this is a tag which has not yet been defined, this is the + kind. If the tag has been defined, this is DEBUG_KIND_ILLEGAL. */ + enum debug_type_kind kind; +}; + +/* We use a hash table to associate names and types. */ + +struct ieee_name_type_hash_table +{ + struct bfd_hash_table root; +}; + +struct ieee_name_type_hash_entry +{ + struct bfd_hash_entry root; + /* Information for this name. */ + struct ieee_name_type *types; +}; + +/* This is a list of enums. */ + +struct ieee_defined_enum +{ + /* Next enum. */ + struct ieee_defined_enum *next; + /* Type index. */ + unsigned int indx; + /* Whether this enum has been defined. */ + bfd_boolean defined; + /* Tag. */ + const char *tag; + /* Names. */ + const char **names; + /* Values. */ + bfd_signed_vma *vals; +}; + +/* We keep a list of modified versions of types, so that we don't + output them more than once. */ + +struct ieee_modified_type +{ + /* Pointer to this type. */ + unsigned int pointer; + /* Function with unknown arguments returning this type. */ + unsigned int function; + /* Const version of this type. */ + unsigned int const_qualified; + /* Volatile version of this type. */ + unsigned int volatile_qualified; + /* List of arrays of this type of various bounds. */ + struct ieee_modified_array_type *arrays; +}; + +/* A list of arrays bounds. */ + +struct ieee_modified_array_type +{ + /* Next array bounds. */ + struct ieee_modified_array_type *next; + /* Type index with these bounds. */ + unsigned int indx; + /* Low bound. */ + bfd_signed_vma low; + /* High bound. */ + bfd_signed_vma high; +}; + +/* This is a list of pending function parameter information. We don't + output them until we see the first block. */ + +struct ieee_pending_parm +{ + /* Next pending parameter. */ + struct ieee_pending_parm *next; + /* Name. */ + const char *name; + /* Type index. */ + unsigned int type; + /* Whether the type is a reference. */ + bfd_boolean referencep; + /* Kind. */ + enum debug_parm_kind kind; + /* Value. */ + bfd_vma val; +}; + +/* This is the handle passed down by debug_write. */ + +struct ieee_handle +{ + /* BFD we are writing to. */ + bfd *abfd; + /* Whether we got an error in a subroutine called via traverse or + map_over_sections. */ + bfd_boolean error; + /* Current data buffer list. */ + struct ieee_buflist *current; + /* Current data buffer. */ + struct ieee_buf *curbuf; + /* Filename of current compilation unit. */ + const char *filename; + /* Module name of current compilation unit. */ + const char *modname; + /* List of buffer for global types. */ + struct ieee_buflist global_types; + /* List of finished data buffers. */ + struct ieee_buflist data; + /* List of buffers for typedefs in the current compilation unit. */ + struct ieee_buflist types; + /* List of buffers for variables and functions in the current + compilation unit. */ + struct ieee_buflist vars; + /* List of buffers for C++ class definitions in the current + compilation unit. */ + struct ieee_buflist cxx; + /* List of buffers for line numbers in the current compilation unit. */ + struct ieee_buflist linenos; + /* Ranges for the current compilation unit. */ + struct ieee_range *ranges; + /* Ranges for all debugging information. */ + struct ieee_range *global_ranges; + /* Nested pending ranges. */ + struct ieee_range *pending_ranges; + /* Type stack. */ + struct ieee_type_stack *type_stack; + /* Next unallocated type index. */ + unsigned int type_indx; + /* Next unallocated name index. */ + unsigned int name_indx; + /* Typedefs. */ + struct ieee_name_type_hash_table typedefs; + /* Tags. */ + struct ieee_name_type_hash_table tags; + /* Enums. */ + struct ieee_defined_enum *enums; + /* Modified versions of types. */ + struct ieee_modified_type *modified; + /* Number of entries allocated in modified. */ + unsigned int modified_alloc; + /* 4 byte complex type. */ + unsigned int complex_float_index; + /* 8 byte complex type. */ + unsigned int complex_double_index; + /* The depth of block nesting. This is 0 outside a function, and 1 + just after start_function is called. */ + unsigned int block_depth; + /* The name of the current function. */ + const char *fnname; + /* List of buffers for the type of the function we are currently + writing out. */ + struct ieee_buflist fntype; + /* List of buffers for the parameters of the function we are + currently writing out. */ + struct ieee_buflist fnargs; + /* Number of arguments written to fnargs. */ + unsigned int fnargcount; + /* Pending function parameters. */ + struct ieee_pending_parm *pending_parms; + /* Current line number filename. */ + const char *lineno_filename; + /* Line number name index. */ + unsigned int lineno_name_indx; + /* Filename of pending line number. */ + const char *pending_lineno_filename; + /* Pending line number. */ + unsigned long pending_lineno; + /* Address of pending line number. */ + bfd_vma pending_lineno_addr; + /* Highest address seen at end of procedure. */ + bfd_vma highaddr; +}; + +static bfd_boolean ieee_init_buffer + PARAMS ((struct ieee_handle *, struct ieee_buflist *)); +static bfd_boolean ieee_change_buffer + PARAMS ((struct ieee_handle *, struct ieee_buflist *)); +static bfd_boolean ieee_append_buffer + PARAMS ((struct ieee_handle *, struct ieee_buflist *, + struct ieee_buflist *)); +static bfd_boolean ieee_real_write_byte + PARAMS ((struct ieee_handle *, int)); +static bfd_boolean ieee_write_2bytes + PARAMS ((struct ieee_handle *, int)); +static bfd_boolean ieee_write_number + PARAMS ((struct ieee_handle *, bfd_vma)); +static bfd_boolean ieee_write_id + PARAMS ((struct ieee_handle *, const char *)); +static bfd_boolean ieee_write_asn + PARAMS ((struct ieee_handle *, unsigned int, bfd_vma)); +static bfd_boolean ieee_write_atn65 + PARAMS ((struct ieee_handle *, unsigned int, const char *)); +static bfd_boolean ieee_push_type + PARAMS ((struct ieee_handle *, unsigned int, unsigned int, bfd_boolean, + bfd_boolean)); +static unsigned int ieee_pop_type + PARAMS ((struct ieee_handle *)); +static void ieee_pop_unused_type + PARAMS ((struct ieee_handle *)); +static unsigned int ieee_pop_type_used + PARAMS ((struct ieee_handle *, bfd_boolean)); +static bfd_boolean ieee_add_range + PARAMS ((struct ieee_handle *, bfd_boolean, bfd_vma, bfd_vma)); +static bfd_boolean ieee_start_range + PARAMS ((struct ieee_handle *, bfd_vma)); +static bfd_boolean ieee_end_range + PARAMS ((struct ieee_handle *, bfd_vma)); +static bfd_boolean ieee_define_type + PARAMS ((struct ieee_handle *, unsigned int, bfd_boolean, bfd_boolean)); +static bfd_boolean ieee_define_named_type + PARAMS ((struct ieee_handle *, const char *, unsigned int, unsigned int, + bfd_boolean, bfd_boolean, struct ieee_buflist *)); +static struct ieee_modified_type *ieee_get_modified_info + PARAMS ((struct ieee_handle *, unsigned int)); +static struct bfd_hash_entry *ieee_name_type_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static bfd_boolean ieee_write_undefined_tag + PARAMS ((struct ieee_name_type_hash_entry *, PTR)); +static bfd_boolean ieee_finish_compilation_unit + PARAMS ((struct ieee_handle *)); +static void ieee_add_bb11_blocks + PARAMS ((bfd *, asection *, PTR)); +static bfd_boolean ieee_add_bb11 + PARAMS ((struct ieee_handle *, asection *, bfd_vma, bfd_vma)); +static bfd_boolean ieee_output_pending_parms + PARAMS ((struct ieee_handle *)); +static unsigned int ieee_vis_to_flags + PARAMS ((enum debug_visibility)); +static bfd_boolean ieee_class_method_var + PARAMS ((struct ieee_handle *, const char *, enum debug_visibility, bfd_boolean, + bfd_boolean, bfd_boolean, bfd_vma, bfd_boolean)); + +static bfd_boolean ieee_start_compilation_unit + PARAMS ((PTR, const char *)); +static bfd_boolean ieee_start_source + PARAMS ((PTR, const char *)); +static bfd_boolean ieee_empty_type + PARAMS ((PTR)); +static bfd_boolean ieee_void_type + PARAMS ((PTR)); +static bfd_boolean ieee_int_type + PARAMS ((PTR, unsigned int, bfd_boolean)); +static bfd_boolean ieee_float_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean ieee_complex_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean ieee_bool_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean ieee_enum_type + PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); +static bfd_boolean ieee_pointer_type + PARAMS ((PTR)); +static bfd_boolean ieee_function_type + PARAMS ((PTR, int, bfd_boolean)); +static bfd_boolean ieee_reference_type + PARAMS ((PTR)); +static bfd_boolean ieee_range_type + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); +static bfd_boolean ieee_array_type + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, bfd_boolean)); +static bfd_boolean ieee_set_type + PARAMS ((PTR, bfd_boolean)); +static bfd_boolean ieee_offset_type + PARAMS ((PTR)); +static bfd_boolean ieee_method_type + PARAMS ((PTR, bfd_boolean, int, bfd_boolean)); +static bfd_boolean ieee_const_type + PARAMS ((PTR)); +static bfd_boolean ieee_volatile_type + PARAMS ((PTR)); +static bfd_boolean ieee_start_struct_type + PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int)); +static bfd_boolean ieee_struct_field + PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); +static bfd_boolean ieee_end_struct_type + PARAMS ((PTR)); +static bfd_boolean ieee_start_class_type + PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int, bfd_boolean, + bfd_boolean)); +static bfd_boolean ieee_class_static_member + PARAMS ((PTR, const char *, const char *, enum debug_visibility)); +static bfd_boolean ieee_class_baseclass + PARAMS ((PTR, bfd_vma, bfd_boolean, enum debug_visibility)); +static bfd_boolean ieee_class_start_method + PARAMS ((PTR, const char *)); +static bfd_boolean ieee_class_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean, + bfd_vma, bfd_boolean)); +static bfd_boolean ieee_class_static_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean)); +static bfd_boolean ieee_class_end_method + PARAMS ((PTR)); +static bfd_boolean ieee_end_class_type + PARAMS ((PTR)); +static bfd_boolean ieee_typedef_type + PARAMS ((PTR, const char *)); +static bfd_boolean ieee_tag_type + PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); +static bfd_boolean ieee_typdef + PARAMS ((PTR, const char *)); +static bfd_boolean ieee_tag + PARAMS ((PTR, const char *)); +static bfd_boolean ieee_int_constant + PARAMS ((PTR, const char *, bfd_vma)); +static bfd_boolean ieee_float_constant + PARAMS ((PTR, const char *, double)); +static bfd_boolean ieee_typed_constant + PARAMS ((PTR, const char *, bfd_vma)); +static bfd_boolean ieee_variable + PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); +static bfd_boolean ieee_start_function + PARAMS ((PTR, const char *, bfd_boolean)); +static bfd_boolean ieee_function_parameter + PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); +static bfd_boolean ieee_start_block + PARAMS ((PTR, bfd_vma)); +static bfd_boolean ieee_end_block + PARAMS ((PTR, bfd_vma)); +static bfd_boolean ieee_end_function + PARAMS ((PTR)); +static bfd_boolean ieee_lineno + PARAMS ((PTR, const char *, unsigned long, bfd_vma)); + +static const struct debug_write_fns ieee_fns = +{ + ieee_start_compilation_unit, + ieee_start_source, + ieee_empty_type, + ieee_void_type, + ieee_int_type, + ieee_float_type, + ieee_complex_type, + ieee_bool_type, + ieee_enum_type, + ieee_pointer_type, + ieee_function_type, + ieee_reference_type, + ieee_range_type, + ieee_array_type, + ieee_set_type, + ieee_offset_type, + ieee_method_type, + ieee_const_type, + ieee_volatile_type, + ieee_start_struct_type, + ieee_struct_field, + ieee_end_struct_type, + ieee_start_class_type, + ieee_class_static_member, + ieee_class_baseclass, + ieee_class_start_method, + ieee_class_method_variant, + ieee_class_static_method_variant, + ieee_class_end_method, + ieee_end_class_type, + ieee_typedef_type, + ieee_tag_type, + ieee_typdef, + ieee_tag, + ieee_int_constant, + ieee_float_constant, + ieee_typed_constant, + ieee_variable, + ieee_start_function, + ieee_function_parameter, + ieee_start_block, + ieee_end_block, + ieee_end_function, + ieee_lineno +}; + +/* Initialize a buffer to be empty. */ + +static bfd_boolean +ieee_init_buffer (info, buflist) + struct ieee_handle *info ATTRIBUTE_UNUSED; + struct ieee_buflist *buflist; +{ + buflist->head = NULL; + buflist->tail = NULL; + return TRUE; +} + +/* See whether a buffer list has any data. */ + +#define ieee_buffer_emptyp(buflist) ((buflist)->head == NULL) + +/* Change the current buffer to a specified buffer chain. */ + +static bfd_boolean +ieee_change_buffer (info, buflist) + struct ieee_handle *info; + struct ieee_buflist *buflist; +{ + if (buflist->head == NULL) + { + struct ieee_buf *buf; + + buf = (struct ieee_buf *) xmalloc (sizeof *buf); + buf->next = NULL; + buf->c = 0; + buflist->head = buf; + buflist->tail = buf; + } + + info->current = buflist; + info->curbuf = buflist->tail; + + return TRUE; +} + +/* Append a buffer chain. */ + +static bfd_boolean +ieee_append_buffer (info, mainbuf, newbuf) + struct ieee_handle *info ATTRIBUTE_UNUSED; + struct ieee_buflist *mainbuf; + struct ieee_buflist *newbuf; +{ + if (newbuf->head != NULL) + { + if (mainbuf->head == NULL) + mainbuf->head = newbuf->head; + else + mainbuf->tail->next = newbuf->head; + mainbuf->tail = newbuf->tail; + } + return TRUE; +} + +/* Write a byte into the buffer. We use a macro for speed and a + function for the complex cases. */ + +#define ieee_write_byte(info, b) \ + ((info)->curbuf->c < IEEE_BUFSIZE \ + ? ((info)->curbuf->buf[(info)->curbuf->c++] = (b), TRUE) \ + : ieee_real_write_byte ((info), (b))) + +static bfd_boolean +ieee_real_write_byte (info, b) + struct ieee_handle *info; + int b; +{ + if (info->curbuf->c >= IEEE_BUFSIZE) + { + struct ieee_buf *n; + + n = (struct ieee_buf *) xmalloc (sizeof *n); + n->next = NULL; + n->c = 0; + if (info->current->head == NULL) + info->current->head = n; + else + info->current->tail->next = n; + info->current->tail = n; + info->curbuf = n; + } + + info->curbuf->buf[info->curbuf->c] = b; + ++info->curbuf->c; + + return TRUE; +} + +/* Write out two bytes. */ + +static bfd_boolean +ieee_write_2bytes (info, i) + struct ieee_handle *info; + int i; +{ + return (ieee_write_byte (info, i >> 8) + && ieee_write_byte (info, i & 0xff)); +} + +/* Write out an integer. */ + +static bfd_boolean +ieee_write_number (info, v) + struct ieee_handle *info; + bfd_vma v; +{ + bfd_vma t; + bfd_byte ab[20]; + bfd_byte *p; + unsigned int c; + + if (v <= (bfd_vma) ieee_number_end_enum) + return ieee_write_byte (info, (int) v); + + t = v; + p = ab + sizeof ab; + while (t != 0) + { + *--p = t & 0xff; + t >>= 8; + } + c = (ab + 20) - p; + + if (c > (unsigned int) (ieee_number_repeat_end_enum + - ieee_number_repeat_start_enum)) + { + fprintf (stderr, _("IEEE numeric overflow: 0x")); + fprintf_vma (stderr, v); + fprintf (stderr, "\n"); + return FALSE; + } + + if (! ieee_write_byte (info, (int) ieee_number_repeat_start_enum + c)) + return FALSE; + for (; c > 0; --c, ++p) + { + if (! ieee_write_byte (info, *p)) + return FALSE; + } + + return TRUE; +} + +/* Write out a string. */ + +static bfd_boolean +ieee_write_id (info, s) + struct ieee_handle *info; + const char *s; +{ + unsigned int len; + + len = strlen (s); + if (len <= 0x7f) + { + if (! ieee_write_byte (info, len)) + return FALSE; + } + else if (len <= 0xff) + { + if (! ieee_write_byte (info, (int) ieee_extension_length_1_enum) + || ! ieee_write_byte (info, len)) + return FALSE; + } + else if (len <= 0xffff) + { + if (! ieee_write_byte (info, (int) ieee_extension_length_2_enum) + || ! ieee_write_2bytes (info, len)) + return FALSE; + } + else + { + fprintf (stderr, _("IEEE string length overflow: %u\n"), len); + return FALSE; + } + + for (; *s != '\0'; s++) + if (! ieee_write_byte (info, *s)) + return FALSE; + + return TRUE; +} + +/* Write out an ASN record. */ + +static bfd_boolean +ieee_write_asn (info, indx, val) + struct ieee_handle *info; + unsigned int indx; + bfd_vma val; +{ + return (ieee_write_2bytes (info, (int) ieee_asn_record_enum) + && ieee_write_number (info, indx) + && ieee_write_number (info, val)); +} + +/* Write out an ATN65 record. */ + +static bfd_boolean +ieee_write_atn65 (info, indx, s) + struct ieee_handle *info; + unsigned int indx; + const char *s; +{ + return (ieee_write_2bytes (info, (int) ieee_atn_record_enum) + && ieee_write_number (info, indx) + && ieee_write_number (info, 0) + && ieee_write_number (info, 65) + && ieee_write_id (info, s)); +} + +/* Push a type index onto the type stack. */ + +static bfd_boolean +ieee_push_type (info, indx, size, unsignedp, localp) + struct ieee_handle *info; + unsigned int indx; + unsigned int size; + bfd_boolean unsignedp; + bfd_boolean localp; +{ + struct ieee_type_stack *ts; + + ts = (struct ieee_type_stack *) xmalloc (sizeof *ts); + memset (ts, 0, sizeof *ts); + + ts->type.indx = indx; + ts->type.size = size; + ts->type.unsignedp = unsignedp; + ts->type.localp = localp; + + ts->next = info->type_stack; + info->type_stack = ts; + + return TRUE; +} + +/* Pop a type index off the type stack. */ + +static unsigned int +ieee_pop_type (info) + struct ieee_handle *info; +{ + return ieee_pop_type_used (info, TRUE); +} + +/* Pop an unused type index off the type stack. */ + +static void +ieee_pop_unused_type (info) + struct ieee_handle *info; +{ + (void) ieee_pop_type_used (info, FALSE); +} + +/* Pop a used or unused type index off the type stack. */ + +static unsigned int +ieee_pop_type_used (info, used) + struct ieee_handle *info; + bfd_boolean used; +{ + struct ieee_type_stack *ts; + unsigned int ret; + + ts = info->type_stack; + assert (ts != NULL); + + /* If this is a function type, and we need it, we need to append the + actual definition to the typedef block now. */ + if (used && ! ieee_buffer_emptyp (&ts->type.fndef)) + { + struct ieee_buflist *buflist; + + if (ts->type.localp) + { + /* Make sure we have started the types block. */ + if (ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return FALSE; + } + buflist = &info->types; + } + else + { + /* Make sure we started the global type block. */ + if (ieee_buffer_emptyp (&info->global_types)) + { + if (! ieee_change_buffer (info, &info->global_types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 2) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "")) + return FALSE; + } + buflist = &info->global_types; + } + + if (! ieee_append_buffer (info, buflist, &ts->type.fndef)) + return FALSE; + } + + ret = ts->type.indx; + info->type_stack = ts->next; + free (ts); + return ret; +} + +/* Add a range of bytes included in the current compilation unit. */ + +static bfd_boolean +ieee_add_range (info, global, low, high) + struct ieee_handle *info; + bfd_boolean global; + bfd_vma low; + bfd_vma high; +{ + struct ieee_range **plist, *r, **pr; + + if (low == (bfd_vma) -1 || high == (bfd_vma) -1 || low == high) + return TRUE; + + if (global) + plist = &info->global_ranges; + else + plist = &info->ranges; + + for (r = *plist; r != NULL; r = r->next) + { + if (high >= r->low && low <= r->high) + { + /* The new range overlaps r. */ + if (low < r->low) + r->low = low; + if (high > r->high) + r->high = high; + pr = &r->next; + while (*pr != NULL && (*pr)->low <= r->high) + { + struct ieee_range *n; + + if ((*pr)->high > r->high) + r->high = (*pr)->high; + n = (*pr)->next; + free (*pr); + *pr = n; + } + return TRUE; + } + } + + r = (struct ieee_range *) xmalloc (sizeof *r); + memset (r, 0, sizeof *r); + + r->low = low; + r->high = high; + + /* Store the ranges sorted by address. */ + for (pr = plist; *pr != NULL; pr = &(*pr)->next) + if ((*pr)->low > high) + break; + r->next = *pr; + *pr = r; + + return TRUE; +} + +/* Start a new range for which we only have the low address. */ + +static bfd_boolean +ieee_start_range (info, low) + struct ieee_handle *info; + bfd_vma low; +{ + struct ieee_range *r; + + r = (struct ieee_range *) xmalloc (sizeof *r); + memset (r, 0, sizeof *r); + r->low = low; + r->next = info->pending_ranges; + info->pending_ranges = r; + return TRUE; +} + +/* Finish a range started by ieee_start_range. */ + +static bfd_boolean +ieee_end_range (info, high) + struct ieee_handle *info; + bfd_vma high; +{ + struct ieee_range *r; + bfd_vma low; + + assert (info->pending_ranges != NULL); + r = info->pending_ranges; + low = r->low; + info->pending_ranges = r->next; + free (r); + return ieee_add_range (info, FALSE, low, high); +} + +/* Start defining a type. */ + +static bfd_boolean +ieee_define_type (info, size, unsignedp, localp) + struct ieee_handle *info; + unsigned int size; + bfd_boolean unsignedp; + bfd_boolean localp; +{ + return ieee_define_named_type (info, (const char *) NULL, + (unsigned int) -1, size, unsignedp, + localp, (struct ieee_buflist *) NULL); +} + +/* Start defining a named type. */ + +static bfd_boolean +ieee_define_named_type (info, name, indx, size, unsignedp, localp, buflist) + struct ieee_handle *info; + const char *name; + unsigned int indx; + unsigned int size; + bfd_boolean unsignedp; + bfd_boolean localp; + struct ieee_buflist *buflist; +{ + unsigned int type_indx; + unsigned int name_indx; + + if (indx != (unsigned int) -1) + type_indx = indx; + else + { + type_indx = info->type_indx; + ++info->type_indx; + } + + name_indx = info->name_indx; + ++info->name_indx; + + if (name == NULL) + name = ""; + + /* If we were given a buffer, use it; otherwise, use either the + local or the global type information, and make sure that the type + block is started. */ + if (buflist != NULL) + { + if (! ieee_change_buffer (info, buflist)) + return FALSE; + } + else if (localp) + { + if (! ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types)) + return FALSE; + } + else + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return FALSE; + } + } + else + { + if (! ieee_buffer_emptyp (&info->global_types)) + { + if (! ieee_change_buffer (info, &info->global_types)) + return FALSE; + } + else + { + if (! ieee_change_buffer (info, &info->global_types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 2) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "")) + return FALSE; + } + } + + /* Push the new type on the type stack, write out an NN record, and + write out the start of a TY record. The caller will then finish + the TY record. */ + if (! ieee_push_type (info, type_indx, size, unsignedp, localp)) + return FALSE; + + return (ieee_write_byte (info, (int) ieee_nn_record) + && ieee_write_number (info, name_indx) + && ieee_write_id (info, name) + && ieee_write_byte (info, (int) ieee_ty_record_enum) + && ieee_write_number (info, type_indx) + && ieee_write_byte (info, 0xce) + && ieee_write_number (info, name_indx)); +} + +/* Get an entry to the list of modified versions of a type. */ + +static struct ieee_modified_type * +ieee_get_modified_info (info, indx) + struct ieee_handle *info; + unsigned int indx; +{ + if (indx >= info->modified_alloc) + { + unsigned int nalloc; + + nalloc = info->modified_alloc; + if (nalloc == 0) + nalloc = 16; + while (indx >= nalloc) + nalloc *= 2; + info->modified = ((struct ieee_modified_type *) + xrealloc (info->modified, + nalloc * sizeof *info->modified)); + memset (info->modified + info->modified_alloc, 0, + (nalloc - info->modified_alloc) * sizeof *info->modified); + info->modified_alloc = nalloc; + } + + return info->modified + indx; +} + +/* Routines for the hash table mapping names to types. */ + +/* Initialize an entry in the hash table. */ + +static struct bfd_hash_entry * +ieee_name_type_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct ieee_name_type_hash_entry *ret = + (struct ieee_name_type_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == NULL) + ret = ((struct ieee_name_type_hash_entry *) + bfd_hash_allocate (table, sizeof *ret)); + if (ret == NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct ieee_name_type_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + if (ret) + { + /* Set local fields. */ + ret->types = NULL; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in the hash table. */ + +#define ieee_name_type_hash_lookup(table, string, create, copy) \ + ((struct ieee_name_type_hash_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +/* Traverse the hash table. */ + +#define ieee_name_type_hash_traverse(table, func, info) \ + (bfd_hash_traverse \ + (&(table)->root, \ + (bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \ + (info))) + +/* The general routine to write out IEEE debugging information. */ + +bfd_boolean +write_ieee_debugging_info (abfd, dhandle) + bfd *abfd; + PTR dhandle; +{ + struct ieee_handle info; + asection *s; + const char *err; + struct ieee_buf *b; + + memset (&info, 0, sizeof info); + info.abfd = abfd; + info.type_indx = 256; + info.name_indx = 32; + + if (! bfd_hash_table_init (&info.typedefs.root, ieee_name_type_newfunc) + || ! bfd_hash_table_init (&info.tags.root, ieee_name_type_newfunc)) + return FALSE; + + if (! ieee_init_buffer (&info, &info.global_types) + || ! ieee_init_buffer (&info, &info.data) + || ! ieee_init_buffer (&info, &info.types) + || ! ieee_init_buffer (&info, &info.vars) + || ! ieee_init_buffer (&info, &info.cxx) + || ! ieee_init_buffer (&info, &info.linenos) + || ! ieee_init_buffer (&info, &info.fntype) + || ! ieee_init_buffer (&info, &info.fnargs)) + return FALSE; + + if (! debug_write (dhandle, &ieee_fns, (PTR) &info)) + return FALSE; + + if (info.filename != NULL) + { + if (! ieee_finish_compilation_unit (&info)) + return FALSE; + } + + /* Put any undefined tags in the global typedef information. */ + info.error = FALSE; + ieee_name_type_hash_traverse (&info.tags, + ieee_write_undefined_tag, + (PTR) &info); + if (info.error) + return FALSE; + + /* Prepend the global typedef information to the other data. */ + if (! ieee_buffer_emptyp (&info.global_types)) + { + /* The HP debugger seems to have a bug in which it ignores the + last entry in the global types, so we add a dummy entry. */ + if (! ieee_change_buffer (&info, &info.global_types) + || ! ieee_write_byte (&info, (int) ieee_nn_record) + || ! ieee_write_number (&info, info.name_indx) + || ! ieee_write_id (&info, "") + || ! ieee_write_byte (&info, (int) ieee_ty_record_enum) + || ! ieee_write_number (&info, info.type_indx) + || ! ieee_write_byte (&info, 0xce) + || ! ieee_write_number (&info, info.name_indx) + || ! ieee_write_number (&info, 'P') + || ! ieee_write_number (&info, (int) builtin_void + 32) + || ! ieee_write_byte (&info, (int) ieee_be_record_enum)) + return FALSE; + + if (! ieee_append_buffer (&info, &info.global_types, &info.data)) + return FALSE; + info.data = info.global_types; + } + + /* Make sure that we have declare BB11 blocks for each range in the + file. They are added to info->vars. */ + info.error = FALSE; + if (! ieee_init_buffer (&info, &info.vars)) + return FALSE; + bfd_map_over_sections (abfd, ieee_add_bb11_blocks, (PTR) &info); + if (info.error) + return FALSE; + if (! ieee_buffer_emptyp (&info.vars)) + { + if (! ieee_change_buffer (&info, &info.vars) + || ! ieee_write_byte (&info, (int) ieee_be_record_enum)) + return FALSE; + + if (! ieee_append_buffer (&info, &info.data, &info.vars)) + return FALSE; + } + + /* Now all the data is in info.data. Write it out to the BFD. We + normally would need to worry about whether all the other sections + are set up yet, but the IEEE backend will handle this particular + case correctly regardless. */ + if (ieee_buffer_emptyp (&info.data)) + { + /* There is no debugging information. */ + return TRUE; + } + err = NULL; + s = bfd_make_section (abfd, ".debug"); + if (s == NULL) + err = "bfd_make_section"; + if (err == NULL) + { + if (! bfd_set_section_flags (abfd, s, SEC_DEBUGGING | SEC_HAS_CONTENTS)) + err = "bfd_set_section_flags"; + } + if (err == NULL) + { + bfd_size_type size; + + size = 0; + for (b = info.data.head; b != NULL; b = b->next) + size += b->c; + if (! bfd_set_section_size (abfd, s, size)) + err = "bfd_set_section_size"; + } + if (err == NULL) + { + file_ptr offset; + + offset = 0; + for (b = info.data.head; b != NULL; b = b->next) + { + if (! bfd_set_section_contents (abfd, s, b->buf, offset, b->c)) + { + err = "bfd_set_section_contents"; + break; + } + offset += b->c; + } + } + + if (err != NULL) + { + fprintf (stderr, "%s: %s: %s\n", bfd_get_filename (abfd), err, + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + + bfd_hash_table_free (&info.typedefs.root); + bfd_hash_table_free (&info.tags.root); + + return TRUE; +} + +/* Write out information for an undefined tag. This is called via + ieee_name_type_hash_traverse. */ + +static bfd_boolean +ieee_write_undefined_tag (h, p) + struct ieee_name_type_hash_entry *h; + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_name_type *nt; + + for (nt = h->types; nt != NULL; nt = nt->next) + { + unsigned int name_indx; + char code; + + if (nt->kind == DEBUG_KIND_ILLEGAL) + continue; + + if (ieee_buffer_emptyp (&info->global_types)) + { + if (! ieee_change_buffer (info, &info->global_types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 2) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "")) + { + info->error = TRUE; + return FALSE; + } + } + else + { + if (! ieee_change_buffer (info, &info->global_types)) + { + info->error = TRUE; + return FALSE; + } + } + + name_indx = info->name_indx; + ++info->name_indx; + if (! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, name_indx) + || ! ieee_write_id (info, nt->type.name) + || ! ieee_write_byte (info, (int) ieee_ty_record_enum) + || ! ieee_write_number (info, nt->type.indx) + || ! ieee_write_byte (info, 0xce) + || ! ieee_write_number (info, name_indx)) + { + info->error = TRUE; + return FALSE; + } + + switch (nt->kind) + { + default: + abort (); + info->error = TRUE; + return FALSE; + case DEBUG_KIND_STRUCT: + case DEBUG_KIND_CLASS: + code = 'S'; + break; + case DEBUG_KIND_UNION: + case DEBUG_KIND_UNION_CLASS: + code = 'U'; + break; + case DEBUG_KIND_ENUM: + code = 'E'; + break; + } + if (! ieee_write_number (info, code) + || ! ieee_write_number (info, 0)) + { + info->error = TRUE; + return FALSE; + } + } + + return TRUE; +} + +/* Start writing out information for a compilation unit. */ + +static bfd_boolean +ieee_start_compilation_unit (p, filename) + PTR p; + const char *filename; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + const char *modname; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + const char *backslash; +#endif + char *c, *s; + unsigned int nindx; + + if (info->filename != NULL) + { + if (! ieee_finish_compilation_unit (info)) + return FALSE; + } + + info->filename = filename; + modname = strrchr (filename, '/'); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + /* We could have a mixed forward/back slash case. */ + backslash = strrchr (filename, '\\'); + if (modname == NULL || (backslash != NULL && backslash > modname)) + modname = backslash; +#endif + + if (modname != NULL) + ++modname; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + else if (filename[0] && filename[1] == ':') + modname = filename + 2; +#endif + else + modname = filename; + + c = xstrdup (modname); + s = strrchr (c, '.'); + if (s != NULL) + *s = '\0'; + info->modname = c; + + if (! ieee_init_buffer (info, &info->types) + || ! ieee_init_buffer (info, &info->vars) + || ! ieee_init_buffer (info, &info->cxx) + || ! ieee_init_buffer (info, &info->linenos)) + return FALSE; + info->ranges = NULL; + + /* Always include a BB1 and a BB3 block. That is what the output of + the MRI linker seems to look like. */ + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return FALSE; + + nindx = info->name_indx; + ++info->name_indx; + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 3) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return FALSE; + + return TRUE; +} + +/* Finish up a compilation unit. */ + +static bfd_boolean +ieee_finish_compilation_unit (info) + struct ieee_handle *info; +{ + struct ieee_range *r; + + if (! ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_be_record_enum)) + return FALSE; + } + + if (! ieee_buffer_emptyp (&info->cxx)) + { + /* Append any C++ information to the global function and + variable information. */ + assert (! ieee_buffer_emptyp (&info->vars)); + if (! ieee_change_buffer (info, &info->vars)) + return FALSE; + + /* We put the pmisc records in a dummy procedure, just as the + MRI compiler does. */ + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 6) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "__XRYCPP") + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, info->highaddr - 1) + || ! ieee_append_buffer (info, &info->vars, &info->cxx) + || ! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_be_record_enum) + || ! ieee_write_number (info, info->highaddr - 1)) + return FALSE; + } + + if (! ieee_buffer_emptyp (&info->vars)) + { + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_be_record_enum)) + return FALSE; + } + + if (info->pending_lineno_filename != NULL) + { + /* Force out the pending line number. */ + if (! ieee_lineno ((PTR) info, (const char *) NULL, 0, (bfd_vma) -1)) + return FALSE; + } + if (! ieee_buffer_emptyp (&info->linenos)) + { + if (! ieee_change_buffer (info, &info->linenos) + || ! ieee_write_byte (info, (int) ieee_be_record_enum)) + return FALSE; + if (strcmp (info->filename, info->lineno_filename) != 0) + { + /* We were not in the main file. We just closed the + included line number block, and now we must close the + main line number block. */ + if (! ieee_write_byte (info, (int) ieee_be_record_enum)) + return FALSE; + } + } + + if (! ieee_append_buffer (info, &info->data, &info->types) + || ! ieee_append_buffer (info, &info->data, &info->vars) + || ! ieee_append_buffer (info, &info->data, &info->linenos)) + return FALSE; + + /* Build BB10/BB11 blocks based on the ranges we recorded. */ + if (! ieee_change_buffer (info, &info->data)) + return FALSE; + + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 10) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "GNU objcopy")) + return FALSE; + + for (r = info->ranges; r != NULL; r = r->next) + { + bfd_vma low, high; + asection *s; + int kind; + + low = r->low; + high = r->high; + + /* Find the section corresponding to this range. */ + for (s = info->abfd->sections; s != NULL; s = s->next) + { + if (bfd_get_section_vma (info->abfd, s) <= low + && high <= (bfd_get_section_vma (info->abfd, s) + + bfd_section_size (info->abfd, s))) + break; + } + + if (s == NULL) + { + /* Just ignore this range. */ + continue; + } + + /* Coalesce ranges if it seems reasonable. */ + while (r->next != NULL + && high + 0x1000 >= r->next->low + && (r->next->high + <= (bfd_get_section_vma (info->abfd, s) + + bfd_section_size (info->abfd, s)))) + { + r = r->next; + high = r->high; + } + + if ((s->flags & SEC_CODE) != 0) + kind = 1; + else if ((s->flags & SEC_READONLY) != 0) + kind = 3; + else + kind = 2; + + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 11) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, kind) + || ! ieee_write_number (info, s->index + IEEE_SECTION_NUMBER_BASE) + || ! ieee_write_number (info, low) + || ! ieee_write_byte (info, (int) ieee_be_record_enum) + || ! ieee_write_number (info, high - low)) + return FALSE; + + /* Add this range to the list of global ranges. */ + if (! ieee_add_range (info, TRUE, low, high)) + return FALSE; + } + + if (! ieee_write_byte (info, (int) ieee_be_record_enum)) + return FALSE; + + return TRUE; +} + +/* Add BB11 blocks describing each range that we have not already + described. */ + +static void +ieee_add_bb11_blocks (abfd, sec, data) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR data; +{ + struct ieee_handle *info = (struct ieee_handle *) data; + bfd_vma low, high; + struct ieee_range *r; + + low = bfd_get_section_vma (abfd, sec); + high = low + bfd_section_size (abfd, sec); + + /* Find the first range at or after this section. The ranges are + sorted by address. */ + for (r = info->global_ranges; r != NULL; r = r->next) + if (r->high > low) + break; + + while (low < high) + { + if (r == NULL || r->low >= high) + { + if (! ieee_add_bb11 (info, sec, low, high)) + info->error = TRUE; + return; + } + + if (low < r->low + && r->low - low > 0x100) + { + if (! ieee_add_bb11 (info, sec, low, r->low)) + { + info->error = TRUE; + return; + } + } + low = r->high; + + r = r->next; + } +} + +/* Add a single BB11 block for a range. We add it to info->vars. */ + +static bfd_boolean +ieee_add_bb11 (info, sec, low, high) + struct ieee_handle *info; + asection *sec; + bfd_vma low; + bfd_vma high; +{ + int kind; + + if (! ieee_buffer_emptyp (&info->vars)) + { + if (! ieee_change_buffer (info, &info->vars)) + return FALSE; + } + else + { + const char *filename, *modname; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + const char *backslash; +#endif + char *c, *s; + + /* Start the enclosing BB10 block. */ + filename = bfd_get_filename (info->abfd); + modname = strrchr (filename, '/'); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + backslash = strrchr (filename, '\\'); + if (modname == NULL || (backslash != NULL && backslash > modname)) + modname = backslash; +#endif + + if (modname != NULL) + ++modname; +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + else if (filename[0] && filename[1] == ':') + modname = filename + 2; +#endif + else + modname = filename; + + c = xstrdup (modname); + s = strrchr (c, '.'); + if (s != NULL) + *s = '\0'; + + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 10) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, c) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "GNU objcopy")) + return FALSE; + + free (c); + } + + if ((sec->flags & SEC_CODE) != 0) + kind = 1; + else if ((sec->flags & SEC_READONLY) != 0) + kind = 3; + else + kind = 2; + + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 11) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, kind) + || ! ieee_write_number (info, sec->index + IEEE_SECTION_NUMBER_BASE) + || ! ieee_write_number (info, low) + || ! ieee_write_byte (info, (int) ieee_be_record_enum) + || ! ieee_write_number (info, high - low)) + return FALSE; + + return TRUE; +} + +/* Start recording information from a particular source file. This is + used to record which file defined which types, variables, etc. It + is not used for line numbers, since the lineno entry point passes + down the file name anyhow. IEEE debugging information doesn't seem + to store this information anywhere. */ + +static bfd_boolean +ieee_start_source (p, filename) + PTR p ATTRIBUTE_UNUSED; + const char *filename ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +/* Make an empty type. */ + +static bfd_boolean +ieee_empty_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + return ieee_push_type (info, (int) builtin_unknown, 0, FALSE, FALSE); +} + +/* Make a void type. */ + +static bfd_boolean +ieee_void_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + return ieee_push_type (info, (int) builtin_void, 0, FALSE, FALSE); +} + +/* Make an integer type. */ + +static bfd_boolean +ieee_int_type (p, size, unsignedp) + PTR p; + unsigned int size; + bfd_boolean unsignedp; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int indx; + + switch (size) + { + case 1: + indx = (int) builtin_signed_char; + break; + case 2: + indx = (int) builtin_signed_short_int; + break; + case 4: + indx = (int) builtin_signed_long; + break; + case 8: + indx = (int) builtin_signed_long_long; + break; + default: + fprintf (stderr, _("IEEE unsupported integer type size %u\n"), size); + return FALSE; + } + + if (unsignedp) + ++indx; + + return ieee_push_type (info, indx, size, unsignedp, FALSE); +} + +/* Make a floating point type. */ + +static bfd_boolean +ieee_float_type (p, size) + PTR p; + unsigned int size; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int indx; + + switch (size) + { + case 4: + indx = (int) builtin_float; + break; + case 8: + indx = (int) builtin_double; + break; + case 12: + /* FIXME: This size really depends upon the processor. */ + indx = (int) builtin_long_double; + break; + case 16: + indx = (int) builtin_long_long_double; + break; + default: + fprintf (stderr, _("IEEE unsupported float type size %u\n"), size); + return FALSE; + } + + return ieee_push_type (info, indx, size, FALSE, FALSE); +} + +/* Make a complex type. */ + +static bfd_boolean +ieee_complex_type (p, size) + PTR p; + unsigned int size; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + char code; + + switch (size) + { + case 4: + if (info->complex_float_index != 0) + return ieee_push_type (info, info->complex_float_index, size * 2, + FALSE, FALSE); + code = 'c'; + break; + case 12: + case 16: + /* These cases can be output by gcc -gstabs. Outputting the + wrong type is better than crashing. */ + case 8: + if (info->complex_double_index != 0) + return ieee_push_type (info, info->complex_double_index, size * 2, + FALSE, FALSE); + code = 'd'; + break; + default: + fprintf (stderr, _("IEEE unsupported complex type size %u\n"), size); + return FALSE; + } + + /* FIXME: I don't know what the string is for. */ + if (! ieee_define_type (info, size * 2, FALSE, FALSE) + || ! ieee_write_number (info, code) + || ! ieee_write_id (info, "")) + return FALSE; + + if (size == 4) + info->complex_float_index = info->type_stack->type.indx; + else + info->complex_double_index = info->type_stack->type.indx; + + return TRUE; +} + +/* Make a boolean type. IEEE doesn't support these, so we just make + an integer type instead. */ + +static bfd_boolean +ieee_bool_type (p, size) + PTR p; + unsigned int size; +{ + return ieee_int_type (p, size, TRUE); +} + +/* Make an enumeration. */ + +static bfd_boolean +ieee_enum_type (p, tag, names, vals) + PTR p; + const char *tag; + const char **names; + bfd_signed_vma *vals; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_defined_enum *e; + bfd_boolean localp, simple; + unsigned int indx; + int i = 0; + + localp = FALSE; + indx = (unsigned int) -1; + for (e = info->enums; e != NULL; e = e->next) + { + if (tag == NULL) + { + if (e->tag != NULL) + continue; + } + else + { + if (e->tag == NULL + || tag[0] != e->tag[0] + || strcmp (tag, e->tag) != 0) + continue; + } + + if (! e->defined) + { + /* This enum tag has been seen but not defined. */ + indx = e->indx; + break; + } + + if (names != NULL && e->names != NULL) + { + for (i = 0; names[i] != NULL && e->names[i] != NULL; i++) + { + if (names[i][0] != e->names[i][0] + || vals[i] != e->vals[i] + || strcmp (names[i], e->names[i]) != 0) + break; + } + } + + if ((names == NULL && e->names == NULL) + || (names != NULL + && e->names != NULL + && names[i] == NULL + && e->names[i] == NULL)) + { + /* We've seen this enum before. */ + return ieee_push_type (info, e->indx, 0, TRUE, FALSE); + } + + if (tag != NULL) + { + /* We've already seen an enum of the same name, so we must make + sure to output this one locally. */ + localp = TRUE; + break; + } + } + + /* If this is a simple enumeration, in which the values start at 0 + and always increment by 1, we can use type E. Otherwise we must + use type N. */ + + simple = TRUE; + if (names != NULL) + { + for (i = 0; names[i] != NULL; i++) + { + if (vals[i] != i) + { + simple = FALSE; + break; + } + } + } + + if (! ieee_define_named_type (info, tag, indx, 0, TRUE, localp, + (struct ieee_buflist *) NULL) + || ! ieee_write_number (info, simple ? 'E' : 'N')) + return FALSE; + if (simple) + { + /* FIXME: This is supposed to be the enumeration size, but we + don't store that. */ + if (! ieee_write_number (info, 4)) + return FALSE; + } + if (names != NULL) + { + for (i = 0; names[i] != NULL; i++) + { + if (! ieee_write_id (info, names[i])) + return FALSE; + if (! simple) + { + if (! ieee_write_number (info, vals[i])) + return FALSE; + } + } + } + + if (! localp) + { + if (indx == (unsigned int) -1) + { + e = (struct ieee_defined_enum *) xmalloc (sizeof *e); + memset (e, 0, sizeof *e); + e->indx = info->type_stack->type.indx; + e->tag = tag; + + e->next = info->enums; + info->enums = e; + } + + e->names = names; + e->vals = vals; + e->defined = TRUE; + } + + return TRUE; +} + +/* Make a pointer type. */ + +static bfd_boolean +ieee_pointer_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + bfd_boolean localp; + unsigned int indx; + struct ieee_modified_type *m = NULL; + + localp = info->type_stack->type.localp; + indx = ieee_pop_type (info); + + /* A pointer to a simple builtin type can be obtained by adding 32. + FIXME: Will this be a short pointer, and will that matter? */ + if (indx < 32) + return ieee_push_type (info, indx + 32, 0, TRUE, FALSE); + + if (! localp) + { + m = ieee_get_modified_info (p, indx); + if (m == NULL) + return FALSE; + + /* FIXME: The size should depend upon the architecture. */ + if (m->pointer > 0) + return ieee_push_type (info, m->pointer, 4, TRUE, FALSE); + } + + if (! ieee_define_type (info, 4, TRUE, localp) + || ! ieee_write_number (info, 'P') + || ! ieee_write_number (info, indx)) + return FALSE; + + if (! localp) + m->pointer = info->type_stack->type.indx; + + return TRUE; +} + +/* Make a function type. This will be called for a method, but we + don't want to actually add it to the type table in that case. We + handle this by defining the type in a private buffer, and only + adding that buffer to the typedef block if we are going to use it. */ + +static bfd_boolean +ieee_function_type (p, argcount, varargs) + PTR p; + int argcount; + bfd_boolean varargs; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + bfd_boolean localp; + unsigned int *args = NULL; + int i; + unsigned int retindx; + struct ieee_buflist fndef; + struct ieee_modified_type *m; + + localp = FALSE; + + if (argcount > 0) + { + args = (unsigned int *) xmalloc (argcount * sizeof *args); + for (i = argcount - 1; i >= 0; i--) + { + if (info->type_stack->type.localp) + localp = TRUE; + args[i] = ieee_pop_type (info); + } + } + else if (argcount < 0) + varargs = FALSE; + + if (info->type_stack->type.localp) + localp = TRUE; + retindx = ieee_pop_type (info); + + m = NULL; + if (argcount < 0 && ! localp) + { + m = ieee_get_modified_info (p, retindx); + if (m == NULL) + return FALSE; + + if (m->function > 0) + return ieee_push_type (info, m->function, 0, TRUE, FALSE); + } + + /* An attribute of 0x41 means that the frame and push mask are + unknown. */ + if (! ieee_init_buffer (info, &fndef) + || ! ieee_define_named_type (info, (const char *) NULL, + (unsigned int) -1, 0, TRUE, localp, + &fndef) + || ! ieee_write_number (info, 'x') + || ! ieee_write_number (info, 0x41) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, retindx) + || ! ieee_write_number (info, (bfd_vma) argcount + (varargs ? 1 : 0))) + return FALSE; + if (argcount > 0) + { + for (i = 0; i < argcount; i++) + if (! ieee_write_number (info, args[i])) + return FALSE; + free (args); + } + if (varargs) + { + /* A varargs function is represented by writing out the last + argument as type void *, although this makes little sense. */ + if (! ieee_write_number (info, (bfd_vma) builtin_void + 32)) + return FALSE; + } + + if (! ieee_write_number (info, 0)) + return FALSE; + + /* We wrote the information into fndef, in case we don't need it. + It will be appended to info->types by ieee_pop_type. */ + info->type_stack->type.fndef = fndef; + + if (m != NULL) + m->function = info->type_stack->type.indx; + + return TRUE; +} + +/* Make a reference type. */ + +static bfd_boolean +ieee_reference_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* IEEE appears to record a normal pointer type, and then use a + pmisc record to indicate that it is really a reference. */ + + if (! ieee_pointer_type (p)) + return FALSE; + info->type_stack->type.referencep = TRUE; + return TRUE; +} + +/* Make a range type. */ + +static bfd_boolean +ieee_range_type (p, low, high) + PTR p; + bfd_signed_vma low; + bfd_signed_vma high; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int size; + bfd_boolean unsignedp, localp; + + size = info->type_stack->type.size; + unsignedp = info->type_stack->type.unsignedp; + localp = info->type_stack->type.localp; + ieee_pop_unused_type (info); + return (ieee_define_type (info, size, unsignedp, localp) + && ieee_write_number (info, 'R') + && ieee_write_number (info, (bfd_vma) low) + && ieee_write_number (info, (bfd_vma) high) + && ieee_write_number (info, unsignedp ? 0 : 1) + && ieee_write_number (info, size)); +} + +/* Make an array type. */ + +static bfd_boolean +ieee_array_type (p, low, high, stringp) + PTR p; + bfd_signed_vma low; + bfd_signed_vma high; + bfd_boolean stringp ATTRIBUTE_UNUSED; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int eleindx; + bfd_boolean localp; + unsigned int size; + struct ieee_modified_type *m = NULL; + struct ieee_modified_array_type *a; + + /* IEEE does not store the range, so we just ignore it. */ + ieee_pop_unused_type (info); + localp = info->type_stack->type.localp; + size = info->type_stack->type.size; + eleindx = ieee_pop_type (info); + + /* If we don't know the range, treat the size as exactly one + element. */ + if (low < high) + size *= (high - low) + 1; + + if (! localp) + { + m = ieee_get_modified_info (info, eleindx); + if (m == NULL) + return FALSE; + + for (a = m->arrays; a != NULL; a = a->next) + { + if (a->low == low && a->high == high) + return ieee_push_type (info, a->indx, size, FALSE, FALSE); + } + } + + if (! ieee_define_type (info, size, FALSE, localp) + || ! ieee_write_number (info, low == 0 ? 'Z' : 'C') + || ! ieee_write_number (info, eleindx)) + return FALSE; + if (low != 0) + { + if (! ieee_write_number (info, low)) + return FALSE; + } + + if (! ieee_write_number (info, high + 1)) + return FALSE; + + if (! localp) + { + a = (struct ieee_modified_array_type *) xmalloc (sizeof *a); + memset (a, 0, sizeof *a); + + a->indx = info->type_stack->type.indx; + a->low = low; + a->high = high; + + a->next = m->arrays; + m->arrays = a; + } + + return TRUE; +} + +/* Make a set type. */ + +static bfd_boolean +ieee_set_type (p, bitstringp) + PTR p; + bfd_boolean bitstringp ATTRIBUTE_UNUSED; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + bfd_boolean localp; + unsigned int eleindx; + + localp = info->type_stack->type.localp; + eleindx = ieee_pop_type (info); + + /* FIXME: We don't know the size, so we just use 4. */ + + return (ieee_define_type (info, 0, TRUE, localp) + && ieee_write_number (info, 's') + && ieee_write_number (info, 4) + && ieee_write_number (info, eleindx)); +} + +/* Make an offset type. */ + +static bfd_boolean +ieee_offset_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int targetindx, baseindx; + + targetindx = ieee_pop_type (info); + baseindx = ieee_pop_type (info); + + /* FIXME: The MRI C++ compiler does not appear to generate any + useful type information about an offset type. It just records a + pointer to member as an integer. The MRI/HP IEEE spec does + describe a pmisc record which can be used for a pointer to + member. Unfortunately, it does not describe the target type, + which seems pretty important. I'm going to punt this for now. */ + + return ieee_int_type (p, 4, TRUE); +} + +/* Make a method type. */ + +static bfd_boolean +ieee_method_type (p, domain, argcount, varargs) + PTR p; + bfd_boolean domain; + int argcount; + bfd_boolean varargs; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* FIXME: The MRI/HP IEEE spec defines a pmisc record to use for a + method, but the definition is incomplete. We just output an 'x' + type. */ + + if (domain) + ieee_pop_unused_type (info); + + return ieee_function_type (p, argcount, varargs); +} + +/* Make a const qualified type. */ + +static bfd_boolean +ieee_const_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int size; + bfd_boolean unsignedp, localp; + unsigned int indx; + struct ieee_modified_type *m = NULL; + + size = info->type_stack->type.size; + unsignedp = info->type_stack->type.unsignedp; + localp = info->type_stack->type.localp; + indx = ieee_pop_type (info); + + if (! localp) + { + m = ieee_get_modified_info (info, indx); + if (m == NULL) + return FALSE; + + if (m->const_qualified > 0) + return ieee_push_type (info, m->const_qualified, size, unsignedp, + FALSE); + } + + if (! ieee_define_type (info, size, unsignedp, localp) + || ! ieee_write_number (info, 'n') + || ! ieee_write_number (info, 1) + || ! ieee_write_number (info, indx)) + return FALSE; + + if (! localp) + m->const_qualified = info->type_stack->type.indx; + + return TRUE; +} + +/* Make a volatile qualified type. */ + +static bfd_boolean +ieee_volatile_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int size; + bfd_boolean unsignedp, localp; + unsigned int indx; + struct ieee_modified_type *m = NULL; + + size = info->type_stack->type.size; + unsignedp = info->type_stack->type.unsignedp; + localp = info->type_stack->type.localp; + indx = ieee_pop_type (info); + + if (! localp) + { + m = ieee_get_modified_info (info, indx); + if (m == NULL) + return FALSE; + + if (m->volatile_qualified > 0) + return ieee_push_type (info, m->volatile_qualified, size, unsignedp, + FALSE); + } + + if (! ieee_define_type (info, size, unsignedp, localp) + || ! ieee_write_number (info, 'n') + || ! ieee_write_number (info, 2) + || ! ieee_write_number (info, indx)) + return FALSE; + + if (! localp) + m->volatile_qualified = info->type_stack->type.indx; + + return TRUE; +} + +/* Convert an enum debug_visibility into a CXXFLAGS value. */ + +static unsigned int +ieee_vis_to_flags (visibility) + enum debug_visibility visibility; +{ + switch (visibility) + { + default: + abort (); + case DEBUG_VISIBILITY_PUBLIC: + return CXXFLAGS_VISIBILITY_PUBLIC; + case DEBUG_VISIBILITY_PRIVATE: + return CXXFLAGS_VISIBILITY_PRIVATE; + case DEBUG_VISIBILITY_PROTECTED: + return CXXFLAGS_VISIBILITY_PROTECTED; + } + /*NOTREACHED*/ +} + +/* Start defining a struct type. We build it in the strdef field on + the stack, to avoid confusing type definitions required by the + fields with the struct type itself. */ + +static bfd_boolean +ieee_start_struct_type (p, tag, id, structp, size) + PTR p; + const char *tag; + unsigned int id; + bfd_boolean structp; + unsigned int size; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + bfd_boolean localp, ignorep; + bfd_boolean copy; + char ab[20]; + const char *look; + struct ieee_name_type_hash_entry *h; + struct ieee_name_type *nt, *ntlook; + struct ieee_buflist strdef; + + localp = FALSE; + ignorep = FALSE; + + /* We need to create a tag for internal use even if we don't want + one for external use. This will let us refer to an anonymous + struct. */ + if (tag != NULL) + { + look = tag; + copy = FALSE; + } + else + { + sprintf (ab, "__anon%u", id); + look = ab; + copy = TRUE; + } + + /* If we already have references to the tag, we must use the + existing type index. */ + h = ieee_name_type_hash_lookup (&info->tags, look, TRUE, copy); + if (h == NULL) + return FALSE; + + nt = NULL; + for (ntlook = h->types; ntlook != NULL; ntlook = ntlook->next) + { + if (ntlook->id == id) + nt = ntlook; + else if (! ntlook->type.localp) + { + /* We are creating a duplicate definition of a globally + defined tag. Force it to be local to avoid + confusion. */ + localp = TRUE; + } + } + + if (nt != NULL) + { + assert (localp == nt->type.localp); + if (nt->kind == DEBUG_KIND_ILLEGAL && ! localp) + { + /* We've already seen a global definition of the type. + Ignore this new definition. */ + ignorep = TRUE; + } + } + else + { + nt = (struct ieee_name_type *) xmalloc (sizeof *nt); + memset (nt, 0, sizeof *nt); + nt->id = id; + nt->type.name = h->root.string; + nt->next = h->types; + h->types = nt; + nt->type.indx = info->type_indx; + ++info->type_indx; + } + + nt->kind = DEBUG_KIND_ILLEGAL; + + if (! ieee_init_buffer (info, &strdef) + || ! ieee_define_named_type (info, tag, nt->type.indx, size, TRUE, + localp, &strdef) + || ! ieee_write_number (info, structp ? 'S' : 'U') + || ! ieee_write_number (info, size)) + return FALSE; + + if (! ignorep) + { + const char *hold; + + /* We never want nt->type.name to be NULL. We want the rest of + the type to be the object set up on the type stack; it will + have a NULL name if tag is NULL. */ + hold = nt->type.name; + nt->type = info->type_stack->type; + nt->type.name = hold; + } + + info->type_stack->type.name = tag; + info->type_stack->type.strdef = strdef; + info->type_stack->type.ignorep = ignorep; + + return TRUE; +} + +/* Add a field to a struct. */ + +static bfd_boolean +ieee_struct_field (p, name, bitpos, bitsize, visibility) + PTR p; + const char *name; + bfd_vma bitpos; + bfd_vma bitsize; + enum debug_visibility visibility; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int size; + bfd_boolean unsignedp; + bfd_boolean referencep; + bfd_boolean localp; + unsigned int indx; + bfd_vma offset; + + assert (info->type_stack != NULL + && info->type_stack->next != NULL + && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef)); + + /* If we are ignoring this struct definition, just pop and ignore + the type. */ + if (info->type_stack->next->type.ignorep) + { + ieee_pop_unused_type (info); + return TRUE; + } + + size = info->type_stack->type.size; + unsignedp = info->type_stack->type.unsignedp; + referencep = info->type_stack->type.referencep; + localp = info->type_stack->type.localp; + indx = ieee_pop_type (info); + + if (localp) + info->type_stack->type.localp = TRUE; + + if (info->type_stack->type.classdef != NULL) + { + unsigned int flags; + unsigned int nindx; + + /* This is a class. We must add a description of this field to + the class records we are building. */ + + flags = ieee_vis_to_flags (visibility); + nindx = info->type_stack->type.classdef->indx; + if (! ieee_change_buffer (info, + &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, 'd') + || ! ieee_write_asn (info, nindx, flags) + || ! ieee_write_atn65 (info, nindx, name) + || ! ieee_write_atn65 (info, nindx, name)) + return FALSE; + info->type_stack->type.classdef->pmisccount += 4; + + if (referencep) + { + unsigned int nindx; + + /* We need to output a record recording that this field is + really of reference type. We put this on the refs field + of classdef, so that it can be appended to the C++ + records after the class is defined. */ + + nindx = info->name_indx; + ++info->name_indx; + + if (! ieee_change_buffer (info, + &info->type_stack->type.classdef->refs) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, 4) + || ! ieee_write_asn (info, nindx, 'R') + || ! ieee_write_asn (info, nindx, 3) + || ! ieee_write_atn65 (info, nindx, info->type_stack->type.name) + || ! ieee_write_atn65 (info, nindx, name)) + return FALSE; + } + } + + /* If the bitsize doesn't match the expected size, we need to output + a bitfield type. */ + if (size == 0 || bitsize == 0 || bitsize == size * 8) + offset = bitpos / 8; + else + { + if (! ieee_define_type (info, 0, unsignedp, + info->type_stack->type.localp) + || ! ieee_write_number (info, 'g') + || ! ieee_write_number (info, unsignedp ? 0 : 1) + || ! ieee_write_number (info, bitsize) + || ! ieee_write_number (info, indx)) + return FALSE; + indx = ieee_pop_type (info); + offset = bitpos; + } + + /* Switch to the struct we are building in order to output this + field definition. */ + return (ieee_change_buffer (info, &info->type_stack->type.strdef) + && ieee_write_id (info, name) + && ieee_write_number (info, indx) + && ieee_write_number (info, offset)); +} + +/* Finish up a struct type. */ + +static bfd_boolean +ieee_end_struct_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_buflist *pb; + + assert (info->type_stack != NULL + && ! ieee_buffer_emptyp (&info->type_stack->type.strdef)); + + /* If we were ignoring this struct definition because it was a + duplicate defintion, just through away whatever bytes we have + accumulated. Leave the type on the stack. */ + if (info->type_stack->type.ignorep) + return TRUE; + + /* If this is not a duplicate definition of this tag, then localp + will be FALSE, and we can put it in the global type block. + FIXME: We should avoid outputting duplicate definitions which are + the same. */ + if (! info->type_stack->type.localp) + { + /* Make sure we have started the global type block. */ + if (ieee_buffer_emptyp (&info->global_types)) + { + if (! ieee_change_buffer (info, &info->global_types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 2) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "")) + return FALSE; + } + pb = &info->global_types; + } + else + { + /* Make sure we have started the types block. */ + if (ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return FALSE; + } + pb = &info->types; + } + + /* Append the struct definition to the types. */ + if (! ieee_append_buffer (info, pb, &info->type_stack->type.strdef) + || ! ieee_init_buffer (info, &info->type_stack->type.strdef)) + return FALSE; + + /* Leave the struct on the type stack. */ + + return TRUE; +} + +/* Start a class type. */ + +static bfd_boolean +ieee_start_class_type (p, tag, id, structp, size, vptr, ownvptr) + PTR p; + const char *tag; + unsigned int id; + bfd_boolean structp; + unsigned int size; + bfd_boolean vptr; + bfd_boolean ownvptr; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + const char *vclass; + struct ieee_buflist pmiscbuf; + unsigned int indx; + struct ieee_type_class *classdef; + + /* A C++ class is output as a C++ struct along with a set of pmisc + records describing the class. */ + + /* We need to have a name so that we can associate the struct and + the class. */ + if (tag == NULL) + { + char *t; + + t = (char *) xmalloc (20); + sprintf (t, "__anon%u", id); + tag = t; + } + + /* We can't write out the virtual table information until we have + finished the class, because we don't know the virtual table size. + We get the size from the largest voffset we see. */ + vclass = NULL; + if (vptr && ! ownvptr) + { + vclass = info->type_stack->type.name; + assert (vclass != NULL); + /* We don't call ieee_pop_unused_type, since the class should + get defined. */ + (void) ieee_pop_type (info); + } + + if (! ieee_start_struct_type (p, tag, id, structp, size)) + return FALSE; + + indx = info->name_indx; + ++info->name_indx; + + /* We write out pmisc records into the classdef field. We will + write out the pmisc start after we know the number of records we + need. */ + if (! ieee_init_buffer (info, &pmiscbuf) + || ! ieee_change_buffer (info, &pmiscbuf) + || ! ieee_write_asn (info, indx, 'T') + || ! ieee_write_asn (info, indx, structp ? 'o' : 'u') + || ! ieee_write_atn65 (info, indx, tag)) + return FALSE; + + classdef = (struct ieee_type_class *) xmalloc (sizeof *classdef); + memset (classdef, 0, sizeof *classdef); + + classdef->indx = indx; + classdef->pmiscbuf = pmiscbuf; + classdef->pmisccount = 3; + classdef->vclass = vclass; + classdef->ownvptr = ownvptr; + + info->type_stack->type.classdef = classdef; + + return TRUE; +} + +/* Add a static member to a class. */ + +static bfd_boolean +ieee_class_static_member (p, name, physname, visibility) + PTR p; + const char *name; + const char *physname; + enum debug_visibility visibility; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int flags; + unsigned int nindx; + + /* We don't care about the type. Hopefully there will be a call to + ieee_variable declaring the physical name and the type, since + that is where an IEEE consumer must get the type. */ + ieee_pop_unused_type (info); + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL); + + flags = ieee_vis_to_flags (visibility); + flags |= CXXFLAGS_STATIC; + + nindx = info->type_stack->type.classdef->indx; + + if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, 'd') + || ! ieee_write_asn (info, nindx, flags) + || ! ieee_write_atn65 (info, nindx, name) + || ! ieee_write_atn65 (info, nindx, physname)) + return FALSE; + info->type_stack->type.classdef->pmisccount += 4; + + return TRUE; +} + +/* Add a base class to a class. */ + +static bfd_boolean +ieee_class_baseclass (p, bitpos, virtual, visibility) + PTR p; + bfd_vma bitpos; + bfd_boolean virtual; + enum debug_visibility visibility; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + const char *bname; + bfd_boolean localp; + unsigned int bindx; + char *fname; + unsigned int flags; + unsigned int nindx; + + assert (info->type_stack != NULL + && info->type_stack->type.name != NULL + && info->type_stack->next != NULL + && info->type_stack->next->type.classdef != NULL + && ! ieee_buffer_emptyp (&info->type_stack->next->type.strdef)); + + bname = info->type_stack->type.name; + localp = info->type_stack->type.localp; + bindx = ieee_pop_type (info); + + /* We are currently defining both a struct and a class. We must + write out a field definition in the struct which holds the base + class. The stabs debugging reader will create a field named + _vb$CLASS for a virtual base class, so we just use that. FIXME: + we should not depend upon a detail of stabs debugging. */ + if (virtual) + { + fname = (char *) xmalloc (strlen (bname) + sizeof "_vb$"); + sprintf (fname, "_vb$%s", bname); + flags = BASEFLAGS_VIRTUAL; + } + else + { + if (localp) + info->type_stack->type.localp = TRUE; + + fname = (char *) xmalloc (strlen (bname) + sizeof "_b$"); + sprintf (fname, "_b$%s", bname); + + if (! ieee_change_buffer (info, &info->type_stack->type.strdef) + || ! ieee_write_id (info, fname) + || ! ieee_write_number (info, bindx) + || ! ieee_write_number (info, bitpos / 8)) + return FALSE; + flags = 0; + } + + if (visibility == DEBUG_VISIBILITY_PRIVATE) + flags |= BASEFLAGS_PRIVATE; + + nindx = info->type_stack->type.classdef->indx; + + if (! ieee_change_buffer (info, &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, 'b') + || ! ieee_write_asn (info, nindx, flags) + || ! ieee_write_atn65 (info, nindx, bname) + || ! ieee_write_asn (info, nindx, 0) + || ! ieee_write_atn65 (info, nindx, fname)) + return FALSE; + info->type_stack->type.classdef->pmisccount += 5; + + free (fname); + + return TRUE; +} + +/* Start building a method for a class. */ + +static bfd_boolean +ieee_class_start_method (p, name) + PTR p; + const char *name; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL + && info->type_stack->type.classdef->method == NULL); + + info->type_stack->type.classdef->method = name; + + return TRUE; +} + +/* Define a new method variant, either static or not. */ + +static bfd_boolean +ieee_class_method_var (info, physname, visibility, staticp, constp, + volatilep, voffset, context) + struct ieee_handle *info; + const char *physname; + enum debug_visibility visibility; + bfd_boolean staticp; + bfd_boolean constp; + bfd_boolean volatilep; + bfd_vma voffset; + bfd_boolean context; +{ + unsigned int flags; + unsigned int nindx; + bfd_boolean virtual; + + /* We don't need the type of the method. An IEEE consumer which + wants the type must track down the function by the physical name + and get the type from that. */ + ieee_pop_unused_type (info); + + /* We don't use the context. FIXME: We probably ought to use it to + adjust the voffset somehow, but I don't really know how. */ + if (context) + ieee_pop_unused_type (info); + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL + && info->type_stack->type.classdef->method != NULL); + + flags = ieee_vis_to_flags (visibility); + + /* FIXME: We never set CXXFLAGS_OVERRIDE, CXXFLAGS_OPERATOR, + CXXFLAGS_CTORDTOR, CXXFLAGS_CTOR, or CXXFLAGS_INLINE. */ + + if (staticp) + flags |= CXXFLAGS_STATIC; + if (constp) + flags |= CXXFLAGS_CONST; + if (volatilep) + flags |= CXXFLAGS_VOLATILE; + + nindx = info->type_stack->type.classdef->indx; + + virtual = context || voffset > 0; + + if (! ieee_change_buffer (info, + &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, virtual ? 'v' : 'm') + || ! ieee_write_asn (info, nindx, flags) + || ! ieee_write_atn65 (info, nindx, + info->type_stack->type.classdef->method) + || ! ieee_write_atn65 (info, nindx, physname)) + return FALSE; + + if (virtual) + { + if (voffset > info->type_stack->type.classdef->voffset) + info->type_stack->type.classdef->voffset = voffset; + if (! ieee_write_asn (info, nindx, voffset)) + return FALSE; + ++info->type_stack->type.classdef->pmisccount; + } + + if (! ieee_write_asn (info, nindx, 0)) + return FALSE; + + info->type_stack->type.classdef->pmisccount += 5; + + return TRUE; +} + +/* Define a new method variant. */ + +static bfd_boolean +ieee_class_method_variant (p, physname, visibility, constp, volatilep, + voffset, context) + PTR p; + const char *physname; + enum debug_visibility visibility; + bfd_boolean constp; + bfd_boolean volatilep; + bfd_vma voffset; + bfd_boolean context; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + return ieee_class_method_var (info, physname, visibility, FALSE, constp, + volatilep, voffset, context); +} + +/* Define a new static method variant. */ + +static bfd_boolean +ieee_class_static_method_variant (p, physname, visibility, constp, volatilep) + PTR p; + const char *physname; + enum debug_visibility visibility; + bfd_boolean constp; + bfd_boolean volatilep; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + return ieee_class_method_var (info, physname, visibility, TRUE, constp, + volatilep, 0, FALSE); +} + +/* Finish up a method. */ + +static bfd_boolean +ieee_class_end_method (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL + && info->type_stack->type.classdef->method != NULL); + + info->type_stack->type.classdef->method = NULL; + + return TRUE; +} + +/* Finish up a class. */ + +static bfd_boolean +ieee_end_class_type (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int nindx; + + assert (info->type_stack != NULL + && info->type_stack->type.classdef != NULL); + + /* If we were ignoring this class definition because it was a + duplicate definition, just through away whatever bytes we have + accumulated. Leave the type on the stack. */ + if (info->type_stack->type.ignorep) + return TRUE; + + nindx = info->type_stack->type.classdef->indx; + + /* If we have a virtual table, we can write out the information now. */ + if (info->type_stack->type.classdef->vclass != NULL + || info->type_stack->type.classdef->ownvptr) + { + if (! ieee_change_buffer (info, + &info->type_stack->type.classdef->pmiscbuf) + || ! ieee_write_asn (info, nindx, 'z') + || ! ieee_write_atn65 (info, nindx, "") + || ! ieee_write_asn (info, nindx, + info->type_stack->type.classdef->voffset)) + return FALSE; + if (info->type_stack->type.classdef->ownvptr) + { + if (! ieee_write_atn65 (info, nindx, "")) + return FALSE; + } + else + { + if (! ieee_write_atn65 (info, nindx, + info->type_stack->type.classdef->vclass)) + return FALSE; + } + if (! ieee_write_asn (info, nindx, 0)) + return FALSE; + info->type_stack->type.classdef->pmisccount += 5; + } + + /* Now that we know the number of pmisc records, we can write out + the atn62 which starts the pmisc records, and append them to the + C++ buffers. */ + + if (! ieee_change_buffer (info, &info->cxx) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, + info->type_stack->type.classdef->pmisccount)) + return FALSE; + + if (! ieee_append_buffer (info, &info->cxx, + &info->type_stack->type.classdef->pmiscbuf)) + return FALSE; + if (! ieee_buffer_emptyp (&info->type_stack->type.classdef->refs)) + { + if (! ieee_append_buffer (info, &info->cxx, + &info->type_stack->type.classdef->refs)) + return FALSE; + } + + return ieee_end_struct_type (p); +} + +/* Push a previously seen typedef onto the type stack. */ + +static bfd_boolean +ieee_typedef_type (p, name) + PTR p; + const char *name; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_name_type_hash_entry *h; + struct ieee_name_type *nt; + + h = ieee_name_type_hash_lookup (&info->typedefs, name, FALSE, FALSE); + + /* h should never be NULL, since that would imply that the generic + debugging code has asked for a typedef which it has not yet + defined. */ + assert (h != NULL); + + /* We always use the most recently defined type for this name, which + will be the first one on the list. */ + + nt = h->types; + if (! ieee_push_type (info, nt->type.indx, nt->type.size, + nt->type.unsignedp, nt->type.localp)) + return FALSE; + + /* Copy over any other type information we may have. */ + info->type_stack->type = nt->type; + + return TRUE; +} + +/* Push a tagged type onto the type stack. */ + +static bfd_boolean +ieee_tag_type (p, name, id, kind) + PTR p; + const char *name; + unsigned int id; + enum debug_type_kind kind; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + bfd_boolean localp; + bfd_boolean copy; + char ab[20]; + struct ieee_name_type_hash_entry *h; + struct ieee_name_type *nt; + + if (kind == DEBUG_KIND_ENUM) + { + struct ieee_defined_enum *e; + + if (name == NULL) + abort (); + for (e = info->enums; e != NULL; e = e->next) + if (e->tag != NULL && strcmp (e->tag, name) == 0) + return ieee_push_type (info, e->indx, 0, TRUE, FALSE); + + e = (struct ieee_defined_enum *) xmalloc (sizeof *e); + memset (e, 0, sizeof *e); + + e->indx = info->type_indx; + ++info->type_indx; + e->tag = name; + e->defined = FALSE; + + e->next = info->enums; + info->enums = e; + + return ieee_push_type (info, e->indx, 0, TRUE, FALSE); + } + + localp = FALSE; + + copy = FALSE; + if (name == NULL) + { + sprintf (ab, "__anon%u", id); + name = ab; + copy = TRUE; + } + + h = ieee_name_type_hash_lookup (&info->tags, name, TRUE, copy); + if (h == NULL) + return FALSE; + + for (nt = h->types; nt != NULL; nt = nt->next) + { + if (nt->id == id) + { + if (! ieee_push_type (info, nt->type.indx, nt->type.size, + nt->type.unsignedp, nt->type.localp)) + return FALSE; + /* Copy over any other type information we may have. */ + info->type_stack->type = nt->type; + return TRUE; + } + + if (! nt->type.localp) + { + /* This is a duplicate of a global type, so it must be + local. */ + localp = TRUE; + } + } + + nt = (struct ieee_name_type *) xmalloc (sizeof *nt); + memset (nt, 0, sizeof *nt); + + nt->id = id; + nt->type.name = h->root.string; + nt->type.indx = info->type_indx; + nt->type.localp = localp; + ++info->type_indx; + nt->kind = kind; + + nt->next = h->types; + h->types = nt; + + if (! ieee_push_type (info, nt->type.indx, 0, FALSE, localp)) + return FALSE; + + info->type_stack->type.name = h->root.string; + + return TRUE; +} + +/* Output a typedef. */ + +static bfd_boolean +ieee_typdef (p, name) + PTR p; + const char *name; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_write_type type; + unsigned int indx; + bfd_boolean found; + bfd_boolean localp; + struct ieee_name_type_hash_entry *h; + struct ieee_name_type *nt; + + type = info->type_stack->type; + indx = type.indx; + + /* If this is a simple builtin type using a builtin name, we don't + want to output the typedef itself. We also want to change the + type index to correspond to the name being used. We recognize + names used in stabs debugging output even if they don't exactly + correspond to the names used for the IEEE builtin types. */ + found = FALSE; + if (indx <= (unsigned int) builtin_bcd_float) + { + switch ((enum builtin_types) indx) + { + default: + break; + + case builtin_void: + if (strcmp (name, "void") == 0) + found = TRUE; + break; + + case builtin_signed_char: + case builtin_char: + if (strcmp (name, "signed char") == 0) + { + indx = (unsigned int) builtin_signed_char; + found = TRUE; + } + else if (strcmp (name, "char") == 0) + { + indx = (unsigned int) builtin_char; + found = TRUE; + } + break; + + case builtin_unsigned_char: + if (strcmp (name, "unsigned char") == 0) + found = TRUE; + break; + + case builtin_signed_short_int: + case builtin_short: + case builtin_short_int: + case builtin_signed_short: + if (strcmp (name, "signed short int") == 0) + { + indx = (unsigned int) builtin_signed_short_int; + found = TRUE; + } + else if (strcmp (name, "short") == 0) + { + indx = (unsigned int) builtin_short; + found = TRUE; + } + else if (strcmp (name, "short int") == 0) + { + indx = (unsigned int) builtin_short_int; + found = TRUE; + } + else if (strcmp (name, "signed short") == 0) + { + indx = (unsigned int) builtin_signed_short; + found = TRUE; + } + break; + + case builtin_unsigned_short_int: + case builtin_unsigned_short: + if (strcmp (name, "unsigned short int") == 0 + || strcmp (name, "short unsigned int") == 0) + { + indx = builtin_unsigned_short_int; + found = TRUE; + } + else if (strcmp (name, "unsigned short") == 0) + { + indx = builtin_unsigned_short; + found = TRUE; + } + break; + + case builtin_signed_long: + case builtin_int: /* FIXME: Size depends upon architecture. */ + case builtin_long: + if (strcmp (name, "signed long") == 0) + { + indx = builtin_signed_long; + found = TRUE; + } + else if (strcmp (name, "int") == 0) + { + indx = builtin_int; + found = TRUE; + } + else if (strcmp (name, "long") == 0 + || strcmp (name, "long int") == 0) + { + indx = builtin_long; + found = TRUE; + } + break; + + case builtin_unsigned_long: + case builtin_unsigned: /* FIXME: Size depends upon architecture. */ + case builtin_unsigned_int: /* FIXME: Like builtin_unsigned. */ + if (strcmp (name, "unsigned long") == 0 + || strcmp (name, "long unsigned int") == 0) + { + indx = builtin_unsigned_long; + found = TRUE; + } + else if (strcmp (name, "unsigned") == 0) + { + indx = builtin_unsigned; + found = TRUE; + } + else if (strcmp (name, "unsigned int") == 0) + { + indx = builtin_unsigned_int; + found = TRUE; + } + break; + + case builtin_signed_long_long: + if (strcmp (name, "signed long long") == 0 + || strcmp (name, "long long int") == 0) + found = TRUE; + break; + + case builtin_unsigned_long_long: + if (strcmp (name, "unsigned long long") == 0 + || strcmp (name, "long long unsigned int") == 0) + found = TRUE; + break; + + case builtin_float: + if (strcmp (name, "float") == 0) + found = TRUE; + break; + + case builtin_double: + if (strcmp (name, "double") == 0) + found = TRUE; + break; + + case builtin_long_double: + if (strcmp (name, "long double") == 0) + found = TRUE; + break; + + case builtin_long_long_double: + if (strcmp (name, "long long double") == 0) + found = TRUE; + break; + } + + if (found) + type.indx = indx; + } + + h = ieee_name_type_hash_lookup (&info->typedefs, name, TRUE, FALSE); + if (h == NULL) + return FALSE; + + /* See if we have already defined this type with this name. */ + localp = type.localp; + for (nt = h->types; nt != NULL; nt = nt->next) + { + if (nt->id == indx) + { + /* If this is a global definition, then we don't need to + do anything here. */ + if (! nt->type.localp) + { + ieee_pop_unused_type (info); + return TRUE; + } + } + else + { + /* This is a duplicate definition, so make this one local. */ + localp = TRUE; + } + } + + /* We need to add a new typedef for this type. */ + + nt = (struct ieee_name_type *) xmalloc (sizeof *nt); + memset (nt, 0, sizeof *nt); + nt->id = indx; + nt->type = type; + nt->type.name = name; + nt->type.localp = localp; + nt->kind = DEBUG_KIND_ILLEGAL; + + nt->next = h->types; + h->types = nt; + + if (found) + { + /* This is one of the builtin typedefs, so we don't need to + actually define it. */ + ieee_pop_unused_type (info); + return TRUE; + } + + indx = ieee_pop_type (info); + + if (! ieee_define_named_type (info, name, (unsigned int) -1, type.size, + type.unsignedp, localp, + (struct ieee_buflist *) NULL) + || ! ieee_write_number (info, 'T') + || ! ieee_write_number (info, indx)) + return FALSE; + + /* Remove the type we just added to the type stack. This should not + be ieee_pop_unused_type, since the type is used, we just don't + need it now. */ + (void) ieee_pop_type (info); + + return TRUE; +} + +/* Output a tag for a type. We don't have to do anything here. */ + +static bfd_boolean +ieee_tag (p, name) + PTR p; + const char *name ATTRIBUTE_UNUSED; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* This should not be ieee_pop_unused_type, since we want the type + to be defined. */ + (void) ieee_pop_type (info); + return TRUE; +} + +/* Output an integer constant. */ + +static bfd_boolean +ieee_int_constant (p, name, val) + PTR p ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; + bfd_vma val ATTRIBUTE_UNUSED; +{ + /* FIXME. */ + return TRUE; +} + +/* Output a floating point constant. */ + +static bfd_boolean +ieee_float_constant (p, name, val) + PTR p ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; + double val ATTRIBUTE_UNUSED; +{ + /* FIXME. */ + return TRUE; +} + +/* Output a typed constant. */ + +static bfd_boolean +ieee_typed_constant (p, name, val) + PTR p; + const char *name ATTRIBUTE_UNUSED; + bfd_vma val ATTRIBUTE_UNUSED; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* FIXME. */ + ieee_pop_unused_type (info); + return TRUE; +} + +/* Output a variable. */ + +static bfd_boolean +ieee_variable (p, name, kind, val) + PTR p; + const char *name; + enum debug_var_kind kind; + bfd_vma val; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + unsigned int name_indx; + unsigned int size; + bfd_boolean referencep; + unsigned int type_indx; + bfd_boolean asn; + int refflag; + + size = info->type_stack->type.size; + referencep = info->type_stack->type.referencep; + type_indx = ieee_pop_type (info); + + assert (! ieee_buffer_emptyp (&info->vars)); + if (! ieee_change_buffer (info, &info->vars)) + return FALSE; + + name_indx = info->name_indx; + ++info->name_indx; + + /* Write out an NN and an ATN record for this variable. */ + if (! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, name_indx) + || ! ieee_write_id (info, name) + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, name_indx) + || ! ieee_write_number (info, type_indx)) + return FALSE; + switch (kind) + { + default: + abort (); + return FALSE; + case DEBUG_GLOBAL: + if (! ieee_write_number (info, 8) + || ! ieee_add_range (info, FALSE, val, val + size)) + return FALSE; + refflag = 0; + asn = TRUE; + break; + case DEBUG_STATIC: + if (! ieee_write_number (info, 3) + || ! ieee_add_range (info, FALSE, val, val + size)) + return FALSE; + refflag = 1; + asn = TRUE; + break; + case DEBUG_LOCAL_STATIC: + if (! ieee_write_number (info, 3) + || ! ieee_add_range (info, FALSE, val, val + size)) + return FALSE; + refflag = 2; + asn = TRUE; + break; + case DEBUG_LOCAL: + if (! ieee_write_number (info, 1) + || ! ieee_write_number (info, val)) + return FALSE; + refflag = 2; + asn = FALSE; + break; + case DEBUG_REGISTER: + if (! ieee_write_number (info, 2) + || ! ieee_write_number (info, + ieee_genreg_to_regno (info->abfd, val))) + return FALSE; + refflag = 2; + asn = FALSE; + break; + } + + if (asn) + { + if (! ieee_write_asn (info, name_indx, val)) + return FALSE; + } + + /* If this is really a reference type, then we just output it with + pointer type, and must now output a C++ record indicating that it + is really reference type. */ + if (referencep) + { + unsigned int nindx; + + nindx = info->name_indx; + ++info->name_indx; + + /* If this is a global variable, we want to output the misc + record in the C++ misc record block. Otherwise, we want to + output it just after the variable definition, which is where + the current buffer is. */ + if (refflag != 2) + { + if (! ieee_change_buffer (info, &info->cxx)) + return FALSE; + } + + if (! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, 3) + || ! ieee_write_asn (info, nindx, 'R') + || ! ieee_write_asn (info, nindx, refflag) + || ! ieee_write_atn65 (info, nindx, name)) + return FALSE; + } + + return TRUE; +} + +/* Start outputting information for a function. */ + +static bfd_boolean +ieee_start_function (p, name, global) + PTR p; + const char *name; + bfd_boolean global; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + bfd_boolean referencep; + unsigned int retindx, typeindx; + + referencep = info->type_stack->type.referencep; + retindx = ieee_pop_type (info); + + /* Besides recording a BB4 or BB6 block, we record the type of the + function in the BB1 typedef block. We can't write out the full + type until we have seen all the parameters, so we accumulate it + in info->fntype and info->fnargs. */ + if (! ieee_buffer_emptyp (&info->fntype)) + { + /* FIXME: This might happen someday if we support nested + functions. */ + abort (); + } + + info->fnname = name; + + /* An attribute of 0x40 means that the push mask is unknown. */ + if (! ieee_define_named_type (info, name, (unsigned int) -1, 0, FALSE, TRUE, + &info->fntype) + || ! ieee_write_number (info, 'x') + || ! ieee_write_number (info, 0x40) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, retindx)) + return FALSE; + + typeindx = ieee_pop_type (info); + + if (! ieee_init_buffer (info, &info->fnargs)) + return FALSE; + info->fnargcount = 0; + + /* If the function return value is actually a reference type, we + must add a record indicating that. */ + if (referencep) + { + unsigned int nindx; + + nindx = info->name_indx; + ++info->name_indx; + if (! ieee_change_buffer (info, &info->cxx) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, 3) + || ! ieee_write_asn (info, nindx, 'R') + || ! ieee_write_asn (info, nindx, global ? 0 : 1) + || ! ieee_write_atn65 (info, nindx, name)) + return FALSE; + } + + assert (! ieee_buffer_emptyp (&info->vars)); + if (! ieee_change_buffer (info, &info->vars)) + return FALSE; + + /* The address is written out as the first block. */ + + ++info->block_depth; + + return (ieee_write_byte (info, (int) ieee_bb_record_enum) + && ieee_write_byte (info, global ? 4 : 6) + && ieee_write_number (info, 0) + && ieee_write_id (info, name) + && ieee_write_number (info, 0) + && ieee_write_number (info, typeindx)); +} + +/* Add a function parameter. This will normally be called before the + first block, so we postpone them until we see the block. */ + +static bfd_boolean +ieee_function_parameter (p, name, kind, val) + PTR p; + const char *name; + enum debug_parm_kind kind; + bfd_vma val; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + struct ieee_pending_parm *m, **pm; + + assert (info->block_depth == 1); + + m = (struct ieee_pending_parm *) xmalloc (sizeof *m); + memset (m, 0, sizeof *m); + + m->next = NULL; + m->name = name; + m->referencep = info->type_stack->type.referencep; + m->type = ieee_pop_type (info); + m->kind = kind; + m->val = val; + + for (pm = &info->pending_parms; *pm != NULL; pm = &(*pm)->next) + ; + *pm = m; + + /* Add the type to the fnargs list. */ + if (! ieee_change_buffer (info, &info->fnargs) + || ! ieee_write_number (info, m->type)) + return FALSE; + ++info->fnargcount; + + return TRUE; +} + +/* Output pending function parameters. */ + +static bfd_boolean +ieee_output_pending_parms (info) + struct ieee_handle *info; +{ + struct ieee_pending_parm *m; + unsigned int refcount; + + refcount = 0; + for (m = info->pending_parms; m != NULL; m = m->next) + { + enum debug_var_kind vkind; + + switch (m->kind) + { + default: + abort (); + return FALSE; + case DEBUG_PARM_STACK: + case DEBUG_PARM_REFERENCE: + vkind = DEBUG_LOCAL; + break; + case DEBUG_PARM_REG: + case DEBUG_PARM_REF_REG: + vkind = DEBUG_REGISTER; + break; + } + + if (! ieee_push_type (info, m->type, 0, FALSE, FALSE)) + return FALSE; + info->type_stack->type.referencep = m->referencep; + if (m->referencep) + ++refcount; + if (! ieee_variable ((PTR) info, m->name, vkind, m->val)) + return FALSE; + } + + /* If there are any reference parameters, we need to output a + miscellaneous record indicating them. */ + if (refcount > 0) + { + unsigned int nindx, varindx; + + /* FIXME: The MRI compiler outputs the demangled function name + here, but we are outputting the mangled name. */ + nindx = info->name_indx; + ++info->name_indx; + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, nindx) + || ! ieee_write_id (info, "") + || ! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, nindx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 62) + || ! ieee_write_number (info, 80) + || ! ieee_write_number (info, refcount + 3) + || ! ieee_write_asn (info, nindx, 'B') + || ! ieee_write_atn65 (info, nindx, info->fnname) + || ! ieee_write_asn (info, nindx, 0)) + return FALSE; + for (m = info->pending_parms, varindx = 1; + m != NULL; + m = m->next, varindx++) + { + if (m->referencep) + { + if (! ieee_write_asn (info, nindx, varindx)) + return FALSE; + } + } + } + + m = info->pending_parms; + while (m != NULL) + { + struct ieee_pending_parm *next; + + next = m->next; + free (m); + m = next; + } + + info->pending_parms = NULL; + + return TRUE; +} + +/* Start a block. If this is the first block, we output the address + to finish the BB4 or BB6, and then output the function parameters. */ + +static bfd_boolean +ieee_start_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + if (! ieee_change_buffer (info, &info->vars)) + return FALSE; + + if (info->block_depth == 1) + { + if (! ieee_write_number (info, addr) + || ! ieee_output_pending_parms (info)) + return FALSE; + } + else + { + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 6) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, "") + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, addr)) + return FALSE; + } + + if (! ieee_start_range (info, addr)) + return FALSE; + + ++info->block_depth; + + return TRUE; +} + +/* End a block. */ + +static bfd_boolean +ieee_end_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + /* The address we are given is the end of the block, but IEEE seems + to want to the address of the last byte in the block, so we + subtract one. */ + if (! ieee_change_buffer (info, &info->vars) + || ! ieee_write_byte (info, (int) ieee_be_record_enum) + || ! ieee_write_number (info, addr - 1)) + return FALSE; + + if (! ieee_end_range (info, addr)) + return FALSE; + + --info->block_depth; + + if (addr > info->highaddr) + info->highaddr = addr; + + return TRUE; +} + +/* End a function. */ + +static bfd_boolean +ieee_end_function (p) + PTR p; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + assert (info->block_depth == 1); + + --info->block_depth; + + /* Now we can finish up fntype, and add it to the typdef section. + At this point, fntype is the 'x' type up to the argument count, + and fnargs is the argument types. We must add the argument + count, and we must add the level. FIXME: We don't record varargs + functions correctly. In fact, stabs debugging does not give us + enough information to do so. */ + if (! ieee_change_buffer (info, &info->fntype) + || ! ieee_write_number (info, info->fnargcount) + || ! ieee_change_buffer (info, &info->fnargs) + || ! ieee_write_number (info, 0)) + return FALSE; + + /* Make sure the typdef block has been started. */ + if (ieee_buffer_emptyp (&info->types)) + { + if (! ieee_change_buffer (info, &info->types) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 1) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->modname)) + return FALSE; + } + + if (! ieee_append_buffer (info, &info->types, &info->fntype) + || ! ieee_append_buffer (info, &info->types, &info->fnargs)) + return FALSE; + + info->fnname = NULL; + if (! ieee_init_buffer (info, &info->fntype) + || ! ieee_init_buffer (info, &info->fnargs)) + return FALSE; + info->fnargcount = 0; + + return TRUE; +} + +/* Record line number information. */ + +static bfd_boolean +ieee_lineno (p, filename, lineno, addr) + PTR p; + const char *filename; + unsigned long lineno; + bfd_vma addr; +{ + struct ieee_handle *info = (struct ieee_handle *) p; + + assert (info->filename != NULL); + + /* The HP simulator seems to get confused when more than one line is + listed for the same address, at least if they are in different + files. We handle this by always listing the last line for a + given address, since that seems to be the one that gdb uses. */ + if (info->pending_lineno_filename != NULL + && addr != info->pending_lineno_addr) + { + /* Make sure we have a line number block. */ + if (! ieee_buffer_emptyp (&info->linenos)) + { + if (! ieee_change_buffer (info, &info->linenos)) + return FALSE; + } + else + { + info->lineno_name_indx = info->name_indx; + ++info->name_indx; + if (! ieee_change_buffer (info, &info->linenos) + || ! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 5) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->filename) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, info->lineno_name_indx) + || ! ieee_write_id (info, "")) + return FALSE; + info->lineno_filename = info->filename; + } + + if (strcmp (info->pending_lineno_filename, info->lineno_filename) != 0) + { + if (strcmp (info->filename, info->lineno_filename) != 0) + { + /* We were not in the main file. Close the block for the + included file. */ + if (! ieee_write_byte (info, (int) ieee_be_record_enum)) + return FALSE; + if (strcmp (info->filename, info->pending_lineno_filename) == 0) + { + /* We need a new NN record, and we aren't about to + output one. */ + info->lineno_name_indx = info->name_indx; + ++info->name_indx; + if (! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, info->lineno_name_indx) + || ! ieee_write_id (info, "")) + return FALSE; + } + } + if (strcmp (info->filename, info->pending_lineno_filename) != 0) + { + /* We are not changing to the main file. Open a block for + the new included file. */ + info->lineno_name_indx = info->name_indx; + ++info->name_indx; + if (! ieee_write_byte (info, (int) ieee_bb_record_enum) + || ! ieee_write_byte (info, 5) + || ! ieee_write_number (info, 0) + || ! ieee_write_id (info, info->pending_lineno_filename) + || ! ieee_write_byte (info, (int) ieee_nn_record) + || ! ieee_write_number (info, info->lineno_name_indx) + || ! ieee_write_id (info, "")) + return FALSE; + } + info->lineno_filename = info->pending_lineno_filename; + } + + if (! ieee_write_2bytes (info, (int) ieee_atn_record_enum) + || ! ieee_write_number (info, info->lineno_name_indx) + || ! ieee_write_number (info, 0) + || ! ieee_write_number (info, 7) + || ! ieee_write_number (info, info->pending_lineno) + || ! ieee_write_number (info, 0) + || ! ieee_write_asn (info, info->lineno_name_indx, + info->pending_lineno_addr)) + return FALSE; + } + + info->pending_lineno_filename = filename; + info->pending_lineno = lineno; + info->pending_lineno_addr = addr; + + return TRUE; +} diff --git a/contrib/binutils-2.14/binutils/is-ranlib.c b/contrib/binutils-2.14/binutils/is-ranlib.c new file mode 100644 index 0000000000..22ce3aa4ee --- /dev/null +++ b/contrib/binutils-2.14/binutils/is-ranlib.c @@ -0,0 +1,3 @@ +/* Linked with ar.o to flag that this program is 'ranlib' (not 'ar'). */ + +int is_ranlib = 1; diff --git a/contrib/binutils-2.14/binutils/is-strip.c b/contrib/binutils-2.14/binutils/is-strip.c new file mode 100644 index 0000000000..338245d08b --- /dev/null +++ b/contrib/binutils-2.14/binutils/is-strip.c @@ -0,0 +1,4 @@ +/* Linked with objcopy.o to flag that this program is 'strip' (not + 'objcopy'). */ + +int is_strip = 1; diff --git a/contrib/binutils-2.14/binutils/nm.c b/contrib/binutils-2.14/binutils/nm.c new file mode 100644 index 0000000000..8463acb1ab --- /dev/null +++ b/contrib/binutils-2.14/binutils/nm.c @@ -0,0 +1,1708 @@ +/* nm.c -- Describe symbol table of a rel file. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "bfd.h" +#include "progress.h" +#include "bucomm.h" +#include "budemang.h" +#include "getopt.h" +#include "aout/stab_gnu.h" +#include "aout/ranlib.h" +#include "demangle.h" +#include "libiberty.h" +#include "elf-bfd.h" +#include "elf/common.h" + +/* When sorting by size, we use this structure to hold the size and a + pointer to the minisymbol. */ + +struct size_sym +{ + const PTR minisym; + bfd_vma size; +}; + +/* When fetching relocs, we use this structure to pass information to + get_relocs. */ + +struct get_relocs_info +{ + asection **secs; + arelent ***relocs; + long *relcount; + asymbol **syms; +}; + +struct extended_symbol_info +{ + symbol_info *sinfo; + bfd_vma ssize; + elf_symbol_type *elfinfo; + /* FIXME: We should add more fields for Type, Line, Section. */ +}; +#define SYM_NAME(sym) (sym->sinfo->name) +#define SYM_VALUE(sym) (sym->sinfo->value) +#define SYM_TYPE(sym) (sym->sinfo->type) +#define SYM_STAB_NAME(sym) (sym->sinfo->stab_name) +#define SYM_STAB_DESC(sym) (sym->sinfo->stab_desc) +#define SYM_STAB_OTHER(sym) (sym->sinfo->stab_other) +#define SYM_SIZE(sym) \ + (sym->elfinfo ? sym->elfinfo->internal_elf_sym.st_size: sym->ssize) + +static void usage + PARAMS ((FILE *, int)); +static void set_print_radix + PARAMS ((char *)); +static void set_output_format + PARAMS ((char *)); +static void display_archive + PARAMS ((bfd *)); +static bfd_boolean display_file + PARAMS ((char *)); +static void display_rel_file + PARAMS ((bfd *, bfd *)); +static long filter_symbols + PARAMS ((bfd *, bfd_boolean, PTR, long, unsigned int)); +static long sort_symbols_by_size + PARAMS ((bfd *, bfd_boolean, PTR, long, unsigned int, struct size_sym **)); +static void print_symbols + PARAMS ((bfd *, bfd_boolean, PTR, long, unsigned int, bfd *)); +static void print_size_symbols + PARAMS ((bfd *, bfd_boolean, struct size_sym *, long, bfd *)); +static void print_symname + PARAMS ((const char *, const char *, bfd *)); +static void print_symbol + PARAMS ((bfd *, asymbol *, bfd_vma ssize, bfd *)); +static void print_symdef_entry + PARAMS ((bfd *)); + +/* The sorting functions. */ +static int numeric_forward + PARAMS ((const PTR, const PTR)); +static int numeric_reverse + PARAMS ((const PTR, const PTR)); +static int non_numeric_forward + PARAMS ((const PTR, const PTR)); +static int non_numeric_reverse + PARAMS ((const PTR, const PTR)); +static int size_forward1 + PARAMS ((const PTR, const PTR)); +static int size_forward2 + PARAMS ((const PTR, const PTR)); + +/* The output formatting functions. */ +static void print_object_filename_bsd + PARAMS ((char *)); +static void print_object_filename_sysv + PARAMS ((char *)); +static void print_object_filename_posix + PARAMS ((char *)); +static void print_archive_filename_bsd + PARAMS ((char *)); +static void print_archive_filename_sysv + PARAMS ((char *)); +static void print_archive_filename_posix + PARAMS ((char *)); +static void print_archive_member_bsd + PARAMS ((char *, const char *)); +static void print_archive_member_sysv + PARAMS ((char *, const char *)); +static void print_archive_member_posix + PARAMS ((char *, const char *)); +static void print_symbol_filename_bsd + PARAMS ((bfd *, bfd *)); +static void print_symbol_filename_sysv + PARAMS ((bfd *, bfd *)); +static void print_symbol_filename_posix + PARAMS ((bfd *, bfd *)); +static void print_value + PARAMS ((bfd *, bfd_vma)); +static void print_symbol_info_bsd + PARAMS ((struct extended_symbol_info *, bfd *)); +static void print_symbol_info_sysv + PARAMS ((struct extended_symbol_info *, bfd *)); +static void print_symbol_info_posix + PARAMS ((struct extended_symbol_info *, bfd *)); +static void get_relocs + PARAMS ((bfd *, asection *, PTR)); +static const char * get_symbol_type + PARAMS ((unsigned int)); + +/* Support for different output formats. */ +struct output_fns + { + /* Print the name of an object file given on the command line. */ + void (*print_object_filename) PARAMS ((char *)); + + /* Print the name of an archive file given on the command line. */ + void (*print_archive_filename) PARAMS ((char *)); + + /* Print the name of an archive member file. */ + void (*print_archive_member) PARAMS ((char *, const char *)); + + /* Print the name of the file (and archive, if there is one) + containing a symbol. */ + void (*print_symbol_filename) PARAMS ((bfd *, bfd *)); + + /* Print a line of information about a symbol. */ + void (*print_symbol_info) PARAMS ((struct extended_symbol_info *, bfd *)); + }; + +static struct output_fns formats[] = +{ + {print_object_filename_bsd, + print_archive_filename_bsd, + print_archive_member_bsd, + print_symbol_filename_bsd, + print_symbol_info_bsd}, + {print_object_filename_sysv, + print_archive_filename_sysv, + print_archive_member_sysv, + print_symbol_filename_sysv, + print_symbol_info_sysv}, + {print_object_filename_posix, + print_archive_filename_posix, + print_archive_member_posix, + print_symbol_filename_posix, + print_symbol_info_posix} +}; + +/* Indices in `formats'. */ +#define FORMAT_BSD 0 +#define FORMAT_SYSV 1 +#define FORMAT_POSIX 2 +#define FORMAT_DEFAULT FORMAT_BSD + +/* The output format to use. */ +static struct output_fns *format = &formats[FORMAT_DEFAULT]; + +/* Command options. */ + +static int do_demangle = 0; /* Pretty print C++ symbol names. */ +static int external_only = 0; /* Print external symbols only. */ +static int defined_only = 0; /* Print defined symbols only. */ +static int no_sort = 0; /* Don't sort; print syms in order found. */ +static int print_debug_syms = 0;/* Print debugger-only symbols too. */ +static int print_armap = 0; /* Describe __.SYMDEF data in archive files. */ +static int print_size = 0; /* Print size of defined symbols. */ +static int reverse_sort = 0; /* Sort in downward(alpha or numeric) order. */ +static int sort_numerically = 0;/* Sort in numeric rather than alpha order. */ +static int sort_by_size = 0; /* Sort by size of symbol. */ +static int undefined_only = 0; /* Print undefined symbols only. */ +static int dynamic = 0; /* Print dynamic symbols. */ +static int show_version = 0; /* Show the version number. */ +static int show_stats = 0; /* Show statistics. */ +static int line_numbers = 0; /* Print line numbers for symbols. */ + +/* When to print the names of files. Not mutually exclusive in SYSV format. */ +static int filename_per_file = 0; /* Once per file, on its own line. */ +static int filename_per_symbol = 0; /* Once per symbol, at start of line. */ + +/* Print formats for printing a symbol value. */ +#ifndef BFD64 +static char value_format[] = "%08lx"; +#else +#if BFD_HOST_64BIT_LONG +static char value_format[] = "%016lx"; +#else +/* We don't use value_format for this case. */ +#endif +#endif +#ifdef BFD64 +static int print_width = 16; +#else +static int print_width = 8; +#endif +static int print_radix = 16; +/* Print formats for printing stab info. */ +static char other_format[] = "%02x"; +static char desc_format[] = "%04x"; + +static char *target = NULL; + +/* Used to cache the line numbers for a BFD. */ +static bfd *lineno_cache_bfd; +static bfd *lineno_cache_rel_bfd; + +#define OPTION_TARGET 200 + +static struct option long_options[] = +{ + {"debug-syms", no_argument, &print_debug_syms, 1}, + {"demangle", optional_argument, 0, 'C'}, + {"dynamic", no_argument, &dynamic, 1}, + {"extern-only", no_argument, &external_only, 1}, + {"format", required_argument, 0, 'f'}, + {"help", no_argument, 0, 'h'}, + {"line-numbers", no_argument, 0, 'l'}, + {"no-cplus", no_argument, &do_demangle, 0}, /* Linux compatibility. */ + {"no-demangle", no_argument, &do_demangle, 0}, + {"no-sort", no_argument, &no_sort, 1}, + {"numeric-sort", no_argument, &sort_numerically, 1}, + {"portability", no_argument, 0, 'P'}, + {"print-armap", no_argument, &print_armap, 1}, + {"print-file-name", no_argument, 0, 'o'}, + {"print-size", no_argument, 0, 'S'}, + {"radix", required_argument, 0, 't'}, + {"reverse-sort", no_argument, &reverse_sort, 1}, + {"size-sort", no_argument, &sort_by_size, 1}, + {"stats", no_argument, &show_stats, 1}, + {"target", required_argument, 0, OPTION_TARGET}, + {"defined-only", no_argument, &defined_only, 1}, + {"undefined-only", no_argument, &undefined_only, 1}, + {"version", no_argument, &show_version, 1}, + {0, no_argument, 0, 0} +}; + +/* Some error-reporting functions. */ + +static void +usage (stream, status) + FILE *stream; + int status; +{ + fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name); + fprintf (stream, _(" List symbols in [file(s)] (a.out by default).\n")); + fprintf (stream, _(" The options are:\n\ + -a, --debug-syms Display debugger-only symbols\n\ + -A, --print-file-name Print name of the input file before every symbol\n\ + -B Same as --format=bsd\n\ + -C, --demangle[=STYLE] Decode low-level symbol names into user-level names\n\ + The STYLE, if specified, can be `auto' (the default),\n\ + `gnu', `lucid', `arm', `hp', `edg', `gnu-v3', `java'\n\ + or `gnat'\n\ + --no-demangle Do not demangle low-level symbol names\n\ + -D, --dynamic Display dynamic symbols instead of normal symbols\n\ + --defined-only Display only defined symbols\n\ + -e (ignored)\n\ + -f, --format=FORMAT Use the output format FORMAT. FORMAT can be `bsd',\n\ + `sysv' or `posix'. The default is `bsd'\n\ + -g, --extern-only Display only external symbols\n\ + -l, --line-numbers Use debugging information to find a filename and\n\ + line number for each symbol\n\ + -n, --numeric-sort Sort symbols numerically by address\n\ + -o Same as -A\n\ + -p, --no-sort Do not sort the symbols\n\ + -P, --portability Same as --format=posix\n\ + -r, --reverse-sort Reverse the sense of the sort\n\ + -S, --print-size Print size of defined symbols\n\ + -s, --print-armap Include index for symbols from archive members\n\ + --size-sort Sort symbols by size\n\ + -t, --radix=RADIX Use RADIX for printing symbol values\n\ + --target=BFDNAME Specify the target object format as BFDNAME\n\ + -u, --undefined-only Display only undefined symbols\n\ + -X 32_64 (ignored)\n\ + -h, --help Display this information\n\ + -V, --version Display this program's version number\n\ +\n")); + list_supported_targets (program_name, stream); + if (status == 0) + fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO); + exit (status); +} + +/* Set the radix for the symbol value and size according to RADIX. */ + +static void +set_print_radix (radix) + char *radix; +{ + switch (*radix) + { + case 'x': + break; + case 'd': + case 'o': + if (*radix == 'd') + print_radix = 10; + else + print_radix = 8; +#ifndef BFD64 + value_format[4] = *radix; +#else +#if BFD_HOST_64BIT_LONG + value_format[5] = *radix; +#else + /* This case requires special handling for octal and decimal + printing. */ +#endif +#endif + other_format[3] = desc_format[3] = *radix; + break; + default: + fatal (_("%s: invalid radix"), radix); + } +} + +static void +set_output_format (f) + char *f; +{ + int i; + + switch (*f) + { + case 'b': + case 'B': + i = FORMAT_BSD; + break; + case 'p': + case 'P': + i = FORMAT_POSIX; + break; + case 's': + case 'S': + i = FORMAT_SYSV; + break; + default: + fatal (_("%s: invalid output format"), f); + } + format = &formats[i]; +} + +int main PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int retval; + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); + setlocale (LC_COLLATE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = *argv; + xmalloc_set_program_name (program_name); + + START_PROGRESS (program_name, 0); + + bfd_init (); + set_default_bfd_target (); + + while ((c = getopt_long (argc, argv, "aABCDef:gHhlnopPrSst:uvVvX:", + long_options, (int *) 0)) != EOF) + { + switch (c) + { + case 'a': + print_debug_syms = 1; + break; + case 'A': + case 'o': + filename_per_symbol = 1; + break; + case 'B': /* For MIPS compatibility. */ + set_output_format ("bsd"); + break; + case 'C': + do_demangle = 1; + if (optarg != NULL) + { + enum demangling_styles style; + + style = cplus_demangle_name_to_style (optarg); + if (style == unknown_demangling) + fatal (_("unknown demangling style `%s'"), + optarg); + + cplus_demangle_set_style (style); + } + break; + case 'D': + dynamic = 1; + break; + case 'e': + /* Ignored for HP/UX compatibility. */ + break; + case 'f': + set_output_format (optarg); + break; + case 'g': + external_only = 1; + break; + case 'H': + case 'h': + usage (stdout, 0); + case 'l': + line_numbers = 1; + break; + case 'n': + case 'v': + sort_numerically = 1; + break; + case 'p': + no_sort = 1; + break; + case 'P': + set_output_format ("posix"); + break; + case 'r': + reverse_sort = 1; + break; + case 's': + print_armap = 1; + break; + case 'S': + print_size = 1; + break; + case 't': + set_print_radix (optarg); + break; + case 'u': + undefined_only = 1; + break; + case 'V': + show_version = 1; + break; + case 'X': + /* Ignored for (partial) AIX compatibility. On AIX, the + argument has values 32, 64, or 32_64, and specfies that + only 32-bit, only 64-bit, or both kinds of objects should + be examined. The default is 32. So plain AIX nm on a + library archive with both kinds of objects will ignore + the 64-bit ones. For GNU nm, the default is and always + has been -X 32_64, and other options are not supported. */ + if (strcmp (optarg, "32_64") != 0) + fatal (_("Only -X 32_64 is supported")); + break; + + case OPTION_TARGET: /* --target */ + target = optarg; + break; + + case 0: /* A long option that just sets a flag. */ + break; + + default: + usage (stderr, 1); + } + } + + if (show_version) + print_version ("nm"); + + if (sort_by_size && undefined_only) + { + non_fatal (_("Using the --size-sort and --undefined-only options together")); + non_fatal (_("will produce no output, since undefined symbols have no size.")); + return 0; + } + + /* OK, all options now parsed. If no filename specified, do a.out. */ + if (optind == argc) + return !display_file ("a.out"); + + retval = 0; + + if (argc - optind > 1) + filename_per_file = 1; + + /* We were given several filenames to do. */ + while (optind < argc) + { + PROGRESS (1); + if (!display_file (argv[optind++])) + retval++; + } + + END_PROGRESS (program_name); + +#ifdef HAVE_SBRK + if (show_stats) + { + char *lim = (char *) sbrk (0); + + non_fatal (_("data size %ld"), (long) (lim - (char *) &environ)); + } +#endif + + exit (retval); + return retval; +} + +static const char * +get_symbol_type (type) + unsigned int type; +{ + static char buff [32]; + + switch (type) + { + case STT_NOTYPE: return "NOTYPE"; + case STT_OBJECT: return "OBJECT"; + case STT_FUNC: return "FUNC"; + case STT_SECTION: return "SECTION"; + case STT_FILE: return "FILE"; + case STT_COMMON: return "COMMON"; + case STT_TLS: return "TLS"; + default: + if (type >= STT_LOPROC && type <= STT_HIPROC) + sprintf (buff, _(": %d"), type); + else if (type >= STT_LOOS && type <= STT_HIOS) + sprintf (buff, _(": %d"), type); + else + sprintf (buff, _(": %d"), type); + return buff; + } +} + +static void +display_archive (file) + bfd *file; +{ + bfd *arfile = NULL; + bfd *last_arfile = NULL; + char **matching; + + (*format->print_archive_filename) (bfd_get_filename (file)); + + if (print_armap) + print_symdef_entry (file); + + for (;;) + { + PROGRESS (1); + + arfile = bfd_openr_next_archived_file (file, arfile); + + if (arfile == NULL) + { + if (bfd_get_error () != bfd_error_no_more_archived_files) + bfd_fatal (bfd_get_filename (file)); + break; + } + + if (bfd_check_format_matches (arfile, bfd_object, &matching)) + { + char buf[30]; + + bfd_sprintf_vma (arfile, buf, (bfd_vma) -1); + print_width = strlen (buf); + (*format->print_archive_member) (bfd_get_filename (file), + bfd_get_filename (arfile)); + display_rel_file (arfile, file); + } + else + { + bfd_nonfatal (bfd_get_filename (arfile)); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } + } + + if (last_arfile != NULL) + { + bfd_close (last_arfile); + lineno_cache_bfd = NULL; + lineno_cache_rel_bfd = NULL; + } + last_arfile = arfile; + } + + if (last_arfile != NULL) + { + bfd_close (last_arfile); + lineno_cache_bfd = NULL; + lineno_cache_rel_bfd = NULL; + } +} + +static bfd_boolean +display_file (filename) + char *filename; +{ + bfd_boolean retval = TRUE; + bfd *file; + char **matching; + + file = bfd_openr (filename, target); + if (file == NULL) + { + bfd_nonfatal (filename); + return FALSE; + } + + if (bfd_check_format (file, bfd_archive)) + { + display_archive (file); + } + else if (bfd_check_format_matches (file, bfd_object, &matching)) + { + char buf[30]; + + bfd_sprintf_vma (file, buf, (bfd_vma) -1); + print_width = strlen (buf); + (*format->print_object_filename) (filename); + display_rel_file (file, NULL); + } + else + { + bfd_nonfatal (filename); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } + retval = FALSE; + } + + if (!bfd_close (file)) + bfd_fatal (filename); + + lineno_cache_bfd = NULL; + lineno_cache_rel_bfd = NULL; + + return retval; +} + +/* These globals are used to pass information into the sorting + routines. */ +static bfd *sort_bfd; +static bfd_boolean sort_dynamic; +static asymbol *sort_x; +static asymbol *sort_y; + +/* Symbol-sorting predicates */ +#define valueof(x) ((x)->section->vma + (x)->value) + +/* Numeric sorts. Undefined symbols are always considered "less than" + defined symbols with zero values. Common symbols are not treated + specially -- i.e., their sizes are used as their "values". */ + +static int +numeric_forward (P_x, P_y) + const PTR P_x; + const PTR P_y; +{ + asymbol *x, *y; + asection *xs, *ys; + + x = bfd_minisymbol_to_symbol (sort_bfd, sort_dynamic, P_x, sort_x); + y = bfd_minisymbol_to_symbol (sort_bfd, sort_dynamic, P_y, sort_y); + if (x == NULL || y == NULL) + bfd_fatal (bfd_get_filename (sort_bfd)); + + xs = bfd_get_section (x); + ys = bfd_get_section (y); + + if (bfd_is_und_section (xs)) + { + if (! bfd_is_und_section (ys)) + return -1; + } + else if (bfd_is_und_section (ys)) + return 1; + else if (valueof (x) != valueof (y)) + return valueof (x) < valueof (y) ? -1 : 1; + + return non_numeric_forward (P_x, P_y); +} + +static int +numeric_reverse (x, y) + const PTR x; + const PTR y; +{ + return - numeric_forward (x, y); +} + +static int +non_numeric_forward (P_x, P_y) + const PTR P_x; + const PTR P_y; +{ + asymbol *x, *y; + const char *xn, *yn; + + x = bfd_minisymbol_to_symbol (sort_bfd, sort_dynamic, P_x, sort_x); + y = bfd_minisymbol_to_symbol (sort_bfd, sort_dynamic, P_y, sort_y); + if (x == NULL || y == NULL) + bfd_fatal (bfd_get_filename (sort_bfd)); + + xn = bfd_asymbol_name (x); + yn = bfd_asymbol_name (y); + + if (yn == NULL) + return xn != NULL; + if (xn == NULL) + return -1; + +#ifdef HAVE_STRCOLL + /* Solaris 2.5 has a bug in strcoll. + strcoll returns invalid values when confronted with empty strings. */ + if (*yn == '\0') + return *xn != '\0'; + if (*xn == '\0') + return -1; + + return strcoll (xn, yn); +#else + return strcmp (xn, yn); +#endif +} + +static int +non_numeric_reverse (x, y) + const PTR x; + const PTR y; +{ + return - non_numeric_forward (x, y); +} + +static int (*(sorters[2][2])) PARAMS ((const PTR, const PTR)) = +{ + { non_numeric_forward, non_numeric_reverse }, + { numeric_forward, numeric_reverse } +}; + +/* This sort routine is used by sort_symbols_by_size. It is similar + to numeric_forward, but when symbols have the same value it sorts + by section VMA. This simplifies the sort_symbols_by_size code + which handles symbols at the end of sections. Also, this routine + tries to sort file names before other symbols with the same value. + That will make the file name have a zero size, which will make + sort_symbols_by_size choose the non file name symbol, leading to + more meaningful output. For similar reasons, this code sorts + gnu_compiled_* and gcc2_compiled before other symbols with the same + value. */ + +static int +size_forward1 (P_x, P_y) + const PTR P_x; + const PTR P_y; +{ + asymbol *x, *y; + asection *xs, *ys; + const char *xn, *yn; + size_t xnl, ynl; + int xf, yf; + + x = bfd_minisymbol_to_symbol (sort_bfd, sort_dynamic, P_x, sort_x); + y = bfd_minisymbol_to_symbol (sort_bfd, sort_dynamic, P_y, sort_y); + if (x == NULL || y == NULL) + bfd_fatal (bfd_get_filename (sort_bfd)); + + xs = bfd_get_section (x); + ys = bfd_get_section (y); + + if (bfd_is_und_section (xs)) + abort (); + if (bfd_is_und_section (ys)) + abort (); + + if (valueof (x) != valueof (y)) + return valueof (x) < valueof (y) ? -1 : 1; + + if (xs->vma != ys->vma) + return xs->vma < ys->vma ? -1 : 1; + + xn = bfd_asymbol_name (x); + yn = bfd_asymbol_name (y); + xnl = strlen (xn); + ynl = strlen (yn); + + /* The symbols gnu_compiled and gcc2_compiled convey even less + information than the file name, so sort them out first. */ + + xf = (strstr (xn, "gnu_compiled") != NULL + || strstr (xn, "gcc2_compiled") != NULL); + yf = (strstr (yn, "gnu_compiled") != NULL + || strstr (yn, "gcc2_compiled") != NULL); + + if (xf && ! yf) + return -1; + if (! xf && yf) + return 1; + + /* We use a heuristic for the file name. It may not work on non + Unix systems, but it doesn't really matter; the only difference + is precisely which symbol names get printed. */ + +#define file_symbol(s, sn, snl) \ + (((s)->flags & BSF_FILE) != 0 \ + || ((sn)[(snl) - 2] == '.' \ + && ((sn)[(snl) - 1] == 'o' \ + || (sn)[(snl) - 1] == 'a'))) + + xf = file_symbol (x, xn, xnl); + yf = file_symbol (y, yn, ynl); + + if (xf && ! yf) + return -1; + if (! xf && yf) + return 1; + + return non_numeric_forward (P_x, P_y); +} + +/* This sort routine is used by sort_symbols_by_size. It is sorting + an array of size_sym structures into size order. */ + +static int +size_forward2 (P_x, P_y) + const PTR P_x; + const PTR P_y; +{ + const struct size_sym *x = (const struct size_sym *) P_x; + const struct size_sym *y = (const struct size_sym *) P_y; + + if (x->size < y->size) + return reverse_sort ? 1 : -1; + else if (x->size > y->size) + return reverse_sort ? -1 : 1; + else + return sorters[0][reverse_sort] (x->minisym, y->minisym); +} + +/* Sort the symbols by size. ELF provides a size but for other formats + we have to make a guess by assuming that the difference between the + address of a symbol and the address of the next higher symbol is the + size. */ + +static long +sort_symbols_by_size (abfd, dynamic, minisyms, symcount, size, symsizesp) + bfd *abfd; + bfd_boolean dynamic; + PTR minisyms; + long symcount; + unsigned int size; + struct size_sym **symsizesp; +{ + struct size_sym *symsizes; + bfd_byte *from, *fromend; + asymbol *sym = NULL; + asymbol *store_sym, *store_next; + + qsort (minisyms, symcount, size, size_forward1); + + /* We are going to return a special set of symbols and sizes to + print. */ + symsizes = (struct size_sym *) xmalloc (symcount * sizeof (struct size_sym)); + *symsizesp = symsizes; + + /* Note that filter_symbols has already removed all absolute and + undefined symbols. Here we remove all symbols whose size winds + up as zero. */ + from = (bfd_byte *) minisyms; + fromend = from + symcount * size; + + store_sym = sort_x; + store_next = sort_y; + + if (from < fromend) + { + sym = bfd_minisymbol_to_symbol (abfd, dynamic, (const PTR) from, + store_sym); + if (sym == NULL) + bfd_fatal (bfd_get_filename (abfd)); + } + + for (; from < fromend; from += size) + { + asymbol *next; + asection *sec; + bfd_vma sz; + asymbol *temp; + + if (from + size < fromend) + { + next = bfd_minisymbol_to_symbol (abfd, + dynamic, + (const PTR) (from + size), + store_next); + if (next == NULL) + bfd_fatal (bfd_get_filename (abfd)); + } + else + next = NULL; + + sec = bfd_get_section (sym); + + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + sz = ((elf_symbol_type *) sym)->internal_elf_sym.st_size; + else if (bfd_is_com_section (sec)) + sz = sym->value; + else + { + if (from + size < fromend + && sec == bfd_get_section (next)) + sz = valueof (next) - valueof (sym); + else + sz = (bfd_get_section_vma (abfd, sec) + + bfd_section_size (abfd, sec) + - valueof (sym)); + } + + if (sz != 0) + { + symsizes->minisym = (const PTR) from; + symsizes->size = sz; + ++symsizes; + } + + sym = next; + + temp = store_sym; + store_sym = store_next; + store_next = temp; + } + + symcount = symsizes - *symsizesp; + + /* We must now sort again by size. */ + qsort ((PTR) *symsizesp, symcount, sizeof (struct size_sym), size_forward2); + + return symcount; +} + +/* If ARCHIVE_BFD is non-NULL, it is the archive containing ABFD. */ + +static void +display_rel_file (abfd, archive_bfd) + bfd *abfd; + bfd *archive_bfd; +{ + long symcount; + PTR minisyms; + unsigned int size; + struct size_sym *symsizes; + + if (! dynamic) + { + if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) + { + non_fatal (_("%s: no symbols"), bfd_get_filename (abfd)); + return; + } + } + + symcount = bfd_read_minisymbols (abfd, dynamic, &minisyms, &size); + if (symcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + + if (symcount == 0) + { + non_fatal (_("%s: no symbols"), bfd_get_filename (abfd)); + return; + } + + /* Discard the symbols we don't want to print. + It's OK to do this in place; we'll free the storage anyway + (after printing). */ + + symcount = filter_symbols (abfd, dynamic, minisyms, symcount, size); + + symsizes = NULL; + if (! no_sort) + { + sort_bfd = abfd; + sort_dynamic = dynamic; + sort_x = bfd_make_empty_symbol (abfd); + sort_y = bfd_make_empty_symbol (abfd); + if (sort_x == NULL || sort_y == NULL) + bfd_fatal (bfd_get_filename (abfd)); + + if (! sort_by_size) + qsort (minisyms, symcount, size, + sorters[sort_numerically][reverse_sort]); + else + symcount = sort_symbols_by_size (abfd, dynamic, minisyms, symcount, + size, &symsizes); + } + + if (! sort_by_size) + print_symbols (abfd, dynamic, minisyms, symcount, size, archive_bfd); + else + print_size_symbols (abfd, dynamic, symsizes, symcount, archive_bfd); + + free (minisyms); +} + +/* Choose which symbol entries to print; + compact them downward to get rid of the rest. + Return the number of symbols to be printed. */ + +static long +filter_symbols (abfd, dynamic, minisyms, symcount, size) + bfd *abfd; + bfd_boolean dynamic; + PTR minisyms; + long symcount; + unsigned int size; +{ + bfd_byte *from, *fromend, *to; + asymbol *store; + + store = bfd_make_empty_symbol (abfd); + if (store == NULL) + bfd_fatal (bfd_get_filename (abfd)); + + from = (bfd_byte *) minisyms; + fromend = from + symcount * size; + to = (bfd_byte *) minisyms; + + for (; from < fromend; from += size) + { + int keep = 0; + asymbol *sym; + + PROGRESS (1); + + sym = bfd_minisymbol_to_symbol (abfd, dynamic, (const PTR) from, store); + if (sym == NULL) + bfd_fatal (bfd_get_filename (abfd)); + + if (undefined_only) + keep = bfd_is_und_section (sym->section); + else if (external_only) + keep = ((sym->flags & BSF_GLOBAL) != 0 + || (sym->flags & BSF_WEAK) != 0 + || bfd_is_und_section (sym->section) + || bfd_is_com_section (sym->section)); + else + keep = 1; + + if (keep + && ! print_debug_syms + && (sym->flags & BSF_DEBUGGING) != 0) + keep = 0; + + if (keep + && sort_by_size + && (bfd_is_abs_section (sym->section) + || bfd_is_und_section (sym->section))) + keep = 0; + + if (keep + && defined_only) + { + if (bfd_is_und_section (sym->section)) + keep = 0; + } + + if (keep) + { + memcpy (to, from, size); + to += size; + } + } + + return (to - (bfd_byte *) minisyms) / size; +} + +/* Print symbol name NAME, read from ABFD, with printf format FORMAT, + demangling it if requested. */ + +static void +print_symname (format, name, abfd) + const char *format; + const char *name; + bfd *abfd; +{ + if (do_demangle && *name) + { + char *res = demangle (abfd, name); + + printf (format, res); + free (res); + return; + } + + printf (format, name); +} + +/* Print the symbols. If ARCHIVE_BFD is non-NULL, it is the archive + containing ABFD. */ + +static void +print_symbols (abfd, dynamic, minisyms, symcount, size, archive_bfd) + bfd *abfd; + bfd_boolean dynamic; + PTR minisyms; + long symcount; + unsigned int size; + bfd *archive_bfd; +{ + asymbol *store; + bfd_byte *from, *fromend; + + store = bfd_make_empty_symbol (abfd); + if (store == NULL) + bfd_fatal (bfd_get_filename (abfd)); + + from = (bfd_byte *) minisyms; + fromend = from + symcount * size; + for (; from < fromend; from += size) + { + asymbol *sym; + + sym = bfd_minisymbol_to_symbol (abfd, dynamic, from, store); + if (sym == NULL) + bfd_fatal (bfd_get_filename (abfd)); + + print_symbol (abfd, sym, (bfd_vma) 0, archive_bfd); + } +} + +/* Print the symbols when sorting by size. */ + +static void +print_size_symbols (abfd, dynamic, symsizes, symcount, archive_bfd) + bfd *abfd; + bfd_boolean dynamic; + struct size_sym *symsizes; + long symcount; + bfd *archive_bfd; +{ + asymbol *store; + struct size_sym *from, *fromend; + + store = bfd_make_empty_symbol (abfd); + if (store == NULL) + bfd_fatal (bfd_get_filename (abfd)); + + from = symsizes; + fromend = from + symcount; + for (; from < fromend; from++) + { + asymbol *sym; + bfd_vma ssize; + + sym = bfd_minisymbol_to_symbol (abfd, dynamic, from->minisym, store); + if (sym == NULL) + bfd_fatal (bfd_get_filename (abfd)); + + /* For elf we have already computed the correct symbol size. */ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + ssize = from->size; + else + ssize = from->size - bfd_section_vma (abfd, bfd_get_section (sym)); + + print_symbol (abfd, sym, ssize, archive_bfd); + } +} + +/* Print a single symbol. */ + +static void +print_symbol (abfd, sym, ssize, archive_bfd) + bfd *abfd; + asymbol *sym; + bfd_vma ssize; + bfd *archive_bfd; +{ + symbol_info syminfo; + struct extended_symbol_info info; + + PROGRESS (1); + + (*format->print_symbol_filename) (archive_bfd, abfd); + + bfd_get_symbol_info (abfd, sym, &syminfo); + info.sinfo = &syminfo; + info.ssize = ssize; + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + info.elfinfo = (elf_symbol_type *) sym; + else + info.elfinfo = NULL; + (*format->print_symbol_info) (&info, abfd); + + if (line_numbers) + { + static asymbol **syms; + static long symcount; + const char *filename, *functionname; + unsigned int lineno; + + /* We need to get the canonical symbols in order to call + bfd_find_nearest_line. This is inefficient, but, then, you + don't have to use --line-numbers. */ + if (abfd != lineno_cache_bfd && syms != NULL) + { + free (syms); + syms = NULL; + } + if (syms == NULL) + { + long symsize; + + symsize = bfd_get_symtab_upper_bound (abfd); + if (symsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + syms = (asymbol **) xmalloc (symsize); + symcount = bfd_canonicalize_symtab (abfd, syms); + if (symcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + lineno_cache_bfd = abfd; + } + + if (bfd_is_und_section (bfd_get_section (sym))) + { + static asection **secs; + static arelent ***relocs; + static long *relcount; + static unsigned int seccount; + unsigned int i; + const char *symname; + + /* For an undefined symbol, we try to find a reloc for the + symbol, and print the line number of the reloc. */ + if (abfd != lineno_cache_rel_bfd && relocs != NULL) + { + for (i = 0; i < seccount; i++) + if (relocs[i] != NULL) + free (relocs[i]); + free (secs); + free (relocs); + free (relcount); + secs = NULL; + relocs = NULL; + relcount = NULL; + } + + if (relocs == NULL) + { + struct get_relocs_info info; + + seccount = bfd_count_sections (abfd); + + secs = (asection **) xmalloc (seccount * sizeof *secs); + relocs = (arelent ***) xmalloc (seccount * sizeof *relocs); + relcount = (long *) xmalloc (seccount * sizeof *relcount); + + info.secs = secs; + info.relocs = relocs; + info.relcount = relcount; + info.syms = syms; + bfd_map_over_sections (abfd, get_relocs, (PTR) &info); + lineno_cache_rel_bfd = abfd; + } + + symname = bfd_asymbol_name (sym); + for (i = 0; i < seccount; i++) + { + long j; + + for (j = 0; j < relcount[i]; j++) + { + arelent *r; + + r = relocs[i][j]; + if (r->sym_ptr_ptr != NULL + && (*r->sym_ptr_ptr)->section == sym->section + && (*r->sym_ptr_ptr)->value == sym->value + && strcmp (symname, + bfd_asymbol_name (*r->sym_ptr_ptr)) == 0 + && bfd_find_nearest_line (abfd, secs[i], syms, + r->address, &filename, + &functionname, &lineno) + && filename != NULL) + { + /* We only print the first one we find. */ + printf ("\t%s:%u", filename, lineno); + i = seccount; + break; + } + } + } + } + else if (bfd_get_section (sym)->owner == abfd) + { + if (bfd_find_nearest_line (abfd, bfd_get_section (sym), syms, + sym->value, &filename, &functionname, + &lineno) + && filename != NULL + && lineno != 0) + { + printf ("\t%s:%u", filename, lineno); + } + } + } + + putchar ('\n'); +} + +/* The following 3 groups of functions are called unconditionally, + once at the start of processing each file of the appropriate type. + They should check `filename_per_file' and `filename_per_symbol', + as appropriate for their output format, to determine whether to + print anything. */ + +/* Print the name of an object file given on the command line. */ + +static void +print_object_filename_bsd (filename) + char *filename; +{ + if (filename_per_file && !filename_per_symbol) + printf ("\n%s:\n", filename); +} + +static void +print_object_filename_sysv (filename) + char *filename; +{ + if (undefined_only) + printf (_("\n\nUndefined symbols from %s:\n\n"), filename); + else + printf (_("\n\nSymbols from %s:\n\n"), filename); + if (print_width == 8) + printf (_("\ +Name Value Class Type Size Line Section\n\n")); + else + printf (_("\ +Name Value Class Type Size Line Section\n\n")); +} + +static void +print_object_filename_posix (filename) + char *filename; +{ + if (filename_per_file && !filename_per_symbol) + printf ("%s:\n", filename); +} + +/* Print the name of an archive file given on the command line. */ + +static void +print_archive_filename_bsd (filename) + char *filename; +{ + if (filename_per_file) + printf ("\n%s:\n", filename); +} + +static void +print_archive_filename_sysv (filename) + char *filename ATTRIBUTE_UNUSED; +{ +} + +static void +print_archive_filename_posix (filename) + char *filename ATTRIBUTE_UNUSED; +{ +} + +/* Print the name of an archive member file. */ + +static void +print_archive_member_bsd (archive, filename) + char *archive ATTRIBUTE_UNUSED; + const char *filename; +{ + if (!filename_per_symbol) + printf ("\n%s:\n", filename); +} + +static void +print_archive_member_sysv (archive, filename) + char *archive; + const char *filename; +{ + if (undefined_only) + printf (_("\n\nUndefined symbols from %s[%s]:\n\n"), archive, filename); + else + printf (_("\n\nSymbols from %s[%s]:\n\n"), archive, filename); + if (print_width == 8) + printf (_("\ +Name Value Class Type Size Line Section\n\n")); + else + printf (_("\ +Name Value Class Type Size Line Section\n\n")); +} + +static void +print_archive_member_posix (archive, filename) + char *archive; + const char *filename; +{ + if (!filename_per_symbol) + printf ("%s[%s]:\n", archive, filename); +} + +/* Print the name of the file (and archive, if there is one) + containing a symbol. */ + +static void +print_symbol_filename_bsd (archive_bfd, abfd) + bfd *archive_bfd, *abfd; +{ + if (filename_per_symbol) + { + if (archive_bfd) + printf ("%s:", bfd_get_filename (archive_bfd)); + printf ("%s:", bfd_get_filename (abfd)); + } +} + +static void +print_symbol_filename_sysv (archive_bfd, abfd) + bfd *archive_bfd, *abfd; +{ + if (filename_per_symbol) + { + if (archive_bfd) + printf ("%s:", bfd_get_filename (archive_bfd)); + printf ("%s:", bfd_get_filename (abfd)); + } +} + +static void +print_symbol_filename_posix (archive_bfd, abfd) + bfd *archive_bfd, *abfd; +{ + if (filename_per_symbol) + { + if (archive_bfd) + printf ("%s[%s]: ", bfd_get_filename (archive_bfd), + bfd_get_filename (abfd)); + else + printf ("%s: ", bfd_get_filename (abfd)); + } +} + +/* Print a symbol value. */ + +static void +print_value (abfd, val) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_vma val; +{ +#if ! defined (BFD64) || BFD_HOST_64BIT_LONG + printf (value_format, val); +#else + /* We have a 64 bit value to print, but the host is only 32 bit. */ + if (print_radix == 16) + bfd_fprintf_vma (abfd, stdout, val); + else + { + char buf[30]; + char *s; + + s = buf + sizeof buf; + *--s = '\0'; + while (val > 0) + { + *--s = (val % print_radix) + '0'; + val /= print_radix; + } + while ((buf + sizeof buf - 1) - s < 16) + *--s = '0'; + printf ("%s", s); + } +#endif +} + +/* Print a line of information about a symbol. */ + +static void +print_symbol_info_bsd (info, abfd) + struct extended_symbol_info *info; + bfd *abfd; +{ + if (bfd_is_undefined_symclass (SYM_TYPE (info))) + { + if (print_width == 16) + printf (" "); + printf (" "); + } + else + { + /* Normally we print the value of the symbol. If we are printing the + size or sorting by size then we print its size, execpt for the + (weird) special case where both flags are defined, in which case we + print both values. This conforms to documented behaviour. */ + if (sort_by_size && !print_size) + print_value (abfd, SYM_SIZE (info)); + else + print_value (abfd, SYM_VALUE (info)); + + if (print_size && SYM_SIZE (info)) + { + printf (" "); + print_value (abfd, SYM_SIZE (info)); + } + } + + printf (" %c", SYM_TYPE (info)); + + if (SYM_TYPE (info) == '-') + { + /* A stab. */ + printf (" "); + printf (other_format, SYM_STAB_OTHER (info)); + printf (" "); + printf (desc_format, SYM_STAB_DESC (info)); + printf (" %5s", SYM_STAB_NAME (info)); + } + print_symname (" %s", SYM_NAME (info), abfd); +} + +static void +print_symbol_info_sysv (info, abfd) + struct extended_symbol_info *info; + bfd *abfd; +{ + print_symname ("%-20s|", SYM_NAME (info), abfd); + + if (bfd_is_undefined_symclass (SYM_TYPE (info))) + { + if (print_width == 8) + printf (" "); + else + printf (" "); + } + else + print_value (abfd, SYM_VALUE (info)); + + printf ("| %c |", SYM_TYPE (info)); + + if (SYM_TYPE (info) == '-') + { + /* A stab. */ + printf ("%18s| ", SYM_STAB_NAME (info)); /* (C) Type. */ + printf (desc_format, SYM_STAB_DESC (info)); /* Size. */ + printf ("| |"); /* Line, Section. */ + } + else + { + /* Type, Size, Line, Section */ + if (info->elfinfo) + printf ("%18s|", + get_symbol_type (ELF_ST_TYPE (info->elfinfo->internal_elf_sym.st_info))); + else + printf (" |"); + + if (SYM_SIZE (info)) + print_value (abfd, SYM_SIZE (info)); + else + { + if (print_width == 8) + printf (" "); + else + printf (" "); + } + + if (info->elfinfo) + printf("| |%s", info->elfinfo->symbol.section->name); + else + printf("| |"); + } +} + +static void +print_symbol_info_posix (info, abfd) + struct extended_symbol_info *info; + bfd *abfd; +{ + print_symname ("%s ", SYM_NAME (info), abfd); + printf ("%c ", SYM_TYPE (info)); + + if (bfd_is_undefined_symclass (SYM_TYPE (info))) + printf (" "); + else + { + print_value (abfd, SYM_VALUE (info)); + printf (" "); + if (SYM_SIZE (info)) + print_value (abfd, SYM_SIZE (info)); + } +} + +static void +print_symdef_entry (abfd) + bfd *abfd; +{ + symindex idx = BFD_NO_MORE_SYMBOLS; + carsym *thesym; + bfd_boolean everprinted = FALSE; + + for (idx = bfd_get_next_mapent (abfd, idx, &thesym); + idx != BFD_NO_MORE_SYMBOLS; + idx = bfd_get_next_mapent (abfd, idx, &thesym)) + { + bfd *elt; + if (!everprinted) + { + printf (_("\nArchive index:\n")); + everprinted = TRUE; + } + elt = bfd_get_elt_at_index (abfd, idx); + if (elt == NULL) + bfd_fatal ("bfd_get_elt_at_index"); + if (thesym->name != (char *) NULL) + { + print_symname ("%s", thesym->name, abfd); + printf (" in %s\n", bfd_get_filename (elt)); + } + } +} + +/* This function is used to get the relocs for a particular section. + It is called via bfd_map_over_sections. */ + +static void +get_relocs (abfd, sec, dataarg) + bfd *abfd; + asection *sec; + PTR dataarg; +{ + struct get_relocs_info *data = (struct get_relocs_info *) dataarg; + + *data->secs = sec; + + if ((sec->flags & SEC_RELOC) == 0) + { + *data->relocs = NULL; + *data->relcount = 0; + } + else + { + long relsize; + + relsize = bfd_get_reloc_upper_bound (abfd, sec); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + *data->relocs = (arelent **) xmalloc (relsize); + *data->relcount = bfd_canonicalize_reloc (abfd, sec, *data->relocs, + data->syms); + if (*data->relcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + } + + ++data->secs; + ++data->relocs; + ++data->relcount; +} diff --git a/contrib/binutils-2.14/binutils/not-ranlib.c b/contrib/binutils-2.14/binutils/not-ranlib.c new file mode 100644 index 0000000000..6e61331b78 --- /dev/null +++ b/contrib/binutils-2.14/binutils/not-ranlib.c @@ -0,0 +1,3 @@ +/* Linked with ar.o to flag that this program is 'ar' (not 'ranlib'). */ + +int is_ranlib = 0; diff --git a/contrib/binutils-2.14/binutils/not-strip.c b/contrib/binutils-2.14/binutils/not-strip.c new file mode 100644 index 0000000000..854a6697ad --- /dev/null +++ b/contrib/binutils-2.14/binutils/not-strip.c @@ -0,0 +1,4 @@ +/* Linked with objcopy.o to flag that this program is 'objcopy' (not + 'strip'). */ + +int is_strip = 0; diff --git a/contrib/binutils-2.14/binutils/objcopy.c b/contrib/binutils-2.14/binutils/objcopy.c new file mode 100644 index 0000000000..27c844fbb7 --- /dev/null +++ b/contrib/binutils-2.14/binutils/objcopy.c @@ -0,0 +1,2850 @@ +/* objcopy.c -- copy object file from input to output, optionally massaging it. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "bfd.h" +#include "progress.h" +#include "bucomm.h" +#include "getopt.h" +#include "libiberty.h" +#include "budbg.h" +#include "filenames.h" +#include + +/* A list of symbols to explicitly strip out, or to keep. A linked + list is good enough for a small number from the command line, but + this will slow things down a lot if many symbols are being + deleted. */ + +struct symlist +{ + const char *name; + struct symlist *next; +}; + +/* A list to support redefine_sym. */ +struct redefine_node +{ + char *source; + char *target; + struct redefine_node *next; +}; + +typedef struct section_rename +{ + const char * old_name; + const char * new_name; + flagword flags; + struct section_rename * next; +} +section_rename; + +/* List of sections to be renamed. */ +static section_rename * section_rename_list; + +static void copy_usage + PARAMS ((FILE *, int)); +static void strip_usage + PARAMS ((FILE *, int)); +static flagword parse_flags + PARAMS ((const char *)); +static struct section_list *find_section_list + PARAMS ((const char *, bfd_boolean)); +static void setup_section + PARAMS ((bfd *, asection *, PTR)); +static void copy_section + PARAMS ((bfd *, asection *, PTR)); +static void get_sections + PARAMS ((bfd *, asection *, PTR)); +static int compare_section_lma + PARAMS ((const PTR, const PTR)); +static void add_specific_symbol + PARAMS ((const char *, struct symlist **)); +static void add_specific_symbols + PARAMS ((const char *, struct symlist **)); +static bfd_boolean is_specified_symbol + PARAMS ((const char *, struct symlist *)); +static bfd_boolean is_strip_section + PARAMS ((bfd *, asection *)); +static unsigned int filter_symbols + PARAMS ((bfd *, bfd *, asymbol **, asymbol **, long)); +static void mark_symbols_used_in_relocations + PARAMS ((bfd *, asection *, PTR)); +static void filter_bytes + PARAMS ((char *, bfd_size_type *)); +static bfd_boolean write_debugging_info + PARAMS ((bfd *, PTR, long *, asymbol ***)); +static void copy_object + PARAMS ((bfd *, bfd *)); +static void copy_archive + PARAMS ((bfd *, bfd *, const char *)); +static void copy_file + PARAMS ((const char *, const char *, const char *, const char *)); +static int strip_main + PARAMS ((int, char **)); +static int copy_main + PARAMS ((int, char **)); +static const char *lookup_sym_redefinition + PARAMS((const char *)); +static void redefine_list_append + PARAMS ((const char *, const char *)); +static const char * find_section_rename + PARAMS ((bfd *, sec_ptr, flagword *)); +static void add_section_rename + PARAMS ((const char *, const char *, flagword)); + +#define RETURN_NONFATAL(s) {bfd_nonfatal (s); status = 1; return;} + +static asymbol **isympp = NULL; /* Input symbols */ +static asymbol **osympp = NULL; /* Output symbols that survive stripping */ + +/* If `copy_byte' >= 0, copy only that byte of every `interleave' bytes. */ +static int copy_byte = -1; +static int interleave = 4; + +static bfd_boolean verbose; /* Print file and target names. */ +static bfd_boolean preserve_dates; /* Preserve input file timestamp. */ +static int status = 0; /* Exit status. */ + +enum strip_action + { + STRIP_UNDEF, + STRIP_NONE, /* don't strip */ + STRIP_DEBUG, /* strip all debugger symbols */ + STRIP_UNNEEDED, /* strip unnecessary symbols */ + STRIP_ALL /* strip all symbols */ + }; + +/* Which symbols to remove. */ +static enum strip_action strip_symbols; + +enum locals_action + { + LOCALS_UNDEF, + LOCALS_START_L, /* discard locals starting with L */ + LOCALS_ALL /* discard all locals */ + }; + +/* Which local symbols to remove. Overrides STRIP_ALL. */ +static enum locals_action discard_locals; + +/* What kind of change to perform. */ +enum change_action +{ + CHANGE_IGNORE, + CHANGE_MODIFY, + CHANGE_SET +}; + +/* Structure used to hold lists of sections and actions to take. */ +struct section_list +{ + struct section_list * next; /* Next section to change. */ + const char * name; /* Section name. */ + bfd_boolean used; /* Whether this entry was used. */ + bfd_boolean remove; /* Whether to remove this section. */ + bfd_boolean copy; /* Whether to copy this section. */ + enum change_action change_vma;/* Whether to change or set VMA. */ + bfd_vma vma_val; /* Amount to change by or set to. */ + enum change_action change_lma;/* Whether to change or set LMA. */ + bfd_vma lma_val; /* Amount to change by or set to. */ + bfd_boolean set_flags; /* Whether to set the section flags. */ + flagword flags; /* What to set the section flags to. */ +}; + +static struct section_list *change_sections; + +/* TRUE if some sections are to be removed. */ +static bfd_boolean sections_removed; + +/* TRUE if only some sections are to be copied. */ +static bfd_boolean sections_copied; + +/* Changes to the start address. */ +static bfd_vma change_start = 0; +static bfd_boolean set_start_set = FALSE; +static bfd_vma set_start; + +/* Changes to section addresses. */ +static bfd_vma change_section_address = 0; + +/* Filling gaps between sections. */ +static bfd_boolean gap_fill_set = FALSE; +static bfd_byte gap_fill = 0; + +/* Pad to a given address. */ +static bfd_boolean pad_to_set = FALSE; +static bfd_vma pad_to; + +/* Use alternate machine code? */ +static int use_alt_mach_code = 0; + +/* List of sections to add. */ +struct section_add +{ + /* Next section to add. */ + struct section_add *next; + /* Name of section to add. */ + const char *name; + /* Name of file holding section contents. */ + const char *filename; + /* Size of file. */ + size_t size; + /* Contents of file. */ + bfd_byte *contents; + /* BFD section, after it has been added. */ + asection *section; +}; + +/* List of sections to add to the output BFD. */ +static struct section_add *add_sections; + +/* Whether to convert debugging information. */ +static bfd_boolean convert_debugging = FALSE; + +/* Whether to change the leading character in symbol names. */ +static bfd_boolean change_leading_char = FALSE; + +/* Whether to remove the leading character from global symbol names. */ +static bfd_boolean remove_leading_char = FALSE; + +/* List of symbols to strip, keep, localize, keep-global, weaken, + or redefine. */ +static struct symlist *strip_specific_list = NULL; +static struct symlist *keep_specific_list = NULL; +static struct symlist *localize_specific_list = NULL; +static struct symlist *keepglobal_specific_list = NULL; +static struct symlist *weaken_specific_list = NULL; +static struct redefine_node *redefine_sym_list = NULL; + +/* If this is TRUE, we weaken global symbols (set BSF_WEAK). */ +static bfd_boolean weaken = FALSE; + +/* Prefix symbols/sections. */ +static char *prefix_symbols_string = 0; +static char *prefix_sections_string = 0; +static char *prefix_alloc_sections_string = 0; + +/* 150 isn't special; it's just an arbitrary non-ASCII char value. */ + +#define OPTION_ADD_SECTION 150 +#define OPTION_CHANGE_ADDRESSES (OPTION_ADD_SECTION + 1) +#define OPTION_CHANGE_LEADING_CHAR (OPTION_CHANGE_ADDRESSES + 1) +#define OPTION_CHANGE_START (OPTION_CHANGE_LEADING_CHAR + 1) +#define OPTION_CHANGE_SECTION_ADDRESS (OPTION_CHANGE_START + 1) +#define OPTION_CHANGE_SECTION_LMA (OPTION_CHANGE_SECTION_ADDRESS + 1) +#define OPTION_CHANGE_SECTION_VMA (OPTION_CHANGE_SECTION_LMA + 1) +#define OPTION_CHANGE_WARNINGS (OPTION_CHANGE_SECTION_VMA + 1) +#define OPTION_DEBUGGING (OPTION_CHANGE_WARNINGS + 1) +#define OPTION_GAP_FILL (OPTION_DEBUGGING + 1) +#define OPTION_NO_CHANGE_WARNINGS (OPTION_GAP_FILL + 1) +#define OPTION_PAD_TO (OPTION_NO_CHANGE_WARNINGS + 1) +#define OPTION_REMOVE_LEADING_CHAR (OPTION_PAD_TO + 1) +#define OPTION_SET_SECTION_FLAGS (OPTION_REMOVE_LEADING_CHAR + 1) +#define OPTION_SET_START (OPTION_SET_SECTION_FLAGS + 1) +#define OPTION_STRIP_UNNEEDED (OPTION_SET_START + 1) +#define OPTION_WEAKEN (OPTION_STRIP_UNNEEDED + 1) +#define OPTION_REDEFINE_SYM (OPTION_WEAKEN + 1) +#define OPTION_SREC_LEN (OPTION_REDEFINE_SYM + 1) +#define OPTION_SREC_FORCES3 (OPTION_SREC_LEN + 1) +#define OPTION_STRIP_SYMBOLS (OPTION_SREC_FORCES3 + 1) +#define OPTION_KEEP_SYMBOLS (OPTION_STRIP_SYMBOLS + 1) +#define OPTION_LOCALIZE_SYMBOLS (OPTION_KEEP_SYMBOLS + 1) +#define OPTION_KEEPGLOBAL_SYMBOLS (OPTION_LOCALIZE_SYMBOLS + 1) +#define OPTION_WEAKEN_SYMBOLS (OPTION_KEEPGLOBAL_SYMBOLS + 1) +#define OPTION_RENAME_SECTION (OPTION_WEAKEN_SYMBOLS + 1) +#define OPTION_ALT_MACH_CODE (OPTION_RENAME_SECTION + 1) +#define OPTION_PREFIX_SYMBOLS (OPTION_ALT_MACH_CODE + 1) +#define OPTION_PREFIX_SECTIONS (OPTION_PREFIX_SYMBOLS + 1) +#define OPTION_PREFIX_ALLOC_SECTIONS (OPTION_PREFIX_SECTIONS + 1) +#define OPTION_FORMATS_INFO (OPTION_PREFIX_ALLOC_SECTIONS + 1) + +/* Options to handle if running as "strip". */ + +static struct option strip_options[] = +{ + {"discard-all", no_argument, 0, 'x'}, + {"discard-locals", no_argument, 0, 'X'}, + {"format", required_argument, 0, 'F'}, /* Obsolete */ + {"help", no_argument, 0, 'h'}, + {"info", no_argument, 0, OPTION_FORMATS_INFO}, + {"input-format", required_argument, 0, 'I'}, /* Obsolete */ + {"input-target", required_argument, 0, 'I'}, + {"keep-symbol", required_argument, 0, 'K'}, + {"output-format", required_argument, 0, 'O'}, /* Obsolete */ + {"output-target", required_argument, 0, 'O'}, + {"output-file", required_argument, 0, 'o'}, + {"preserve-dates", no_argument, 0, 'p'}, + {"remove-section", required_argument, 0, 'R'}, + {"strip-all", no_argument, 0, 's'}, + {"strip-debug", no_argument, 0, 'S'}, + {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, + {"strip-symbol", required_argument, 0, 'N'}, + {"target", required_argument, 0, 'F'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {0, no_argument, 0, 0} +}; + +/* Options to handle if running as "objcopy". */ + +static struct option copy_options[] = +{ + {"add-section", required_argument, 0, OPTION_ADD_SECTION}, + {"adjust-start", required_argument, 0, OPTION_CHANGE_START}, + {"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES}, + {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS}, + {"adjust-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS}, + {"alt-machine-code", required_argument, 0, OPTION_ALT_MACH_CODE}, + {"binary-architecture", required_argument, 0, 'B'}, + {"byte", required_argument, 0, 'b'}, + {"change-addresses", required_argument, 0, OPTION_CHANGE_ADDRESSES}, + {"change-leading-char", no_argument, 0, OPTION_CHANGE_LEADING_CHAR}, + {"change-section-address", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS}, + {"change-section-lma", required_argument, 0, OPTION_CHANGE_SECTION_LMA}, + {"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA}, + {"change-start", required_argument, 0, OPTION_CHANGE_START}, + {"change-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS}, + {"debugging", no_argument, 0, OPTION_DEBUGGING}, + {"discard-all", no_argument, 0, 'x'}, + {"discard-locals", no_argument, 0, 'X'}, + {"format", required_argument, 0, 'F'}, /* Obsolete */ + {"gap-fill", required_argument, 0, OPTION_GAP_FILL}, + {"help", no_argument, 0, 'h'}, + {"info", no_argument, 0, OPTION_FORMATS_INFO}, + {"input-format", required_argument, 0, 'I'}, /* Obsolete */ + {"input-target", required_argument, 0, 'I'}, + {"interleave", required_argument, 0, 'i'}, + {"keep-global-symbol", required_argument, 0, 'G'}, + {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS}, + {"keep-symbol", required_argument, 0, 'K'}, + {"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS}, + {"localize-symbol", required_argument, 0, 'L'}, + {"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS}, + {"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS}, + {"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS}, + {"only-section", required_argument, 0, 'j'}, + {"output-format", required_argument, 0, 'O'}, /* Obsolete */ + {"output-target", required_argument, 0, 'O'}, + {"pad-to", required_argument, 0, OPTION_PAD_TO}, + {"prefix-symbols", required_argument, 0, OPTION_PREFIX_SYMBOLS}, + {"prefix-sections", required_argument, 0, OPTION_PREFIX_SECTIONS}, + {"prefix-alloc-sections", required_argument, 0, OPTION_PREFIX_ALLOC_SECTIONS}, + {"preserve-dates", no_argument, 0, 'p'}, + {"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM}, + {"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR}, + {"remove-section", required_argument, 0, 'R'}, + {"rename-section", required_argument, 0, OPTION_RENAME_SECTION}, + {"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS}, + {"set-start", required_argument, 0, OPTION_SET_START}, + {"srec-len", required_argument, 0, OPTION_SREC_LEN}, + {"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3}, + {"strip-all", no_argument, 0, 'S'}, + {"strip-debug", no_argument, 0, 'g'}, + {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED}, + {"strip-symbol", required_argument, 0, 'N'}, + {"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS}, + {"target", required_argument, 0, 'F'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"weaken", no_argument, 0, OPTION_WEAKEN}, + {"weaken-symbol", required_argument, 0, 'W'}, + {"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS}, + {0, no_argument, 0, 0} +}; + +/* IMPORTS */ +extern char *program_name; + +/* This flag distinguishes between strip and objcopy: + 1 means this is 'strip'; 0 means this is 'objcopy'. + -1 means if we should use argv[0] to decide. */ +extern int is_strip; + +/* The maximum length of an S record. This variable is declared in srec.c + and can be modified by the --srec-len parameter. */ +extern unsigned int Chunk; + +/* Restrict the generation of Srecords to type S3 only. + This variable is declare in bfd/srec.c and can be toggled + on by the --srec-forceS3 command line switch. */ +extern bfd_boolean S3Forced; + +/* Defined in bfd/binary.c. Used to set architecture of input binary files. */ +extern enum bfd_architecture bfd_external_binary_architecture; + + +static void +copy_usage (stream, exit_status) + FILE *stream; + int exit_status; +{ + fprintf (stream, _("Usage: %s [option(s)] in-file [out-file]\n"), program_name); + fprintf (stream, _(" Copies a binary file, possibly transforming it in the process\n")); + fprintf (stream, _(" The options are:\n")); + fprintf (stream, _("\ + -I --input-target Assume input file is in format \n\ + -O --output-target Create an output file in format \n\ + -B --binary-architecture Set arch of output file, when input is binary\n\ + -F --target Set both input and output format to \n\ + --debugging Convert debugging information, if possible\n\ + -p --preserve-dates Copy modified/access timestamps to the output\n\ + -j --only-section Only copy section into the output\n\ + -R --remove-section Remove section from the output\n\ + -S --strip-all Remove all symbol and relocation information\n\ + -g --strip-debug Remove all debugging symbols\n\ + --strip-unneeded Remove all symbols not needed by relocations\n\ + -N --strip-symbol Do not copy symbol \n\ + -K --keep-symbol Only copy symbol \n\ + -L --localize-symbol Force symbol to be marked as a local\n\ + -G --keep-global-symbol Localize all symbols except \n\ + -W --weaken-symbol Force symbol to be marked as a weak\n\ + --weaken Force all global symbols to be marked as weak\n\ + -x --discard-all Remove all non-global symbols\n\ + -X --discard-locals Remove any compiler-generated symbols\n\ + -i --interleave Only copy one out of every bytes\n\ + -b --byte Select byte in every interleaved block\n\ + --gap-fill Fill gaps between sections with \n\ + --pad-to Pad the last section up to address \n\ + --set-start Set the start address to \n\ + {--change-start|--adjust-start} \n\ + Add to the start address\n\ + {--change-addresses|--adjust-vma} \n\ + Add to LMA, VMA and start addresses\n\ + {--change-section-address|--adjust-section-vma} {=|+|-}\n\ + Change LMA and VMA of section by \n\ + --change-section-lma {=|+|-}\n\ + Change the LMA of section by \n\ + --change-section-vma {=|+|-}\n\ + Change the VMA of section by \n\ + {--[no-]change-warnings|--[no-]adjust-warnings}\n\ + Warn if a named section does not exist\n\ + --set-section-flags =\n\ + Set section 's properties to \n\ + --add-section = Add section found in to output\n\ + --rename-section =[,] Rename section to \n\ + --change-leading-char Force output format's leading character style\n\ + --remove-leading-char Remove leading character from global symbols\n\ + --redefine-sym = Redefine symbol name to \n\ + --srec-len Restrict the length of generated Srecords\n\ + --srec-forceS3 Restrict the type of generated Srecords to S3\n\ + --strip-symbols -N for all symbols listed in \n\ + --keep-symbols -K for all symbols listed in \n\ + --localize-symbols -L for all symbols listed in \n\ + --keep-global-symbols -G for all symbols listed in \n\ + --weaken-symbols -W for all symbols listed in \n\ + --alt-machine-code Use alternate machine code for output\n\ + --prefix-symbols Add to start of every symbol name\n\ + --prefix-sections Add to start of every section name\n\ + --prefix-alloc-sections \n\ + Add to start of every allocatable\n\ + section name\n\ + -v --verbose List all object files modified\n\ + -V --version Display this program's version number\n\ + -h --help Display this output\n\ + --info List object formats & architectures supported\n\ +")); + list_supported_targets (program_name, stream); + if (exit_status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); + exit (exit_status); +} + +static void +strip_usage (stream, exit_status) + FILE *stream; + int exit_status; +{ + fprintf (stream, _("Usage: %s in-file(s)\n"), program_name); + fprintf (stream, _(" Removes symbols and sections from files\n")); + fprintf (stream, _(" The options are:\n")); + fprintf (stream, _("\ + -I --input-target= Assume input file is in format \n\ + -O --output-target= Create an output file in format \n\ + -F --target= Set both input and output format to \n\ + -p --preserve-dates Copy modified/access timestamps to the output\n\ + -R --remove-section= Remove section from the output\n\ + -s --strip-all Remove all symbol and relocation information\n\ + -g -S -d --strip-debug Remove all debugging symbols\n\ + --strip-unneeded Remove all symbols not needed by relocations\n\ + -N --strip-symbol= Do not copy symbol \n\ + -K --keep-symbol= Only copy symbol \n\ + -x --discard-all Remove all non-global symbols\n\ + -X --discard-locals Remove any compiler-generated symbols\n\ + -v --verbose List all object files modified\n\ + -V --version Display this program's version number\n\ + -h --help Display this output\n\ + --info List object formats & architectures supported\n\ + -o Place stripped output into \n\ +")); + + list_supported_targets (program_name, stream); + if (exit_status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); + exit (exit_status); +} + +/* Parse section flags into a flagword, with a fatal error if the + string can't be parsed. */ + +static flagword +parse_flags (s) + const char *s; +{ + flagword ret; + const char *snext; + int len; + + ret = SEC_NO_FLAGS; + + do + { + snext = strchr (s, ','); + if (snext == NULL) + len = strlen (s); + else + { + len = snext - s; + ++snext; + } + + if (0) ; +#define PARSE_FLAG(fname,fval) \ + else if (strncasecmp (fname, s, len) == 0) ret |= fval + PARSE_FLAG ("alloc", SEC_ALLOC); + PARSE_FLAG ("load", SEC_LOAD); + PARSE_FLAG ("noload", SEC_NEVER_LOAD); + PARSE_FLAG ("readonly", SEC_READONLY); + PARSE_FLAG ("debug", SEC_DEBUGGING); + PARSE_FLAG ("code", SEC_CODE); + PARSE_FLAG ("data", SEC_DATA); + PARSE_FLAG ("rom", SEC_ROM); + PARSE_FLAG ("share", SEC_SHARED); + PARSE_FLAG ("contents", SEC_HAS_CONTENTS); +#undef PARSE_FLAG + else + { + char *copy; + + copy = xmalloc (len + 1); + strncpy (copy, s, len); + copy[len] = '\0'; + non_fatal (_("unrecognized section flag `%s'"), copy); + fatal (_("supported flags: %s"), + "alloc, load, noload, readonly, debug, code, data, rom, share, contents"); + } + + s = snext; + } + while (s != NULL); + + return ret; +} + +/* Find and optionally add an entry in the change_sections list. */ + +static struct section_list * +find_section_list (name, add) + const char *name; + bfd_boolean add; +{ + register struct section_list *p; + + for (p = change_sections; p != NULL; p = p->next) + if (strcmp (p->name, name) == 0) + return p; + + if (! add) + return NULL; + + p = (struct section_list *) xmalloc (sizeof (struct section_list)); + p->name = name; + p->used = FALSE; + p->remove = FALSE; + p->copy = FALSE; + p->change_vma = CHANGE_IGNORE; + p->change_lma = CHANGE_IGNORE; + p->vma_val = 0; + p->lma_val = 0; + p->set_flags = FALSE; + p->flags = 0; + + p->next = change_sections; + change_sections = p; + + return p; +} + +/* Add a symbol to strip_specific_list. */ + +static void +add_specific_symbol (name, list) + const char *name; + struct symlist **list; +{ + struct symlist *tmp_list; + + tmp_list = (struct symlist *) xmalloc (sizeof (struct symlist)); + tmp_list->name = name; + tmp_list->next = *list; + *list = tmp_list; +} + +/* Add symbols listed in `filename' to strip_specific_list. */ + +#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t') +#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0') + +static void +add_specific_symbols (filename, list) + const char *filename; + struct symlist **list; +{ + struct stat st; + FILE * f; + char * line; + char * buffer; + unsigned int line_count; + + if (stat (filename, & st) < 0) + fatal (_("cannot stat: %s: %s"), filename, strerror (errno)); + if (st.st_size == 0) + return; + + buffer = (char *) xmalloc (st.st_size + 2); + f = fopen (filename, FOPEN_RT); + if (f == NULL) + fatal (_("cannot open: %s: %s"), filename, strerror (errno)); + + if (fread (buffer, 1, st.st_size, f) == 0 || ferror (f)) + fatal (_("%s: fread failed"), filename); + + fclose (f); + buffer [st.st_size] = '\n'; + buffer [st.st_size + 1] = '\0'; + + line_count = 1; + + for (line = buffer; * line != '\0'; line ++) + { + char * eol; + char * name; + char * name_end; + int finished = FALSE; + + for (eol = line;; eol ++) + { + switch (* eol) + { + case '\n': + * eol = '\0'; + /* Cope with \n\r. */ + if (eol[1] == '\r') + ++ eol; + finished = TRUE; + break; + + case '\r': + * eol = '\0'; + /* Cope with \r\n. */ + if (eol[1] == '\n') + ++ eol; + finished = TRUE; + break; + + case 0: + finished = TRUE; + break; + + case '#': + /* Line comment, Terminate the line here, in case a + name is present and then allow the rest of the + loop to find the real end of the line. */ + * eol = '\0'; + break; + + default: + break; + } + + if (finished) + break; + } + + /* A name may now exist somewhere between 'line' and 'eol'. + Strip off leading whitespace and trailing whitespace, + then add it to the list. */ + for (name = line; IS_WHITESPACE (* name); name ++) + ; + for (name_end = name; + (! IS_WHITESPACE (* name_end)) + && (! IS_LINE_TERMINATOR (* name_end)); + name_end ++) + ; + + if (! IS_LINE_TERMINATOR (* name_end)) + { + char * extra; + + for (extra = name_end + 1; IS_WHITESPACE (* extra); extra ++) + ; + + if (! IS_LINE_TERMINATOR (* extra)) + non_fatal (_("Ignoring rubbish found on line %d of %s"), + line_count, filename); + } + + * name_end = '\0'; + + if (name_end > name) + add_specific_symbol (name, list); + + /* Advance line pointer to end of line. The 'eol ++' in the for + loop above will then advance us to the start of the next line. */ + line = eol; + line_count ++; + } +} + +/* See whether a symbol should be stripped or kept based on + strip_specific_list and keep_symbols. */ + +static bfd_boolean +is_specified_symbol (name, list) + const char *name; + struct symlist *list; +{ + struct symlist *tmp_list; + + for (tmp_list = list; tmp_list; tmp_list = tmp_list->next) + if (strcmp (name, tmp_list->name) == 0) + return TRUE; + + return FALSE; +} + +/* See if a section is being removed. */ + +static bfd_boolean +is_strip_section (abfd, sec) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; +{ + struct section_list *p; + + if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0 + && (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_UNNEEDED + || strip_symbols == STRIP_ALL + || discard_locals == LOCALS_ALL + || convert_debugging)) + return TRUE; + + if (! sections_removed && ! sections_copied) + return FALSE; + + p = find_section_list (bfd_get_section_name (abfd, sec), FALSE); + if (sections_removed && p != NULL && p->remove) + return TRUE; + if (sections_copied && (p == NULL || ! p->copy)) + return TRUE; + return FALSE; +} + +/* Choose which symbol entries to copy; put the result in OSYMS. + We don't copy in place, because that confuses the relocs. + Return the number of symbols to print. */ + +static unsigned int +filter_symbols (abfd, obfd, osyms, isyms, symcount) + bfd *abfd; + bfd *obfd; + asymbol **osyms, **isyms; + long symcount; +{ + register asymbol **from = isyms, **to = osyms; + long src_count = 0, dst_count = 0; + int relocatable = (abfd->flags & (HAS_RELOC | EXEC_P | DYNAMIC)) + == HAS_RELOC; + + for (; src_count < symcount; src_count++) + { + asymbol *sym = from[src_count]; + flagword flags = sym->flags; + char *name = (char *) bfd_asymbol_name (sym); + int keep; + bfd_boolean undefined; + bfd_boolean rem_leading_char; + bfd_boolean add_leading_char; + + undefined = bfd_is_und_section (bfd_get_section (sym)); + + if (redefine_sym_list) + { + char *old_name, *new_name; + + old_name = (char *) bfd_asymbol_name (sym); + new_name = (char *) lookup_sym_redefinition (old_name); + bfd_asymbol_name (sym) = new_name; + name = new_name; + } + + /* Check if we will remove the current leading character. */ + rem_leading_char = + (name[0] == bfd_get_symbol_leading_char (abfd)) + && (change_leading_char + || (remove_leading_char + && ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0 + || undefined + || bfd_is_com_section (bfd_get_section (sym))))); + + /* Check if we will add a new leading character. */ + add_leading_char = + change_leading_char + && (bfd_get_symbol_leading_char (obfd) != '\0') + && (bfd_get_symbol_leading_char (abfd) == '\0' + || (name[0] == bfd_get_symbol_leading_char (abfd))); + + /* Short circuit for change_leading_char if we can do it in-place. */ + if (rem_leading_char && add_leading_char && !prefix_symbols_string) + { + name[0] = bfd_get_symbol_leading_char (obfd); + bfd_asymbol_name (sym) = name; + rem_leading_char = FALSE; + add_leading_char = FALSE; + } + + /* Remove leading char. */ + if (rem_leading_char) + bfd_asymbol_name (sym) = ++name; + + /* Add new leading char and/or prefix. */ + if (add_leading_char || prefix_symbols_string) + { + char *n, *ptr; + + ptr = n = xmalloc (1 + strlen (prefix_symbols_string) + strlen (name) + 1); + if (add_leading_char) + *ptr++ = bfd_get_symbol_leading_char (obfd); + + if (prefix_symbols_string) + { + strcpy (ptr, prefix_symbols_string); + ptr += strlen (prefix_symbols_string); + } + + strcpy (ptr, name); + bfd_asymbol_name (sym) = n; + name = n; + } + + if (strip_symbols == STRIP_ALL) + keep = 0; + else if ((flags & BSF_KEEP) != 0 /* Used in relocation. */ + || ((flags & BSF_SECTION_SYM) != 0 + && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags + & BSF_KEEP) != 0)) + keep = 1; + else if (relocatable /* Relocatable file. */ + && (flags & (BSF_GLOBAL | BSF_WEAK)) != 0) + keep = 1; + else if (bfd_decode_symclass (sym) == 'I') + /* Global symbols in $idata sections need to be retained + even if relocatable is FALSE. External users of the + library containing the $idata section may reference these + symbols. */ + keep = 1; + else if ((flags & BSF_GLOBAL) != 0 /* Global symbol. */ + || (flags & BSF_WEAK) != 0 + || undefined + || bfd_is_com_section (bfd_get_section (sym))) + keep = strip_symbols != STRIP_UNNEEDED; + else if ((flags & BSF_DEBUGGING) != 0) /* Debugging symbol. */ + keep = (strip_symbols != STRIP_DEBUG + && strip_symbols != STRIP_UNNEEDED + && ! convert_debugging); + else if (bfd_get_section (sym)->comdat) + /* COMDAT sections store special information in local + symbols, so we cannot risk stripping any of them. */ + keep = 1; + else /* Local symbol. */ + keep = (strip_symbols != STRIP_UNNEEDED + && (discard_locals != LOCALS_ALL + && (discard_locals != LOCALS_START_L + || ! bfd_is_local_label (abfd, sym)))); + + if (keep && is_specified_symbol (name, strip_specific_list)) + keep = 0; + if (!keep && is_specified_symbol (name, keep_specific_list)) + keep = 1; + if (keep && is_strip_section (abfd, bfd_get_section (sym))) + keep = 0; + + if (keep && (flags & BSF_GLOBAL) != 0 + && (weaken || is_specified_symbol (name, weaken_specific_list))) + { + sym->flags &=~ BSF_GLOBAL; + sym->flags |= BSF_WEAK; + } + if (keep && !undefined && (flags & (BSF_GLOBAL | BSF_WEAK)) + && (is_specified_symbol (name, localize_specific_list) + || (keepglobal_specific_list != NULL + && ! is_specified_symbol (name, keepglobal_specific_list)))) + { + sym->flags &= ~(BSF_GLOBAL | BSF_WEAK); + sym->flags |= BSF_LOCAL; + } + + if (keep) + to[dst_count++] = sym; + } + + to[dst_count] = NULL; + + return dst_count; +} + +/* Find the redefined name of symbol SOURCE. */ + +static const char * +lookup_sym_redefinition (source) + const char *source; +{ + struct redefine_node *list; + + for (list = redefine_sym_list; list != NULL; list = list->next) + if (strcmp (source, list->source) == 0) + return list->target; + + return source; +} + +/* Add a node to a symbol redefine list. */ + +static void +redefine_list_append (source, target) + const char *source; + const char *target; +{ + struct redefine_node **p; + struct redefine_node *list; + struct redefine_node *new_node; + + for (p = &redefine_sym_list; (list = *p) != NULL; p = &list->next) + { + if (strcmp (source, list->source) == 0) + fatal (_("%s: Multiple redefinition of symbol \"%s\""), + "--redefine-sym", + source); + + if (strcmp (target, list->target) == 0) + fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"), + "--redefine-sym", + target); + } + + new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node)); + + new_node->source = strdup (source); + new_node->target = strdup (target); + new_node->next = NULL; + + *p = new_node; +} + +/* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long. + Adjust *SIZE. */ + +static void +filter_bytes (memhunk, size) + char *memhunk; + bfd_size_type *size; +{ + char *from = memhunk + copy_byte, *to = memhunk, *end = memhunk + *size; + + for (; from < end; from += interleave) + *to++ = *from; + + if (*size % interleave > (bfd_size_type) copy_byte) + *size = (*size / interleave) + 1; + else + *size /= interleave; +} + +/* Copy object file IBFD onto OBFD. */ + +static void +copy_object (ibfd, obfd) + bfd *ibfd; + bfd *obfd; +{ + bfd_vma start; + long symcount; + asection **osections = NULL; + bfd_size_type *gaps = NULL; + bfd_size_type max_gap = 0; + long symsize; + PTR dhandle; + enum bfd_architecture iarch; + unsigned int imach; + + if (ibfd->xvec->byteorder != obfd->xvec->byteorder + && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN + && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) + { + fatal (_("Unable to change endianness of input file(s)")); + return; + } + + if (!bfd_set_format (obfd, bfd_get_format (ibfd))) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + if (verbose) + printf (_("copy from %s(%s) to %s(%s)\n"), + bfd_get_filename (ibfd), bfd_get_target (ibfd), + bfd_get_filename (obfd), bfd_get_target (obfd)); + + if (set_start_set) + start = set_start; + else + start = bfd_get_start_address (ibfd); + start += change_start; + + /* Neither the start address nor the flags + need to be set for a core file. */ + if (bfd_get_format (obfd) != bfd_core) + { + if (!bfd_set_start_address (obfd, start) + || !bfd_set_file_flags (obfd, + (bfd_get_file_flags (ibfd) + & bfd_applicable_file_flags (obfd)))) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + } + + /* Copy architecture of input file to output file. */ + iarch = bfd_get_arch (ibfd); + imach = bfd_get_mach (ibfd); + if (!bfd_set_arch_mach (obfd, iarch, imach) + && (ibfd->target_defaulted + || bfd_get_arch (ibfd) != bfd_get_arch (obfd))) + non_fatal (_("Warning: Output file cannot represent architecture %s"), + bfd_printable_arch_mach (bfd_get_arch (ibfd), + bfd_get_mach (ibfd))); + + if (!bfd_set_format (obfd, bfd_get_format (ibfd))) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + if (isympp) + free (isympp); + + if (osympp != isympp) + free (osympp); + + /* BFD mandates that all output sections be created and sizes set before + any output is done. Thus, we traverse all sections multiple times. */ + bfd_map_over_sections (ibfd, setup_section, (void *) obfd); + + if (add_sections != NULL) + { + struct section_add *padd; + struct section_list *pset; + + for (padd = add_sections; padd != NULL; padd = padd->next) + { + padd->section = bfd_make_section (obfd, padd->name); + if (padd->section == NULL) + { + non_fatal (_("can't create section `%s': %s"), + padd->name, bfd_errmsg (bfd_get_error ())); + status = 1; + return; + } + else + { + flagword flags; + + if (! bfd_set_section_size (obfd, padd->section, padd->size)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + pset = find_section_list (padd->name, FALSE); + if (pset != NULL) + pset->used = TRUE; + + if (pset != NULL && pset->set_flags) + flags = pset->flags | SEC_HAS_CONTENTS; + else + flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA; + + if (! bfd_set_section_flags (obfd, padd->section, flags)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + if (pset != NULL) + { + if (pset->change_vma != CHANGE_IGNORE) + if (! bfd_set_section_vma (obfd, padd->section, pset->vma_val)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + if (pset->change_lma != CHANGE_IGNORE) + { + padd->section->lma = pset->lma_val; + + if (! bfd_set_section_alignment + (obfd, padd->section, + bfd_section_alignment (obfd, padd->section))) + RETURN_NONFATAL (bfd_get_filename (obfd)); + } + } + } + } + } + + if (gap_fill_set || pad_to_set) + { + asection **set; + unsigned int c, i; + + /* We must fill in gaps between the sections and/or we must pad + the last section to a specified address. We do this by + grabbing a list of the sections, sorting them by VMA, and + increasing the section sizes as required to fill the gaps. + We write out the gap contents below. */ + + c = bfd_count_sections (obfd); + osections = (asection **) xmalloc (c * sizeof (asection *)); + set = osections; + bfd_map_over_sections (obfd, get_sections, (void *) &set); + + qsort (osections, c, sizeof (asection *), compare_section_lma); + + gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type)); + memset (gaps, 0, c * sizeof (bfd_size_type)); + + if (gap_fill_set) + { + for (i = 0; i < c - 1; i++) + { + flagword flags; + bfd_size_type size; + bfd_vma gap_start, gap_stop; + + flags = bfd_get_section_flags (obfd, osections[i]); + if ((flags & SEC_HAS_CONTENTS) == 0 + || (flags & SEC_LOAD) == 0) + continue; + + size = bfd_section_size (obfd, osections[i]); + gap_start = bfd_section_lma (obfd, osections[i]) + size; + gap_stop = bfd_section_lma (obfd, osections[i + 1]); + if (gap_start < gap_stop) + { + if (! bfd_set_section_size (obfd, osections[i], + size + (gap_stop - gap_start))) + { + non_fatal (_("Can't fill gap after %s: %s"), + bfd_get_section_name (obfd, osections[i]), + bfd_errmsg (bfd_get_error ())); + status = 1; + break; + } + gaps[i] = gap_stop - gap_start; + if (max_gap < gap_stop - gap_start) + max_gap = gap_stop - gap_start; + } + } + } + + if (pad_to_set) + { + bfd_vma lma; + bfd_size_type size; + + lma = bfd_section_lma (obfd, osections[c - 1]); + size = bfd_section_size (obfd, osections[c - 1]); + if (lma + size < pad_to) + { + if (! bfd_set_section_size (obfd, osections[c - 1], + pad_to - lma)) + { + non_fatal (_("Can't add padding to %s: %s"), + bfd_get_section_name (obfd, osections[c - 1]), + bfd_errmsg (bfd_get_error ())); + status = 1; + } + else + { + gaps[c - 1] = pad_to - (lma + size); + if (max_gap < pad_to - (lma + size)) + max_gap = pad_to - (lma + size); + } + } + } + } + + /* Symbol filtering must happen after the output sections + have been created, but before their contents are set. */ + dhandle = NULL; + symsize = bfd_get_symtab_upper_bound (ibfd); + if (symsize < 0) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + osympp = isympp = (asymbol **) xmalloc (symsize); + symcount = bfd_canonicalize_symtab (ibfd, isympp); + if (symcount < 0) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + if (convert_debugging) + dhandle = read_debugging_info (ibfd, isympp, symcount); + + if (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_ALL + || strip_symbols == STRIP_UNNEEDED + || discard_locals != LOCALS_UNDEF + || strip_specific_list != NULL + || keep_specific_list != NULL + || localize_specific_list != NULL + || keepglobal_specific_list != NULL + || weaken_specific_list != NULL + || prefix_symbols_string + || sections_removed + || sections_copied + || convert_debugging + || change_leading_char + || remove_leading_char + || redefine_sym_list + || weaken) + { + /* Mark symbols used in output relocations so that they + are kept, even if they are local labels or static symbols. + + Note we iterate over the input sections examining their + relocations since the relocations for the output sections + haven't been set yet. mark_symbols_used_in_relocations will + ignore input sections which have no corresponding output + section. */ + if (strip_symbols != STRIP_ALL) + bfd_map_over_sections (ibfd, + mark_symbols_used_in_relocations, + (PTR)isympp); + osympp = (asymbol **) xmalloc ((symcount + 1) * sizeof (asymbol *)); + symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount); + } + + if (convert_debugging && dhandle != NULL) + { + if (! write_debugging_info (obfd, dhandle, &symcount, &osympp)) + { + status = 1; + return; + } + } + + bfd_set_symtab (obfd, osympp, symcount); + + /* This has to happen after the symbol table has been set. */ + bfd_map_over_sections (ibfd, copy_section, (void *) obfd); + + if (add_sections != NULL) + { + struct section_add *padd; + + for (padd = add_sections; padd != NULL; padd = padd->next) + { + if (! bfd_set_section_contents (obfd, padd->section, + (PTR) padd->contents, + (file_ptr) 0, + (bfd_size_type) padd->size)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + } + } + + if (gap_fill_set || pad_to_set) + { + bfd_byte *buf; + int c, i; + + /* Fill in the gaps. */ + if (max_gap > 8192) + max_gap = 8192; + buf = (bfd_byte *) xmalloc (max_gap); + memset (buf, gap_fill, (size_t) max_gap); + + c = bfd_count_sections (obfd); + for (i = 0; i < c; i++) + { + if (gaps[i] != 0) + { + bfd_size_type left; + file_ptr off; + + left = gaps[i]; + off = bfd_section_size (obfd, osections[i]) - left; + + while (left > 0) + { + bfd_size_type now; + + if (left > 8192) + now = 8192; + else + now = left; + + if (! bfd_set_section_contents (obfd, osections[i], buf, + off, now)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + left -= now; + off += now; + } + } + } + } + + /* Allow the BFD backend to copy any private data it understands + from the input BFD to the output BFD. This is done last to + permit the routine to look at the filtered symbol table, which is + important for the ECOFF code at least. */ + if (! bfd_copy_private_bfd_data (ibfd, obfd)) + { + non_fatal (_("%s: error copying private BFD data: %s"), + bfd_get_filename (obfd), + bfd_errmsg (bfd_get_error ())); + status = 1; + return; + } + + /* Switch to the alternate machine code. We have to do this at the + very end, because we only initialize the header when we create + the first section. */ + if (use_alt_mach_code != 0) + { + if (!bfd_alt_mach_code (obfd, use_alt_mach_code)) + non_fatal (_("unknown alternate machine code, ignored")); + } +} + +#undef MKDIR +#if defined (_WIN32) && !defined (__CYGWIN32__) +#define MKDIR(DIR, MODE) mkdir (DIR) +#else +#define MKDIR(DIR, MODE) mkdir (DIR, MODE) +#endif + +/* Read each archive element in turn from IBFD, copy the + contents to temp file, and keep the temp file handle. */ + +static void +copy_archive (ibfd, obfd, output_target) + bfd *ibfd; + bfd *obfd; + const char *output_target; +{ + struct name_list + { + struct name_list *next; + const char *name; + bfd *obfd; + } *list, *l; + bfd **ptr = &obfd->archive_head; + bfd *this_element; + char *dir = make_tempname (bfd_get_filename (obfd)); + + /* Make a temp directory to hold the contents. */ + if (MKDIR (dir, 0700) != 0) + { + fatal (_("cannot mkdir %s for archive copying (error: %s)"), + dir, strerror (errno)); + } + obfd->has_armap = ibfd->has_armap; + + list = NULL; + + this_element = bfd_openr_next_archived_file (ibfd, NULL); + + if (!bfd_set_format (obfd, bfd_get_format (ibfd))) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + while (!status && this_element != (bfd *) NULL) + { + char *output_name; + bfd *output_bfd; + bfd *last_element; + struct stat buf; + int stat_status = 0; + + /* Create an output file for this member. */ + output_name = concat (dir, "/", + bfd_get_filename (this_element), (char *) 0); + + /* If the file already exists, make another temp dir. */ + if (stat (output_name, &buf) >= 0) + { + output_name = make_tempname (output_name); + if (MKDIR (output_name, 0700) != 0) + { + fatal (_("cannot mkdir %s for archive copying (error: %s)"), + output_name, strerror (errno)); + } + l = (struct name_list *) xmalloc (sizeof (struct name_list)); + l->name = output_name; + l->next = list; + l->obfd = NULL; + list = l; + output_name = concat (output_name, "/", + bfd_get_filename (this_element), (char *) 0); + } + + output_bfd = bfd_openw (output_name, output_target); + if (preserve_dates) + { + stat_status = bfd_stat_arch_elt (this_element, &buf); + + if (stat_status != 0) + non_fatal (_("internal stat error on %s"), + bfd_get_filename (this_element)); + } + + l = (struct name_list *) xmalloc (sizeof (struct name_list)); + l->name = output_name; + l->next = list; + list = l; + + if (output_bfd == (bfd *) NULL) + RETURN_NONFATAL (output_name); + + if (bfd_check_format (this_element, bfd_object)) + copy_object (this_element, output_bfd); + + if (!bfd_close (output_bfd)) + { + bfd_nonfatal (bfd_get_filename (output_bfd)); + /* Error in new object file. Don't change archive. */ + status = 1; + } + + if (preserve_dates && stat_status == 0) + set_times (output_name, &buf); + + /* Open the newly output file and attach to our list. */ + output_bfd = bfd_openr (output_name, output_target); + + l->obfd = output_bfd; + + *ptr = output_bfd; + ptr = &output_bfd->next; + + last_element = this_element; + + this_element = bfd_openr_next_archived_file (ibfd, last_element); + + bfd_close (last_element); + } + *ptr = (bfd *) NULL; + + if (!bfd_close (obfd)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + if (!bfd_close (ibfd)) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + /* Delete all the files that we opened. */ + for (l = list; l != NULL; l = l->next) + { + if (l->obfd == NULL) + rmdir (l->name); + else + { + bfd_close (l->obfd); + unlink (l->name); + } + } + rmdir (dir); +} + +/* The top-level control. */ + +static void +copy_file (input_filename, output_filename, input_target, output_target) + const char *input_filename; + const char *output_filename; + const char *input_target; + const char *output_target; +{ + bfd *ibfd; + char **obj_matching; + char **core_matching; + + /* To allow us to do "strip *" without dying on the first + non-object file, failures are nonfatal. */ + ibfd = bfd_openr (input_filename, input_target); + if (ibfd == NULL) + RETURN_NONFATAL (input_filename); + + if (bfd_check_format (ibfd, bfd_archive)) + { + bfd *obfd; + + /* bfd_get_target does not return the correct value until + bfd_check_format succeeds. */ + if (output_target == NULL) + output_target = bfd_get_target (ibfd); + + obfd = bfd_openw (output_filename, output_target); + if (obfd == NULL) + RETURN_NONFATAL (output_filename); + + copy_archive (ibfd, obfd, output_target); + } + else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching)) + { + bfd *obfd; + do_copy: + /* bfd_get_target does not return the correct value until + bfd_check_format succeeds. */ + if (output_target == NULL) + output_target = bfd_get_target (ibfd); + + obfd = bfd_openw (output_filename, output_target); + if (obfd == NULL) + RETURN_NONFATAL (output_filename); + + copy_object (ibfd, obfd); + + if (!bfd_close (obfd)) + RETURN_NONFATAL (output_filename); + + if (!bfd_close (ibfd)) + RETURN_NONFATAL (input_filename); + } + else + { + bfd_error_type obj_error = bfd_get_error (); + bfd_error_type core_error; + + if (bfd_check_format_matches (ibfd, bfd_core, &core_matching)) + { + /* This probably can't happen.. */ + if (obj_error == bfd_error_file_ambiguously_recognized) + free (obj_matching); + goto do_copy; + } + + core_error = bfd_get_error (); + /* Report the object error in preference to the core error. */ + if (obj_error != core_error) + bfd_set_error (obj_error); + + bfd_nonfatal (input_filename); + + if (obj_error == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (obj_matching); + free (obj_matching); + } + if (core_error == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (core_matching); + free (core_matching); + } + + status = 1; + } +} + +/* Add a name to the section renaming list. */ + +static void +add_section_rename (old_name, new_name, flags) + const char * old_name; + const char * new_name; + flagword flags; +{ + section_rename * rename; + + /* Check for conflicts first. */ + for (rename = section_rename_list; rename != NULL; rename = rename->next) + if (strcmp (rename->old_name, old_name) == 0) + { + /* Silently ignore duplicate definitions. */ + if (strcmp (rename->new_name, new_name) == 0 + && rename->flags == flags) + return; + + fatal (_("Multiple renames of section %s"), old_name); + } + + rename = (section_rename *) xmalloc (sizeof (* rename)); + + rename->old_name = old_name; + rename->new_name = new_name; + rename->flags = flags; + rename->next = section_rename_list; + + section_rename_list = rename; +} + +/* Check the section rename list for a new name of the input section + ISECTION. Return the new name if one is found. + Also set RETURNED_FLAGS to the flags to be used for this section. */ + +static const char * +find_section_rename (ibfd, isection, returned_flags) + bfd * ibfd ATTRIBUTE_UNUSED; + sec_ptr isection; + flagword * returned_flags; +{ + const char * old_name = bfd_section_name (ibfd, isection); + section_rename * rename; + + /* Default to using the flags of the input section. */ + * returned_flags = bfd_get_section_flags (ibfd, isection); + + for (rename = section_rename_list; rename != NULL; rename = rename->next) + if (strcmp (rename->old_name, old_name) == 0) + { + if (rename->flags != (flagword) -1) + * returned_flags = rename->flags; + + return rename->new_name; + } + + return old_name; +} + +/* Create a section in OBFD with the same + name and attributes as ISECTION in IBFD. */ + +static void +setup_section (ibfd, isection, obfdarg) + bfd *ibfd; + sec_ptr isection; + PTR obfdarg; +{ + bfd *obfd = (bfd *) obfdarg; + struct section_list *p; + sec_ptr osection; + bfd_size_type size; + bfd_vma vma; + bfd_vma lma; + flagword flags; + const char *err; + const char * name; + char *prefix = NULL; + + if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0 + && (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_UNNEEDED + || strip_symbols == STRIP_ALL + || discard_locals == LOCALS_ALL + || convert_debugging)) + return; + + p = find_section_list (bfd_section_name (ibfd, isection), FALSE); + if (p != NULL) + p->used = TRUE; + + if (sections_removed && p != NULL && p->remove) + return; + if (sections_copied && (p == NULL || ! p->copy)) + return; + + /* Get the, possibly new, name of the output section. */ + name = find_section_rename (ibfd, isection, & flags); + + /* Prefix sections. */ + if ((prefix_alloc_sections_string) && (bfd_get_section_flags (ibfd, isection) & SEC_ALLOC)) + prefix = prefix_alloc_sections_string; + else if (prefix_sections_string) + prefix = prefix_sections_string; + + if (prefix) + { + char *n; + + n = xmalloc (strlen (prefix) + strlen (name) + 1); + strcpy (n, prefix); + strcat (n, name); + name = n; + } + + osection = bfd_make_section_anyway (obfd, name); + + if (osection == NULL) + { + err = _("making"); + goto loser; + } + + size = bfd_section_size (ibfd, isection); + if (copy_byte >= 0) + size = (size + interleave - 1) / interleave; + if (! bfd_set_section_size (obfd, osection, size)) + { + err = _("size"); + goto loser; + } + + vma = bfd_section_vma (ibfd, isection); + if (p != NULL && p->change_vma == CHANGE_MODIFY) + vma += p->vma_val; + else if (p != NULL && p->change_vma == CHANGE_SET) + vma = p->vma_val; + else + vma += change_section_address; + + if (! bfd_set_section_vma (obfd, osection, vma)) + { + err = _("vma"); + goto loser; + } + + lma = isection->lma; + if ((p != NULL) && p->change_lma != CHANGE_IGNORE) + { + if (p->change_lma == CHANGE_MODIFY) + lma += p->lma_val; + else if (p->change_lma == CHANGE_SET) + lma = p->lma_val; + else + abort (); + } + else + lma += change_section_address; + + osection->lma = lma; + + /* FIXME: This is probably not enough. If we change the LMA we + may have to recompute the header for the file as well. */ + if (!bfd_set_section_alignment (obfd, + osection, + bfd_section_alignment (ibfd, isection))) + { + err = _("alignment"); + goto loser; + } + + if (p != NULL && p->set_flags) + flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC)); + if (!bfd_set_section_flags (obfd, osection, flags)) + { + err = _("flags"); + goto loser; + } + + /* Copy merge entity size. */ + osection->entsize = isection->entsize; + + /* This used to be mangle_section; we do here to avoid using + bfd_get_section_by_name since some formats allow multiple + sections with the same name. */ + isection->output_section = osection; + isection->output_offset = 0; + + /* Allow the BFD backend to copy any private data it understands + from the input section to the output section. */ + if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection)) + { + err = _("private data"); + goto loser; + } + + /* All went well. */ + return; + +loser: + non_fatal (_("%s: section `%s': error in %s: %s"), + bfd_get_filename (ibfd), + bfd_section_name (ibfd, isection), + err, bfd_errmsg (bfd_get_error ())); + status = 1; +} + +/* Copy the data of input section ISECTION of IBFD + to an output section with the same name in OBFD. + If stripping then don't copy any relocation info. */ + +static void +copy_section (ibfd, isection, obfdarg) + bfd *ibfd; + sec_ptr isection; + PTR obfdarg; +{ + bfd *obfd = (bfd *) obfdarg; + struct section_list *p; + arelent **relpp; + long relcount; + sec_ptr osection; + bfd_size_type size; + long relsize; + flagword flags; + + /* If we have already failed earlier on, + do not keep on generating complaints now. */ + if (status != 0) + return; + + flags = bfd_get_section_flags (ibfd, isection); + if ((flags & SEC_DEBUGGING) != 0 + && (strip_symbols == STRIP_DEBUG + || strip_symbols == STRIP_UNNEEDED + || strip_symbols == STRIP_ALL + || discard_locals == LOCALS_ALL + || convert_debugging)) + return; + + if ((flags & SEC_GROUP) != 0) + return; + + p = find_section_list (bfd_section_name (ibfd, isection), FALSE); + + if (sections_removed && p != NULL && p->remove) + return; + if (sections_copied && (p == NULL || ! p->copy)) + return; + + osection = isection->output_section; + size = bfd_get_section_size_before_reloc (isection); + + if (size == 0 || osection == 0) + return; + + /* Core files do not need to be relocated. */ + if (bfd_get_format (obfd) == bfd_core) + relsize = 0; + else + relsize = bfd_get_reloc_upper_bound (ibfd, isection); + + if (relsize < 0) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + if (relsize == 0) + bfd_set_reloc (obfd, osection, (arelent **) NULL, 0); + else + { + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp); + if (relcount < 0) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + if (strip_symbols == STRIP_ALL) + { + /* Remove relocations which are not in + keep_strip_specific_list. */ + arelent **temp_relpp; + long temp_relcount = 0; + long i; + + temp_relpp = (arelent **) xmalloc (relsize); + for (i = 0; i < relcount; i++) + if (is_specified_symbol + (bfd_asymbol_name (*relpp [i]->sym_ptr_ptr), + keep_specific_list)) + temp_relpp [temp_relcount++] = relpp [i]; + relcount = temp_relcount; + free (relpp); + relpp = temp_relpp; + } + + bfd_set_reloc (obfd, osection, + (relcount == 0 ? (arelent **) NULL : relpp), relcount); + } + + isection->_cooked_size = isection->_raw_size; + isection->reloc_done = TRUE; + + if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS + && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS) + { + PTR memhunk = (PTR) xmalloc ((unsigned) size); + + if (!bfd_get_section_contents (ibfd, isection, memhunk, (file_ptr) 0, + size)) + RETURN_NONFATAL (bfd_get_filename (ibfd)); + + if (copy_byte >= 0) + filter_bytes (memhunk, &size); + + if (!bfd_set_section_contents (obfd, osection, memhunk, (file_ptr) 0, + size)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + + free (memhunk); + } + else if (p != NULL && p->set_flags && (p->flags & SEC_HAS_CONTENTS) != 0) + { + PTR memhunk = (PTR) xmalloc ((unsigned) size); + + /* We don't permit the user to turn off the SEC_HAS_CONTENTS + flag--they can just remove the section entirely and add it + back again. However, we do permit them to turn on the + SEC_HAS_CONTENTS flag, and take it to mean that the section + contents should be zeroed out. */ + + memset (memhunk, 0, size); + if (! bfd_set_section_contents (obfd, osection, memhunk, (file_ptr) 0, + size)) + RETURN_NONFATAL (bfd_get_filename (obfd)); + free (memhunk); + } +} + +/* Get all the sections. This is used when --gap-fill or --pad-to is + used. */ + +static void +get_sections (obfd, osection, secppparg) + bfd *obfd ATTRIBUTE_UNUSED; + asection *osection; + PTR secppparg; +{ + asection ***secppp = (asection ***) secppparg; + + **secppp = osection; + ++(*secppp); +} + +/* Sort sections by VMA. This is called via qsort, and is used when + --gap-fill or --pad-to is used. We force non loadable or empty + sections to the front, where they are easier to ignore. */ + +static int +compare_section_lma (arg1, arg2) + const PTR arg1; + const PTR arg2; +{ + const asection **sec1 = (const asection **) arg1; + const asection **sec2 = (const asection **) arg2; + flagword flags1, flags2; + + /* Sort non loadable sections to the front. */ + flags1 = (*sec1)->flags; + flags2 = (*sec2)->flags; + if ((flags1 & SEC_HAS_CONTENTS) == 0 + || (flags1 & SEC_LOAD) == 0) + { + if ((flags2 & SEC_HAS_CONTENTS) != 0 + && (flags2 & SEC_LOAD) != 0) + return -1; + } + else + { + if ((flags2 & SEC_HAS_CONTENTS) == 0 + || (flags2 & SEC_LOAD) == 0) + return 1; + } + + /* Sort sections by LMA. */ + if ((*sec1)->lma > (*sec2)->lma) + return 1; + else if ((*sec1)->lma < (*sec2)->lma) + return -1; + + /* Sort sections with the same LMA by size. */ + if ((*sec1)->_raw_size > (*sec2)->_raw_size) + return 1; + else if ((*sec1)->_raw_size < (*sec2)->_raw_size) + return -1; + + return 0; +} + +/* Mark all the symbols which will be used in output relocations with + the BSF_KEEP flag so that those symbols will not be stripped. + + Ignore relocations which will not appear in the output file. */ + +static void +mark_symbols_used_in_relocations (ibfd, isection, symbolsarg) + bfd *ibfd; + sec_ptr isection; + PTR symbolsarg; +{ + asymbol **symbols = (asymbol **) symbolsarg; + long relsize; + arelent **relpp; + long relcount, i; + + /* Ignore an input section with no corresponding output section. */ + if (isection->output_section == NULL) + return; + + relsize = bfd_get_reloc_upper_bound (ibfd, isection); + if (relsize < 0) + bfd_fatal (bfd_get_filename (ibfd)); + + if (relsize == 0) + return; + + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, symbols); + if (relcount < 0) + bfd_fatal (bfd_get_filename (ibfd)); + + /* Examine each symbol used in a relocation. If it's not one of the + special bfd section symbols, then mark it with BSF_KEEP. */ + for (i = 0; i < relcount; i++) + { + if (*relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol + && *relpp[i]->sym_ptr_ptr != bfd_abs_section_ptr->symbol + && *relpp[i]->sym_ptr_ptr != bfd_und_section_ptr->symbol) + (*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP; + } + + if (relpp != NULL) + free (relpp); +} + +/* Write out debugging information. */ + +static bfd_boolean +write_debugging_info (obfd, dhandle, symcountp, symppp) + bfd *obfd; + PTR dhandle; + long *symcountp ATTRIBUTE_UNUSED; + asymbol ***symppp ATTRIBUTE_UNUSED; +{ + if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour) + return write_ieee_debugging_info (obfd, dhandle); + + if (bfd_get_flavour (obfd) == bfd_target_coff_flavour + || bfd_get_flavour (obfd) == bfd_target_elf_flavour) + { + bfd_byte *syms, *strings; + bfd_size_type symsize, stringsize; + asection *stabsec, *stabstrsec; + + if (! write_stabs_in_sections_debugging_info (obfd, dhandle, &syms, + &symsize, &strings, + &stringsize)) + return FALSE; + + stabsec = bfd_make_section (obfd, ".stab"); + stabstrsec = bfd_make_section (obfd, ".stabstr"); + if (stabsec == NULL + || stabstrsec == NULL + || ! bfd_set_section_size (obfd, stabsec, symsize) + || ! bfd_set_section_size (obfd, stabstrsec, stringsize) + || ! bfd_set_section_alignment (obfd, stabsec, 2) + || ! bfd_set_section_alignment (obfd, stabstrsec, 0) + || ! bfd_set_section_flags (obfd, stabsec, + (SEC_HAS_CONTENTS + | SEC_READONLY + | SEC_DEBUGGING)) + || ! bfd_set_section_flags (obfd, stabstrsec, + (SEC_HAS_CONTENTS + | SEC_READONLY + | SEC_DEBUGGING))) + { + non_fatal (_("%s: can't create debugging section: %s"), + bfd_get_filename (obfd), + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + + /* We can get away with setting the section contents now because + the next thing the caller is going to do is copy over the + real sections. We may someday have to split the contents + setting out of this function. */ + if (! bfd_set_section_contents (obfd, stabsec, syms, (file_ptr) 0, + symsize) + || ! bfd_set_section_contents (obfd, stabstrsec, strings, + (file_ptr) 0, stringsize)) + { + non_fatal (_("%s: can't set debugging section contents: %s"), + bfd_get_filename (obfd), + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + + return TRUE; + } + + non_fatal (_("%s: don't know how to write debugging information for %s"), + bfd_get_filename (obfd), bfd_get_target (obfd)); + return FALSE; +} + +static int +strip_main (argc, argv) + int argc; + char *argv[]; +{ + char *input_target = NULL; + char *output_target = NULL; + bfd_boolean show_version = FALSE; + bfd_boolean formats_info = FALSE; + int c; + int i; + struct section_list *p; + char *output_file = NULL; + + while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVv", + strip_options, (int *) 0)) != EOF) + { + switch (c) + { + case 'I': + input_target = optarg; + break; + case 'O': + output_target = optarg; + break; + case 'F': + input_target = output_target = optarg; + break; + case 'R': + p = find_section_list (optarg, TRUE); + p->remove = TRUE; + sections_removed = TRUE; + break; + case 's': + strip_symbols = STRIP_ALL; + break; + case 'S': + case 'g': + case 'd': /* Historic BSD alias for -g. Used by early NetBSD. */ + strip_symbols = STRIP_DEBUG; + break; + case OPTION_STRIP_UNNEEDED: + strip_symbols = STRIP_UNNEEDED; + break; + case 'K': + add_specific_symbol (optarg, &keep_specific_list); + break; + case 'N': + add_specific_symbol (optarg, &strip_specific_list); + break; + case 'o': + output_file = optarg; + break; + case 'p': + preserve_dates = TRUE; + break; + case 'x': + discard_locals = LOCALS_ALL; + break; + case 'X': + discard_locals = LOCALS_START_L; + break; + case 'v': + verbose = TRUE; + break; + case 'V': + show_version = TRUE; + break; + case OPTION_FORMATS_INFO: + formats_info = TRUE; + break; + case 0: + /* We've been given a long option. */ + break; + case 'H': + case 'h': + strip_usage (stdout, 0); + default: + strip_usage (stderr, 1); + } + } + + if (formats_info) + { + display_info (); + return 0; + } + + if (show_version) + print_version ("strip"); + + /* Default is to strip all symbols. */ + if (strip_symbols == STRIP_UNDEF + && discard_locals == LOCALS_UNDEF + && strip_specific_list == NULL) + strip_symbols = STRIP_ALL; + + if (output_target == (char *) NULL) + output_target = input_target; + + i = optind; + if (i == argc + || (output_file != NULL && (i + 1) < argc)) + strip_usage (stderr, 1); + + for (; i < argc; i++) + { + int hold_status = status; + struct stat statbuf; + char *tmpname; + + if (preserve_dates) + { + if (stat (argv[i], &statbuf) < 0) + { + non_fatal (_("%s: cannot stat: %s"), argv[i], strerror (errno)); + continue; + } + } + + if (output_file != NULL) + tmpname = output_file; + else + tmpname = make_tempname (argv[i]); + status = 0; + + copy_file (argv[i], tmpname, input_target, output_target); + if (status == 0) + { + if (preserve_dates) + set_times (tmpname, &statbuf); + if (output_file == NULL) + smart_rename (tmpname, argv[i], preserve_dates); + status = hold_status; + } + else + unlink (tmpname); + if (output_file == NULL) + free (tmpname); + } + + return 0; +} + +static int +copy_main (argc, argv) + int argc; + char *argv[]; +{ + char * binary_architecture = NULL; + char *input_filename = NULL; + char *output_filename = NULL; + char *input_target = NULL; + char *output_target = NULL; + bfd_boolean show_version = FALSE; + bfd_boolean change_warn = TRUE; + bfd_boolean formats_info = FALSE; + int c; + struct section_list *p; + struct stat statbuf; + + while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:", + copy_options, (int *) 0)) != EOF) + { + switch (c) + { + case 'b': + copy_byte = atoi (optarg); + if (copy_byte < 0) + fatal (_("byte number must be non-negative")); + break; + + case 'B': + binary_architecture = optarg; + break; + + case 'i': + interleave = atoi (optarg); + if (interleave < 1) + fatal (_("interleave must be positive")); + break; + + case 'I': + case 's': /* "source" - 'I' is preferred */ + input_target = optarg; + break; + + case 'O': + case 'd': /* "destination" - 'O' is preferred */ + output_target = optarg; + break; + + case 'F': + input_target = output_target = optarg; + break; + + case 'j': + p = find_section_list (optarg, TRUE); + if (p->remove) + fatal (_("%s both copied and removed"), optarg); + p->copy = TRUE; + sections_copied = TRUE; + break; + + case 'R': + p = find_section_list (optarg, TRUE); + if (p->copy) + fatal (_("%s both copied and removed"), optarg); + p->remove = TRUE; + sections_removed = TRUE; + break; + + case 'S': + strip_symbols = STRIP_ALL; + break; + + case 'g': + strip_symbols = STRIP_DEBUG; + break; + + case OPTION_STRIP_UNNEEDED: + strip_symbols = STRIP_UNNEEDED; + break; + + case 'K': + add_specific_symbol (optarg, &keep_specific_list); + break; + + case 'N': + add_specific_symbol (optarg, &strip_specific_list); + break; + + case 'L': + add_specific_symbol (optarg, &localize_specific_list); + break; + + case 'G': + add_specific_symbol (optarg, &keepglobal_specific_list); + break; + + case 'W': + add_specific_symbol (optarg, &weaken_specific_list); + break; + + case 'p': + preserve_dates = TRUE; + break; + + case 'x': + discard_locals = LOCALS_ALL; + break; + + case 'X': + discard_locals = LOCALS_START_L; + break; + + case 'v': + verbose = TRUE; + break; + + case 'V': + show_version = TRUE; + break; + + case OPTION_FORMATS_INFO: + formats_info = TRUE; + break; + + case OPTION_WEAKEN: + weaken = TRUE; + break; + + case OPTION_ADD_SECTION: + { + const char *s; + struct stat st; + struct section_add *pa; + int len; + char *name; + FILE *f; + + s = strchr (optarg, '='); + + if (s == NULL) + fatal (_("bad format for %s"), "--add-section"); + + if (stat (s + 1, & st) < 0) + fatal (_("cannot stat: %s: %s"), s + 1, strerror (errno)); + + pa = (struct section_add *) xmalloc (sizeof (struct section_add)); + + len = s - optarg; + name = (char *) xmalloc (len + 1); + strncpy (name, optarg, len); + name[len] = '\0'; + pa->name = name; + + pa->filename = s + 1; + + pa->size = st.st_size; + + pa->contents = (bfd_byte *) xmalloc (pa->size); + f = fopen (pa->filename, FOPEN_RB); + + if (f == NULL) + fatal (_("cannot open: %s: %s"), pa->filename, strerror (errno)); + + if (fread (pa->contents, 1, pa->size, f) == 0 + || ferror (f)) + fatal (_("%s: fread failed"), pa->filename); + + fclose (f); + + pa->next = add_sections; + add_sections = pa; + } + break; + + case OPTION_CHANGE_START: + change_start = parse_vma (optarg, "--change-start"); + break; + + case OPTION_CHANGE_SECTION_ADDRESS: + case OPTION_CHANGE_SECTION_LMA: + case OPTION_CHANGE_SECTION_VMA: + { + const char *s; + int len; + char *name; + char *option = NULL; + bfd_vma val; + enum change_action what = CHANGE_IGNORE; + + switch (c) + { + case OPTION_CHANGE_SECTION_ADDRESS: + option = "--change-section-address"; + break; + case OPTION_CHANGE_SECTION_LMA: + option = "--change-section-lma"; + break; + case OPTION_CHANGE_SECTION_VMA: + option = "--change-section-vma"; + break; + } + + s = strchr (optarg, '='); + if (s == NULL) + { + s = strchr (optarg, '+'); + if (s == NULL) + { + s = strchr (optarg, '-'); + if (s == NULL) + fatal (_("bad format for %s"), option); + } + } + + len = s - optarg; + name = (char *) xmalloc (len + 1); + strncpy (name, optarg, len); + name[len] = '\0'; + + p = find_section_list (name, TRUE); + + val = parse_vma (s + 1, option); + + switch (*s) + { + case '=': what = CHANGE_SET; break; + case '-': val = - val; /* Drop through. */ + case '+': what = CHANGE_MODIFY; break; + } + + switch (c) + { + case OPTION_CHANGE_SECTION_ADDRESS: + p->change_vma = what; + p->vma_val = val; + /* Drop through. */ + + case OPTION_CHANGE_SECTION_LMA: + p->change_lma = what; + p->lma_val = val; + break; + + case OPTION_CHANGE_SECTION_VMA: + p->change_vma = what; + p->vma_val = val; + break; + } + } + break; + + case OPTION_CHANGE_ADDRESSES: + change_section_address = parse_vma (optarg, "--change-addresses"); + change_start = change_section_address; + break; + + case OPTION_CHANGE_WARNINGS: + change_warn = TRUE; + break; + + case OPTION_CHANGE_LEADING_CHAR: + change_leading_char = TRUE; + break; + + case OPTION_DEBUGGING: + convert_debugging = TRUE; + break; + + case OPTION_GAP_FILL: + { + bfd_vma gap_fill_vma; + + gap_fill_vma = parse_vma (optarg, "--gap-fill"); + gap_fill = (bfd_byte) gap_fill_vma; + if ((bfd_vma) gap_fill != gap_fill_vma) + { + char buff[20]; + + sprintf_vma (buff, gap_fill_vma); + + non_fatal (_("Warning: truncating gap-fill from 0x%s to 0x%x"), + buff, gap_fill); + } + gap_fill_set = TRUE; + } + break; + + case OPTION_NO_CHANGE_WARNINGS: + change_warn = FALSE; + break; + + case OPTION_PAD_TO: + pad_to = parse_vma (optarg, "--pad-to"); + pad_to_set = TRUE; + break; + + case OPTION_REMOVE_LEADING_CHAR: + remove_leading_char = TRUE; + break; + + case OPTION_REDEFINE_SYM: + { + /* Push this redefinition onto redefine_symbol_list. */ + + int len; + const char *s; + const char *nextarg; + char *source, *target; + + s = strchr (optarg, '='); + if (s == NULL) + fatal (_("bad format for %s"), "--redefine-sym"); + + len = s - optarg; + source = (char *) xmalloc (len + 1); + strncpy (source, optarg, len); + source[len] = '\0'; + + nextarg = s + 1; + len = strlen (nextarg); + target = (char *) xmalloc (len + 1); + strcpy (target, nextarg); + + redefine_list_append (source, target); + + free (source); + free (target); + } + break; + + case OPTION_SET_SECTION_FLAGS: + { + const char *s; + int len; + char *name; + + s = strchr (optarg, '='); + if (s == NULL) + fatal (_("bad format for %s"), "--set-section-flags"); + + len = s - optarg; + name = (char *) xmalloc (len + 1); + strncpy (name, optarg, len); + name[len] = '\0'; + + p = find_section_list (name, TRUE); + + p->set_flags = TRUE; + p->flags = parse_flags (s + 1); + } + break; + + case OPTION_RENAME_SECTION: + { + flagword flags; + const char *eq, *fl; + char *old_name; + char *new_name; + unsigned int len; + + eq = strchr (optarg, '='); + if (eq == NULL) + fatal (_("bad format for %s"), "--rename-section"); + + len = eq - optarg; + if (len == 0) + fatal (_("bad format for %s"), "--rename-section"); + + old_name = (char *) xmalloc (len + 1); + strncpy (old_name, optarg, len); + old_name[len] = 0; + + eq++; + fl = strchr (eq, ','); + if (fl) + { + flags = parse_flags (fl + 1); + len = fl - eq; + } + else + { + flags = -1; + len = strlen (eq); + } + + if (len == 0) + fatal (_("bad format for %s"), "--rename-section"); + + new_name = (char *) xmalloc (len + 1); + strncpy (new_name, eq, len); + new_name[len] = 0; + + add_section_rename (old_name, new_name, flags); + } + break; + + case OPTION_SET_START: + set_start = parse_vma (optarg, "--set-start"); + set_start_set = TRUE; + break; + + case OPTION_SREC_LEN: + Chunk = parse_vma (optarg, "--srec-len"); + break; + + case OPTION_SREC_FORCES3: + S3Forced = TRUE; + break; + + case OPTION_STRIP_SYMBOLS: + add_specific_symbols (optarg, &strip_specific_list); + break; + + case OPTION_KEEP_SYMBOLS: + add_specific_symbols (optarg, &keep_specific_list); + break; + + case OPTION_LOCALIZE_SYMBOLS: + add_specific_symbols (optarg, &localize_specific_list); + break; + + case OPTION_KEEPGLOBAL_SYMBOLS: + add_specific_symbols (optarg, &keepglobal_specific_list); + break; + + case OPTION_WEAKEN_SYMBOLS: + add_specific_symbols (optarg, &weaken_specific_list); + break; + + case OPTION_ALT_MACH_CODE: + use_alt_mach_code = atoi (optarg); + if (use_alt_mach_code <= 0) + fatal (_("alternate machine code index must be positive")); + break; + + case OPTION_PREFIX_SYMBOLS: + prefix_symbols_string = optarg; + break; + + case OPTION_PREFIX_SECTIONS: + prefix_sections_string = optarg; + break; + + case OPTION_PREFIX_ALLOC_SECTIONS: + prefix_alloc_sections_string = optarg; + break; + + case 0: + break; /* we've been given a long option */ + + case 'H': + case 'h': + copy_usage (stdout, 0); + + default: + copy_usage (stderr, 1); + } + } + + if (formats_info) + { + display_info (); + return 0; + } + + if (show_version) + print_version ("objcopy"); + + if (copy_byte >= interleave) + fatal (_("byte number must be less than interleave")); + + if (optind == argc || optind + 2 < argc) + copy_usage (stderr, 1); + + input_filename = argv[optind]; + if (optind + 1 < argc) + output_filename = argv[optind + 1]; + + /* Default is to strip no symbols. */ + if (strip_symbols == STRIP_UNDEF && discard_locals == LOCALS_UNDEF) + strip_symbols = STRIP_NONE; + + if (output_target == (char *) NULL) + output_target = input_target; + + if (binary_architecture != (char *) NULL) + { + if (input_target && strcmp (input_target, "binary") == 0) + { + const bfd_arch_info_type * temp_arch_info; + + temp_arch_info = bfd_scan_arch (binary_architecture); + + if (temp_arch_info != NULL) + bfd_external_binary_architecture = temp_arch_info->arch; + else + fatal (_("architecture %s unknown"), binary_architecture); + } + else + { + non_fatal (_("Warning: input target 'binary' required for binary architecture parameter.")); + non_fatal (_(" Argument %s ignored"), binary_architecture); + } + } + + if (preserve_dates) + if (stat (input_filename, & statbuf) < 0) + fatal (_("Cannot stat: %s: %s"), input_filename, strerror (errno)); + + /* If there is no destination file, or the source and destination files + are the same, then create a temp and rename the result into the input. */ + if ((output_filename == (char *) NULL) || + (strcmp (input_filename, output_filename) == 0)) + { + char *tmpname = make_tempname (input_filename); + + copy_file (input_filename, tmpname, input_target, output_target); + if (status == 0) + { + if (preserve_dates) + set_times (tmpname, &statbuf); + smart_rename (tmpname, input_filename, preserve_dates); + } + else + unlink (tmpname); + } + else + { + copy_file (input_filename, output_filename, input_target, output_target); + + if (status == 0 && preserve_dates) + set_times (output_filename, &statbuf); + } + + if (change_warn) + { + for (p = change_sections; p != NULL; p = p->next) + { + if (! p->used) + { + if (p->change_vma != CHANGE_IGNORE) + { + char buff [20]; + + sprintf_vma (buff, p->vma_val); + + /* xgettext:c-format */ + non_fatal (_("%s %s%c0x%s never used"), + "--change-section-vma", + p->name, + p->change_vma == CHANGE_SET ? '=' : '+', + buff); + } + + if (p->change_lma != CHANGE_IGNORE) + { + char buff [20]; + + sprintf_vma (buff, p->lma_val); + + /* xgettext:c-format */ + non_fatal (_("%s %s%c0x%s never used"), + "--change-section-lma", + p->name, + p->change_lma == CHANGE_SET ? '=' : '+', + buff); + } + } + } + } + + return 0; +} + +int main PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char *argv[]; +{ +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = argv[0]; + xmalloc_set_program_name (program_name); + + START_PROGRESS (program_name, 0); + + strip_symbols = STRIP_UNDEF; + discard_locals = LOCALS_UNDEF; + + bfd_init (); + set_default_bfd_target (); + + if (is_strip < 0) + { + int i = strlen (program_name); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + /* Drop the .exe suffix, if any. */ + if (i > 4 && FILENAME_CMP (program_name + i - 4, ".exe") == 0) + { + i -= 4; + program_name[i] = '\0'; + } +#endif + is_strip = (i >= 5 && FILENAME_CMP (program_name + i - 5, "strip") == 0); + } + + if (is_strip) + strip_main (argc, argv); + else + copy_main (argc, argv); + + END_PROGRESS (program_name); + + return status; +} diff --git a/contrib/binutils-2.14/binutils/objdump.c b/contrib/binutils-2.14/binutils/objdump.c new file mode 100644 index 0000000000..3c927bd7ae --- /dev/null +++ b/contrib/binutils-2.14/binutils/objdump.c @@ -0,0 +1,2809 @@ +/* objdump.c -- dump information about an object file. + Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "bfd.h" +#include "bfdver.h" +#include "progress.h" +#include "bucomm.h" +#include "budemang.h" +#include "getopt.h" +#include "safe-ctype.h" +#include "dis-asm.h" +#include "libiberty.h" +#include "demangle.h" +#include "debug.h" +#include "budbg.h" + +/* Internal headers for the ELF .stab-dump code - sorry. */ +#define BYTES_IN_WORD 32 +#include "aout/aout64.h" + +#ifdef NEED_DECLARATION_FPRINTF +/* This is needed by INIT_DISASSEMBLE_INFO. */ +extern int fprintf + PARAMS ((FILE *, const char *, ...)); +#endif + +/* Exit status. */ +static int exit_status = 0; + +static char *default_target = NULL; /* Default at runtime. */ + +static int show_version = 0; /* Show the version number. */ +static int dump_section_contents; /* -s */ +static int dump_section_headers; /* -h */ +static bfd_boolean dump_file_header; /* -f */ +static int dump_symtab; /* -t */ +static int dump_dynamic_symtab; /* -T */ +static int dump_reloc_info; /* -r */ +static int dump_dynamic_reloc_info; /* -R */ +static int dump_ar_hdrs; /* -a */ +static int dump_private_headers; /* -p */ +static int prefix_addresses; /* --prefix-addresses */ +static int with_line_numbers; /* -l */ +static bfd_boolean with_source_code; /* -S */ +static int show_raw_insn; /* --show-raw-insn */ +static int dump_stab_section_info; /* --stabs */ +static int do_demangle; /* -C, --demangle */ +static bfd_boolean disassemble; /* -d */ +static bfd_boolean disassemble_all; /* -D */ +static int disassemble_zeroes; /* --disassemble-zeroes */ +static bfd_boolean formats_info; /* -i */ +static char *only; /* -j secname */ +static int wide_output; /* -w */ +static bfd_vma start_address = (bfd_vma) -1; /* --start-address */ +static bfd_vma stop_address = (bfd_vma) -1; /* --stop-address */ +static int dump_debugging; /* --debugging */ +static bfd_vma adjust_section_vma = 0; /* --adjust-vma */ +static int file_start_context = 0; /* --file-start-context */ + +/* Extra info to pass to the disassembler address printing function. */ +struct objdump_disasm_info +{ + bfd *abfd; + asection *sec; + bfd_boolean require_sec; +}; + +/* Architecture to disassemble for, or default if NULL. */ +static char *machine = (char *) NULL; + +/* Target specific options to the disassembler. */ +static char *disassembler_options = (char *) NULL; + +/* Endianness to disassemble for, or default if BFD_ENDIAN_UNKNOWN. */ +static enum bfd_endian endian = BFD_ENDIAN_UNKNOWN; + +/* The symbol table. */ +static asymbol **syms; + +/* Number of symbols in `syms'. */ +static long symcount = 0; + +/* The sorted symbol table. */ +static asymbol **sorted_syms; + +/* Number of symbols in `sorted_syms'. */ +static long sorted_symcount = 0; + +/* The dynamic symbol table. */ +static asymbol **dynsyms; + +/* Number of symbols in `dynsyms'. */ +static long dynsymcount = 0; + +static bfd_byte *stabs; +static bfd_size_type stab_size; + +static char *strtab; +static bfd_size_type stabstr_size; + +/* Static declarations. */ + +static void usage + PARAMS ((FILE *, int)); +static void nonfatal + PARAMS ((const char *)); +static void display_file + PARAMS ((char *, char *)); +static void dump_section_header + PARAMS ((bfd *, asection *, PTR)); +static void dump_headers + PARAMS ((bfd *)); +static void dump_data + PARAMS ((bfd *)); +static void dump_relocs + PARAMS ((bfd *)); +static void dump_dynamic_relocs + PARAMS ((bfd *)); +static void dump_reloc_set + PARAMS ((bfd *, asection *, arelent **, long)); +static void dump_symbols + PARAMS ((bfd *, bfd_boolean)); +static void dump_bfd_header + PARAMS ((bfd *)); +static void dump_bfd_private_header + PARAMS ((bfd *)); +static void dump_bfd + PARAMS ((bfd *)); +static void display_bfd + PARAMS ((bfd *)); +static void objdump_print_value + PARAMS ((bfd_vma, struct disassemble_info *, bfd_boolean)); +static void objdump_print_symname + PARAMS ((bfd *, struct disassemble_info *, asymbol *)); +static asymbol *find_symbol_for_address + PARAMS ((bfd *, asection *, bfd_vma, bfd_boolean, long *)); +static void objdump_print_addr_with_sym + PARAMS ((bfd *, asection *, asymbol *, bfd_vma, + struct disassemble_info *, bfd_boolean)); +static void objdump_print_addr + PARAMS ((bfd_vma, struct disassemble_info *, bfd_boolean)); +static void objdump_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); +static int objdump_symbol_at_address + PARAMS ((bfd_vma, struct disassemble_info *)); +static void show_line + PARAMS ((bfd *, asection *, bfd_vma)); +static void disassemble_bytes + PARAMS ((struct disassemble_info *, disassembler_ftype, bfd_boolean, + bfd_byte *, bfd_vma, bfd_vma, arelent ***, arelent **)); +static void disassemble_data + PARAMS ((bfd *)); +static asymbol ** slurp_symtab + PARAMS ((bfd *)); +static asymbol ** slurp_dynamic_symtab + PARAMS ((bfd *)); +static long remove_useless_symbols + PARAMS ((asymbol **, long)); +static int compare_symbols + PARAMS ((const PTR, const PTR)); +static int compare_relocs + PARAMS ((const PTR, const PTR)); +static void dump_stabs + PARAMS ((bfd *)); +static bfd_boolean read_section_stabs + PARAMS ((bfd *, const char *, const char *)); +static void print_section_stabs + PARAMS ((bfd *, const char *, const char *)); +static void dump_section_stabs + PARAMS ((bfd *, char *, char *)); + +static void +usage (stream, status) + FILE *stream; + int status; +{ + fprintf (stream, _("Usage: %s \n"), program_name); + fprintf (stream, _(" Display information from object .\n")); + fprintf (stream, _(" At least one of the following switches must be given:\n")); + fprintf (stream, _("\ + -a, --archive-headers Display archive header information\n\ + -f, --file-headers Display the contents of the overall file header\n\ + -p, --private-headers Display object format specific file header contents\n\ + -h, --[section-]headers Display the contents of the section headers\n\ + -x, --all-headers Display the contents of all headers\n\ + -d, --disassemble Display assembler contents of executable sections\n\ + -D, --disassemble-all Display assembler contents of all sections\n\ + -S, --source Intermix source code with disassembly\n\ + -s, --full-contents Display the full contents of all sections requested\n\ + -g, --debugging Display debug information in object file\n\ + -G, --stabs Display (in raw form) any STABS info in the file\n\ + -t, --syms Display the contents of the symbol table(s)\n\ + -T, --dynamic-syms Display the contents of the dynamic symbol table\n\ + -r, --reloc Display the relocation entries in the file\n\ + -R, --dynamic-reloc Display the dynamic relocation entries in the file\n\ + -v, --version Display this program's version number\n\ + -i, --info List object formats and architectures supported\n\ + -H, --help Display this information\n\ +")); + if (status != 2) + { + fprintf (stream, _("\n The following switches are optional:\n")); + fprintf (stream, _("\ + -b, --target=BFDNAME Specify the target object format as BFDNAME\n\ + -m, --architecture=MACHINE Specify the target architecture as MACHINE\n\ + -j, --section=NAME Only display information for section NAME\n\ + -M, --disassembler-options=OPT Pass text OPT on to the disassembler\n\ + -EB --endian=big Assume big endian format when disassembling\n\ + -EL --endian=little Assume little endian format when disassembling\n\ + --file-start-context Include context from start of file (with -S)\n\ + -l, --line-numbers Include line numbers and filenames in output\n\ + -C, --demangle[=STYLE] Decode mangled/processed symbol names\n\ + The STYLE, if specified, can be `auto', `gnu',\n\ + `lucid', `arm', `hp', `edg', `gnu-v3', `java'\n\ + or `gnat'\n\ + -w, --wide Format output for more than 80 columns\n\ + -z, --disassemble-zeroes Do not skip blocks of zeroes when disassembling\n\ + --start-address=ADDR Only process data whose address is >= ADDR\n\ + --stop-address=ADDR Only process data whose address is <= ADDR\n\ + --prefix-addresses Print complete address alongside disassembly\n\ + --[no-]show-raw-insn Display hex alongside symbolic disassembly\n\ + --adjust-vma=OFFSET Add OFFSET to all displayed section addresses\n\ +\n")); + list_supported_targets (program_name, stream); + list_supported_architectures (program_name, stream); + + disassembler_usage (stream); + } + if (status == 0) + fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO); + exit (status); +} + +/* 150 isn't special; it's just an arbitrary non-ASCII char value. */ + +#define OPTION_ENDIAN (150) +#define OPTION_START_ADDRESS (OPTION_ENDIAN + 1) +#define OPTION_STOP_ADDRESS (OPTION_START_ADDRESS + 1) +#define OPTION_ADJUST_VMA (OPTION_STOP_ADDRESS + 1) + +static struct option long_options[]= +{ + {"adjust-vma", required_argument, NULL, OPTION_ADJUST_VMA}, + {"all-headers", no_argument, NULL, 'x'}, + {"private-headers", no_argument, NULL, 'p'}, + {"architecture", required_argument, NULL, 'm'}, + {"archive-headers", no_argument, NULL, 'a'}, + {"debugging", no_argument, NULL, 'g'}, + {"demangle", optional_argument, NULL, 'C'}, + {"disassemble", no_argument, NULL, 'd'}, + {"disassemble-all", no_argument, NULL, 'D'}, + {"disassembler-options", required_argument, NULL, 'M'}, + {"disassemble-zeroes", no_argument, NULL, 'z'}, + {"dynamic-reloc", no_argument, NULL, 'R'}, + {"dynamic-syms", no_argument, NULL, 'T'}, + {"endian", required_argument, NULL, OPTION_ENDIAN}, + {"file-headers", no_argument, NULL, 'f'}, + {"file-start-context", no_argument, &file_start_context, 1}, + {"full-contents", no_argument, NULL, 's'}, + {"headers", no_argument, NULL, 'h'}, + {"help", no_argument, NULL, 'H'}, + {"info", no_argument, NULL, 'i'}, + {"line-numbers", no_argument, NULL, 'l'}, + {"no-show-raw-insn", no_argument, &show_raw_insn, -1}, + {"prefix-addresses", no_argument, &prefix_addresses, 1}, + {"reloc", no_argument, NULL, 'r'}, + {"section", required_argument, NULL, 'j'}, + {"section-headers", no_argument, NULL, 'h'}, + {"show-raw-insn", no_argument, &show_raw_insn, 1}, + {"source", no_argument, NULL, 'S'}, + {"stabs", no_argument, NULL, 'G'}, + {"start-address", required_argument, NULL, OPTION_START_ADDRESS}, + {"stop-address", required_argument, NULL, OPTION_STOP_ADDRESS}, + {"syms", no_argument, NULL, 't'}, + {"target", required_argument, NULL, 'b'}, + {"version", no_argument, NULL, 'V'}, + {"wide", no_argument, NULL, 'w'}, + {0, no_argument, 0, 0} +}; + +static void +nonfatal (msg) + const char *msg; +{ + bfd_nonfatal (msg); + exit_status = 1; +} + +static void +dump_section_header (abfd, section, ignored) + bfd *abfd ATTRIBUTE_UNUSED; + asection *section; + PTR ignored ATTRIBUTE_UNUSED; +{ + char *comma = ""; + unsigned int opb = bfd_octets_per_byte (abfd); + + printf ("%3d %-13s %08lx ", section->index, + bfd_get_section_name (abfd, section), + (unsigned long) bfd_section_size (abfd, section) / opb); + bfd_printf_vma (abfd, bfd_get_section_vma (abfd, section)); + printf (" "); + bfd_printf_vma (abfd, section->lma); + printf (" %08lx 2**%u", (unsigned long) section->filepos, + bfd_get_section_alignment (abfd, section)); + if (! wide_output) + printf ("\n "); + printf (" "); + +#define PF(x, y) \ + if (section->flags & x) { printf ("%s%s", comma, y); comma = ", "; } + + PF (SEC_HAS_CONTENTS, "CONTENTS"); + PF (SEC_ALLOC, "ALLOC"); + PF (SEC_CONSTRUCTOR, "CONSTRUCTOR"); + PF (SEC_LOAD, "LOAD"); + PF (SEC_RELOC, "RELOC"); + PF (SEC_READONLY, "READONLY"); + PF (SEC_CODE, "CODE"); + PF (SEC_DATA, "DATA"); + PF (SEC_ROM, "ROM"); + PF (SEC_DEBUGGING, "DEBUGGING"); + PF (SEC_NEVER_LOAD, "NEVER_LOAD"); + PF (SEC_EXCLUDE, "EXCLUDE"); + PF (SEC_SORT_ENTRIES, "SORT_ENTRIES"); + PF (SEC_BLOCK, "BLOCK"); + PF (SEC_CLINK, "CLINK"); + PF (SEC_SMALL_DATA, "SMALL_DATA"); + PF (SEC_SHARED, "SHARED"); + PF (SEC_ARCH_BIT_0, "ARCH_BIT_0"); + PF (SEC_THREAD_LOCAL, "THREAD_LOCAL"); + + if ((section->flags & SEC_LINK_ONCE) != 0) + { + const char *ls; + + switch (section->flags & SEC_LINK_DUPLICATES) + { + default: + abort (); + case SEC_LINK_DUPLICATES_DISCARD: + ls = "LINK_ONCE_DISCARD"; + break; + case SEC_LINK_DUPLICATES_ONE_ONLY: + ls = "LINK_ONCE_ONE_ONLY"; + break; + case SEC_LINK_DUPLICATES_SAME_SIZE: + ls = "LINK_ONCE_SAME_SIZE"; + break; + case SEC_LINK_DUPLICATES_SAME_CONTENTS: + ls = "LINK_ONCE_SAME_CONTENTS"; + break; + } + printf ("%s%s", comma, ls); + + if (section->comdat != NULL) + printf (" (COMDAT %s %ld)", section->comdat->name, + section->comdat->symbol); + + comma = ", "; + } + + printf ("\n"); +#undef PF +} + +static void +dump_headers (abfd) + bfd *abfd; +{ + printf (_("Sections:\n")); + +#ifndef BFD64 + printf (_("Idx Name Size VMA LMA File off Algn")); +#else + /* With BFD64, non-ELF returns -1 and wants always 64 bit addresses. */ + if (bfd_get_arch_size (abfd) == 32) + printf (_("Idx Name Size VMA LMA File off Algn")); + else + printf (_("Idx Name Size VMA LMA File off Algn")); +#endif + + if (wide_output) + printf (_(" Flags")); + if (abfd->flags & HAS_LOAD_PAGE) + printf (_(" Pg")); + printf ("\n"); + + bfd_map_over_sections (abfd, dump_section_header, (PTR) NULL); +} + +static asymbol ** +slurp_symtab (abfd) + bfd *abfd; +{ + asymbol **sy = (asymbol **) NULL; + long storage; + + if (!(bfd_get_file_flags (abfd) & HAS_SYMS)) + { + symcount = 0; + return NULL; + } + + storage = bfd_get_symtab_upper_bound (abfd); + if (storage < 0) + bfd_fatal (bfd_get_filename (abfd)); + if (storage) + sy = (asymbol **) xmalloc (storage); + + symcount = bfd_canonicalize_symtab (abfd, sy); + if (symcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + return sy; +} + +/* Read in the dynamic symbols. */ + +static asymbol ** +slurp_dynamic_symtab (abfd) + bfd *abfd; +{ + asymbol **sy = (asymbol **) NULL; + long storage; + + storage = bfd_get_dynamic_symtab_upper_bound (abfd); + if (storage < 0) + { + if (!(bfd_get_file_flags (abfd) & DYNAMIC)) + { + non_fatal (_("%s: not a dynamic object"), bfd_get_filename (abfd)); + dynsymcount = 0; + return NULL; + } + + bfd_fatal (bfd_get_filename (abfd)); + } + if (storage) + sy = (asymbol **) xmalloc (storage); + + dynsymcount = bfd_canonicalize_dynamic_symtab (abfd, sy); + if (dynsymcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + return sy; +} + +/* Filter out (in place) symbols that are useless for disassembly. + COUNT is the number of elements in SYMBOLS. + Return the number of useful symbols. */ + +static long +remove_useless_symbols (symbols, count) + asymbol **symbols; + long count; +{ + register asymbol **in_ptr = symbols, **out_ptr = symbols; + + while (--count >= 0) + { + asymbol *sym = *in_ptr++; + + if (sym->name == NULL || sym->name[0] == '\0') + continue; + if (sym->flags & (BSF_DEBUGGING)) + continue; + if (bfd_is_und_section (sym->section) + || bfd_is_com_section (sym->section)) + continue; + + *out_ptr++ = sym; + } + return out_ptr - symbols; +} + +/* Sort symbols into value order. */ + +static int +compare_symbols (ap, bp) + const PTR ap; + const PTR bp; +{ + const asymbol *a = *(const asymbol **)ap; + const asymbol *b = *(const asymbol **)bp; + const char *an, *bn; + size_t anl, bnl; + bfd_boolean af, bf; + flagword aflags, bflags; + + if (bfd_asymbol_value (a) > bfd_asymbol_value (b)) + return 1; + else if (bfd_asymbol_value (a) < bfd_asymbol_value (b)) + return -1; + + if (a->section > b->section) + return 1; + else if (a->section < b->section) + return -1; + + an = bfd_asymbol_name (a); + bn = bfd_asymbol_name (b); + anl = strlen (an); + bnl = strlen (bn); + + /* The symbols gnu_compiled and gcc2_compiled convey no real + information, so put them after other symbols with the same value. */ + af = (strstr (an, "gnu_compiled") != NULL + || strstr (an, "gcc2_compiled") != NULL); + bf = (strstr (bn, "gnu_compiled") != NULL + || strstr (bn, "gcc2_compiled") != NULL); + + if (af && ! bf) + return 1; + if (! af && bf) + return -1; + + /* We use a heuristic for the file name, to try to sort it after + more useful symbols. It may not work on non Unix systems, but it + doesn't really matter; the only difference is precisely which + symbol names get printed. */ + +#define file_symbol(s, sn, snl) \ + (((s)->flags & BSF_FILE) != 0 \ + || ((sn)[(snl) - 2] == '.' \ + && ((sn)[(snl) - 1] == 'o' \ + || (sn)[(snl) - 1] == 'a'))) + + af = file_symbol (a, an, anl); + bf = file_symbol (b, bn, bnl); + + if (af && ! bf) + return 1; + if (! af && bf) + return -1; + + /* Try to sort global symbols before local symbols before function + symbols before debugging symbols. */ + + aflags = a->flags; + bflags = b->flags; + + if ((aflags & BSF_DEBUGGING) != (bflags & BSF_DEBUGGING)) + { + if ((aflags & BSF_DEBUGGING) != 0) + return 1; + else + return -1; + } + if ((aflags & BSF_FUNCTION) != (bflags & BSF_FUNCTION)) + { + if ((aflags & BSF_FUNCTION) != 0) + return -1; + else + return 1; + } + if ((aflags & BSF_LOCAL) != (bflags & BSF_LOCAL)) + { + if ((aflags & BSF_LOCAL) != 0) + return 1; + else + return -1; + } + if ((aflags & BSF_GLOBAL) != (bflags & BSF_GLOBAL)) + { + if ((aflags & BSF_GLOBAL) != 0) + return -1; + else + return 1; + } + + /* Symbols that start with '.' might be section names, so sort them + after symbols that don't start with '.'. */ + if (an[0] == '.' && bn[0] != '.') + return 1; + if (an[0] != '.' && bn[0] == '.') + return -1; + + /* Finally, if we can't distinguish them in any other way, try to + get consistent results by sorting the symbols by name. */ + return strcmp (an, bn); +} + +/* Sort relocs into address order. */ + +static int +compare_relocs (ap, bp) + const PTR ap; + const PTR bp; +{ + const arelent *a = *(const arelent **)ap; + const arelent *b = *(const arelent **)bp; + + if (a->address > b->address) + return 1; + else if (a->address < b->address) + return -1; + + /* So that associated relocations tied to the same address show up + in the correct order, we don't do any further sorting. */ + if (a > b) + return 1; + else if (a < b) + return -1; + else + return 0; +} + +/* Print VMA to STREAM. If SKIP_ZEROES is TRUE, omit leading zeroes. */ + +static void +objdump_print_value (vma, info, skip_zeroes) + bfd_vma vma; + struct disassemble_info *info; + bfd_boolean skip_zeroes; +{ + char buf[30]; + char *p; + struct objdump_disasm_info *aux + = (struct objdump_disasm_info *) info->application_data; + + bfd_sprintf_vma (aux->abfd, buf, vma); + if (! skip_zeroes) + p = buf; + else + { + for (p = buf; *p == '0'; ++p) + ; + if (*p == '\0') + --p; + } + (*info->fprintf_func) (info->stream, "%s", p); +} + +/* Print the name of a symbol. */ + +static void +objdump_print_symname (abfd, info, sym) + bfd *abfd; + struct disassemble_info *info; + asymbol *sym; +{ + char *alloc; + const char *name; + + alloc = NULL; + name = bfd_asymbol_name (sym); + if (do_demangle && name[0] != '\0') + { + /* Demangle the name. */ + alloc = demangle (abfd, name); + name = alloc; + } + + if (info != NULL) + (*info->fprintf_func) (info->stream, "%s", name); + else + printf ("%s", name); + + if (alloc != NULL) + free (alloc); +} + +/* Locate a symbol given a bfd, a section, and a VMA. If REQUIRE_SEC + is TRUE, then always require the symbol to be in the section. This + returns NULL if there is no suitable symbol. If PLACE is not NULL, + then *PLACE is set to the index of the symbol in sorted_syms. */ + +static asymbol * +find_symbol_for_address (abfd, sec, vma, require_sec, place) + bfd *abfd; + asection *sec; + bfd_vma vma; + bfd_boolean require_sec; + long *place; +{ + /* @@ Would it speed things up to cache the last two symbols returned, + and maybe their address ranges? For many processors, only one memory + operand can be present at a time, so the 2-entry cache wouldn't be + constantly churned by code doing heavy memory accesses. */ + + /* Indices in `sorted_syms'. */ + long min = 0; + long max = sorted_symcount; + long thisplace; + unsigned int opb = bfd_octets_per_byte (abfd); + + if (sorted_symcount < 1) + return NULL; + + /* Perform a binary search looking for the closest symbol to the + required value. We are searching the range (min, max]. */ + while (min + 1 < max) + { + asymbol *sym; + + thisplace = (max + min) / 2; + sym = sorted_syms[thisplace]; + + if (bfd_asymbol_value (sym) > vma) + max = thisplace; + else if (bfd_asymbol_value (sym) < vma) + min = thisplace; + else + { + min = thisplace; + break; + } + } + + /* The symbol we want is now in min, the low end of the range we + were searching. If there are several symbols with the same + value, we want the first one. */ + thisplace = min; + while (thisplace > 0 + && (bfd_asymbol_value (sorted_syms[thisplace]) + == bfd_asymbol_value (sorted_syms[thisplace - 1]))) + --thisplace; + + /* If the file is relocateable, and the symbol could be from this + section, prefer a symbol from this section over symbols from + others, even if the other symbol's value might be closer. + + Note that this may be wrong for some symbol references if the + sections have overlapping memory ranges, but in that case there's + no way to tell what's desired without looking at the relocation + table. */ + if (sorted_syms[thisplace]->section != sec + && (require_sec + || ((abfd->flags & HAS_RELOC) != 0 + && vma >= bfd_get_section_vma (abfd, sec) + && vma < (bfd_get_section_vma (abfd, sec) + + bfd_section_size (abfd, sec) / opb)))) + { + long i; + + for (i = thisplace + 1; i < sorted_symcount; i++) + { + if (bfd_asymbol_value (sorted_syms[i]) + != bfd_asymbol_value (sorted_syms[thisplace])) + break; + } + + --i; + + for (; i >= 0; i--) + { + if (sorted_syms[i]->section == sec + && (i == 0 + || sorted_syms[i - 1]->section != sec + || (bfd_asymbol_value (sorted_syms[i]) + != bfd_asymbol_value (sorted_syms[i - 1])))) + { + thisplace = i; + break; + } + } + + if (sorted_syms[thisplace]->section != sec) + { + /* We didn't find a good symbol with a smaller value. + Look for one with a larger value. */ + for (i = thisplace + 1; i < sorted_symcount; i++) + { + if (sorted_syms[i]->section == sec) + { + thisplace = i; + break; + } + } + } + + if (sorted_syms[thisplace]->section != sec + && (require_sec + || ((abfd->flags & HAS_RELOC) != 0 + && vma >= bfd_get_section_vma (abfd, sec) + && vma < (bfd_get_section_vma (abfd, sec) + + bfd_section_size (abfd, sec))))) + { + /* There is no suitable symbol. */ + return NULL; + } + } + + if (place != NULL) + *place = thisplace; + + return sorted_syms[thisplace]; +} + +/* Print an address to INFO symbolically. */ + +static void +objdump_print_addr_with_sym (abfd, sec, sym, vma, info, skip_zeroes) + bfd *abfd; + asection *sec; + asymbol *sym; + bfd_vma vma; + struct disassemble_info *info; + bfd_boolean skip_zeroes; +{ + objdump_print_value (vma, info, skip_zeroes); + + if (sym == NULL) + { + bfd_vma secaddr; + + (*info->fprintf_func) (info->stream, " <%s", + bfd_get_section_name (abfd, sec)); + secaddr = bfd_get_section_vma (abfd, sec); + if (vma < secaddr) + { + (*info->fprintf_func) (info->stream, "-0x"); + objdump_print_value (secaddr - vma, info, TRUE); + } + else if (vma > secaddr) + { + (*info->fprintf_func) (info->stream, "+0x"); + objdump_print_value (vma - secaddr, info, TRUE); + } + (*info->fprintf_func) (info->stream, ">"); + } + else + { + (*info->fprintf_func) (info->stream, " <"); + objdump_print_symname (abfd, info, sym); + if (bfd_asymbol_value (sym) > vma) + { + (*info->fprintf_func) (info->stream, "-0x"); + objdump_print_value (bfd_asymbol_value (sym) - vma, info, TRUE); + } + else if (vma > bfd_asymbol_value (sym)) + { + (*info->fprintf_func) (info->stream, "+0x"); + objdump_print_value (vma - bfd_asymbol_value (sym), info, TRUE); + } + (*info->fprintf_func) (info->stream, ">"); + } +} + +/* Print VMA to INFO, symbolically if possible. If SKIP_ZEROES is + TRUE, don't output leading zeroes. */ + +static void +objdump_print_addr (vma, info, skip_zeroes) + bfd_vma vma; + struct disassemble_info *info; + bfd_boolean skip_zeroes; +{ + struct objdump_disasm_info *aux; + asymbol *sym; + + if (sorted_symcount < 1) + { + (*info->fprintf_func) (info->stream, "0x"); + objdump_print_value (vma, info, skip_zeroes); + return; + } + + aux = (struct objdump_disasm_info *) info->application_data; + sym = find_symbol_for_address (aux->abfd, aux->sec, vma, aux->require_sec, + (long *) NULL); + objdump_print_addr_with_sym (aux->abfd, aux->sec, sym, vma, info, + skip_zeroes); +} + +/* Print VMA to INFO. This function is passed to the disassembler + routine. */ + +static void +objdump_print_address (vma, info) + bfd_vma vma; + struct disassemble_info *info; +{ + objdump_print_addr (vma, info, ! prefix_addresses); +} + +/* Determine of the given address has a symbol associated with it. */ + +static int +objdump_symbol_at_address (vma, info) + bfd_vma vma; + struct disassemble_info * info; +{ + struct objdump_disasm_info * aux; + asymbol * sym; + + /* No symbols - do not bother checking. */ + if (sorted_symcount < 1) + return 0; + + aux = (struct objdump_disasm_info *) info->application_data; + sym = find_symbol_for_address (aux->abfd, aux->sec, vma, aux->require_sec, + (long *) NULL); + + return (sym != NULL && (bfd_asymbol_value (sym) == vma)); +} + +/* Hold the last function name and the last line number we displayed + in a disassembly. */ + +static char *prev_functionname; +static unsigned int prev_line; + +/* We keep a list of all files that we have seen when doing a + dissassembly with source, so that we know how much of the file to + display. This can be important for inlined functions. */ + +struct print_file_list +{ + struct print_file_list *next; + char *filename; + unsigned int line; + FILE *f; +}; + +static struct print_file_list *print_files; + +/* The number of preceding context lines to show when we start + displaying a file for the first time. */ + +#define SHOW_PRECEDING_CONTEXT_LINES (5) + +/* Skip ahead to a given line in a file, optionally printing each + line. */ + +static void skip_to_line + PARAMS ((struct print_file_list *, unsigned int, bfd_boolean)); + +static void +skip_to_line (p, line, show) + struct print_file_list *p; + unsigned int line; + bfd_boolean show; +{ + while (p->line < line) + { + char buf[100]; + + if (fgets (buf, sizeof buf, p->f) == NULL) + { + fclose (p->f); + p->f = NULL; + break; + } + + if (show) + printf ("%s", buf); + + if (strchr (buf, '\n') != NULL) + ++p->line; + } +} + +/* Show the line number, or the source line, in a dissassembly + listing. */ + +static void +show_line (abfd, section, addr_offset) + bfd *abfd; + asection *section; + bfd_vma addr_offset; +{ + const char *filename; + const char *functionname; + unsigned int line; + + if (! with_line_numbers && ! with_source_code) + return; + + if (! bfd_find_nearest_line (abfd, section, syms, addr_offset, &filename, + &functionname, &line)) + return; + + if (filename != NULL && *filename == '\0') + filename = NULL; + if (functionname != NULL && *functionname == '\0') + functionname = NULL; + + if (with_line_numbers) + { + if (functionname != NULL + && (prev_functionname == NULL + || strcmp (functionname, prev_functionname) != 0)) + printf ("%s():\n", functionname); + if (line > 0 && line != prev_line) + printf ("%s:%u\n", filename == NULL ? "???" : filename, line); + } + + if (with_source_code + && filename != NULL + && line > 0) + { + struct print_file_list **pp, *p; + + for (pp = &print_files; *pp != NULL; pp = &(*pp)->next) + if (strcmp ((*pp)->filename, filename) == 0) + break; + p = *pp; + + if (p != NULL) + { + if (p != print_files) + { + int l; + + /* We have reencountered a file name which we saw + earlier. This implies that either we are dumping out + code from an included file, or the same file was + linked in more than once. There are two common cases + of an included file: inline functions in a header + file, and a bison or flex skeleton file. In the + former case we want to just start printing (but we + back up a few lines to give context); in the latter + case we want to continue from where we left off. I + can't think of a good way to distinguish the cases, + so I used a heuristic based on the file name. */ + if (strcmp (p->filename + strlen (p->filename) - 2, ".h") != 0) + l = p->line; + else + { + l = line - SHOW_PRECEDING_CONTEXT_LINES; + if (l < 0) + l = 0; + } + + if (p->f == NULL) + { + p->f = fopen (p->filename, "r"); + p->line = 0; + } + if (p->f != NULL) + skip_to_line (p, l, FALSE); + + if (print_files->f != NULL) + { + fclose (print_files->f); + print_files->f = NULL; + } + } + + if (p->f != NULL) + { + skip_to_line (p, line, TRUE); + *pp = p->next; + p->next = print_files; + print_files = p; + } + } + else + { + FILE *f; + + f = fopen (filename, "r"); + if (f != NULL) + { + int l; + + p = ((struct print_file_list *) + xmalloc (sizeof (struct print_file_list))); + p->filename = xmalloc (strlen (filename) + 1); + strcpy (p->filename, filename); + p->line = 0; + p->f = f; + + if (print_files != NULL && print_files->f != NULL) + { + fclose (print_files->f); + print_files->f = NULL; + } + p->next = print_files; + print_files = p; + + if (file_start_context) + l = 0; + else + l = line - SHOW_PRECEDING_CONTEXT_LINES; + if (l < 0) + l = 0; + skip_to_line (p, l, FALSE); + if (p->f != NULL) + skip_to_line (p, line, TRUE); + } + } + } + + if (functionname != NULL + && (prev_functionname == NULL + || strcmp (functionname, prev_functionname) != 0)) + { + if (prev_functionname != NULL) + free (prev_functionname); + prev_functionname = xmalloc (strlen (functionname) + 1); + strcpy (prev_functionname, functionname); + } + + if (line > 0 && line != prev_line) + prev_line = line; +} + +/* Pseudo FILE object for strings. */ +typedef struct +{ + char *buffer; + size_t size; + char *current; +} SFILE; + +/* sprintf to a "stream" */ + +static int +objdump_sprintf VPARAMS ((SFILE *f, const char *format, ...)) +{ + char *buf; + size_t n; + + VA_OPEN (args, format); + VA_FIXEDARG (args, SFILE *, f); + VA_FIXEDARG (args, const char *, format); + + vasprintf (&buf, format, args); + + if (buf == NULL) + { + va_end (args); + fatal (_("Out of virtual memory")); + } + + n = strlen (buf); + + while ((size_t) ((f->buffer + f->size) - f->current) < n + 1) + { + size_t curroff; + + curroff = f->current - f->buffer; + f->size *= 2; + f->buffer = xrealloc (f->buffer, f->size); + f->current = f->buffer + curroff; + } + + memcpy (f->current, buf, n); + f->current += n; + f->current[0] = '\0'; + + free (buf); + + VA_CLOSE (args); + return n; +} + +/* The number of zeroes we want to see before we start skipping them. + The number is arbitrarily chosen. */ + +#ifndef SKIP_ZEROES +#define SKIP_ZEROES (8) +#endif + +/* The number of zeroes to skip at the end of a section. If the + number of zeroes at the end is between SKIP_ZEROES_AT_END and + SKIP_ZEROES, they will be disassembled. If there are fewer than + SKIP_ZEROES_AT_END, they will be skipped. This is a heuristic + attempt to avoid disassembling zeroes inserted by section + alignment. */ + +#ifndef SKIP_ZEROES_AT_END +#define SKIP_ZEROES_AT_END (3) +#endif + +/* Disassemble some data in memory between given values. */ + +static void +disassemble_bytes (info, disassemble_fn, insns, data, + start_offset, stop_offset, relppp, + relppend) + struct disassemble_info *info; + disassembler_ftype disassemble_fn; + bfd_boolean insns; + bfd_byte *data; + bfd_vma start_offset; + bfd_vma stop_offset; + arelent ***relppp; + arelent **relppend; +{ + struct objdump_disasm_info *aux; + asection *section; + int octets_per_line; + bfd_boolean done_dot; + int skip_addr_chars; + bfd_vma addr_offset; + int opb = info->octets_per_byte; + + aux = (struct objdump_disasm_info *) info->application_data; + section = aux->sec; + + if (insns) + octets_per_line = 4; + else + octets_per_line = 16; + + /* Figure out how many characters to skip at the start of an + address, to make the disassembly look nicer. We discard leading + zeroes in chunks of 4, ensuring that there is always a leading + zero remaining. */ + skip_addr_chars = 0; + if (! prefix_addresses) + { + char buf[30]; + char *s; + + bfd_sprintf_vma + (aux->abfd, buf, + (section->vma + + bfd_section_size (section->owner, section) / opb)); + s = buf; + while (s[0] == '0' && s[1] == '0' && s[2] == '0' && s[3] == '0' + && s[4] == '0') + { + skip_addr_chars += 4; + s += 4; + } + } + + info->insn_info_valid = 0; + + done_dot = FALSE; + addr_offset = start_offset; + while (addr_offset < stop_offset) + { + bfd_vma z; + int octets = 0; + bfd_boolean need_nl = FALSE; + + /* If we see more than SKIP_ZEROES octets of zeroes, we just + print `...'. */ + for (z = addr_offset * opb; z < stop_offset * opb; z++) + if (data[z] != 0) + break; + if (! disassemble_zeroes + && (info->insn_info_valid == 0 + || info->branch_delay_insns == 0) + && (z - addr_offset * opb >= SKIP_ZEROES + || (z == stop_offset * opb && + z - addr_offset * opb < SKIP_ZEROES_AT_END))) + { + printf ("\t...\n"); + + /* If there are more nonzero octets to follow, we only skip + zeroes in multiples of 4, to try to avoid running over + the start of an instruction which happens to start with + zero. */ + if (z != stop_offset * opb) + z = addr_offset * opb + ((z - addr_offset * opb) &~ 3); + + octets = z - addr_offset * opb; + } + else + { + char buf[50]; + SFILE sfile; + int bpc = 0; + int pb = 0; + + done_dot = FALSE; + + if (with_line_numbers || with_source_code) + /* The line number tables will refer to unadjusted + section VMAs, so we must undo any VMA modifications + when calling show_line. */ + show_line (aux->abfd, section, addr_offset - adjust_section_vma); + + if (! prefix_addresses) + { + char *s; + + bfd_sprintf_vma (aux->abfd, buf, section->vma + addr_offset); + for (s = buf + skip_addr_chars; *s == '0'; s++) + *s = ' '; + if (*s == '\0') + *--s = '0'; + printf ("%s:\t", buf + skip_addr_chars); + } + else + { + aux->require_sec = TRUE; + objdump_print_address (section->vma + addr_offset, info); + aux->require_sec = FALSE; + putchar (' '); + } + + if (insns) + { + sfile.size = 120; + sfile.buffer = xmalloc (sfile.size); + sfile.current = sfile.buffer; + info->fprintf_func = (fprintf_ftype) objdump_sprintf; + info->stream = (FILE *) &sfile; + info->bytes_per_line = 0; + info->bytes_per_chunk = 0; + +#ifdef DISASSEMBLER_NEEDS_RELOCS + /* FIXME: This is wrong. It tests the number of octets + in the last instruction, not the current one. */ + if (*relppp < relppend + && (**relppp)->address >= addr_offset + && (**relppp)->address <= addr_offset + octets / opb) + info->flags = INSN_HAS_RELOC; + else +#endif + info->flags = 0; + + octets = (*disassemble_fn) (section->vma + addr_offset, info); + info->fprintf_func = (fprintf_ftype) fprintf; + info->stream = stdout; + if (info->bytes_per_line != 0) + octets_per_line = info->bytes_per_line; + if (octets < 0) + { + if (sfile.current != sfile.buffer) + printf ("%s\n", sfile.buffer); + free (sfile.buffer); + break; + } + } + else + { + bfd_vma j; + + octets = octets_per_line; + if (addr_offset + octets / opb > stop_offset) + octets = (stop_offset - addr_offset) * opb; + + for (j = addr_offset * opb; j < addr_offset * opb + octets; ++j) + { + if (ISPRINT (data[j])) + buf[j - addr_offset * opb] = data[j]; + else + buf[j - addr_offset * opb] = '.'; + } + buf[j - addr_offset * opb] = '\0'; + } + + if (prefix_addresses + ? show_raw_insn > 0 + : show_raw_insn >= 0) + { + bfd_vma j; + + /* If ! prefix_addresses and ! wide_output, we print + octets_per_line octets per line. */ + pb = octets; + if (pb > octets_per_line && ! prefix_addresses && ! wide_output) + pb = octets_per_line; + + if (info->bytes_per_chunk) + bpc = info->bytes_per_chunk; + else + bpc = 1; + + for (j = addr_offset * opb; j < addr_offset * opb + pb; j += bpc) + { + int k; + if (bpc > 1 && info->display_endian == BFD_ENDIAN_LITTLE) + { + for (k = bpc - 1; k >= 0; k--) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); + } + else + { + for (k = 0; k < bpc; k++) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); + } + } + + for (; pb < octets_per_line; pb += bpc) + { + int k; + + for (k = 0; k < bpc; k++) + printf (" "); + putchar (' '); + } + + /* Separate raw data from instruction by extra space. */ + if (insns) + putchar ('\t'); + else + printf (" "); + } + + if (! insns) + printf ("%s", buf); + else + { + printf ("%s", sfile.buffer); + free (sfile.buffer); + } + + if (prefix_addresses + ? show_raw_insn > 0 + : show_raw_insn >= 0) + { + while (pb < octets) + { + bfd_vma j; + char *s; + + putchar ('\n'); + j = addr_offset * opb + pb; + + bfd_sprintf_vma (aux->abfd, buf, section->vma + j / opb); + for (s = buf + skip_addr_chars; *s == '0'; s++) + *s = ' '; + if (*s == '\0') + *--s = '0'; + printf ("%s:\t", buf + skip_addr_chars); + + pb += octets_per_line; + if (pb > octets) + pb = octets; + for (; j < addr_offset * opb + pb; j += bpc) + { + int k; + + if (bpc > 1 && info->display_endian == BFD_ENDIAN_LITTLE) + { + for (k = bpc - 1; k >= 0; k--) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); + } + else + { + for (k = 0; k < bpc; k++) + printf ("%02x", (unsigned) data[j + k]); + putchar (' '); + } + } + } + } + + if (!wide_output) + putchar ('\n'); + else + need_nl = TRUE; + } + + if ((section->flags & SEC_RELOC) != 0 +#ifndef DISASSEMBLER_NEEDS_RELOCS + && dump_reloc_info +#endif + ) + { + while ((*relppp) < relppend + && ((**relppp)->address >= (bfd_vma) addr_offset + && (**relppp)->address < (bfd_vma) addr_offset + octets / opb)) +#ifdef DISASSEMBLER_NEEDS_RELOCS + if (! dump_reloc_info) + ++(*relppp); + else +#endif + { + arelent *q; + + q = **relppp; + + if (wide_output) + putchar ('\t'); + else + printf ("\t\t\t"); + + objdump_print_value (section->vma + q->address, info, TRUE); + + printf (": %s\t", q->howto->name); + + if (q->sym_ptr_ptr == NULL || *q->sym_ptr_ptr == NULL) + printf ("*unknown*"); + else + { + const char *sym_name; + + sym_name = bfd_asymbol_name (*q->sym_ptr_ptr); + if (sym_name != NULL && *sym_name != '\0') + objdump_print_symname (aux->abfd, info, *q->sym_ptr_ptr); + else + { + asection *sym_sec; + + sym_sec = bfd_get_section (*q->sym_ptr_ptr); + sym_name = bfd_get_section_name (aux->abfd, sym_sec); + if (sym_name == NULL || *sym_name == '\0') + sym_name = "*unknown*"; + printf ("%s", sym_name); + } + } + + if (q->addend) + { + printf ("+0x"); + objdump_print_value (q->addend, info, TRUE); + } + + printf ("\n"); + need_nl = FALSE; + ++(*relppp); + } + } + + if (need_nl) + printf ("\n"); + + addr_offset += octets / opb; + } +} + +/* Disassemble the contents of an object file. */ + +static void +disassemble_data (abfd) + bfd *abfd; +{ + unsigned long addr_offset; + disassembler_ftype disassemble_fn; + struct disassemble_info disasm_info; + struct objdump_disasm_info aux; + asection *section; + unsigned int opb; + + print_files = NULL; + prev_functionname = NULL; + prev_line = -1; + + /* We make a copy of syms to sort. We don't want to sort syms + because that will screw up the relocs. */ + sorted_syms = (asymbol **) xmalloc (symcount * sizeof (asymbol *)); + memcpy (sorted_syms, syms, symcount * sizeof (asymbol *)); + + sorted_symcount = remove_useless_symbols (sorted_syms, symcount); + + /* Sort the symbols into section and symbol order. */ + qsort (sorted_syms, sorted_symcount, sizeof (asymbol *), compare_symbols); + + INIT_DISASSEMBLE_INFO (disasm_info, stdout, fprintf); + + disasm_info.application_data = (PTR) &aux; + aux.abfd = abfd; + aux.require_sec = FALSE; + disasm_info.print_address_func = objdump_print_address; + disasm_info.symbol_at_address_func = objdump_symbol_at_address; + + if (machine != (char *) NULL) + { + const bfd_arch_info_type *info = bfd_scan_arch (machine); + + if (info == NULL) + fatal (_("Can't use supplied machine %s"), machine); + + abfd->arch_info = info; + } + + if (endian != BFD_ENDIAN_UNKNOWN) + { + struct bfd_target *xvec; + + xvec = (struct bfd_target *) xmalloc (sizeof (struct bfd_target)); + memcpy (xvec, abfd->xvec, sizeof (struct bfd_target)); + xvec->byteorder = endian; + abfd->xvec = xvec; + } + + disassemble_fn = disassembler (abfd); + if (!disassemble_fn) + { + non_fatal (_("Can't disassemble for architecture %s\n"), + bfd_printable_arch_mach (bfd_get_arch (abfd), 0)); + exit_status = 1; + return; + } + + opb = bfd_octets_per_byte (abfd); + + disasm_info.flavour = bfd_get_flavour (abfd); + disasm_info.arch = bfd_get_arch (abfd); + disasm_info.mach = bfd_get_mach (abfd); + disasm_info.disassembler_options = disassembler_options; + disasm_info.octets_per_byte = opb; + + if (bfd_big_endian (abfd)) + disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_BIG; + else if (bfd_little_endian (abfd)) + disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_LITTLE; + else + /* ??? Aborting here seems too drastic. We could default to big or little + instead. */ + disasm_info.endian = BFD_ENDIAN_UNKNOWN; + + for (section = abfd->sections; + section != (asection *) NULL; + section = section->next) + { + bfd_byte *data = NULL; + bfd_size_type datasize = 0; + arelent **relbuf = NULL; + arelent **relpp = NULL; + arelent **relppend = NULL; + unsigned long stop_offset; + asymbol *sym = NULL; + long place = 0; + + if ((section->flags & SEC_LOAD) == 0 + || (! disassemble_all + && only == NULL + && (section->flags & SEC_CODE) == 0)) + continue; + if (only != (char *) NULL && strcmp (only, section->name) != 0) + continue; + + if ((section->flags & SEC_RELOC) != 0 +#ifndef DISASSEMBLER_NEEDS_RELOCS + && dump_reloc_info +#endif + ) + { + long relsize; + + relsize = bfd_get_reloc_upper_bound (abfd, section); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + if (relsize > 0) + { + long relcount; + + relbuf = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (abfd, section, relbuf, syms); + if (relcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + + /* Sort the relocs by address. */ + qsort (relbuf, relcount, sizeof (arelent *), compare_relocs); + + relpp = relbuf; + relppend = relpp + relcount; + + /* Skip over the relocs belonging to addresses below the + start address. */ + if (start_address != (bfd_vma) -1) + while (relpp < relppend + && (*relpp)->address < start_address) + ++relpp; + } + } + + printf (_("Disassembly of section %s:\n"), section->name); + + datasize = bfd_get_section_size_before_reloc (section); + if (datasize == 0) + continue; + + data = (bfd_byte *) xmalloc ((size_t) datasize); + + bfd_get_section_contents (abfd, section, data, 0, datasize); + + aux.sec = section; + disasm_info.buffer = data; + disasm_info.buffer_vma = section->vma; + disasm_info.buffer_length = datasize; + disasm_info.section = section; + + if (start_address == (bfd_vma) -1 + || start_address < disasm_info.buffer_vma) + addr_offset = 0; + else + addr_offset = start_address - disasm_info.buffer_vma; + + if (stop_address == (bfd_vma) -1) + stop_offset = datasize / opb; + else + { + if (stop_address < disasm_info.buffer_vma) + stop_offset = 0; + else + stop_offset = stop_address - disasm_info.buffer_vma; + if (stop_offset > disasm_info.buffer_length / opb) + stop_offset = disasm_info.buffer_length / opb; + } + + sym = find_symbol_for_address (abfd, section, section->vma + addr_offset, + TRUE, &place); + + while (addr_offset < stop_offset) + { + asymbol *nextsym; + unsigned long nextstop_offset; + bfd_boolean insns; + + if (sym != NULL && bfd_asymbol_value (sym) <= section->vma + addr_offset) + { + int x; + + for (x = place; + (x < sorted_symcount + && bfd_asymbol_value (sorted_syms[x]) <= section->vma + addr_offset); + ++x) + continue; + + disasm_info.symbols = & sorted_syms[place]; + disasm_info.num_symbols = x - place; + } + else + disasm_info.symbols = NULL; + + if (! prefix_addresses) + { + (* disasm_info.fprintf_func) (disasm_info.stream, "\n"); + objdump_print_addr_with_sym (abfd, section, sym, + section->vma + addr_offset, + &disasm_info, + FALSE); + (* disasm_info.fprintf_func) (disasm_info.stream, ":\n"); + } + + if (sym != NULL && bfd_asymbol_value (sym) > section->vma + addr_offset) + nextsym = sym; + else if (sym == NULL) + nextsym = NULL; + else + { + /* Search forward for the next appropriate symbol in + SECTION. Note that all the symbols are sorted + together into one big array, and that some sections + may have overlapping addresses. */ + while (place < sorted_symcount + && (sorted_syms[place]->section != section + || (bfd_asymbol_value (sorted_syms[place]) + <= bfd_asymbol_value (sym)))) + ++place; + if (place >= sorted_symcount) + nextsym = NULL; + else + nextsym = sorted_syms[place]; + } + + if (sym != NULL && bfd_asymbol_value (sym) > section->vma + addr_offset) + { + nextstop_offset = bfd_asymbol_value (sym) - section->vma; + if (nextstop_offset > stop_offset) + nextstop_offset = stop_offset; + } + else if (nextsym == NULL) + nextstop_offset = stop_offset; + else + { + nextstop_offset = bfd_asymbol_value (nextsym) - section->vma; + if (nextstop_offset > stop_offset) + nextstop_offset = stop_offset; + } + + /* If a symbol is explicitly marked as being an object + rather than a function, just dump the bytes without + disassembling them. */ + if (disassemble_all + || sym == NULL + || bfd_asymbol_value (sym) > section->vma + addr_offset + || ((sym->flags & BSF_OBJECT) == 0 + && (strstr (bfd_asymbol_name (sym), "gnu_compiled") + == NULL) + && (strstr (bfd_asymbol_name (sym), "gcc2_compiled") + == NULL)) + || (sym->flags & BSF_FUNCTION) != 0) + insns = TRUE; + else + insns = FALSE; + + disassemble_bytes (&disasm_info, disassemble_fn, insns, data, + addr_offset, nextstop_offset, &relpp, relppend); + + addr_offset = nextstop_offset; + sym = nextsym; + } + + free (data); + + if (relbuf != NULL) + free (relbuf); + } + free (sorted_syms); +} + +/* Dump the stabs sections from an object file that has a section that + uses Sun stabs encoding. */ + +static void +dump_stabs (abfd) + bfd *abfd; +{ + dump_section_stabs (abfd, ".stab", ".stabstr"); + dump_section_stabs (abfd, ".stab.excl", ".stab.exclstr"); + dump_section_stabs (abfd, ".stab.index", ".stab.indexstr"); + dump_section_stabs (abfd, "$GDB_SYMBOLS$", "$GDB_STRINGS$"); +} + +/* Read ABFD's stabs section STABSECT_NAME into `stabs' + and string table section STRSECT_NAME into `strtab'. + If the section exists and was read, allocate the space and return TRUE. + Otherwise return FALSE. */ + +static bfd_boolean +read_section_stabs (abfd, stabsect_name, strsect_name) + bfd *abfd; + const char *stabsect_name; + const char *strsect_name; +{ + asection *stabsect, *stabstrsect; + + stabsect = bfd_get_section_by_name (abfd, stabsect_name); + if (0 == stabsect) + { + printf (_("No %s section present\n\n"), stabsect_name); + return FALSE; + } + + stabstrsect = bfd_get_section_by_name (abfd, strsect_name); + if (0 == stabstrsect) + { + non_fatal (_("%s has no %s section"), + bfd_get_filename (abfd), strsect_name); + exit_status = 1; + return FALSE; + } + + stab_size = bfd_section_size (abfd, stabsect); + stabstr_size = bfd_section_size (abfd, stabstrsect); + + stabs = (bfd_byte *) xmalloc (stab_size); + strtab = (char *) xmalloc (stabstr_size); + + if (! bfd_get_section_contents (abfd, stabsect, (PTR) stabs, 0, stab_size)) + { + non_fatal (_("Reading %s section of %s failed: %s"), + stabsect_name, bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + free (stabs); + free (strtab); + exit_status = 1; + return FALSE; + } + + if (! bfd_get_section_contents (abfd, stabstrsect, (PTR) strtab, 0, + stabstr_size)) + { + non_fatal (_("Reading %s section of %s failed: %s\n"), + strsect_name, bfd_get_filename (abfd), + bfd_errmsg (bfd_get_error ())); + free (stabs); + free (strtab); + exit_status = 1; + return FALSE; + } + + return TRUE; +} + +/* Stabs entries use a 12 byte format: + 4 byte string table index + 1 byte stab type + 1 byte stab other field + 2 byte stab desc field + 4 byte stab value + FIXME: This will have to change for a 64 bit object format. */ + +#define STRDXOFF (0) +#define TYPEOFF (4) +#define OTHEROFF (5) +#define DESCOFF (6) +#define VALOFF (8) +#define STABSIZE (12) + +/* Print ABFD's stabs section STABSECT_NAME (in `stabs'), + using string table section STRSECT_NAME (in `strtab'). */ + +static void +print_section_stabs (abfd, stabsect_name, strsect_name) + bfd *abfd; + const char *stabsect_name; + const char *strsect_name ATTRIBUTE_UNUSED; +{ + int i; + unsigned file_string_table_offset = 0, next_file_string_table_offset = 0; + bfd_byte *stabp, *stabs_end; + + stabp = stabs; + stabs_end = stabp + stab_size; + + printf (_("Contents of %s section:\n\n"), stabsect_name); + printf ("Symnum n_type n_othr n_desc n_value n_strx String\n"); + + /* Loop through all symbols and print them. + + We start the index at -1 because there is a dummy symbol on + the front of stabs-in-{coff,elf} sections that supplies sizes. */ + for (i = -1; stabp < stabs_end; stabp += STABSIZE, i++) + { + const char *name; + unsigned long strx; + unsigned char type, other; + unsigned short desc; + bfd_vma value; + + strx = bfd_h_get_32 (abfd, stabp + STRDXOFF); + type = bfd_h_get_8 (abfd, stabp + TYPEOFF); + other = bfd_h_get_8 (abfd, stabp + OTHEROFF); + desc = bfd_h_get_16 (abfd, stabp + DESCOFF); + value = bfd_h_get_32 (abfd, stabp + VALOFF); + + printf ("\n%-6d ", i); + /* Either print the stab name, or, if unnamed, print its number + again (makes consistent formatting for tools like awk). */ + name = bfd_get_stab_name (type); + if (name != NULL) + printf ("%-6s", name); + else if (type == N_UNDF) + printf ("HdrSym"); + else + printf ("%-6d", type); + printf (" %-6d %-6d ", other, desc); + bfd_printf_vma (abfd, value); + printf (" %-6lu", strx); + + /* Symbols with type == 0 (N_UNDF) specify the length of the + string table associated with this file. We use that info + to know how to relocate the *next* file's string table indices. */ + if (type == N_UNDF) + { + file_string_table_offset = next_file_string_table_offset; + next_file_string_table_offset += value; + } + else + { + /* Using the (possibly updated) string table offset, print the + string (if any) associated with this symbol. */ + if ((strx + file_string_table_offset) < stabstr_size) + printf (" %s", &strtab[strx + file_string_table_offset]); + else + printf (" *"); + } + } + printf ("\n\n"); +} + +static void +dump_section_stabs (abfd, stabsect_name, strsect_name) + bfd *abfd; + char *stabsect_name; + char *strsect_name; +{ + asection *s; + + /* Check for section names for which stabsect_name is a prefix, to + handle .stab0, etc. */ + for (s = abfd->sections; + s != NULL; + s = s->next) + { + int len; + + len = strlen (stabsect_name); + + /* If the prefix matches, and the files section name ends with a + nul or a digit, then we match. I.e., we want either an exact + match or a section followed by a number. */ + if (strncmp (stabsect_name, s->name, len) == 0 + && (s->name[len] == '\000' + || ISDIGIT (s->name[len]))) + { + if (read_section_stabs (abfd, s->name, strsect_name)) + { + print_section_stabs (abfd, s->name, strsect_name); + free (stabs); + free (strtab); + } + } + } +} + + +static void +dump_bfd_header (abfd) + bfd *abfd; +{ + char *comma = ""; + + printf (_("architecture: %s, "), + bfd_printable_arch_mach (bfd_get_arch (abfd), + bfd_get_mach (abfd))); + printf (_("flags 0x%08x:\n"), abfd->flags); + +#define PF(x, y) if (abfd->flags & x) {printf("%s%s", comma, y); comma=", ";} + PF (HAS_RELOC, "HAS_RELOC"); + PF (EXEC_P, "EXEC_P"); + PF (HAS_LINENO, "HAS_LINENO"); + PF (HAS_DEBUG, "HAS_DEBUG"); + PF (HAS_SYMS, "HAS_SYMS"); + PF (HAS_LOCALS, "HAS_LOCALS"); + PF (DYNAMIC, "DYNAMIC"); + PF (WP_TEXT, "WP_TEXT"); + PF (D_PAGED, "D_PAGED"); + PF (BFD_IS_RELAXABLE, "BFD_IS_RELAXABLE"); + PF (HAS_LOAD_PAGE, "HAS_LOAD_PAGE"); + printf (_("\nstart address 0x")); + bfd_printf_vma (abfd, abfd->start_address); + printf ("\n"); +} + + +static void +dump_bfd_private_header (abfd) +bfd *abfd; +{ + bfd_print_private_bfd_data (abfd, stdout); +} + +/* Dump selected contents of ABFD. */ + +static void +dump_bfd (abfd) + bfd *abfd; +{ + /* If we are adjusting section VMA's, change them all now. Changing + the BFD information is a hack. However, we must do it, or + bfd_find_nearest_line will not do the right thing. */ + if (adjust_section_vma != 0) + { + asection *s; + + for (s = abfd->sections; s != NULL; s = s->next) + { + s->vma += adjust_section_vma; + s->lma += adjust_section_vma; + } + } + + printf (_("\n%s: file format %s\n"), bfd_get_filename (abfd), + abfd->xvec->name); + if (dump_ar_hdrs) + print_arelt_descr (stdout, abfd, TRUE); + if (dump_file_header) + dump_bfd_header (abfd); + if (dump_private_headers) + dump_bfd_private_header (abfd); + putchar ('\n'); + if (dump_section_headers) + dump_headers (abfd); + + if (dump_symtab || dump_reloc_info || disassemble || dump_debugging) + syms = slurp_symtab (abfd); + if (dump_dynamic_symtab || dump_dynamic_reloc_info) + dynsyms = slurp_dynamic_symtab (abfd); + + if (dump_symtab) + dump_symbols (abfd, FALSE); + if (dump_dynamic_symtab) + dump_symbols (abfd, TRUE); + if (dump_stab_section_info) + dump_stabs (abfd); + if (dump_reloc_info && ! disassemble) + dump_relocs (abfd); + if (dump_dynamic_reloc_info) + dump_dynamic_relocs (abfd); + if (dump_section_contents) + dump_data (abfd); + if (disassemble) + disassemble_data (abfd); + if (dump_debugging) + { + PTR dhandle; + + dhandle = read_debugging_info (abfd, syms, symcount); + if (dhandle != NULL) + { + if (! print_debugging_info (stdout, dhandle)) + { + non_fatal (_("%s: printing debugging information failed"), + bfd_get_filename (abfd)); + exit_status = 1; + } + } + } + + if (syms) + { + free (syms); + syms = NULL; + } + + if (dynsyms) + { + free (dynsyms); + dynsyms = NULL; + } +} + +static void +display_bfd (abfd) + bfd *abfd; +{ + char **matching; + + if (bfd_check_format_matches (abfd, bfd_object, &matching)) + { + dump_bfd (abfd); + return; + } + + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + nonfatal (bfd_get_filename (abfd)); + list_matching_formats (matching); + free (matching); + return; + } + + if (bfd_get_error () != bfd_error_file_not_recognized) + { + nonfatal (bfd_get_filename (abfd)); + return; + } + + if (bfd_check_format_matches (abfd, bfd_core, &matching)) + { + dump_bfd (abfd); + return; + } + + nonfatal (bfd_get_filename (abfd)); + + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } +} + +static void +display_file (filename, target) + char *filename; + char *target; +{ + bfd *file, *arfile = (bfd *) NULL; + + file = bfd_openr (filename, target); + if (file == NULL) + { + nonfatal (filename); + return; + } + + if (bfd_check_format (file, bfd_archive)) + { + bfd *last_arfile = NULL; + + printf (_("In archive %s:\n"), bfd_get_filename (file)); + for (;;) + { + bfd_set_error (bfd_error_no_error); + + arfile = bfd_openr_next_archived_file (file, arfile); + if (arfile == NULL) + { + if (bfd_get_error () != bfd_error_no_more_archived_files) + nonfatal (bfd_get_filename (file)); + break; + } + + display_bfd (arfile); + + if (last_arfile != NULL) + bfd_close (last_arfile); + last_arfile = arfile; + } + + if (last_arfile != NULL) + bfd_close (last_arfile); + } + else + display_bfd (file); + + bfd_close (file); +} + +/* Actually display the various requested regions. */ + +static void +dump_data (abfd) + bfd *abfd; +{ + asection *section; + bfd_byte *data = 0; + bfd_size_type datasize = 0; + bfd_size_type addr_offset; + bfd_size_type start_offset, stop_offset; + unsigned int opb = bfd_octets_per_byte (abfd); + + for (section = abfd->sections; section != NULL; section = + section->next) + { + int onaline = 16; + + if (only == (char *) NULL || + strcmp (only, section->name) == 0) + { + if (section->flags & SEC_HAS_CONTENTS) + { + char buf[64]; + int count, width; + + printf (_("Contents of section %s:\n"), section->name); + + if (bfd_section_size (abfd, section) == 0) + continue; + data = (bfd_byte *) xmalloc ((size_t) bfd_section_size (abfd, section)); + datasize = bfd_section_size (abfd, section); + + + bfd_get_section_contents (abfd, section, (PTR) data, 0, bfd_section_size (abfd, section)); + + if (start_address == (bfd_vma) -1 + || start_address < section->vma) + start_offset = 0; + else + start_offset = start_address - section->vma; + if (stop_address == (bfd_vma) -1) + stop_offset = bfd_section_size (abfd, section) / opb; + else + { + if (stop_address < section->vma) + stop_offset = 0; + else + stop_offset = stop_address - section->vma; + if (stop_offset > bfd_section_size (abfd, section) / opb) + stop_offset = bfd_section_size (abfd, section) / opb; + } + + width = 4; + + bfd_sprintf_vma (abfd, buf, start_offset + section->vma); + if (strlen (buf) >= sizeof (buf)) + abort (); + count = 0; + while (buf[count] == '0' && buf[count+1] != '\0') + count++; + count = strlen (buf) - count; + if (count > width) + width = count; + + bfd_sprintf_vma (abfd, buf, stop_offset + section->vma - 1); + if (strlen (buf) >= sizeof (buf)) + abort (); + count = 0; + while (buf[count] == '0' && buf[count+1] != '\0') + count++; + count = strlen (buf) - count; + if (count > width) + width = count; + + for (addr_offset = start_offset; + addr_offset < stop_offset; addr_offset += onaline / opb) + { + bfd_size_type j; + + bfd_sprintf_vma (abfd, buf, (addr_offset + section->vma)); + count = strlen (buf); + if (count >= sizeof (buf)) + abort (); + putchar (' '); + while (count < width) + { + putchar ('0'); + count++; + } + fputs (buf + count - width, stdout); + putchar (' '); + + for (j = addr_offset * opb; + j < addr_offset * opb + onaline; j++) + { + if (j < stop_offset * opb) + printf ("%02x", (unsigned) (data[j])); + else + printf (" "); + if ((j & 3) == 3) + printf (" "); + } + + printf (" "); + for (j = addr_offset * opb; + j < addr_offset * opb + onaline; j++) + { + if (j >= stop_offset * opb) + printf (" "); + else + printf ("%c", ISPRINT (data[j]) ? data[j] : '.'); + } + putchar ('\n'); + } + free (data); + } + } + } +} + +/* Should perhaps share code and display with nm? */ + +static void +dump_symbols (abfd, dynamic) + bfd *abfd ATTRIBUTE_UNUSED; + bfd_boolean dynamic; +{ + asymbol **current; + long max; + long count; + + if (dynamic) + { + current = dynsyms; + max = dynsymcount; + printf ("DYNAMIC SYMBOL TABLE:\n"); + } + else + { + current = syms; + max = symcount; + printf ("SYMBOL TABLE:\n"); + } + + if (max == 0) + printf (_("no symbols\n")); + + for (count = 0; count < max; count++) + { + if (*current) + { + bfd *cur_bfd = bfd_asymbol_bfd (*current); + + if (cur_bfd != NULL) + { + const char *name; + char *alloc; + + name = (*current)->name; + alloc = NULL; + if (do_demangle && name != NULL && *name != '\0') + { + /* If we want to demangle the name, we demangle it + here, and temporarily clobber it while calling + bfd_print_symbol. FIXME: This is a gross hack. */ + alloc = demangle (cur_bfd, name); + (*current)->name = alloc; + } + + bfd_print_symbol (cur_bfd, stdout, *current, + bfd_print_symbol_all); + + (*current)->name = name; + if (alloc != NULL) + free (alloc); + + printf ("\n"); + } + } + current++; + } + printf ("\n"); + printf ("\n"); +} + +static void +dump_relocs (abfd) + bfd *abfd; +{ + arelent **relpp; + long relcount; + asection *a; + + for (a = abfd->sections; a != (asection *) NULL; a = a->next) + { + long relsize; + + if (bfd_is_abs_section (a)) + continue; + if (bfd_is_und_section (a)) + continue; + if (bfd_is_com_section (a)) + continue; + + if (only) + { + if (strcmp (only, a->name)) + continue; + } + else if ((a->flags & SEC_RELOC) == 0) + continue; + + relsize = bfd_get_reloc_upper_bound (abfd, a); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + printf ("RELOCATION RECORDS FOR [%s]:", a->name); + + if (relsize == 0) + { + printf (" (none)\n\n"); + } + else + { + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (abfd, a, relpp, syms); + + if (relcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + else if (relcount == 0) + printf (" (none)\n\n"); + else + { + printf ("\n"); + dump_reloc_set (abfd, a, relpp, relcount); + printf ("\n\n"); + } + free (relpp); + } + } +} + +static void +dump_dynamic_relocs (abfd) + bfd *abfd; +{ + long relsize; + arelent **relpp; + long relcount; + + relsize = bfd_get_dynamic_reloc_upper_bound (abfd); + if (relsize < 0) + bfd_fatal (bfd_get_filename (abfd)); + + printf ("DYNAMIC RELOCATION RECORDS"); + + if (relsize == 0) + printf (" (none)\n\n"); + else + { + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_dynamic_reloc (abfd, relpp, dynsyms); + + if (relcount < 0) + bfd_fatal (bfd_get_filename (abfd)); + else if (relcount == 0) + printf (" (none)\n\n"); + else + { + printf ("\n"); + dump_reloc_set (abfd, (asection *) NULL, relpp, relcount); + printf ("\n\n"); + } + free (relpp); + } +} + +static void +dump_reloc_set (abfd, sec, relpp, relcount) + bfd *abfd; + asection *sec; + arelent **relpp; + long relcount; +{ + arelent **p; + char *last_filename, *last_functionname; + unsigned int last_line; + + /* Get column headers lined up reasonably. */ + { + static int width; + + if (width == 0) + { + char buf[30]; + bfd_sprintf_vma (abfd, buf, (bfd_vma) -1); + width = strlen (buf) - 7; + } + printf ("OFFSET %*s TYPE %*s VALUE \n", width, "", 12, ""); + } + + last_filename = NULL; + last_functionname = NULL; + last_line = 0; + + for (p = relpp; relcount && *p != (arelent *) NULL; p++, relcount--) + { + arelent *q = *p; + const char *filename, *functionname; + unsigned int line; + const char *sym_name; + const char *section_name; + + if (start_address != (bfd_vma) -1 + && q->address < start_address) + continue; + if (stop_address != (bfd_vma) -1 + && q->address > stop_address) + continue; + + if (with_line_numbers + && sec != NULL + && bfd_find_nearest_line (abfd, sec, syms, q->address, + &filename, &functionname, &line)) + { + if (functionname != NULL + && (last_functionname == NULL + || strcmp (functionname, last_functionname) != 0)) + { + printf ("%s():\n", functionname); + if (last_functionname != NULL) + free (last_functionname); + last_functionname = xstrdup (functionname); + } + + if (line > 0 + && (line != last_line + || (filename != NULL + && last_filename != NULL + && strcmp (filename, last_filename) != 0))) + { + printf ("%s:%u\n", filename == NULL ? "???" : filename, line); + last_line = line; + if (last_filename != NULL) + free (last_filename); + if (filename == NULL) + last_filename = NULL; + else + last_filename = xstrdup (filename); + } + } + + if (q->sym_ptr_ptr && *q->sym_ptr_ptr) + { + sym_name = (*(q->sym_ptr_ptr))->name; + section_name = (*(q->sym_ptr_ptr))->section->name; + } + else + { + sym_name = NULL; + section_name = NULL; + } + + if (sym_name) + { + bfd_printf_vma (abfd, q->address); + if (q->howto->name) + printf (" %-16s ", q->howto->name); + else + printf (" %-16d ", q->howto->type); + objdump_print_symname (abfd, (struct disassemble_info *) NULL, + *q->sym_ptr_ptr); + } + else + { + if (section_name == (const char *) NULL) + section_name = "*unknown*"; + bfd_printf_vma (abfd, q->address); + printf (" %-16s [%s]", + q->howto->name, + section_name); + } + + if (q->addend) + { + printf ("+0x"); + bfd_printf_vma (abfd, q->addend); + } + + printf ("\n"); + } +} + +int main PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + char *target = default_target; + bfd_boolean seenflag = FALSE; + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = *argv; + xmalloc_set_program_name (program_name); + + START_PROGRESS (program_name, 0); + + bfd_init (); + set_default_bfd_target (); + + while ((c = getopt_long (argc, argv, "pib:m:M:VvCdDlfaHhrRtTxsSj:wE:zgG", + long_options, (int *) 0)) + != EOF) + { + switch (c) + { + case 0: + break; /* We've been given a long option. */ + case 'm': + machine = optarg; + break; + case 'M': + disassembler_options = optarg; + break; + case 'j': + only = optarg; + break; + case 'l': + with_line_numbers = TRUE; + break; + case 'b': + target = optarg; + break; + case 'C': + do_demangle = TRUE; + if (optarg != NULL) + { + enum demangling_styles style; + + style = cplus_demangle_name_to_style (optarg); + if (style == unknown_demangling) + fatal (_("unknown demangling style `%s'"), + optarg); + + cplus_demangle_set_style (style); + } + break; + case 'w': + wide_output = TRUE; + break; + case OPTION_ADJUST_VMA: + adjust_section_vma = parse_vma (optarg, "--adjust-vma"); + break; + case OPTION_START_ADDRESS: + start_address = parse_vma (optarg, "--start-address"); + break; + case OPTION_STOP_ADDRESS: + stop_address = parse_vma (optarg, "--stop-address"); + break; + case 'E': + if (strcmp (optarg, "B") == 0) + endian = BFD_ENDIAN_BIG; + else if (strcmp (optarg, "L") == 0) + endian = BFD_ENDIAN_LITTLE; + else + { + non_fatal (_("unrecognized -E option")); + usage (stderr, 1); + } + break; + case OPTION_ENDIAN: + if (strncmp (optarg, "big", strlen (optarg)) == 0) + endian = BFD_ENDIAN_BIG; + else if (strncmp (optarg, "little", strlen (optarg)) == 0) + endian = BFD_ENDIAN_LITTLE; + else + { + non_fatal (_("unrecognized --endian type `%s'"), optarg); + usage (stderr, 1); + } + break; + + case 'f': + dump_file_header = TRUE; + seenflag = TRUE; + break; + case 'i': + formats_info = TRUE; + seenflag = TRUE; + break; + case 'p': + dump_private_headers = TRUE; + seenflag = TRUE; + break; + case 'x': + dump_private_headers = TRUE; + dump_symtab = TRUE; + dump_reloc_info = TRUE; + dump_file_header = TRUE; + dump_ar_hdrs = TRUE; + dump_section_headers = TRUE; + seenflag = TRUE; + break; + case 't': + dump_symtab = TRUE; + seenflag = TRUE; + break; + case 'T': + dump_dynamic_symtab = TRUE; + seenflag = TRUE; + break; + case 'd': + disassemble = TRUE; + seenflag = TRUE; + break; + case 'z': + disassemble_zeroes = TRUE; + break; + case 'D': + disassemble = TRUE; + disassemble_all = TRUE; + seenflag = TRUE; + break; + case 'S': + disassemble = TRUE; + with_source_code = TRUE; + seenflag = TRUE; + break; + case 'g': + dump_debugging = 1; + seenflag = TRUE; + break; + case 'G': + dump_stab_section_info = TRUE; + seenflag = TRUE; + break; + case 's': + dump_section_contents = TRUE; + seenflag = TRUE; + break; + case 'r': + dump_reloc_info = TRUE; + seenflag = TRUE; + break; + case 'R': + dump_dynamic_reloc_info = TRUE; + seenflag = TRUE; + break; + case 'a': + dump_ar_hdrs = TRUE; + seenflag = TRUE; + break; + case 'h': + dump_section_headers = TRUE; + seenflag = TRUE; + break; + case 'H': + usage (stdout, 0); + seenflag = TRUE; + case 'v': + case 'V': + show_version = TRUE; + seenflag = TRUE; + break; + + default: + usage (stderr, 1); + } + } + + if (show_version) + print_version ("objdump"); + + if (!seenflag) + usage (stderr, 2); + + if (formats_info) + exit_status = display_info (); + else + { + if (optind == argc) + display_file ("a.out", target); + else + for (; optind < argc;) + display_file (argv[optind++], target); + } + + END_PROGRESS (program_name); + + return exit_status; +} diff --git a/contrib/binutils-2.14/binutils/prdbg.c b/contrib/binutils-2.14/binutils/prdbg.c new file mode 100644 index 0000000000..b29eec6b56 --- /dev/null +++ b/contrib/binutils-2.14/binutils/prdbg.c @@ -0,0 +1,1896 @@ +/* prdbg.c -- Print out generic debugging information. + Copyright 1995, 1996, 2002 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file prints out the generic debugging information, by + supplying a set of routines to debug_write. */ + +#include +#include + +#include "bfd.h" +#include "bucomm.h" +#include "libiberty.h" +#include "debug.h" +#include "budbg.h" + +/* This is the structure we use as a handle for these routines. */ + +struct pr_handle +{ + /* File to print information to. */ + FILE *f; + /* Current indentation level. */ + unsigned int indent; + /* Type stack. */ + struct pr_stack *stack; + /* Parameter number we are about to output. */ + int parameter; +}; + +/* The type stack. */ + +struct pr_stack +{ + /* Next element on the stack. */ + struct pr_stack *next; + /* This element. */ + char *type; + /* Current visibility of fields if this is a class. */ + enum debug_visibility visibility; + /* Name of the current method we are handling. */ + const char *method; +}; + +static void indent + PARAMS ((struct pr_handle *)); +static bfd_boolean push_type + PARAMS ((struct pr_handle *, const char *)); +static bfd_boolean prepend_type + PARAMS ((struct pr_handle *, const char *)); +static bfd_boolean append_type + PARAMS ((struct pr_handle *, const char *)); +static bfd_boolean substitute_type + PARAMS ((struct pr_handle *, const char *)); +static bfd_boolean indent_type + PARAMS ((struct pr_handle *)); +static char *pop_type + PARAMS ((struct pr_handle *)); +static void print_vma + PARAMS ((bfd_vma, char *, bfd_boolean, bfd_boolean)); +static bfd_boolean pr_fix_visibility + PARAMS ((struct pr_handle *, enum debug_visibility)); +static bfd_boolean pr_start_compilation_unit + PARAMS ((PTR, const char *)); +static bfd_boolean pr_start_source + PARAMS ((PTR, const char *)); +static bfd_boolean pr_empty_type + PARAMS ((PTR)); +static bfd_boolean pr_void_type + PARAMS ((PTR)); +static bfd_boolean pr_int_type + PARAMS ((PTR, unsigned int, bfd_boolean)); +static bfd_boolean pr_float_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean pr_complex_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean pr_bool_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean pr_enum_type + PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); +static bfd_boolean pr_pointer_type + PARAMS ((PTR)); +static bfd_boolean pr_function_type + PARAMS ((PTR, int, bfd_boolean)); +static bfd_boolean pr_reference_type + PARAMS ((PTR)); +static bfd_boolean pr_range_type + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); +static bfd_boolean pr_array_type + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, bfd_boolean)); +static bfd_boolean pr_set_type + PARAMS ((PTR, bfd_boolean)); +static bfd_boolean pr_offset_type + PARAMS ((PTR)); +static bfd_boolean pr_method_type + PARAMS ((PTR, bfd_boolean, int, bfd_boolean)); +static bfd_boolean pr_const_type + PARAMS ((PTR)); +static bfd_boolean pr_volatile_type + PARAMS ((PTR)); +static bfd_boolean pr_start_struct_type + PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int)); +static bfd_boolean pr_struct_field + PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); +static bfd_boolean pr_end_struct_type + PARAMS ((PTR)); +static bfd_boolean pr_start_class_type + PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int, + bfd_boolean, bfd_boolean)); +static bfd_boolean pr_class_static_member + PARAMS ((PTR, const char *, const char *, enum debug_visibility)); +static bfd_boolean pr_class_baseclass + PARAMS ((PTR, bfd_vma, bfd_boolean, enum debug_visibility)); +static bfd_boolean pr_class_start_method + PARAMS ((PTR, const char *)); +static bfd_boolean pr_class_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean, + bfd_vma, bfd_boolean)); +static bfd_boolean pr_class_static_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, + bfd_boolean)); +static bfd_boolean pr_class_end_method + PARAMS ((PTR)); +static bfd_boolean pr_end_class_type + PARAMS ((PTR)); +static bfd_boolean pr_typedef_type + PARAMS ((PTR, const char *)); +static bfd_boolean pr_tag_type + PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); +static bfd_boolean pr_typdef + PARAMS ((PTR, const char *)); +static bfd_boolean pr_tag + PARAMS ((PTR, const char *)); +static bfd_boolean pr_int_constant + PARAMS ((PTR, const char *, bfd_vma)); +static bfd_boolean pr_float_constant + PARAMS ((PTR, const char *, double)); +static bfd_boolean pr_typed_constant + PARAMS ((PTR, const char *, bfd_vma)); +static bfd_boolean pr_variable + PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); +static bfd_boolean pr_start_function + PARAMS ((PTR, const char *, bfd_boolean)); +static bfd_boolean pr_function_parameter + PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); +static bfd_boolean pr_start_block + PARAMS ((PTR, bfd_vma)); +static bfd_boolean pr_end_block + PARAMS ((PTR, bfd_vma)); +static bfd_boolean pr_end_function + PARAMS ((PTR)); +static bfd_boolean pr_lineno + PARAMS ((PTR, const char *, unsigned long, bfd_vma)); + +static const struct debug_write_fns pr_fns = +{ + pr_start_compilation_unit, + pr_start_source, + pr_empty_type, + pr_void_type, + pr_int_type, + pr_float_type, + pr_complex_type, + pr_bool_type, + pr_enum_type, + pr_pointer_type, + pr_function_type, + pr_reference_type, + pr_range_type, + pr_array_type, + pr_set_type, + pr_offset_type, + pr_method_type, + pr_const_type, + pr_volatile_type, + pr_start_struct_type, + pr_struct_field, + pr_end_struct_type, + pr_start_class_type, + pr_class_static_member, + pr_class_baseclass, + pr_class_start_method, + pr_class_method_variant, + pr_class_static_method_variant, + pr_class_end_method, + pr_end_class_type, + pr_typedef_type, + pr_tag_type, + pr_typdef, + pr_tag, + pr_int_constant, + pr_float_constant, + pr_typed_constant, + pr_variable, + pr_start_function, + pr_function_parameter, + pr_start_block, + pr_end_block, + pr_end_function, + pr_lineno +}; + +/* Print out the generic debugging information recorded in dhandle. */ + +bfd_boolean +print_debugging_info (f, dhandle) + FILE *f; + PTR dhandle; +{ + struct pr_handle info; + + info.f = f; + info.indent = 0; + info.stack = NULL; + info.parameter = 0; + + return debug_write (dhandle, &pr_fns, (PTR) &info); +} + +/* Indent to the current indentation level. */ + +static void +indent (info) + struct pr_handle *info; +{ + unsigned int i; + + for (i = 0; i < info->indent; i++) + putc (' ', info->f); +} + +/* Push a type on the type stack. */ + +static bfd_boolean +push_type (info, type) + struct pr_handle *info; + const char *type; +{ + struct pr_stack *n; + + if (type == NULL) + return FALSE; + + n = (struct pr_stack *) xmalloc (sizeof *n); + memset (n, 0, sizeof *n); + + n->type = xstrdup (type); + n->visibility = DEBUG_VISIBILITY_IGNORE; + n->method = NULL; + n->next = info->stack; + info->stack = n; + + return TRUE; +} + +/* Prepend a string onto the type on the top of the type stack. */ + +static bfd_boolean +prepend_type (info, s) + struct pr_handle *info; + const char *s; +{ + char *n; + + assert (info->stack != NULL); + + n = (char *) xmalloc (strlen (s) + strlen (info->stack->type) + 1); + sprintf (n, "%s%s", s, info->stack->type); + free (info->stack->type); + info->stack->type = n; + + return TRUE; +} + +/* Append a string to the type on the top of the type stack. */ + +static bfd_boolean +append_type (info, s) + struct pr_handle *info; + const char *s; +{ + unsigned int len; + + if (s == NULL) + return FALSE; + + assert (info->stack != NULL); + + len = strlen (info->stack->type); + info->stack->type = (char *) xrealloc (info->stack->type, + len + strlen (s) + 1); + strcpy (info->stack->type + len, s); + + return TRUE; +} + +/* We use an underscore to indicate where the name should go in a type + string. This function substitutes a string for the underscore. If + there is no underscore, the name follows the type. */ + +static bfd_boolean +substitute_type (info, s) + struct pr_handle *info; + const char *s; +{ + char *u; + + assert (info->stack != NULL); + + u = strchr (info->stack->type, '|'); + if (u != NULL) + { + char *n; + + n = (char *) xmalloc (strlen (info->stack->type) + strlen (s)); + + memcpy (n, info->stack->type, u - info->stack->type); + strcpy (n + (u - info->stack->type), s); + strcat (n, u + 1); + + free (info->stack->type); + info->stack->type = n; + + return TRUE; + } + + if (strchr (s, '|') != NULL + && (strchr (info->stack->type, '{') != NULL + || strchr (info->stack->type, '(') != NULL)) + { + if (! prepend_type (info, "(") + || ! append_type (info, ")")) + return FALSE; + } + + if (*s == '\0') + return TRUE; + + return (append_type (info, " ") + && append_type (info, s)); +} + +/* Indent the type at the top of the stack by appending spaces. */ + +static bfd_boolean +indent_type (info) + struct pr_handle *info; +{ + unsigned int i; + + for (i = 0; i < info->indent; i++) + { + if (! append_type (info, " ")) + return FALSE; + } + + return TRUE; +} + +/* Pop a type from the type stack. */ + +static char * +pop_type (info) + struct pr_handle *info; +{ + struct pr_stack *o; + char *ret; + + assert (info->stack != NULL); + + o = info->stack; + info->stack = o->next; + ret = o->type; + free (o); + + return ret; +} + +/* Print a VMA value into a string. */ + +static void +print_vma (vma, buf, unsignedp, hexp) + bfd_vma vma; + char *buf; + bfd_boolean unsignedp; + bfd_boolean hexp; +{ + if (sizeof (vma) <= sizeof (unsigned long)) + { + if (hexp) + sprintf (buf, "0x%lx", (unsigned long) vma); + else if (unsignedp) + sprintf (buf, "%lu", (unsigned long) vma); + else + sprintf (buf, "%ld", (long) vma); + } + else + { + buf[0] = '0'; + buf[1] = 'x'; + sprintf_vma (buf + 2, vma); + } +} + +/* Start a new compilation unit. */ + +static bfd_boolean +pr_start_compilation_unit (p, filename) + PTR p; + const char *filename; +{ + struct pr_handle *info = (struct pr_handle *) p; + + assert (info->indent == 0); + + fprintf (info->f, "%s:\n", filename); + + return TRUE; +} + +/* Start a source file within a compilation unit. */ + +static bfd_boolean +pr_start_source (p, filename) + PTR p; + const char *filename; +{ + struct pr_handle *info = (struct pr_handle *) p; + + assert (info->indent == 0); + + fprintf (info->f, " %s:\n", filename); + + return TRUE; +} + +/* Push an empty type onto the type stack. */ + +static bfd_boolean +pr_empty_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return push_type (info, ""); +} + +/* Push a void type onto the type stack. */ + +static bfd_boolean +pr_void_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return push_type (info, "void"); +} + +/* Push an integer type onto the type stack. */ + +static bfd_boolean +pr_int_type (p, size, unsignedp) + PTR p; + unsigned int size; + bfd_boolean unsignedp; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[10]; + + sprintf (ab, "%sint%d", unsignedp ? "u" : "", size * 8); + return push_type (info, ab); +} + +/* Push a floating type onto the type stack. */ + +static bfd_boolean +pr_float_type (p, size) + PTR p; + unsigned int size; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[10]; + + if (size == 4) + return push_type (info, "float"); + else if (size == 8) + return push_type (info, "double"); + + sprintf (ab, "float%d", size * 8); + return push_type (info, ab); +} + +/* Push a complex type onto the type stack. */ + +static bfd_boolean +pr_complex_type (p, size) + PTR p; + unsigned int size; +{ + struct pr_handle *info = (struct pr_handle *) p; + + if (! pr_float_type (p, size)) + return FALSE; + + return prepend_type (info, "complex "); +} + +/* Push a bfd_boolean type onto the type stack. */ + +static bfd_boolean +pr_bool_type (p, size) + PTR p; + unsigned int size; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[10]; + + sprintf (ab, "bool%d", size * 8); + + return push_type (info, ab); +} + +/* Push an enum type onto the type stack. */ + +static bfd_boolean +pr_enum_type (p, tag, names, values) + PTR p; + const char *tag; + const char **names; + bfd_signed_vma *values; +{ + struct pr_handle *info = (struct pr_handle *) p; + unsigned int i; + bfd_signed_vma val; + + if (! push_type (info, "enum ")) + return FALSE; + if (tag != NULL) + { + if (! append_type (info, tag) + || ! append_type (info, " ")) + return FALSE; + } + if (! append_type (info, "{ ")) + return FALSE; + + if (names == NULL) + { + if (! append_type (info, "/* undefined */")) + return FALSE; + } + else + { + val = 0; + for (i = 0; names[i] != NULL; i++) + { + if (i > 0) + { + if (! append_type (info, ", ")) + return FALSE; + } + + if (! append_type (info, names[i])) + return FALSE; + + if (values[i] != val) + { + char ab[20]; + + print_vma (values[i], ab, FALSE, FALSE); + if (! append_type (info, " = ") + || ! append_type (info, ab)) + return FALSE; + val = values[i]; + } + + ++val; + } + } + + return append_type (info, " }"); +} + +/* Turn the top type on the stack into a pointer. */ + +static bfd_boolean +pr_pointer_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *s; + + assert (info->stack != NULL); + + s = strchr (info->stack->type, '|'); + if (s != NULL && s[1] == '[') + return substitute_type (info, "(*|)"); + return substitute_type (info, "*|"); +} + +/* Turn the top type on the stack into a function returning that type. */ + +static bfd_boolean +pr_function_type (p, argcount, varargs) + PTR p; + int argcount; + bfd_boolean varargs; +{ + struct pr_handle *info = (struct pr_handle *) p; + char **arg_types; + unsigned int len; + char *s; + + assert (info->stack != NULL); + + len = 10; + + if (argcount <= 0) + { + arg_types = NULL; + len += 15; + } + else + { + int i; + + arg_types = (char **) xmalloc (argcount * sizeof *arg_types); + for (i = argcount - 1; i >= 0; i--) + { + if (! substitute_type (info, "")) + return FALSE; + arg_types[i] = pop_type (info); + if (arg_types[i] == NULL) + return FALSE; + len += strlen (arg_types[i]) + 2; + } + if (varargs) + len += 5; + } + + /* Now the return type is on the top of the stack. */ + + s = (char *) xmalloc (len); + strcpy (s, "(|) ("); + + if (argcount < 0) + strcat (s, "/* unknown */"); + else + { + int i; + + for (i = 0; i < argcount; i++) + { + if (i > 0) + strcat (s, ", "); + strcat (s, arg_types[i]); + } + if (varargs) + { + if (i > 0) + strcat (s, ", "); + strcat (s, "..."); + } + if (argcount > 0) + free (arg_types); + } + + strcat (s, ")"); + + if (! substitute_type (info, s)) + return FALSE; + + free (s); + + return TRUE; +} + +/* Turn the top type on the stack into a reference to that type. */ + +static bfd_boolean +pr_reference_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + assert (info->stack != NULL); + + return substitute_type (info, "&|"); +} + +/* Make a range type. */ + +static bfd_boolean +pr_range_type (p, lower, upper) + PTR p; + bfd_signed_vma lower; + bfd_signed_vma upper; +{ + struct pr_handle *info = (struct pr_handle *) p; + char abl[20], abu[20]; + + assert (info->stack != NULL); + + if (! substitute_type (info, "")) + return FALSE; + + print_vma (lower, abl, FALSE, FALSE); + print_vma (upper, abu, FALSE, FALSE); + + return (prepend_type (info, "range (") + && append_type (info, "):") + && append_type (info, abl) + && append_type (info, ":") + && append_type (info, abu)); +} + +/* Make an array type. */ + +static bfd_boolean +pr_array_type (p, lower, upper, stringp) + PTR p; + bfd_signed_vma lower; + bfd_signed_vma upper; + bfd_boolean stringp; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *range_type; + char abl[20], abu[20], ab[50]; + + range_type = pop_type (info); + if (range_type == NULL) + return FALSE; + + if (lower == 0) + { + if (upper == -1) + sprintf (ab, "|[]"); + else + { + print_vma (upper + 1, abu, FALSE, FALSE); + sprintf (ab, "|[%s]", abu); + } + } + else + { + print_vma (lower, abl, FALSE, FALSE); + print_vma (upper, abu, FALSE, FALSE); + sprintf (ab, "|[%s:%s]", abl, abu); + } + + if (! substitute_type (info, ab)) + return FALSE; + + if (strcmp (range_type, "int") != 0) + { + if (! append_type (info, ":") + || ! append_type (info, range_type)) + return FALSE; + } + + if (stringp) + { + if (! append_type (info, " /* string */")) + return FALSE; + } + + return TRUE; +} + +/* Make a set type. */ + +static bfd_boolean +pr_set_type (p, bitstringp) + PTR p; + bfd_boolean bitstringp; +{ + struct pr_handle *info = (struct pr_handle *) p; + + if (! substitute_type (info, "")) + return FALSE; + + if (! prepend_type (info, "set { ") + || ! append_type (info, " }")) + return FALSE; + + if (bitstringp) + { + if (! append_type (info, "/* bitstring */")) + return FALSE; + } + + return TRUE; +} + +/* Make an offset type. */ + +static bfd_boolean +pr_offset_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + if (! substitute_type (info, "")) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + return (substitute_type (info, "") + && prepend_type (info, " ") + && prepend_type (info, t) + && append_type (info, "::|")); +} + +/* Make a method type. */ + +static bfd_boolean +pr_method_type (p, domain, argcount, varargs) + PTR p; + bfd_boolean domain; + int argcount; + bfd_boolean varargs; +{ + struct pr_handle *info = (struct pr_handle *) p; + unsigned int len; + char *domain_type; + char **arg_types; + char *s; + + len = 10; + + if (! domain) + domain_type = NULL; + else + { + if (! substitute_type (info, "")) + return FALSE; + domain_type = pop_type (info); + if (domain_type == NULL) + return FALSE; + if (strncmp (domain_type, "class ", sizeof "class " - 1) == 0 + && strchr (domain_type + sizeof "class " - 1, ' ') == NULL) + domain_type += sizeof "class " - 1; + else if (strncmp (domain_type, "union class ", + sizeof "union class ") == 0 + && (strchr (domain_type + sizeof "union class " - 1, ' ') + == NULL)) + domain_type += sizeof "union class " - 1; + len += strlen (domain_type); + } + + if (argcount <= 0) + { + arg_types = NULL; + len += 15; + } + else + { + int i; + + arg_types = (char **) xmalloc (argcount * sizeof *arg_types); + for (i = argcount - 1; i >= 0; i--) + { + if (! substitute_type (info, "")) + return FALSE; + arg_types[i] = pop_type (info); + if (arg_types[i] == NULL) + return FALSE; + len += strlen (arg_types[i]) + 2; + } + if (varargs) + len += 5; + } + + /* Now the return type is on the top of the stack. */ + + s = (char *) xmalloc (len); + if (! domain) + *s = '\0'; + else + strcpy (s, domain_type); + strcat (s, "::| ("); + + if (argcount < 0) + strcat (s, "/* unknown */"); + else + { + int i; + + for (i = 0; i < argcount; i++) + { + if (i > 0) + strcat (s, ", "); + strcat (s, arg_types[i]); + } + if (varargs) + { + if (i > 0) + strcat (s, ", "); + strcat (s, "..."); + } + if (argcount > 0) + free (arg_types); + } + + strcat (s, ")"); + + if (! substitute_type (info, s)) + return FALSE; + + free (s); + + return TRUE; +} + +/* Make a const qualified type. */ + +static bfd_boolean +pr_const_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return substitute_type (info, "const |"); +} + +/* Make a volatile qualified type. */ + +static bfd_boolean +pr_volatile_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return substitute_type (info, "volatile |"); +} + +/* Start accumulating a struct type. */ + +static bfd_boolean +pr_start_struct_type (p, tag, id, structp, size) + PTR p; + const char *tag; + unsigned int id; + bfd_boolean structp; + unsigned int size; +{ + struct pr_handle *info = (struct pr_handle *) p; + + info->indent += 2; + + if (! push_type (info, structp ? "struct " : "union ")) + return FALSE; + if (tag != NULL) + { + if (! append_type (info, tag)) + return FALSE; + } + else + { + char idbuf[20]; + + sprintf (idbuf, "%%anon%u", id); + if (! append_type (info, idbuf)) + return FALSE; + } + + if (! append_type (info, " {")) + return FALSE; + if (size != 0 || tag != NULL) + { + char ab[30]; + + if (! append_type (info, " /*")) + return FALSE; + + if (size != 0) + { + sprintf (ab, " size %u", size); + if (! append_type (info, ab)) + return FALSE; + } + if (tag != NULL) + { + sprintf (ab, " id %u", id); + if (! append_type (info, ab)) + return FALSE; + } + if (! append_type (info, " */")) + return FALSE; + } + if (! append_type (info, "\n")) + return FALSE; + + info->stack->visibility = DEBUG_VISIBILITY_PUBLIC; + + return indent_type (info); +} + +/* Output the visibility of a field in a struct. */ + +static bfd_boolean +pr_fix_visibility (info, visibility) + struct pr_handle *info; + enum debug_visibility visibility; +{ + const char *s = NULL; + char *t; + unsigned int len; + + assert (info->stack != NULL); + + if (info->stack->visibility == visibility) + return TRUE; + + switch (visibility) + { + case DEBUG_VISIBILITY_PUBLIC: + s = "public"; + break; + case DEBUG_VISIBILITY_PRIVATE: + s = "private"; + break; + case DEBUG_VISIBILITY_PROTECTED: + s = "protected"; + break; + case DEBUG_VISIBILITY_IGNORE: + s = "/* ignore */"; + break; + default: + abort (); + return FALSE; + } + + /* Trim off a trailing space in the struct string, to make the + output look a bit better, then stick on the visibility string. */ + + t = info->stack->type; + len = strlen (t); + assert (t[len - 1] == ' '); + t[len - 1] = '\0'; + + if (! append_type (info, s) + || ! append_type (info, ":\n") + || ! indent_type (info)) + return FALSE; + + info->stack->visibility = visibility; + + return TRUE; +} + +/* Add a field to a struct type. */ + +static bfd_boolean +pr_struct_field (p, name, bitpos, bitsize, visibility) + PTR p; + const char *name; + bfd_vma bitpos; + bfd_vma bitsize; + enum debug_visibility visibility; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + char *t; + + if (! substitute_type (info, name)) + return FALSE; + + if (! append_type (info, "; /* ")) + return FALSE; + + if (bitsize != 0) + { + print_vma (bitsize, ab, TRUE, FALSE); + if (! append_type (info, "bitsize ") + || ! append_type (info, ab) + || ! append_type (info, ", ")) + return FALSE; + } + + print_vma (bitpos, ab, TRUE, FALSE); + if (! append_type (info, "bitpos ") + || ! append_type (info, ab) + || ! append_type (info, " */\n") + || ! indent_type (info)) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + if (! pr_fix_visibility (info, visibility)) + return FALSE; + + return append_type (info, t); +} + +/* Finish a struct type. */ + +static bfd_boolean +pr_end_struct_type (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *s; + + assert (info->stack != NULL); + assert (info->indent >= 2); + + info->indent -= 2; + + /* Change the trailing indentation to have a close brace. */ + s = info->stack->type + strlen (info->stack->type) - 2; + assert (s[0] == ' ' && s[1] == ' ' && s[2] == '\0'); + + *s++ = '}'; + *s = '\0'; + + return TRUE; +} + +/* Start a class type. */ + +static bfd_boolean +pr_start_class_type (p, tag, id, structp, size, vptr, ownvptr) + PTR p; + const char *tag; + unsigned int id; + bfd_boolean structp; + unsigned int size; + bfd_boolean vptr; + bfd_boolean ownvptr; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *tv = NULL; + + info->indent += 2; + + if (vptr && ! ownvptr) + { + tv = pop_type (info); + if (tv == NULL) + return FALSE; + } + + if (! push_type (info, structp ? "class " : "union class ")) + return FALSE; + if (tag != NULL) + { + if (! append_type (info, tag)) + return FALSE; + } + else + { + char idbuf[20]; + + sprintf (idbuf, "%%anon%u", id); + if (! append_type (info, idbuf)) + return FALSE; + } + + if (! append_type (info, " {")) + return FALSE; + if (size != 0 || vptr || ownvptr || tag != NULL) + { + if (! append_type (info, " /*")) + return FALSE; + + if (size != 0) + { + char ab[20]; + + sprintf (ab, "%u", size); + if (! append_type (info, " size ") + || ! append_type (info, ab)) + return FALSE; + } + + if (vptr) + { + if (! append_type (info, " vtable ")) + return FALSE; + if (ownvptr) + { + if (! append_type (info, "self ")) + return FALSE; + } + else + { + if (! append_type (info, tv) + || ! append_type (info, " ")) + return FALSE; + } + } + + if (tag != NULL) + { + char ab[30]; + + sprintf (ab, " id %u", id); + if (! append_type (info, ab)) + return FALSE; + } + + if (! append_type (info, " */")) + return FALSE; + } + + info->stack->visibility = DEBUG_VISIBILITY_PRIVATE; + + return (append_type (info, "\n") + && indent_type (info)); +} + +/* Add a static member to a class. */ + +static bfd_boolean +pr_class_static_member (p, name, physname, visibility) + PTR p; + const char *name; + const char *physname; + enum debug_visibility visibility; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + if (! substitute_type (info, name)) + return FALSE; + + if (! prepend_type (info, "static ") + || ! append_type (info, "; /* ") + || ! append_type (info, physname) + || ! append_type (info, " */\n") + || ! indent_type (info)) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + if (! pr_fix_visibility (info, visibility)) + return FALSE; + + return append_type (info, t); +} + +/* Add a base class to a class. */ + +static bfd_boolean +pr_class_baseclass (p, bitpos, virtual, visibility) + PTR p; + bfd_vma bitpos; + bfd_boolean virtual; + enum debug_visibility visibility; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + const char *prefix; + char ab[20]; + char *s, *l, *n; + + assert (info->stack != NULL && info->stack->next != NULL); + + if (! substitute_type (info, "")) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + if (strncmp (t, "class ", sizeof "class " - 1) == 0) + t += sizeof "class " - 1; + + /* Push it back on to take advantage of the prepend_type and + append_type routines. */ + if (! push_type (info, t)) + return FALSE; + + if (virtual) + { + if (! prepend_type (info, "virtual ")) + return FALSE; + } + + switch (visibility) + { + case DEBUG_VISIBILITY_PUBLIC: + prefix = "public "; + break; + case DEBUG_VISIBILITY_PROTECTED: + prefix = "protected "; + break; + case DEBUG_VISIBILITY_PRIVATE: + prefix = "private "; + break; + default: + prefix = "/* unknown visibility */ "; + break; + } + + if (! prepend_type (info, prefix)) + return FALSE; + + if (bitpos != 0) + { + print_vma (bitpos, ab, TRUE, FALSE); + if (! append_type (info, " /* bitpos ") + || ! append_type (info, ab) + || ! append_type (info, " */")) + return FALSE; + } + + /* Now the top of the stack is something like "public A / * bitpos + 10 * /". The next element on the stack is something like "class + xx { / * size 8 * /\n...". We want to substitute the top of the + stack in before the {. */ + s = strchr (info->stack->next->type, '{'); + assert (s != NULL); + --s; + + /* If there is already a ':', then we already have a baseclass, and + we must append this one after a comma. */ + for (l = info->stack->next->type; l != s; l++) + if (*l == ':') + break; + if (! prepend_type (info, l == s ? " : " : ", ")) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + n = (char *) xmalloc (strlen (info->stack->type) + strlen (t) + 1); + memcpy (n, info->stack->type, s - info->stack->type); + strcpy (n + (s - info->stack->type), t); + strcat (n, s); + + free (info->stack->type); + info->stack->type = n; + + free (t); + + return TRUE; +} + +/* Start adding a method to a class. */ + +static bfd_boolean +pr_class_start_method (p, name) + PTR p; + const char *name; +{ + struct pr_handle *info = (struct pr_handle *) p; + + assert (info->stack != NULL); + info->stack->method = name; + return TRUE; +} + +/* Add a variant to a method. */ + +static bfd_boolean +pr_class_method_variant (p, physname, visibility, constp, volatilep, voffset, + context) + PTR p; + const char *physname; + enum debug_visibility visibility; + bfd_boolean constp; + bfd_boolean volatilep; + bfd_vma voffset; + bfd_boolean context; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *method_type; + char *context_type; + + assert (info->stack != NULL); + assert (info->stack->next != NULL); + + /* Put the const and volatile qualifiers on the type. */ + if (volatilep) + { + if (! append_type (info, " volatile")) + return FALSE; + } + if (constp) + { + if (! append_type (info, " const")) + return FALSE; + } + + /* Stick the name of the method into its type. */ + if (! substitute_type (info, + (context + ? info->stack->next->next->method + : info->stack->next->method))) + return FALSE; + + /* Get the type. */ + method_type = pop_type (info); + if (method_type == NULL) + return FALSE; + + /* Pull off the context type if there is one. */ + if (! context) + context_type = NULL; + else + { + context_type = pop_type (info); + if (context_type == NULL) + return FALSE; + } + + /* Now the top of the stack is the class. */ + + if (! pr_fix_visibility (info, visibility)) + return FALSE; + + if (! append_type (info, method_type) + || ! append_type (info, " /* ") + || ! append_type (info, physname) + || ! append_type (info, " ")) + return FALSE; + if (context || voffset != 0) + { + char ab[20]; + + if (context) + { + if (! append_type (info, "context ") + || ! append_type (info, context_type) + || ! append_type (info, " ")) + return FALSE; + } + print_vma (voffset, ab, TRUE, FALSE); + if (! append_type (info, "voffset ") + || ! append_type (info, ab)) + return FALSE; + } + + return (append_type (info, " */;\n") + && indent_type (info)); +} + +/* Add a static variant to a method. */ + +static bfd_boolean +pr_class_static_method_variant (p, physname, visibility, constp, volatilep) + PTR p; + const char *physname; + enum debug_visibility visibility; + bfd_boolean constp; + bfd_boolean volatilep; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *method_type; + + assert (info->stack != NULL); + assert (info->stack->next != NULL); + assert (info->stack->next->method != NULL); + + /* Put the const and volatile qualifiers on the type. */ + if (volatilep) + { + if (! append_type (info, " volatile")) + return FALSE; + } + if (constp) + { + if (! append_type (info, " const")) + return FALSE; + } + + /* Mark it as static. */ + if (! prepend_type (info, "static ")) + return FALSE; + + /* Stick the name of the method into its type. */ + if (! substitute_type (info, info->stack->next->method)) + return FALSE; + + /* Get the type. */ + method_type = pop_type (info); + if (method_type == NULL) + return FALSE; + + /* Now the top of the stack is the class. */ + + if (! pr_fix_visibility (info, visibility)) + return FALSE; + + return (append_type (info, method_type) + && append_type (info, " /* ") + && append_type (info, physname) + && append_type (info, " */;\n") + && indent_type (info)); +} + +/* Finish up a method. */ + +static bfd_boolean +pr_class_end_method (p) + PTR p; +{ + struct pr_handle *info = (struct pr_handle *) p; + + info->stack->method = NULL; + return TRUE; +} + +/* Finish up a class. */ + +static bfd_boolean +pr_end_class_type (p) + PTR p; +{ + return pr_end_struct_type (p); +} + +/* Push a type on the stack using a typedef name. */ + +static bfd_boolean +pr_typedef_type (p, name) + PTR p; + const char *name; +{ + struct pr_handle *info = (struct pr_handle *) p; + + return push_type (info, name); +} + +/* Push a type on the stack using a tag name. */ + +static bfd_boolean +pr_tag_type (p, name, id, kind) + PTR p; + const char *name; + unsigned int id; + enum debug_type_kind kind; +{ + struct pr_handle *info = (struct pr_handle *) p; + const char *t, *tag; + char idbuf[20]; + + switch (kind) + { + case DEBUG_KIND_STRUCT: + t = "struct "; + break; + case DEBUG_KIND_UNION: + t = "union "; + break; + case DEBUG_KIND_ENUM: + t = "enum "; + break; + case DEBUG_KIND_CLASS: + t = "class "; + break; + case DEBUG_KIND_UNION_CLASS: + t = "union class "; + break; + default: + abort (); + return FALSE; + } + + if (! push_type (info, t)) + return FALSE; + if (name != NULL) + tag = name; + else + { + sprintf (idbuf, "%%anon%u", id); + tag = idbuf; + } + + if (! append_type (info, tag)) + return FALSE; + if (name != NULL && kind != DEBUG_KIND_ENUM) + { + sprintf (idbuf, " /* id %u */", id); + if (! append_type (info, idbuf)) + return FALSE; + } + + return TRUE; +} + +/* Output a typedef. */ + +static bfd_boolean +pr_typdef (p, name) + PTR p; + const char *name; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *s; + + if (! substitute_type (info, name)) + return FALSE; + + s = pop_type (info); + if (s == NULL) + return FALSE; + + indent (info); + fprintf (info->f, "typedef %s;\n", s); + + free (s); + + return TRUE; +} + +/* Output a tag. The tag should already be in the string on the + stack, so all we have to do here is print it out. */ + +static bfd_boolean +pr_tag (p, name) + PTR p; + const char *name ATTRIBUTE_UNUSED; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + indent (info); + fprintf (info->f, "%s;\n", t); + + free (t); + + return TRUE; +} + +/* Output an integer constant. */ + +static bfd_boolean +pr_int_constant (p, name, val) + PTR p; + const char *name; + bfd_vma val; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + + indent (info); + print_vma (val, ab, FALSE, FALSE); + fprintf (info->f, "const int %s = %s;\n", name, ab); + return TRUE; +} + +/* Output a floating point constant. */ + +static bfd_boolean +pr_float_constant (p, name, val) + PTR p; + const char *name; + double val; +{ + struct pr_handle *info = (struct pr_handle *) p; + + indent (info); + fprintf (info->f, "const double %s = %g;\n", name, val); + return TRUE; +} + +/* Output a typed constant. */ + +static bfd_boolean +pr_typed_constant (p, name, val) + PTR p; + const char *name; + bfd_vma val; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + char ab[20]; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + indent (info); + print_vma (val, ab, FALSE, FALSE); + fprintf (info->f, "const %s %s = %s;\n", t, name, ab); + + free (t); + + return TRUE; +} + +/* Output a variable. */ + +static bfd_boolean +pr_variable (p, name, kind, val) + PTR p; + const char *name; + enum debug_var_kind kind; + bfd_vma val; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + char ab[20]; + + if (! substitute_type (info, name)) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + indent (info); + switch (kind) + { + case DEBUG_STATIC: + case DEBUG_LOCAL_STATIC: + fprintf (info->f, "static "); + break; + case DEBUG_REGISTER: + fprintf (info->f, "register "); + break; + default: + break; + } + print_vma (val, ab, TRUE, TRUE); + fprintf (info->f, "%s /* %s */;\n", t, ab); + + free (t); + + return TRUE; +} + +/* Start outputting a function. */ + +static bfd_boolean +pr_start_function (p, name, global) + PTR p; + const char *name; + bfd_boolean global; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + + if (! substitute_type (info, name)) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + indent (info); + if (! global) + fprintf (info->f, "static "); + fprintf (info->f, "%s (", t); + + info->parameter = 1; + + return TRUE; +} + +/* Output a function parameter. */ + +static bfd_boolean +pr_function_parameter (p, name, kind, val) + PTR p; + const char *name; + enum debug_parm_kind kind; + bfd_vma val; +{ + struct pr_handle *info = (struct pr_handle *) p; + char *t; + char ab[20]; + + if (kind == DEBUG_PARM_REFERENCE + || kind == DEBUG_PARM_REF_REG) + { + if (! pr_reference_type (p)) + return FALSE; + } + + if (! substitute_type (info, name)) + return FALSE; + + t = pop_type (info); + if (t == NULL) + return FALSE; + + if (info->parameter != 1) + fprintf (info->f, ", "); + + if (kind == DEBUG_PARM_REG || kind == DEBUG_PARM_REF_REG) + fprintf (info->f, "register "); + + print_vma (val, ab, TRUE, TRUE); + fprintf (info->f, "%s /* %s */", t, ab); + + free (t); + + ++info->parameter; + + return TRUE; +} + +/* Start writing out a block. */ + +static bfd_boolean +pr_start_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + + if (info->parameter > 0) + { + fprintf (info->f, ")\n"); + info->parameter = 0; + } + + indent (info); + print_vma (addr, ab, TRUE, TRUE); + fprintf (info->f, "{ /* %s */\n", ab); + + info->indent += 2; + + return TRUE; +} + +/* Write out line number information. */ + +static bfd_boolean +pr_lineno (p, filename, lineno, addr) + PTR p; + const char *filename; + unsigned long lineno; + bfd_vma addr; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + + indent (info); + print_vma (addr, ab, TRUE, TRUE); + fprintf (info->f, "/* file %s line %lu addr %s */\n", filename, lineno, ab); + + return TRUE; +} + +/* Finish writing out a block. */ + +static bfd_boolean +pr_end_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct pr_handle *info = (struct pr_handle *) p; + char ab[20]; + + info->indent -= 2; + + indent (info); + print_vma (addr, ab, TRUE, TRUE); + fprintf (info->f, "} /* %s */\n", ab); + + return TRUE; +} + +/* Finish writing out a function. */ + +static bfd_boolean +pr_end_function (p) + PTR p ATTRIBUTE_UNUSED; +{ + return TRUE; +} diff --git a/contrib/binutils-2.14/binutils/rdcoff.c b/contrib/binutils-2.14/binutils/rdcoff.c new file mode 100644 index 0000000000..cca9b0e64b --- /dev/null +++ b/contrib/binutils-2.14/binutils/rdcoff.c @@ -0,0 +1,908 @@ +/* stabs.c -- Parse COFF debugging information + Copyright 1996, 2000, 2002 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file contains code which parses COFF debugging information. */ + +#include "bfd.h" +#include "coff/internal.h" +#include "bucomm.h" +#include "libiberty.h" +#include "debug.h" +#include "budbg.h" + +/* FIXME: We should not need this BFD internal file. We need it for + the N_BTMASK, etc., values. */ +#include "libcoff.h" + +/* These macros extract the right mask and shifts for this BFD. They + assume that there is a local variable named ABFD. This is so that + macros like ISFCN and DECREF, from coff/internal.h, will work + without modification. */ +#define N_BTMASK (coff_data (abfd)->local_n_btmask) +#define N_BTSHFT (coff_data (abfd)->local_n_btshft) +#define N_TMASK (coff_data (abfd)->local_n_tmask) +#define N_TSHIFT (coff_data (abfd)->local_n_tshift) + +/* This structure is used to hold the symbols, as well as the current + location within the symbols. */ + +struct coff_symbols +{ + /* The symbols. */ + asymbol **syms; + /* The number of symbols. */ + long symcount; + /* The index of the current symbol. */ + long symno; + /* The index of the current symbol in the COFF symbol table (where + each auxent counts as a symbol). */ + long coff_symno; +}; + +/* The largest basic type we are prepared to handle. */ + +#define T_MAX (T_LNGDBL) + +/* This structure is used to hold slots. */ + +struct coff_slots +{ + /* Next set of slots. */ + struct coff_slots *next; + /* Slots. */ +#define COFF_SLOTS (16) + debug_type slots[COFF_SLOTS]; +}; + +/* This structure is used to map symbol indices to types. */ + +struct coff_types +{ + /* Slots. */ + struct coff_slots *slots; + /* Basic types. */ + debug_type basic[T_MAX + 1]; +}; + +static debug_type *coff_get_slot + PARAMS ((struct coff_types *, int)); +static debug_type parse_coff_type + PARAMS ((bfd *, struct coff_symbols *, struct coff_types *, long, int, + union internal_auxent *, bfd_boolean, PTR)); +static debug_type parse_coff_base_type + PARAMS ((bfd *, struct coff_symbols *, struct coff_types *, long, int, + union internal_auxent *, PTR)); +static debug_type parse_coff_struct_type + PARAMS ((bfd *, struct coff_symbols *, struct coff_types *, int, + union internal_auxent *, PTR)); +static debug_type parse_coff_enum_type + PARAMS ((bfd *, struct coff_symbols *, struct coff_types *, + union internal_auxent *, PTR)); +static bfd_boolean parse_coff_symbol + PARAMS ((bfd *, struct coff_types *, asymbol *, long, + struct internal_syment *, PTR, debug_type, bfd_boolean)); +static bfd_boolean external_coff_symbol_p + PARAMS ((int sym_class)); + +/* Return the slot for a type. */ + +static debug_type * +coff_get_slot (types, indx) + struct coff_types *types; + int indx; +{ + struct coff_slots **pps; + + pps = &types->slots; + + while (indx >= COFF_SLOTS) + { + if (*pps == NULL) + { + *pps = (struct coff_slots *) xmalloc (sizeof **pps); + memset (*pps, 0, sizeof **pps); + } + pps = &(*pps)->next; + indx -= COFF_SLOTS; + } + + if (*pps == NULL) + { + *pps = (struct coff_slots *) xmalloc (sizeof **pps); + memset (*pps, 0, sizeof **pps); + } + + return (*pps)->slots + indx; +} + +/* Parse a COFF type code in NTYPE. */ + +static debug_type +parse_coff_type (abfd, symbols, types, coff_symno, ntype, pauxent, useaux, + dhandle) + bfd *abfd; + struct coff_symbols *symbols; + struct coff_types *types; + long coff_symno; + int ntype; + union internal_auxent *pauxent; + bfd_boolean useaux; + PTR dhandle; +{ + debug_type type; + + if ((ntype & ~N_BTMASK) != 0) + { + int newtype; + + newtype = DECREF (ntype); + + if (ISPTR (ntype)) + { + type = parse_coff_type (abfd, symbols, types, coff_symno, newtype, + pauxent, useaux, dhandle); + type = debug_make_pointer_type (dhandle, type); + } + else if (ISFCN (ntype)) + { + type = parse_coff_type (abfd, symbols, types, coff_symno, newtype, + pauxent, useaux, dhandle); + type = debug_make_function_type (dhandle, type, (debug_type *) NULL, + FALSE); + } + else if (ISARY (ntype)) + { + int n; + + if (pauxent == NULL) + n = 0; + else + { + unsigned short *dim; + int i; + + /* FIXME: If pauxent->x_sym.x_tagndx.l == 0, gdb sets + the c_naux field of the syment to 0. */ + + /* Move the dimensions down, so that the next array + picks up the next one. */ + dim = pauxent->x_sym.x_fcnary.x_ary.x_dimen; + n = dim[0]; + for (i = 0; *dim != 0 && i < DIMNUM - 1; i++, dim++) + *dim = *(dim + 1); + *dim = 0; + } + + type = parse_coff_type (abfd, symbols, types, coff_symno, newtype, + pauxent, FALSE, dhandle); + type = debug_make_array_type (dhandle, type, + parse_coff_base_type (abfd, symbols, + types, + coff_symno, + T_INT, + NULL, dhandle), + 0, n - 1, FALSE); + } + else + { + non_fatal (_("parse_coff_type: Bad type code 0x%x"), ntype); + return DEBUG_TYPE_NULL; + } + + return type; + } + + if (pauxent != NULL && pauxent->x_sym.x_tagndx.l > 0) + { + debug_type *slot; + + /* This is a reference to an existing type. FIXME: gdb checks + that the class is not C_STRTAG, nor C_UNTAG, nor C_ENTAG. */ + slot = coff_get_slot (types, pauxent->x_sym.x_tagndx.l); + if (*slot != DEBUG_TYPE_NULL) + return *slot; + else + return debug_make_indirect_type (dhandle, slot, (const char *) NULL); + } + + /* If the aux entry has already been used for something, useaux will + have been set to false, indicating that parse_coff_base_type + should not use it. We need to do it this way, rather than simply + passing pauxent as NULL, because we need to be able handle + multiple array dimensions while still discarding pauxent after + having handled all of them. */ + if (! useaux) + pauxent = NULL; + + return parse_coff_base_type (abfd, symbols, types, coff_symno, ntype, + pauxent, dhandle); +} + +/* Parse a basic COFF type in NTYPE. */ + +static debug_type +parse_coff_base_type (abfd, symbols, types, coff_symno, ntype, pauxent, + dhandle) + bfd *abfd; + struct coff_symbols *symbols; + struct coff_types *types; + long coff_symno; + int ntype; + union internal_auxent *pauxent; + PTR dhandle; +{ + debug_type ret; + bfd_boolean set_basic; + const char *name; + debug_type *slot; + + if (ntype >= 0 + && ntype <= T_MAX + && types->basic[ntype] != DEBUG_TYPE_NULL) + return types->basic[ntype]; + + set_basic = TRUE; + name = NULL; + + switch (ntype) + { + default: + ret = debug_make_void_type (dhandle); + break; + + case T_NULL: + case T_VOID: + ret = debug_make_void_type (dhandle); + name = "void"; + break; + + case T_CHAR: + ret = debug_make_int_type (dhandle, 1, FALSE); + name = "char"; + break; + + case T_SHORT: + ret = debug_make_int_type (dhandle, 2, FALSE); + name = "short"; + break; + + case T_INT: + /* FIXME: Perhaps the size should depend upon the architecture. */ + ret = debug_make_int_type (dhandle, 4, FALSE); + name = "int"; + break; + + case T_LONG: + ret = debug_make_int_type (dhandle, 4, FALSE); + name = "long"; + break; + + case T_FLOAT: + ret = debug_make_float_type (dhandle, 4); + name = "float"; + break; + + case T_DOUBLE: + ret = debug_make_float_type (dhandle, 8); + name = "double"; + break; + + case T_LNGDBL: + ret = debug_make_float_type (dhandle, 12); + name = "long double"; + break; + + case T_UCHAR: + ret = debug_make_int_type (dhandle, 1, TRUE); + name = "unsigned char"; + break; + + case T_USHORT: + ret = debug_make_int_type (dhandle, 2, TRUE); + name = "unsigned short"; + break; + + case T_UINT: + ret = debug_make_int_type (dhandle, 4, TRUE); + name = "unsigned int"; + break; + + case T_ULONG: + ret = debug_make_int_type (dhandle, 4, TRUE); + name = "unsigned long"; + break; + + case T_STRUCT: + if (pauxent == NULL) + ret = debug_make_struct_type (dhandle, TRUE, 0, + (debug_field *) NULL); + else + ret = parse_coff_struct_type (abfd, symbols, types, ntype, pauxent, + dhandle); + + slot = coff_get_slot (types, coff_symno); + *slot = ret; + + set_basic = FALSE; + break; + + case T_UNION: + if (pauxent == NULL) + ret = debug_make_struct_type (dhandle, FALSE, 0, (debug_field *) NULL); + else + ret = parse_coff_struct_type (abfd, symbols, types, ntype, pauxent, + dhandle); + + slot = coff_get_slot (types, coff_symno); + *slot = ret; + + set_basic = FALSE; + break; + + case T_ENUM: + if (pauxent == NULL) + ret = debug_make_enum_type (dhandle, (const char **) NULL, + (bfd_signed_vma *) NULL); + else + ret = parse_coff_enum_type (abfd, symbols, types, pauxent, dhandle); + + slot = coff_get_slot (types, coff_symno); + *slot = ret; + + set_basic = FALSE; + break; + } + + if (name != NULL) + ret = debug_name_type (dhandle, name, ret); + + if (set_basic + && ntype >= 0 + && ntype <= T_MAX) + types->basic[ntype] = ret; + + return ret; +} + +/* Parse a struct type. */ + +static debug_type +parse_coff_struct_type (abfd, symbols, types, ntype, pauxent, dhandle) + bfd *abfd; + struct coff_symbols *symbols; + struct coff_types *types; + int ntype; + union internal_auxent *pauxent; + PTR dhandle; +{ + long symend; + int alloc; + debug_field *fields; + int count; + bfd_boolean done; + + symend = pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l; + + alloc = 10; + fields = (debug_field *) xmalloc (alloc * sizeof *fields); + count = 0; + + done = FALSE; + while (! done + && symbols->coff_symno < symend + && symbols->symno < symbols->symcount) + { + asymbol *sym; + long this_coff_symno; + struct internal_syment syment; + union internal_auxent auxent; + union internal_auxent *psubaux; + bfd_vma bitpos = 0, bitsize = 0; + + sym = symbols->syms[symbols->symno]; + + if (! bfd_coff_get_syment (abfd, sym, &syment)) + { + non_fatal (_("bfd_coff_get_syment failed: %s"), + bfd_errmsg (bfd_get_error ())); + return DEBUG_TYPE_NULL; + } + + this_coff_symno = symbols->coff_symno; + + ++symbols->symno; + symbols->coff_symno += 1 + syment.n_numaux; + + if (syment.n_numaux == 0) + psubaux = NULL; + else + { + if (! bfd_coff_get_auxent (abfd, sym, 0, &auxent)) + { + non_fatal (_("bfd_coff_get_auxent failed: %s"), + bfd_errmsg (bfd_get_error ())); + return DEBUG_TYPE_NULL; + } + psubaux = &auxent; + } + + switch (syment.n_sclass) + { + case C_MOS: + case C_MOU: + bitpos = 8 * bfd_asymbol_value (sym); + bitsize = 0; + break; + + case C_FIELD: + bitpos = bfd_asymbol_value (sym); + bitsize = auxent.x_sym.x_misc.x_lnsz.x_size; + break; + + case C_EOS: + done = TRUE; + break; + } + + if (! done) + { + debug_type ftype; + debug_field f; + + ftype = parse_coff_type (abfd, symbols, types, this_coff_symno, + syment.n_type, psubaux, TRUE, dhandle); + f = debug_make_field (dhandle, bfd_asymbol_name (sym), ftype, + bitpos, bitsize, DEBUG_VISIBILITY_PUBLIC); + if (f == DEBUG_FIELD_NULL) + return DEBUG_TYPE_NULL; + + if (count + 1 >= alloc) + { + alloc += 10; + fields = ((debug_field *) + xrealloc (fields, alloc * sizeof *fields)); + } + + fields[count] = f; + ++count; + } + } + + fields[count] = DEBUG_FIELD_NULL; + + return debug_make_struct_type (dhandle, ntype == T_STRUCT, + pauxent->x_sym.x_misc.x_lnsz.x_size, + fields); +} + +/* Parse an enum type. */ + +static debug_type +parse_coff_enum_type (abfd, symbols, types, pauxent, dhandle) + bfd *abfd; + struct coff_symbols *symbols; + struct coff_types *types ATTRIBUTE_UNUSED; + union internal_auxent *pauxent; + PTR dhandle; +{ + long symend; + int alloc; + const char **names; + bfd_signed_vma *vals; + int count; + bfd_boolean done; + + symend = pauxent->x_sym.x_fcnary.x_fcn.x_endndx.l; + + alloc = 10; + names = (const char **) xmalloc (alloc * sizeof *names); + vals = (bfd_signed_vma *) xmalloc (alloc * sizeof *vals); + count = 0; + + done = FALSE; + while (! done + && symbols->coff_symno < symend + && symbols->symno < symbols->symcount) + { + asymbol *sym; + struct internal_syment syment; + + sym = symbols->syms[symbols->symno]; + + if (! bfd_coff_get_syment (abfd, sym, &syment)) + { + non_fatal (_("bfd_coff_get_syment failed: %s"), + bfd_errmsg (bfd_get_error ())); + return DEBUG_TYPE_NULL; + } + + ++symbols->symno; + symbols->coff_symno += 1 + syment.n_numaux; + + switch (syment.n_sclass) + { + case C_MOE: + if (count + 1 >= alloc) + { + alloc += 10; + names = ((const char **) + xrealloc (names, alloc * sizeof *names)); + vals = ((bfd_signed_vma *) + xrealloc (vals, alloc * sizeof *vals)); + } + + names[count] = bfd_asymbol_name (sym); + vals[count] = bfd_asymbol_value (sym); + ++count; + break; + + case C_EOS: + done = TRUE; + break; + } + } + + names[count] = NULL; + + return debug_make_enum_type (dhandle, names, vals); +} + +/* Handle a single COFF symbol. */ + +static bfd_boolean +parse_coff_symbol (abfd, types, sym, coff_symno, psyment, dhandle, type, + within_function) + bfd *abfd ATTRIBUTE_UNUSED; + struct coff_types *types; + asymbol *sym; + long coff_symno; + struct internal_syment *psyment; + PTR dhandle; + debug_type type; + bfd_boolean within_function; +{ + switch (psyment->n_sclass) + { + case C_NULL: + break; + + case C_AUTO: + if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type, + DEBUG_LOCAL, bfd_asymbol_value (sym))) + return FALSE; + break; + + case C_WEAKEXT: + case C_EXT: + if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type, + DEBUG_GLOBAL, bfd_asymbol_value (sym))) + return FALSE; + break; + + case C_STAT: + if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type, + (within_function + ? DEBUG_LOCAL_STATIC + : DEBUG_STATIC), + bfd_asymbol_value (sym))) + return FALSE; + break; + + case C_REG: + /* FIXME: We may need to convert the register number. */ + if (! debug_record_variable (dhandle, bfd_asymbol_name (sym), type, + DEBUG_REGISTER, bfd_asymbol_value (sym))) + return FALSE; + break; + + case C_LABEL: + break; + + case C_ARG: + if (! debug_record_parameter (dhandle, bfd_asymbol_name (sym), type, + DEBUG_PARM_STACK, bfd_asymbol_value (sym))) + return FALSE; + break; + + case C_REGPARM: + /* FIXME: We may need to convert the register number. */ + if (! debug_record_parameter (dhandle, bfd_asymbol_name (sym), type, + DEBUG_PARM_REG, bfd_asymbol_value (sym))) + return FALSE; + break; + + case C_TPDEF: + type = debug_name_type (dhandle, bfd_asymbol_name (sym), type); + if (type == DEBUG_TYPE_NULL) + return FALSE; + break; + + case C_STRTAG: + case C_UNTAG: + case C_ENTAG: + { + debug_type *slot; + + type = debug_tag_type (dhandle, bfd_asymbol_name (sym), type); + if (type == DEBUG_TYPE_NULL) + return FALSE; + + /* Store the named type into the slot, so that references get + the name. */ + slot = coff_get_slot (types, coff_symno); + *slot = type; + } + break; + + default: + break; + } + + return TRUE; +} + +/* Determine if a symbol has external visibility. */ + +static bfd_boolean +external_coff_symbol_p (sym_class) + int sym_class; +{ + switch (sym_class) + { + case C_EXT: + case C_WEAKEXT: + return TRUE; + default: + break; + } + return FALSE; +} + +/* This is the main routine. It looks through all the symbols and + handles them. */ + +bfd_boolean +parse_coff (abfd, syms, symcount, dhandle) + bfd *abfd; + asymbol **syms; + long symcount; + PTR dhandle; +{ + struct coff_symbols symbols; + struct coff_types types; + int i; + long next_c_file; + const char *fnname; + int fnclass; + int fntype; + bfd_vma fnend; + alent *linenos; + bfd_boolean within_function; + long this_coff_symno; + + symbols.syms = syms; + symbols.symcount = symcount; + symbols.symno = 0; + symbols.coff_symno = 0; + + types.slots = NULL; + for (i = 0; i <= T_MAX; i++) + types.basic[i] = DEBUG_TYPE_NULL; + + next_c_file = -1; + fnname = NULL; + fnclass = 0; + fntype = 0; + fnend = 0; + linenos = NULL; + within_function = FALSE; + + while (symbols.symno < symcount) + { + asymbol *sym; + const char *name; + struct internal_syment syment; + union internal_auxent auxent; + union internal_auxent *paux; + debug_type type; + + sym = syms[symbols.symno]; + + if (! bfd_coff_get_syment (abfd, sym, &syment)) + { + non_fatal (_("bfd_coff_get_syment failed: %s"), + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + + name = bfd_asymbol_name (sym); + + this_coff_symno = symbols.coff_symno; + + ++symbols.symno; + symbols.coff_symno += 1 + syment.n_numaux; + + /* We only worry about the first auxent, because that is the + only one which is relevant for debugging information. */ + if (syment.n_numaux == 0) + paux = NULL; + else + { + if (! bfd_coff_get_auxent (abfd, sym, 0, &auxent)) + { + non_fatal (_("bfd_coff_get_auxent failed: %s"), + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + paux = &auxent; + } + + if (this_coff_symno == next_c_file && syment.n_sclass != C_FILE) + { + /* The last C_FILE symbol points to the first external + symbol. */ + if (! debug_set_filename (dhandle, "*globals*")) + return FALSE; + } + + switch (syment.n_sclass) + { + case C_EFCN: + case C_EXTDEF: + case C_ULABEL: + case C_USTATIC: + case C_LINE: + case C_ALIAS: + case C_HIDDEN: + /* Just ignore these classes. */ + break; + + case C_FILE: + next_c_file = syment.n_value; + if (! debug_set_filename (dhandle, name)) + return FALSE; + break; + + case C_STAT: + /* Ignore static symbols with a type of T_NULL. These + represent section entries. */ + if (syment.n_type == T_NULL) + break; + /* Fall through. */ + case C_WEAKEXT: + case C_EXT: + if (ISFCN (syment.n_type)) + { + fnname = name; + fnclass = syment.n_sclass; + fntype = syment.n_type; + if (syment.n_numaux > 0) + fnend = bfd_asymbol_value (sym) + auxent.x_sym.x_misc.x_fsize; + else + fnend = 0; + linenos = BFD_SEND (abfd, _get_lineno, (abfd, sym)); + break; + } + type = parse_coff_type (abfd, &symbols, &types, this_coff_symno, + syment.n_type, paux, TRUE, dhandle); + if (type == DEBUG_TYPE_NULL) + return FALSE; + if (! parse_coff_symbol (abfd, &types, sym, this_coff_symno, &syment, + dhandle, type, within_function)) + return FALSE; + break; + + case C_FCN: + if (strcmp (name, ".bf") == 0) + { + if (fnname == NULL) + { + non_fatal (_("%ld: .bf without preceding function"), + this_coff_symno); + return FALSE; + } + + type = parse_coff_type (abfd, &symbols, &types, this_coff_symno, + DECREF (fntype), paux, FALSE, dhandle); + if (type == DEBUG_TYPE_NULL) + return FALSE; + + if (! debug_record_function (dhandle, fnname, type, + external_coff_symbol_p (fnclass), + bfd_asymbol_value (sym))) + return FALSE; + + if (linenos != NULL) + { + int base; + bfd_vma addr; + + if (syment.n_numaux == 0) + base = 0; + else + base = auxent.x_sym.x_misc.x_lnsz.x_lnno - 1; + + addr = bfd_get_section_vma (abfd, bfd_get_section (sym)); + + ++linenos; + + while (linenos->line_number != 0) + { + if (! debug_record_line (dhandle, + linenos->line_number + base, + linenos->u.offset + addr)) + return FALSE; + ++linenos; + } + } + + fnname = NULL; + linenos = NULL; + fnclass = 0; + fntype = 0; + + within_function = TRUE; + } + else if (strcmp (name, ".ef") == 0) + { + if (! within_function) + { + non_fatal (_("%ld: unexpected .ef\n"), this_coff_symno); + return FALSE; + } + + if (bfd_asymbol_value (sym) > fnend) + fnend = bfd_asymbol_value (sym); + if (! debug_end_function (dhandle, fnend)) + return FALSE; + + fnend = 0; + within_function = FALSE; + } + break; + + case C_BLOCK: + if (strcmp (name, ".bb") == 0) + { + if (! debug_start_block (dhandle, bfd_asymbol_value (sym))) + return FALSE; + } + else if (strcmp (name, ".eb") == 0) + { + if (! debug_end_block (dhandle, bfd_asymbol_value (sym))) + return FALSE; + } + break; + + default: + type = parse_coff_type (abfd, &symbols, &types, this_coff_symno, + syment.n_type, paux, TRUE, dhandle); + if (type == DEBUG_TYPE_NULL) + return FALSE; + if (! parse_coff_symbol (abfd, &types, sym, this_coff_symno, &syment, + dhandle, type, within_function)) + return FALSE; + break; + } + } + + return TRUE; +} diff --git a/contrib/binutils-2.14/binutils/rddbg.c b/contrib/binutils-2.14/binutils/rddbg.c new file mode 100644 index 0000000000..2f6ec6e3ea --- /dev/null +++ b/contrib/binutils-2.14/binutils/rddbg.c @@ -0,0 +1,463 @@ +/* rddbg.c -- Read debugging information into a generic form. + Copyright 1995, 1996, 1997, 2000, 2002 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file reads debugging information into a generic form. This + file knows how to dig the debugging information out of an object + file. */ + +#include "bfd.h" +#include "bucomm.h" +#include "libiberty.h" +#include "debug.h" +#include "budbg.h" + +static bfd_boolean read_section_stabs_debugging_info + PARAMS ((bfd *, asymbol **, long, PTR, bfd_boolean *)); +static bfd_boolean read_symbol_stabs_debugging_info + PARAMS ((bfd *, asymbol **, long, PTR, bfd_boolean *)); +static bfd_boolean read_ieee_debugging_info + PARAMS ((bfd *, PTR, bfd_boolean *)); +static void save_stab + PARAMS ((int, int, bfd_vma, const char *)); +static void stab_context + PARAMS ((void)); +static void free_saved_stabs + PARAMS ((void)); + +/* Read debugging information from a BFD. Returns a generic debugging + pointer. */ + +PTR +read_debugging_info (abfd, syms, symcount) + bfd *abfd; + asymbol **syms; + long symcount; +{ + PTR dhandle; + bfd_boolean found; + + dhandle = debug_init (); + if (dhandle == NULL) + return NULL; + + if (! read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, + &found)) + return NULL; + + if (bfd_get_flavour (abfd) == bfd_target_aout_flavour) + { + if (! read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, + &found)) + return NULL; + } + + if (bfd_get_flavour (abfd) == bfd_target_ieee_flavour) + { + if (! read_ieee_debugging_info (abfd, dhandle, &found)) + return NULL; + } + + /* Try reading the COFF symbols if we didn't find any stabs in COFF + sections. */ + if (! found + && bfd_get_flavour (abfd) == bfd_target_coff_flavour + && symcount > 0) + { + if (! parse_coff (abfd, syms, symcount, dhandle)) + return NULL; + found = TRUE; + } + + if (! found) + { + non_fatal (_("%s: no recognized debugging information"), + bfd_get_filename (abfd)); + return NULL; + } + + return dhandle; +} + +/* Read stabs in sections debugging information from a BFD. */ + +static bfd_boolean +read_section_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound) + bfd *abfd; + asymbol **syms; + long symcount; + PTR dhandle; + bfd_boolean *pfound; +{ + static struct + { + const char *secname; + const char *strsecname; + } names[] = { { ".stab", ".stabstr" }, + { "LC_SYMTAB.stabs", "LC_SYMTAB.stabstr" } }; + unsigned int i; + PTR shandle; + + *pfound = FALSE; + shandle = NULL; + + for (i = 0; i < sizeof names / sizeof names[0]; i++) + { + asection *sec, *strsec; + + sec = bfd_get_section_by_name (abfd, names[i].secname); + strsec = bfd_get_section_by_name (abfd, names[i].strsecname); + if (sec != NULL && strsec != NULL) + { + bfd_size_type stabsize, strsize; + bfd_byte *stabs, *strings; + bfd_byte *stab; + bfd_size_type stroff, next_stroff; + + stabsize = bfd_section_size (abfd, sec); + stabs = (bfd_byte *) xmalloc (stabsize); + if (! bfd_get_section_contents (abfd, sec, stabs, 0, stabsize)) + { + fprintf (stderr, "%s: %s: %s\n", + bfd_get_filename (abfd), names[i].secname, + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + + strsize = bfd_section_size (abfd, strsec); + strings = (bfd_byte *) xmalloc (strsize); + if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize)) + { + fprintf (stderr, "%s: %s: %s\n", + bfd_get_filename (abfd), names[i].strsecname, + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + + if (shandle == NULL) + { + shandle = start_stab (dhandle, abfd, TRUE, syms, symcount); + if (shandle == NULL) + return FALSE; + } + + *pfound = TRUE; + + stroff = 0; + next_stroff = 0; + for (stab = stabs; stab < stabs + stabsize; stab += 12) + { + unsigned int strx; + int type; + int other; + int desc; + bfd_vma value; + + /* This code presumes 32 bit values. */ + + strx = bfd_get_32 (abfd, stab); + type = bfd_get_8 (abfd, stab + 4); + other = bfd_get_8 (abfd, stab + 5); + desc = bfd_get_16 (abfd, stab + 6); + value = bfd_get_32 (abfd, stab + 8); + + if (type == 0) + { + /* Special type 0 stabs indicate the offset to the + next string table. */ + stroff = next_stroff; + next_stroff += value; + } + else + { + char *f, *s; + + f = NULL; + + if (stroff + strx > strsize) + { + fprintf (stderr, "%s: %s: stab entry %ld is corrupt, strx = 0x%x, type = %d\n", + bfd_get_filename (abfd), names[i].secname, + (long) (stab - stabs) / 12, strx, type); + continue; + } + + s = (char *) strings + stroff + strx; + + while (s[strlen (s) - 1] == '\\' + && stab + 12 < stabs + stabsize) + { + char *p; + + stab += 12; + p = s + strlen (s) - 1; + *p = '\0'; + s = concat (s, + ((char *) strings + + stroff + + bfd_get_32 (abfd, stab)), + (const char *) NULL); + + /* We have to restore the backslash, because, if + the linker is hashing stabs strings, we may + see the same string more than once. */ + *p = '\\'; + + if (f != NULL) + free (f); + f = s; + } + + save_stab (type, desc, value, s); + + if (! parse_stab (dhandle, shandle, type, desc, value, s)) + { + stab_context (); + free_saved_stabs (); + return FALSE; + } + + /* Don't free f, since I think the stabs code + expects strings to hang around. This should be + straightened out. FIXME. */ + } + } + + free_saved_stabs (); + free (stabs); + + /* Don't free strings, since I think the stabs code expects + the strings to hang around. This should be straightened + out. FIXME. */ + } + } + + if (shandle != NULL) + { + if (! finish_stab (dhandle, shandle)) + return FALSE; + } + + return TRUE; +} + +/* Read stabs in the symbol table. */ + +static bfd_boolean +read_symbol_stabs_debugging_info (abfd, syms, symcount, dhandle, pfound) + bfd *abfd; + asymbol **syms; + long symcount; + PTR dhandle; + bfd_boolean *pfound; +{ + PTR shandle; + asymbol **ps, **symend; + + shandle = NULL; + symend = syms + symcount; + for (ps = syms; ps < symend; ps++) + { + symbol_info i; + + bfd_get_symbol_info (abfd, *ps, &i); + + if (i.type == '-') + { + const char *s; + char *f; + + if (shandle == NULL) + { + shandle = start_stab (dhandle, abfd, FALSE, syms, symcount); + if (shandle == NULL) + return FALSE; + } + + *pfound = TRUE; + + s = i.name; + f = NULL; + while (s[strlen (s) - 1] == '\\' + && ps + 1 < symend) + { + char *sc, *n; + + ++ps; + sc = xstrdup (s); + sc[strlen (sc) - 1] = '\0'; + n = concat (sc, bfd_asymbol_name (*ps), (const char *) NULL); + free (sc); + if (f != NULL) + free (f); + f = n; + s = n; + } + + save_stab (i.stab_type, i.stab_desc, i.value, s); + + if (! parse_stab (dhandle, shandle, i.stab_type, i.stab_desc, + i.value, s)) + { + stab_context (); + free_saved_stabs (); + return FALSE; + } + + /* Don't free f, since I think the stabs code expects + strings to hang around. This should be straightened out. + FIXME. */ + } + } + + free_saved_stabs (); + + if (shandle != NULL) + { + if (! finish_stab (dhandle, shandle)) + return FALSE; + } + + return TRUE; +} + +/* Read IEEE debugging information. */ + +static bfd_boolean +read_ieee_debugging_info (abfd, dhandle, pfound) + bfd *abfd; + PTR dhandle; + bfd_boolean *pfound; +{ + asection *dsec; + bfd_size_type size; + bfd_byte *contents; + + /* The BFD backend puts the debugging information into a section + named .debug. */ + + dsec = bfd_get_section_by_name (abfd, ".debug"); + if (dsec == NULL) + return TRUE; + + size = bfd_section_size (abfd, dsec); + contents = (bfd_byte *) xmalloc (size); + if (! bfd_get_section_contents (abfd, dsec, contents, 0, size)) + return FALSE; + + if (! parse_ieee (dhandle, abfd, contents, size)) + return FALSE; + + free (contents); + + *pfound = TRUE; + + return TRUE; +} + +/* Record stabs strings, so that we can give some context for errors. */ + +#define SAVE_STABS_COUNT (16) + +struct saved_stab +{ + int type; + int desc; + bfd_vma value; + char *string; +}; + +static struct saved_stab saved_stabs[SAVE_STABS_COUNT]; +static int saved_stabs_index; + +/* Save a stabs string. */ + +static void +save_stab (type, desc, value, string) + int type; + int desc; + bfd_vma value; + const char *string; +{ + if (saved_stabs[saved_stabs_index].string != NULL) + free (saved_stabs[saved_stabs_index].string); + saved_stabs[saved_stabs_index].type = type; + saved_stabs[saved_stabs_index].desc = desc; + saved_stabs[saved_stabs_index].value = value; + saved_stabs[saved_stabs_index].string = xstrdup (string); + saved_stabs_index = (saved_stabs_index + 1) % SAVE_STABS_COUNT; +} + +/* Provide context for an error. */ + +static void +stab_context () +{ + int i; + + fprintf (stderr, _("Last stabs entries before error:\n")); + fprintf (stderr, "n_type n_desc n_value string\n"); + + i = saved_stabs_index; + do + { + struct saved_stab *stabp; + + stabp = saved_stabs + i; + if (stabp->string != NULL) + { + const char *s; + + s = bfd_get_stab_name (stabp->type); + if (s != NULL) + fprintf (stderr, "%-6s", s); + else if (stabp->type == 0) + fprintf (stderr, "HdrSym"); + else + fprintf (stderr, "%-6d", stabp->type); + fprintf (stderr, " %-6d ", stabp->desc); + fprintf_vma (stderr, stabp->value); + if (stabp->type != 0) + fprintf (stderr, " %s", stabp->string); + fprintf (stderr, "\n"); + } + i = (i + 1) % SAVE_STABS_COUNT; + } + while (i != saved_stabs_index); +} + +/* Free the saved stab strings. */ + +static void +free_saved_stabs () +{ + int i; + + for (i = 0; i < SAVE_STABS_COUNT; i++) + { + if (saved_stabs[i].string != NULL) + { + free (saved_stabs[i].string); + saved_stabs[i].string = NULL; + } + } + + saved_stabs_index = 0; +} diff --git a/contrib/binutils-2.14/binutils/readelf.c b/contrib/binutils-2.14/binutils/readelf.c new file mode 100644 index 0000000000..c1a52db7ff --- /dev/null +++ b/contrib/binutils-2.14/binutils/readelf.c @@ -0,0 +1,10694 @@ +/* readelf.c -- display contents of an ELF format file + Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + + Originally developed by Eric Youngdale + Modifications by Nick Clifton + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +#include +#include +#include +#include +#include + +#if __GNUC__ >= 2 +/* Define BFD64 here, even if our default architecture is 32 bit ELF + as this will allow us to read in and parse 64bit and 32bit ELF files. + Only do this if we believe that the compiler can support a 64 bit + data type. For now we only rely on GCC being able to do this. */ +#define BFD64 +#endif + +#include "bfd.h" + +#include "elf/common.h" +#include "elf/external.h" +#include "elf/internal.h" +#include "elf/dwarf2.h" + +/* The following headers use the elf/reloc-macros.h file to + automatically generate relocation recognition functions + such as elf_mips_reloc_type() */ + +#define RELOC_MACROS_GEN_FUNC + +#include "elf/alpha.h" +#include "elf/arc.h" +#include "elf/arm.h" +#include "elf/avr.h" +#include "elf/cris.h" +#include "elf/d10v.h" +#include "elf/d30v.h" +#include "elf/dlx.h" +#include "elf/fr30.h" +#include "elf/frv.h" +#include "elf/h8.h" +#include "elf/hppa.h" +#include "elf/i386.h" +#include "elf/i370.h" +#include "elf/i860.h" +#include "elf/i960.h" +#include "elf/ia64.h" +#include "elf/ip2k.h" +#include "elf/m32r.h" +#include "elf/m68k.h" +#include "elf/m68hc11.h" +#include "elf/mcore.h" +#include "elf/mips.h" +#include "elf/mmix.h" +#include "elf/mn10200.h" +#include "elf/mn10300.h" +#include "elf/msp430.h" +#include "elf/or32.h" +#include "elf/pj.h" +#include "elf/ppc.h" +#include "elf/ppc64.h" +#include "elf/s390.h" +#include "elf/sh.h" +#include "elf/sparc.h" +#include "elf/v850.h" +#include "elf/vax.h" +#include "elf/x86-64.h" +#include "elf/xstormy16.h" +#include "elf/iq2000.h" +#include "elf/xtensa.h" + +#include "bucomm.h" +#include "getopt.h" +#include "libiberty.h" + +char *program_name = "readelf"; +unsigned long dynamic_addr; +bfd_size_type dynamic_size; +char *dynamic_strings; +char *string_table; +unsigned long string_table_length; +unsigned long num_dynamic_syms; +Elf_Internal_Sym *dynamic_symbols; +Elf_Internal_Syminfo *dynamic_syminfo; +unsigned long dynamic_syminfo_offset; +unsigned int dynamic_syminfo_nent; +char program_interpreter[64]; +long dynamic_info[DT_JMPREL + 1]; +long version_info[16]; +long loadaddr = 0; +Elf_Internal_Ehdr elf_header; +Elf_Internal_Shdr *section_headers; +Elf_Internal_Dyn *dynamic_segment; +Elf_Internal_Shdr *symtab_shndx_hdr; +int show_name; +int do_dynamic; +int do_syms; +int do_reloc; +int do_sections; +int do_segments; +int do_unwind; +int do_using_dynamic; +int do_header; +int do_dump; +int do_version; +int do_wide; +int do_histogram; +int do_debugging; +int do_debug_info; +int do_debug_abbrevs; +int do_debug_lines; +int do_debug_pubnames; +int do_debug_aranges; +int do_debug_frames; +int do_debug_frames_interp; +int do_debug_macinfo; +int do_debug_str; +int do_debug_loc; +int do_arch; +int do_notes; +int is_32bit_elf; + +/* A dynamic array of flags indicating which sections require dumping. */ +char *dump_sects = NULL; +unsigned int num_dump_sects = 0; + +#define HEX_DUMP (1 << 0) +#define DISASS_DUMP (1 << 1) +#define DEBUG_DUMP (1 << 2) + +/* How to rpint a vma value. */ +typedef enum print_mode +{ + HEX, + DEC, + DEC_5, + UNSIGNED, + PREFIX_HEX, + FULL_HEX, + LONG_HEX +} +print_mode; + +/* Forward declarations for dumb compilers. */ +static void print_vma + PARAMS ((bfd_vma, print_mode)); +static void print_symbol + PARAMS ((int, const char *)); +static bfd_vma (*byte_get) + PARAMS ((unsigned char *, int)); +static bfd_vma byte_get_little_endian + PARAMS ((unsigned char *, int)); +static bfd_vma byte_get_big_endian + PARAMS ((unsigned char *, int)); +static void (*byte_put) + PARAMS ((unsigned char *, bfd_vma, int)); +static void byte_put_little_endian + PARAMS ((unsigned char *, bfd_vma, int)); +static void byte_put_big_endian + PARAMS ((unsigned char *, bfd_vma, int)); +static const char *get_mips_dynamic_type + PARAMS ((unsigned long)); +static const char *get_sparc64_dynamic_type + PARAMS ((unsigned long)); +static const char *get_ppc64_dynamic_type + PARAMS ((unsigned long)); +static const char *get_parisc_dynamic_type + PARAMS ((unsigned long)); +static const char *get_ia64_dynamic_type + PARAMS ((unsigned long)); +static const char *get_dynamic_type + PARAMS ((unsigned long)); +static int slurp_rela_relocs + PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Rela **, + unsigned long *)); +static int slurp_rel_relocs + PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Rela **, + unsigned long *)); +static int dump_relocations + PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Sym *, + unsigned long, char *, int)); +static char *get_file_type + PARAMS ((unsigned)); +static char *get_machine_name + PARAMS ((unsigned)); +static void decode_ARM_machine_flags + PARAMS ((unsigned, char[])); +static char *get_machine_flags + PARAMS ((unsigned, unsigned)); +static const char *get_mips_segment_type + PARAMS ((unsigned long)); +static const char *get_parisc_segment_type + PARAMS ((unsigned long)); +static const char *get_ia64_segment_type + PARAMS ((unsigned long)); +static const char *get_segment_type + PARAMS ((unsigned long)); +static const char *get_mips_section_type_name + PARAMS ((unsigned int)); +static const char *get_parisc_section_type_name + PARAMS ((unsigned int)); +static const char *get_ia64_section_type_name + PARAMS ((unsigned int)); +static const char *get_section_type_name + PARAMS ((unsigned int)); +static const char *get_symbol_binding + PARAMS ((unsigned int)); +static const char *get_symbol_type + PARAMS ((unsigned int)); +static const char *get_symbol_visibility + PARAMS ((unsigned int)); +static const char *get_symbol_index_type + PARAMS ((unsigned int)); +static const char *get_dynamic_flags + PARAMS ((bfd_vma)); +static void usage + PARAMS ((void)); +static void parse_args + PARAMS ((int, char **)); +static int process_file_header + PARAMS ((void)); +static int process_program_headers + PARAMS ((FILE *)); +static int process_section_headers + PARAMS ((FILE *)); +static int process_unwind + PARAMS ((FILE *)); +static void dynamic_segment_mips_val + PARAMS ((Elf_Internal_Dyn *)); +static void dynamic_segment_parisc_val + PARAMS ((Elf_Internal_Dyn *)); +static void dynamic_segment_ia64_val + PARAMS ((Elf_Internal_Dyn *)); +static int process_dynamic_segment + PARAMS ((FILE *)); +static int process_symbol_table + PARAMS ((FILE *)); +static int process_syminfo + PARAMS ((FILE *)); +static int process_section_contents + PARAMS ((FILE *)); +static void process_mips_fpe_exception + PARAMS ((int)); +static int process_mips_specific + PARAMS ((FILE *)); +static int process_file + PARAMS ((char *)); +static int process_relocs + PARAMS ((FILE *)); +static int process_version_sections + PARAMS ((FILE *)); +static char *get_ver_flags + PARAMS ((unsigned int)); +static int get_32bit_section_headers + PARAMS ((FILE *, unsigned int)); +static int get_64bit_section_headers + PARAMS ((FILE *, unsigned int)); +static int get_32bit_program_headers + PARAMS ((FILE *, Elf_Internal_Phdr *)); +static int get_64bit_program_headers + PARAMS ((FILE *, Elf_Internal_Phdr *)); +static int get_file_header + PARAMS ((FILE *)); +static Elf_Internal_Sym *get_32bit_elf_symbols + PARAMS ((FILE *, Elf_Internal_Shdr *)); +static Elf_Internal_Sym *get_64bit_elf_symbols + PARAMS ((FILE *, Elf_Internal_Shdr *)); +static const char *get_elf_section_flags + PARAMS ((bfd_vma)); +static int *get_dynamic_data + PARAMS ((FILE *, unsigned int)); +static int get_32bit_dynamic_segment + PARAMS ((FILE *)); +static int get_64bit_dynamic_segment + PARAMS ((FILE *)); +#ifdef SUPPORT_DISASSEMBLY +static int disassemble_section + PARAMS ((Elf_Internal_Shdr *, FILE *)); +#endif +static int dump_section + PARAMS ((Elf_Internal_Shdr *, FILE *)); +static int display_debug_section + PARAMS ((Elf_Internal_Shdr *, FILE *)); +static int display_debug_info + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_not_supported + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int prescan_debug_info + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_lines + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_pubnames + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_abbrev + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_aranges + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_frames + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_macinfo + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_str + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static int display_debug_loc + PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +static unsigned char *process_abbrev_section + PARAMS ((unsigned char *, unsigned char *)); +static void load_debug_str + PARAMS ((FILE *)); +static void free_debug_str + PARAMS ((void)); +static const char *fetch_indirect_string + PARAMS ((unsigned long)); +static void load_debug_loc + PARAMS ((FILE *)); +static void free_debug_loc + PARAMS ((void)); +static unsigned long read_leb128 + PARAMS ((unsigned char *, int *, int)); +static int process_extended_line_op + PARAMS ((unsigned char *, int, int)); +static void reset_state_machine + PARAMS ((int)); +static char *get_TAG_name + PARAMS ((unsigned long)); +static char *get_AT_name + PARAMS ((unsigned long)); +static char *get_FORM_name + PARAMS ((unsigned long)); +static void free_abbrevs + PARAMS ((void)); +static void add_abbrev + PARAMS ((unsigned long, unsigned long, int)); +static void add_abbrev_attr + PARAMS ((unsigned long, unsigned long)); +static unsigned char *read_and_display_attr + PARAMS ((unsigned long, unsigned long, unsigned char *, unsigned long, + unsigned long, unsigned long, int)); +static unsigned char *read_and_display_attr_value + PARAMS ((unsigned long, unsigned long, unsigned char *, unsigned long, + unsigned long, unsigned long, int)); +static unsigned char *display_block + PARAMS ((unsigned char *, unsigned long)); +static void decode_location_expression + PARAMS ((unsigned char *, unsigned int, unsigned long)); +static void request_dump + PARAMS ((unsigned int, int)); +static const char *get_elf_class + PARAMS ((unsigned int)); +static const char *get_data_encoding + PARAMS ((unsigned int)); +static const char *get_osabi_name + PARAMS ((unsigned int)); +static int guess_is_rela + PARAMS ((unsigned long)); +static const char *get_note_type + PARAMS ((unsigned int)); +static const char *get_netbsd_elfcore_note_type + PARAMS ((unsigned int)); +static int process_note + PARAMS ((Elf_Internal_Note *)); +static int process_corefile_note_segment + PARAMS ((FILE *, bfd_vma, bfd_vma)); +static int process_corefile_note_segments + PARAMS ((FILE *)); +static int process_corefile_contents + PARAMS ((FILE *)); +static int process_arch_specific + PARAMS ((FILE *)); +static int process_gnu_liblist + PARAMS ((FILE *)); + +typedef int Elf32_Word; + +#define UNKNOWN -1 + +#define SECTION_NAME(X) ((X) == NULL ? "" : \ + ((X)->sh_name >= string_table_length \ + ? "" : string_table + (X)->sh_name)) + +/* Given st_shndx I, map to section_headers index. */ +#define SECTION_HEADER_INDEX(I) \ + ((I) < SHN_LORESERVE \ + ? (I) \ + : ((I) <= SHN_HIRESERVE \ + ? 0 \ + : (I) - (SHN_HIRESERVE + 1 - SHN_LORESERVE))) + +/* Reverse of the above. */ +#define SECTION_HEADER_NUM(N) \ + ((N) < SHN_LORESERVE \ + ? (N) \ + : (N) + (SHN_HIRESERVE + 1 - SHN_LORESERVE)) + +#define SECTION_HEADER(I) (section_headers + SECTION_HEADER_INDEX (I)) + +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ + +#define BYTE_GET(field) byte_get (field, sizeof (field)) + +/* If we can support a 64 bit data type then BFD64 should be defined + and sizeof (bfd_vma) == 8. In this case when translating from an + external 8 byte field to an internal field, we can assume that the + internal field is also 8 bytes wide and so we can extract all the data. + If, however, BFD64 is not defined, then we must assume that the + internal data structure only has 4 byte wide fields that are the + equivalent of the 8 byte wide external counterparts, and so we must + truncate the data. */ +#ifdef BFD64 +#define BYTE_GET8(field) byte_get (field, -8) +#else +#define BYTE_GET8(field) byte_get (field, 8) +#endif + +#define NUM_ELEM(array) (sizeof (array) / sizeof ((array)[0])) + +#define GET_ELF_SYMBOLS(file, section) \ + (is_32bit_elf ? get_32bit_elf_symbols (file, section) \ + : get_64bit_elf_symbols (file, section)) + + +static void +error VPARAMS ((const char *message, ...)) +{ + VA_OPEN (args, message); + VA_FIXEDARG (args, const char *, message); + + fprintf (stderr, _("%s: Error: "), program_name); + vfprintf (stderr, message, args); + VA_CLOSE (args); +} + +static void +warn VPARAMS ((const char *message, ...)) +{ + VA_OPEN (args, message); + VA_FIXEDARG (args, const char *, message); + + fprintf (stderr, _("%s: Warning: "), program_name); + vfprintf (stderr, message, args); + VA_CLOSE (args); +} + +static PTR get_data PARAMS ((PTR, FILE *, long, size_t, const char *)); + +static PTR +get_data (var, file, offset, size, reason) + PTR var; + FILE *file; + long offset; + size_t size; + const char *reason; +{ + PTR mvar; + + if (size == 0) + return NULL; + + if (fseek (file, offset, SEEK_SET)) + { + error (_("Unable to seek to %x for %s\n"), offset, reason); + return NULL; + } + + mvar = var; + if (mvar == NULL) + { + mvar = (PTR) malloc (size); + + if (mvar == NULL) + { + error (_("Out of memory allocating %d bytes for %s\n"), + size, reason); + return NULL; + } + } + + if (fread (mvar, size, 1, file) != 1) + { + error (_("Unable to read in %d bytes of %s\n"), size, reason); + if (mvar != var) + free (mvar); + return NULL; + } + + return mvar; +} + +static bfd_vma +byte_get_little_endian (field, size) + unsigned char *field; + int size; +{ + switch (size) + { + case 1: + return *field; + + case 2: + return ((unsigned int) (field[0])) + | (((unsigned int) (field[1])) << 8); + +#ifndef BFD64 + case 8: + /* We want to extract data from an 8 byte wide field and + place it into a 4 byte wide field. Since this is a little + endian source we can just use the 4 byte extraction code. */ + /* Fall through. */ +#endif + case 4: + return ((unsigned long) (field[0])) + | (((unsigned long) (field[1])) << 8) + | (((unsigned long) (field[2])) << 16) + | (((unsigned long) (field[3])) << 24); + +#ifdef BFD64 + case 8: + case -8: + /* This is a special case, generated by the BYTE_GET8 macro. + It means that we are loading an 8 byte value from a field + in an external structure into an 8 byte value in a field + in an internal strcuture. */ + return ((bfd_vma) (field[0])) + | (((bfd_vma) (field[1])) << 8) + | (((bfd_vma) (field[2])) << 16) + | (((bfd_vma) (field[3])) << 24) + | (((bfd_vma) (field[4])) << 32) + | (((bfd_vma) (field[5])) << 40) + | (((bfd_vma) (field[6])) << 48) + | (((bfd_vma) (field[7])) << 56); +#endif + default: + error (_("Unhandled data length: %d\n"), size); + abort (); + } +} + +static void +byte_put_little_endian (field, value, size) + unsigned char * field; + bfd_vma value; + int size; +{ + switch (size) + { + case 8: + field[7] = (((value >> 24) >> 24) >> 8) & 0xff; + field[6] = ((value >> 24) >> 24) & 0xff; + field[5] = ((value >> 24) >> 16) & 0xff; + field[4] = ((value >> 24) >> 8) & 0xff; + /* Fall through. */ + case 4: + field[3] = (value >> 24) & 0xff; + field[2] = (value >> 16) & 0xff; + /* Fall through. */ + case 2: + field[1] = (value >> 8) & 0xff; + /* Fall through. */ + case 1: + field[0] = value & 0xff; + break; + + default: + error (_("Unhandled data length: %d\n"), size); + abort (); + } +} + +/* Print a VMA value. */ +static void +print_vma (vma, mode) + bfd_vma vma; + print_mode mode; +{ +#ifdef BFD64 + if (is_32bit_elf) +#endif + { + switch (mode) + { + case FULL_HEX: printf ("0x"); /* drop through */ + case LONG_HEX: printf ("%8.8lx", (unsigned long) vma); break; + case PREFIX_HEX: printf ("0x"); /* drop through */ + case HEX: printf ("%lx", (unsigned long) vma); break; + case DEC: printf ("%ld", (unsigned long) vma); break; + case DEC_5: printf ("%5ld", (long) vma); break; + case UNSIGNED: printf ("%lu", (unsigned long) vma); break; + } + } +#ifdef BFD64 + else + { + switch (mode) + { + case FULL_HEX: + printf ("0x"); + /* drop through */ + + case LONG_HEX: + printf_vma (vma); + break; + + case PREFIX_HEX: + printf ("0x"); + /* drop through */ + + case HEX: +#if BFD_HOST_64BIT_LONG + printf ("%lx", vma); +#else + if (_bfd_int64_high (vma)) + printf ("%lx%8.8lx", _bfd_int64_high (vma), _bfd_int64_low (vma)); + else + printf ("%lx", _bfd_int64_low (vma)); +#endif + break; + + case DEC: +#if BFD_HOST_64BIT_LONG + printf ("%ld", vma); +#else + if (_bfd_int64_high (vma)) + /* ugg */ + printf ("++%ld", _bfd_int64_low (vma)); + else + printf ("%ld", _bfd_int64_low (vma)); +#endif + break; + + case DEC_5: +#if BFD_HOST_64BIT_LONG + printf ("%5ld", vma); +#else + if (_bfd_int64_high (vma)) + /* ugg */ + printf ("++%ld", _bfd_int64_low (vma)); + else + printf ("%5ld", _bfd_int64_low (vma)); +#endif + break; + + case UNSIGNED: +#if BFD_HOST_64BIT_LONG + printf ("%lu", vma); +#else + if (_bfd_int64_high (vma)) + /* ugg */ + printf ("++%lu", _bfd_int64_low (vma)); + else + printf ("%lu", _bfd_int64_low (vma)); +#endif + break; + } + } +#endif +} + +/* Display a symbol on stdout. If do_wide is not true then + format the symbol to be at most WIDTH characters, + truncating as necessary. If WIDTH is negative then + format the string to be exactly - WIDTH characters, + truncating or padding as necessary. */ + +static void +print_symbol (width, symbol) + int width; + const char *symbol; +{ + if (do_wide) + printf ("%s", symbol); + else if (width < 0) + printf ("%-*.*s", width, width, symbol); + else + printf ("%-.*s", width, symbol); +} + +static bfd_vma +byte_get_big_endian (field, size) + unsigned char *field; + int size; +{ + switch (size) + { + case 1: + return *field; + + case 2: + return ((unsigned int) (field[1])) | (((int) (field[0])) << 8); + + case 4: + return ((unsigned long) (field[3])) + | (((unsigned long) (field[2])) << 8) + | (((unsigned long) (field[1])) << 16) + | (((unsigned long) (field[0])) << 24); + +#ifndef BFD64 + case 8: + /* Although we are extracing data from an 8 byte wide field, we + are returning only 4 bytes of data. */ + return ((unsigned long) (field[7])) + | (((unsigned long) (field[6])) << 8) + | (((unsigned long) (field[5])) << 16) + | (((unsigned long) (field[4])) << 24); +#else + case 8: + case -8: + /* This is a special case, generated by the BYTE_GET8 macro. + It means that we are loading an 8 byte value from a field + in an external structure into an 8 byte value in a field + in an internal strcuture. */ + return ((bfd_vma) (field[7])) + | (((bfd_vma) (field[6])) << 8) + | (((bfd_vma) (field[5])) << 16) + | (((bfd_vma) (field[4])) << 24) + | (((bfd_vma) (field[3])) << 32) + | (((bfd_vma) (field[2])) << 40) + | (((bfd_vma) (field[1])) << 48) + | (((bfd_vma) (field[0])) << 56); +#endif + + default: + error (_("Unhandled data length: %d\n"), size); + abort (); + } +} + +static void +byte_put_big_endian (field, value, size) + unsigned char * field; + bfd_vma value; + int size; +{ + switch (size) + { + case 8: + field[7] = value & 0xff; + field[6] = (value >> 8) & 0xff; + field[5] = (value >> 16) & 0xff; + field[4] = (value >> 24) & 0xff; + value >>= 16; + value >>= 16; + /* Fall through. */ + case 4: + field[3] = value & 0xff; + field[2] = (value >> 8) & 0xff; + value >>= 16; + /* Fall through. */ + case 2: + field[1] = value & 0xff; + value >>= 8; + /* Fall through. */ + case 1: + field[0] = value & 0xff; + break; + + default: + error (_("Unhandled data length: %d\n"), size); + abort (); + } +} + +/* Guess the relocation size commonly used by the specific machines. */ + +static int +guess_is_rela (e_machine) + unsigned long e_machine; +{ + switch (e_machine) + { + /* Targets that use REL relocations. */ + case EM_ARM: + case EM_386: + case EM_486: + case EM_960: + case EM_DLX: + case EM_OPENRISC: + case EM_OR32: + case EM_M32R: + case EM_CYGNUS_M32R: + case EM_D10V: + case EM_CYGNUS_D10V: + case EM_MIPS: + case EM_MIPS_RS3_LE: + return FALSE; + + /* Targets that use RELA relocations. */ + case EM_68K: + case EM_H8_300: + case EM_H8_300H: + case EM_H8S: + case EM_SPARC32PLUS: + case EM_SPARCV9: + case EM_SPARC: + case EM_PPC: + case EM_PPC64: + case EM_V850: + case EM_CYGNUS_V850: + case EM_D30V: + case EM_CYGNUS_D30V: + case EM_MN10200: + case EM_CYGNUS_MN10200: + case EM_MN10300: + case EM_CYGNUS_MN10300: + case EM_FR30: + case EM_CYGNUS_FR30: + case EM_CYGNUS_FRV: + case EM_SH: + case EM_ALPHA: + case EM_MCORE: + case EM_IA_64: + case EM_AVR: + case EM_AVR_OLD: + case EM_CRIS: + case EM_860: + case EM_X86_64: + case EM_S390: + case EM_S390_OLD: + case EM_MMIX: + case EM_MSP430: + case EM_MSP430_OLD: + case EM_XSTORMY16: + case EM_VAX: + case EM_IP2K: + case EM_IP2K_OLD: + case EM_IQ2000: + case EM_XTENSA: + case EM_XTENSA_OLD: + return TRUE; + + case EM_MMA: + case EM_PCP: + case EM_NCPU: + case EM_NDR1: + case EM_STARCORE: + case EM_ME16: + case EM_ST100: + case EM_TINYJ: + case EM_FX66: + case EM_ST9PLUS: + case EM_ST7: + case EM_68HC16: + case EM_68HC11: + case EM_68HC08: + case EM_68HC05: + case EM_SVX: + case EM_ST19: + default: + warn (_("Don't know about relocations on this machine architecture\n")); + return FALSE; + } +} + +static int +slurp_rela_relocs (file, rel_offset, rel_size, relasp, nrelasp) + FILE *file; + unsigned long rel_offset; + unsigned long rel_size; + Elf_Internal_Rela **relasp; + unsigned long *nrelasp; +{ + Elf_Internal_Rela *relas; + unsigned long nrelas; + unsigned int i; + + if (is_32bit_elf) + { + Elf32_External_Rela *erelas; + + erelas = (Elf32_External_Rela *) get_data (NULL, file, rel_offset, + rel_size, _("relocs")); + if (!erelas) + return 0; + + nrelas = rel_size / sizeof (Elf32_External_Rela); + + relas = (Elf_Internal_Rela *) + malloc (nrelas * sizeof (Elf_Internal_Rela)); + + if (relas == NULL) + { + error(_("out of memory parsing relocs")); + return 0; + } + + for (i = 0; i < nrelas; i++) + { + relas[i].r_offset = BYTE_GET (erelas[i].r_offset); + relas[i].r_info = BYTE_GET (erelas[i].r_info); + relas[i].r_addend = BYTE_GET (erelas[i].r_addend); + } + + free (erelas); + } + else + { + Elf64_External_Rela *erelas; + + erelas = (Elf64_External_Rela *) get_data (NULL, file, rel_offset, + rel_size, _("relocs")); + if (!erelas) + return 0; + + nrelas = rel_size / sizeof (Elf64_External_Rela); + + relas = (Elf_Internal_Rela *) + malloc (nrelas * sizeof (Elf_Internal_Rela)); + + if (relas == NULL) + { + error(_("out of memory parsing relocs")); + return 0; + } + + for (i = 0; i < nrelas; i++) + { + relas[i].r_offset = BYTE_GET8 (erelas[i].r_offset); + relas[i].r_info = BYTE_GET8 (erelas[i].r_info); + relas[i].r_addend = BYTE_GET8 (erelas[i].r_addend); + } + + free (erelas); + } + *relasp = relas; + *nrelasp = nrelas; + return 1; +} + +static int +slurp_rel_relocs (file, rel_offset, rel_size, relsp, nrelsp) + FILE *file; + unsigned long rel_offset; + unsigned long rel_size; + Elf_Internal_Rela **relsp; + unsigned long *nrelsp; +{ + Elf_Internal_Rela *rels; + unsigned long nrels; + unsigned int i; + + if (is_32bit_elf) + { + Elf32_External_Rel *erels; + + erels = (Elf32_External_Rel *) get_data (NULL, file, rel_offset, + rel_size, _("relocs")); + if (!erels) + return 0; + + nrels = rel_size / sizeof (Elf32_External_Rel); + + rels = (Elf_Internal_Rela *) malloc (nrels * sizeof (Elf_Internal_Rela)); + + if (rels == NULL) + { + error(_("out of memory parsing relocs")); + return 0; + } + + for (i = 0; i < nrels; i++) + { + rels[i].r_offset = BYTE_GET (erels[i].r_offset); + rels[i].r_info = BYTE_GET (erels[i].r_info); + rels[i].r_addend = 0; + } + + free (erels); + } + else + { + Elf64_External_Rel *erels; + + erels = (Elf64_External_Rel *) get_data (NULL, file, rel_offset, + rel_size, _("relocs")); + if (!erels) + return 0; + + nrels = rel_size / sizeof (Elf64_External_Rel); + + rels = (Elf_Internal_Rela *) malloc (nrels * sizeof (Elf_Internal_Rela)); + + if (rels == NULL) + { + error(_("out of memory parsing relocs")); + return 0; + } + + for (i = 0; i < nrels; i++) + { + rels[i].r_offset = BYTE_GET8 (erels[i].r_offset); + rels[i].r_info = BYTE_GET8 (erels[i].r_info); + rels[i].r_addend = 0; + } + + free (erels); + } + *relsp = rels; + *nrelsp = nrels; + return 1; +} + +/* Display the contents of the relocation data found at the specified offset. */ + +static int +dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) + FILE *file; + unsigned long rel_offset; + unsigned long rel_size; + Elf_Internal_Sym *symtab; + unsigned long nsyms; + char *strtab; + int is_rela; +{ + unsigned int i; + Elf_Internal_Rela *rels; + + + if (is_rela == UNKNOWN) + is_rela = guess_is_rela (elf_header.e_machine); + + if (is_rela) + { + if (!slurp_rela_relocs (file, rel_offset, rel_size, &rels, &rel_size)) + return 0; + } + else + { + if (!slurp_rel_relocs (file, rel_offset, rel_size, &rels, &rel_size)) + return 0; + } + + if (is_32bit_elf) + { + if (is_rela) + { + if (do_wide) + printf (_(" Offset Info Type Sym. Value Symbol's Name + Addend\n")); + else + printf (_(" Offset Info Type Sym.Value Sym. Name + Addend\n")); + } + else + { + if (do_wide) + printf (_(" Offset Info Type Sym. Value Symbol's Name\n")); + else + printf (_(" Offset Info Type Sym.Value Sym. Name\n")); + } + } + else + { + if (is_rela) + { + if (do_wide) + printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n")); + else + printf (_(" Offset Info Type Sym. Value Sym. Name + Addend\n")); + } + else + { + if (do_wide) + printf (_(" Offset Info Type Symbol's Value Symbol's Name\n")); + else + printf (_(" Offset Info Type Sym. Value Sym. Name\n")); + } + } + + for (i = 0; i < rel_size; i++) + { + const char *rtype; + const char *rtype2 = NULL; + const char *rtype3 = NULL; + bfd_vma offset; + bfd_vma info; + bfd_vma symtab_index; + bfd_vma type; + bfd_vma type2 = (bfd_vma) NULL; + bfd_vma type3 = (bfd_vma) NULL; + + offset = rels[i].r_offset; + info = rels[i].r_info; + + if (is_32bit_elf) + { + type = ELF32_R_TYPE (info); + symtab_index = ELF32_R_SYM (info); + } + else + { + /* The #ifdef BFD64 below is to prevent a compile time warning. + We know that if we do not have a 64 bit data type that we + will never execute this code anyway. */ +#ifdef BFD64 + if (elf_header.e_machine == EM_MIPS) + { + /* In little-endian objects, r_info isn't really a 64-bit + little-endian value: it has a 32-bit little-endian + symbol index followed by four individual byte fields. + Reorder INFO accordingly. */ + if (elf_header.e_ident[EI_DATA] != ELFDATA2MSB) + info = (((info & 0xffffffff) << 32) + | ((info >> 56) & 0xff) + | ((info >> 40) & 0xff00) + | ((info >> 24) & 0xff0000) + | ((info >> 8) & 0xff000000)); + type = ELF64_MIPS_R_TYPE (info); + type2 = ELF64_MIPS_R_TYPE2 (info); + type3 = ELF64_MIPS_R_TYPE3 (info); + } + else if (elf_header.e_machine == EM_SPARCV9) + type = ELF64_R_TYPE_ID (info); + else + type = ELF64_R_TYPE (info); + + symtab_index = ELF64_R_SYM (info); +#endif + } + + if (is_32bit_elf) + { +#ifdef _bfd_int64_low + printf ("%8.8lx %8.8lx ", _bfd_int64_low (offset), _bfd_int64_low (info)); +#else + printf ("%8.8lx %8.8lx ", offset, info); +#endif + } + else + { +#ifdef _bfd_int64_low + printf (do_wide + ? "%8.8lx%8.8lx %8.8lx%8.8lx " + : "%4.4lx%8.8lx %4.4lx%8.8lx ", + _bfd_int64_high (offset), + _bfd_int64_low (offset), + _bfd_int64_high (info), + _bfd_int64_low (info)); +#else + printf (do_wide + ? "%16.16lx %16.16lx " + : "%12.12lx %12.12lx ", + offset, info); +#endif + } + + switch (elf_header.e_machine) + { + default: + rtype = NULL; + break; + + case EM_M32R: + case EM_CYGNUS_M32R: + rtype = elf_m32r_reloc_type (type); + break; + + case EM_386: + case EM_486: + rtype = elf_i386_reloc_type (type); + break; + + case EM_68HC11: + case EM_68HC12: + rtype = elf_m68hc11_reloc_type (type); + break; + + case EM_68K: + rtype = elf_m68k_reloc_type (type); + break; + + case EM_960: + rtype = elf_i960_reloc_type (type); + break; + + case EM_AVR: + case EM_AVR_OLD: + rtype = elf_avr_reloc_type (type); + break; + + case EM_OLD_SPARCV9: + case EM_SPARC32PLUS: + case EM_SPARCV9: + case EM_SPARC: + rtype = elf_sparc_reloc_type (type); + break; + + case EM_V850: + case EM_CYGNUS_V850: + rtype = v850_reloc_type (type); + break; + + case EM_D10V: + case EM_CYGNUS_D10V: + rtype = elf_d10v_reloc_type (type); + break; + + case EM_D30V: + case EM_CYGNUS_D30V: + rtype = elf_d30v_reloc_type (type); + break; + + case EM_DLX: + rtype = elf_dlx_reloc_type (type); + break; + + case EM_SH: + rtype = elf_sh_reloc_type (type); + break; + + case EM_MN10300: + case EM_CYGNUS_MN10300: + rtype = elf_mn10300_reloc_type (type); + break; + + case EM_MN10200: + case EM_CYGNUS_MN10200: + rtype = elf_mn10200_reloc_type (type); + break; + + case EM_FR30: + case EM_CYGNUS_FR30: + rtype = elf_fr30_reloc_type (type); + break; + + case EM_CYGNUS_FRV: + rtype = elf_frv_reloc_type (type); + break; + + case EM_MCORE: + rtype = elf_mcore_reloc_type (type); + break; + + case EM_MMIX: + rtype = elf_mmix_reloc_type (type); + break; + + case EM_MSP430: + case EM_MSP430_OLD: + rtype = elf_msp430_reloc_type (type); + break; + + case EM_PPC: + rtype = elf_ppc_reloc_type (type); + break; + + case EM_PPC64: + rtype = elf_ppc64_reloc_type (type); + break; + + case EM_MIPS: + case EM_MIPS_RS3_LE: + rtype = elf_mips_reloc_type (type); + if (!is_32bit_elf) + { + rtype2 = elf_mips_reloc_type (type2); + rtype3 = elf_mips_reloc_type (type3); + } + break; + + case EM_ALPHA: + rtype = elf_alpha_reloc_type (type); + break; + + case EM_ARM: + rtype = elf_arm_reloc_type (type); + break; + + case EM_ARC: + rtype = elf_arc_reloc_type (type); + break; + + case EM_PARISC: + rtype = elf_hppa_reloc_type (type); + break; + + case EM_H8_300: + case EM_H8_300H: + case EM_H8S: + rtype = elf_h8_reloc_type (type); + break; + + case EM_OPENRISC: + case EM_OR32: + rtype = elf_or32_reloc_type (type); + break; + + case EM_PJ: + case EM_PJ_OLD: + rtype = elf_pj_reloc_type (type); + break; + case EM_IA_64: + rtype = elf_ia64_reloc_type (type); + break; + + case EM_CRIS: + rtype = elf_cris_reloc_type (type); + break; + + case EM_860: + rtype = elf_i860_reloc_type (type); + break; + + case EM_X86_64: + rtype = elf_x86_64_reloc_type (type); + break; + + case EM_S370: + rtype = i370_reloc_type (type); + break; + + case EM_S390_OLD: + case EM_S390: + rtype = elf_s390_reloc_type (type); + break; + + case EM_XSTORMY16: + rtype = elf_xstormy16_reloc_type (type); + break; + + case EM_VAX: + rtype = elf_vax_reloc_type (type); + break; + + case EM_IP2K: + case EM_IP2K_OLD: + rtype = elf_ip2k_reloc_type (type); + break; + + case EM_IQ2000: + rtype = elf_iq2000_reloc_type (type); + break; + + case EM_XTENSA_OLD: + case EM_XTENSA: + rtype = elf_xtensa_reloc_type (type); + break; + } + + if (rtype == NULL) +#ifdef _bfd_int64_low + printf (_("unrecognized: %-7lx"), _bfd_int64_low (type)); +#else + printf (_("unrecognized: %-7lx"), type); +#endif + else + printf (do_wide ? "%-22.22s" : "%-17.17s", rtype); + + if (symtab_index) + { + if (symtab == NULL || symtab_index >= nsyms) + printf (" bad symbol index: %08lx", (unsigned long) symtab_index); + else + { + Elf_Internal_Sym *psym; + + psym = symtab + symtab_index; + + printf (" "); + print_vma (psym->st_value, LONG_HEX); + printf (is_32bit_elf ? " " : " "); + + if (psym->st_name == 0) + { + const char *sec_name = ""; + char name_buf[40]; + + if (ELF_ST_TYPE (psym->st_info) == STT_SECTION) + { + bfd_vma sec_index = (bfd_vma) -1; + + if (psym->st_shndx < SHN_LORESERVE) + sec_index = psym->st_shndx; + else if (psym->st_shndx > SHN_LORESERVE) + sec_index = psym->st_shndx - (SHN_HIRESERVE + 1 + - SHN_LORESERVE); + + if (sec_index != (bfd_vma) -1) + sec_name = SECTION_NAME (section_headers + sec_index); + else if (psym->st_shndx == SHN_ABS) + sec_name = "ABS"; + else if (psym->st_shndx == SHN_COMMON) + sec_name = "COMMON"; + else + { + sprintf (name_buf, "
", + (unsigned int) psym->st_shndx); + sec_name = name_buf; + } + } + print_symbol (22, sec_name); + } + else if (strtab == NULL) + printf (_(""), psym->st_name); + else + print_symbol (22, strtab + psym->st_name); + + if (is_rela) + printf (" + %lx", (unsigned long) rels[i].r_addend); + } + } + else if (is_rela) + { + printf ("%*c", is_32bit_elf ? (do_wide ? 34 : 28) : (do_wide ? 26 : 20), ' '); + print_vma (rels[i].r_addend, LONG_HEX); + } + + if (elf_header.e_machine == EM_SPARCV9 + && !strcmp (rtype, "R_SPARC_OLO10")) + printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info)); + + putchar ('\n'); + + if (! is_32bit_elf && elf_header.e_machine == EM_MIPS) + { + printf (" Type2: "); + + if (rtype2 == NULL) +#ifdef _bfd_int64_low + printf (_("unrecognized: %-7lx"), _bfd_int64_low (type2)); +#else + printf (_("unrecognized: %-7lx"), type2); +#endif + else + printf ("%-17.17s", rtype2); + + printf("\n Type3: "); + + if (rtype3 == NULL) +#ifdef _bfd_int64_low + printf (_("unrecognized: %-7lx"), _bfd_int64_low (type3)); +#else + printf (_("unrecognized: %-7lx"), type3); +#endif + else + printf ("%-17.17s", rtype3); + + putchar ('\n'); + } + } + + free (rels); + + return 1; +} + +static const char * +get_mips_dynamic_type (type) + unsigned long type; +{ + switch (type) + { + case DT_MIPS_RLD_VERSION: return "MIPS_RLD_VERSION"; + case DT_MIPS_TIME_STAMP: return "MIPS_TIME_STAMP"; + case DT_MIPS_ICHECKSUM: return "MIPS_ICHECKSUM"; + case DT_MIPS_IVERSION: return "MIPS_IVERSION"; + case DT_MIPS_FLAGS: return "MIPS_FLAGS"; + case DT_MIPS_BASE_ADDRESS: return "MIPS_BASE_ADDRESS"; + case DT_MIPS_MSYM: return "MIPS_MSYM"; + case DT_MIPS_CONFLICT: return "MIPS_CONFLICT"; + case DT_MIPS_LIBLIST: return "MIPS_LIBLIST"; + case DT_MIPS_LOCAL_GOTNO: return "MIPS_LOCAL_GOTNO"; + case DT_MIPS_CONFLICTNO: return "MIPS_CONFLICTNO"; + case DT_MIPS_LIBLISTNO: return "MIPS_LIBLISTNO"; + case DT_MIPS_SYMTABNO: return "MIPS_SYMTABNO"; + case DT_MIPS_UNREFEXTNO: return "MIPS_UNREFEXTNO"; + case DT_MIPS_GOTSYM: return "MIPS_GOTSYM"; + case DT_MIPS_HIPAGENO: return "MIPS_HIPAGENO"; + case DT_MIPS_RLD_MAP: return "MIPS_RLD_MAP"; + case DT_MIPS_DELTA_CLASS: return "MIPS_DELTA_CLASS"; + case DT_MIPS_DELTA_CLASS_NO: return "MIPS_DELTA_CLASS_NO"; + case DT_MIPS_DELTA_INSTANCE: return "MIPS_DELTA_INSTANCE"; + case DT_MIPS_DELTA_INSTANCE_NO: return "MIPS_DELTA_INSTANCE_NO"; + case DT_MIPS_DELTA_RELOC: return "MIPS_DELTA_RELOC"; + case DT_MIPS_DELTA_RELOC_NO: return "MIPS_DELTA_RELOC_NO"; + case DT_MIPS_DELTA_SYM: return "MIPS_DELTA_SYM"; + case DT_MIPS_DELTA_SYM_NO: return "MIPS_DELTA_SYM_NO"; + case DT_MIPS_DELTA_CLASSSYM: return "MIPS_DELTA_CLASSSYM"; + case DT_MIPS_DELTA_CLASSSYM_NO: return "MIPS_DELTA_CLASSSYM_NO"; + case DT_MIPS_CXX_FLAGS: return "MIPS_CXX_FLAGS"; + case DT_MIPS_PIXIE_INIT: return "MIPS_PIXIE_INIT"; + case DT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB"; + case DT_MIPS_LOCALPAGE_GOTIDX: return "MIPS_LOCALPAGE_GOTIDX"; + case DT_MIPS_LOCAL_GOTIDX: return "MIPS_LOCAL_GOTIDX"; + case DT_MIPS_HIDDEN_GOTIDX: return "MIPS_HIDDEN_GOTIDX"; + case DT_MIPS_PROTECTED_GOTIDX: return "MIPS_PROTECTED_GOTIDX"; + case DT_MIPS_OPTIONS: return "MIPS_OPTIONS"; + case DT_MIPS_INTERFACE: return "MIPS_INTERFACE"; + case DT_MIPS_DYNSTR_ALIGN: return "MIPS_DYNSTR_ALIGN"; + case DT_MIPS_INTERFACE_SIZE: return "MIPS_INTERFACE_SIZE"; + case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: return "MIPS_RLD_TEXT_RESOLVE_ADDR"; + case DT_MIPS_PERF_SUFFIX: return "MIPS_PERF_SUFFIX"; + case DT_MIPS_COMPACT_SIZE: return "MIPS_COMPACT_SIZE"; + case DT_MIPS_GP_VALUE: return "MIPS_GP_VALUE"; + case DT_MIPS_AUX_DYNAMIC: return "MIPS_AUX_DYNAMIC"; + default: + return NULL; + } +} + +static const char * +get_sparc64_dynamic_type (type) + unsigned long type; +{ + switch (type) + { + case DT_SPARC_REGISTER: return "SPARC_REGISTER"; + default: + return NULL; + } +} + +static const char * +get_ppc64_dynamic_type (type) + unsigned long type; +{ + switch (type) + { + case DT_PPC64_GLINK: return "PPC64_GLINK"; + case DT_PPC64_OPD: return "PPC64_OPD"; + case DT_PPC64_OPDSZ: return "PPC64_OPDSZ"; + default: + return NULL; + } +} + +static const char * +get_parisc_dynamic_type (type) + unsigned long type; +{ + switch (type) + { + case DT_HP_LOAD_MAP: return "HP_LOAD_MAP"; + case DT_HP_DLD_FLAGS: return "HP_DLD_FLAGS"; + case DT_HP_DLD_HOOK: return "HP_DLD_HOOK"; + case DT_HP_UX10_INIT: return "HP_UX10_INIT"; + case DT_HP_UX10_INITSZ: return "HP_UX10_INITSZ"; + case DT_HP_PREINIT: return "HP_PREINIT"; + case DT_HP_PREINITSZ: return "HP_PREINITSZ"; + case DT_HP_NEEDED: return "HP_NEEDED"; + case DT_HP_TIME_STAMP: return "HP_TIME_STAMP"; + case DT_HP_CHECKSUM: return "HP_CHECKSUM"; + case DT_HP_GST_SIZE: return "HP_GST_SIZE"; + case DT_HP_GST_VERSION: return "HP_GST_VERSION"; + case DT_HP_GST_HASHVAL: return "HP_GST_HASHVAL"; + default: + return NULL; + } +} + +static const char * +get_ia64_dynamic_type (type) + unsigned long type; +{ + switch (type) + { + case DT_IA_64_PLT_RESERVE: return "IA_64_PLT_RESERVE"; + default: + return NULL; + } +} + +static const char * +get_dynamic_type (type) + unsigned long type; +{ + static char buff[32]; + + switch (type) + { + case DT_NULL: return "NULL"; + case DT_NEEDED: return "NEEDED"; + case DT_PLTRELSZ: return "PLTRELSZ"; + case DT_PLTGOT: return "PLTGOT"; + case DT_HASH: return "HASH"; + case DT_STRTAB: return "STRTAB"; + case DT_SYMTAB: return "SYMTAB"; + case DT_RELA: return "RELA"; + case DT_RELASZ: return "RELASZ"; + case DT_RELAENT: return "RELAENT"; + case DT_STRSZ: return "STRSZ"; + case DT_SYMENT: return "SYMENT"; + case DT_INIT: return "INIT"; + case DT_FINI: return "FINI"; + case DT_SONAME: return "SONAME"; + case DT_RPATH: return "RPATH"; + case DT_SYMBOLIC: return "SYMBOLIC"; + case DT_REL: return "REL"; + case DT_RELSZ: return "RELSZ"; + case DT_RELENT: return "RELENT"; + case DT_PLTREL: return "PLTREL"; + case DT_DEBUG: return "DEBUG"; + case DT_TEXTREL: return "TEXTREL"; + case DT_JMPREL: return "JMPREL"; + case DT_BIND_NOW: return "BIND_NOW"; + case DT_INIT_ARRAY: return "INIT_ARRAY"; + case DT_FINI_ARRAY: return "FINI_ARRAY"; + case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ"; + case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ"; + case DT_RUNPATH: return "RUNPATH"; + case DT_FLAGS: return "FLAGS"; + + case DT_PREINIT_ARRAY: return "PREINIT_ARRAY"; + case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ"; + + case DT_CHECKSUM: return "CHECKSUM"; + case DT_PLTPADSZ: return "PLTPADSZ"; + case DT_MOVEENT: return "MOVEENT"; + case DT_MOVESZ: return "MOVESZ"; + case DT_FEATURE: return "FEATURE"; + case DT_POSFLAG_1: return "POSFLAG_1"; + case DT_SYMINSZ: return "SYMINSZ"; + case DT_SYMINENT: return "SYMINENT"; /* aka VALRNGHI */ + + case DT_ADDRRNGLO: return "ADDRRNGLO"; + case DT_CONFIG: return "CONFIG"; + case DT_DEPAUDIT: return "DEPAUDIT"; + case DT_AUDIT: return "AUDIT"; + case DT_PLTPAD: return "PLTPAD"; + case DT_MOVETAB: return "MOVETAB"; + case DT_SYMINFO: return "SYMINFO"; /* aka ADDRRNGHI */ + + case DT_VERSYM: return "VERSYM"; + + case DT_RELACOUNT: return "RELACOUNT"; + case DT_RELCOUNT: return "RELCOUNT"; + case DT_FLAGS_1: return "FLAGS_1"; + case DT_VERDEF: return "VERDEF"; + case DT_VERDEFNUM: return "VERDEFNUM"; + case DT_VERNEED: return "VERNEED"; + case DT_VERNEEDNUM: return "VERNEEDNUM"; + + case DT_AUXILIARY: return "AUXILIARY"; + case DT_USED: return "USED"; + case DT_FILTER: return "FILTER"; + + case DT_GNU_PRELINKED: return "GNU_PRELINKED"; + case DT_GNU_CONFLICT: return "GNU_CONFLICT"; + case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ"; + case DT_GNU_LIBLIST: return "GNU_LIBLIST"; + case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ"; + + default: + if ((type >= DT_LOPROC) && (type <= DT_HIPROC)) + { + const char *result; + + switch (elf_header.e_machine) + { + case EM_MIPS: + case EM_MIPS_RS3_LE: + result = get_mips_dynamic_type (type); + break; + case EM_SPARCV9: + result = get_sparc64_dynamic_type (type); + break; + case EM_PPC64: + result = get_ppc64_dynamic_type (type); + break; + case EM_IA_64: + result = get_ia64_dynamic_type (type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + sprintf (buff, _("Processor Specific: %lx"), type); + } + else if ((type >= DT_LOOS) && (type <= DT_HIOS)) + { + const char *result; + + switch (elf_header.e_machine) + { + case EM_PARISC: + result = get_parisc_dynamic_type (type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + sprintf (buff, _("Operating System specific: %lx"), type); + } + else + sprintf (buff, _(": %lx"), type); + + return buff; + } +} + +static char * +get_file_type (e_type) + unsigned e_type; +{ + static char buff[32]; + + switch (e_type) + { + case ET_NONE: return _("NONE (None)"); + case ET_REL: return _("REL (Relocatable file)"); + case ET_EXEC: return _("EXEC (Executable file)"); + case ET_DYN: return _("DYN (Shared object file)"); + case ET_CORE: return _("CORE (Core file)"); + + default: + if ((e_type >= ET_LOPROC) && (e_type <= ET_HIPROC)) + sprintf (buff, _("Processor Specific: (%x)"), e_type); + else if ((e_type >= ET_LOOS) && (e_type <= ET_HIOS)) + sprintf (buff, _("OS Specific: (%x)"), e_type); + else + sprintf (buff, _(": %x"), e_type); + return buff; + } +} + +static char * +get_machine_name (e_machine) + unsigned e_machine; +{ + static char buff[64]; /* XXX */ + + switch (e_machine) + { + case EM_NONE: return _("None"); + case EM_M32: return "WE32100"; + case EM_SPARC: return "Sparc"; + case EM_386: return "Intel 80386"; + case EM_68K: return "MC68000"; + case EM_88K: return "MC88000"; + case EM_486: return "Intel 80486"; + case EM_860: return "Intel 80860"; + case EM_MIPS: return "MIPS R3000"; + case EM_S370: return "IBM System/370"; + case EM_MIPS_RS3_LE: return "MIPS R4000 big-endian"; + case EM_OLD_SPARCV9: return "Sparc v9 (old)"; + case EM_PARISC: return "HPPA"; + case EM_PPC_OLD: return "Power PC (old)"; + case EM_SPARC32PLUS: return "Sparc v8+" ; + case EM_960: return "Intel 90860"; + case EM_PPC: return "PowerPC"; + case EM_PPC64: return "PowerPC64"; + case EM_V800: return "NEC V800"; + case EM_FR20: return "Fujitsu FR20"; + case EM_RH32: return "TRW RH32"; + case EM_MCORE: return "MCORE"; + case EM_ARM: return "ARM"; + case EM_OLD_ALPHA: return "Digital Alpha (old)"; + case EM_SH: return "Renesas / SuperH SH"; + case EM_SPARCV9: return "Sparc v9"; + case EM_TRICORE: return "Siemens Tricore"; + case EM_ARC: return "ARC"; + case EM_H8_300: return "Renesas H8/300"; + case EM_H8_300H: return "Renesas H8/300H"; + case EM_H8S: return "Renesas H8S"; + case EM_H8_500: return "Renesas H8/500"; + case EM_IA_64: return "Intel IA-64"; + case EM_MIPS_X: return "Stanford MIPS-X"; + case EM_COLDFIRE: return "Motorola Coldfire"; + case EM_68HC12: return "Motorola M68HC12"; + case EM_ALPHA: return "Alpha"; + case EM_CYGNUS_D10V: + case EM_D10V: return "d10v"; + case EM_CYGNUS_D30V: + case EM_D30V: return "d30v"; + case EM_CYGNUS_M32R: + case EM_M32R: return "Renesas M32R (formerly Mitsubishi M32r)"; + case EM_CYGNUS_V850: + case EM_V850: return "NEC v850"; + case EM_CYGNUS_MN10300: + case EM_MN10300: return "mn10300"; + case EM_CYGNUS_MN10200: + case EM_MN10200: return "mn10200"; + case EM_CYGNUS_FR30: + case EM_FR30: return "Fujitsu FR30"; + case EM_CYGNUS_FRV: return "Fujitsu FR-V"; + case EM_PJ_OLD: + case EM_PJ: return "picoJava"; + case EM_MMA: return "Fujitsu Multimedia Accelerator"; + case EM_PCP: return "Siemens PCP"; + case EM_NCPU: return "Sony nCPU embedded RISC processor"; + case EM_NDR1: return "Denso NDR1 microprocesspr"; + case EM_STARCORE: return "Motorola Star*Core processor"; + case EM_ME16: return "Toyota ME16 processor"; + case EM_ST100: return "STMicroelectronics ST100 processor"; + case EM_TINYJ: return "Advanced Logic Corp. TinyJ embedded processor"; + case EM_FX66: return "Siemens FX66 microcontroller"; + case EM_ST9PLUS: return "STMicroelectronics ST9+ 8/16 bit microcontroller"; + case EM_ST7: return "STMicroelectronics ST7 8-bit microcontroller"; + case EM_68HC16: return "Motorola MC68HC16 Microcontroller"; + case EM_68HC11: return "Motorola MC68HC11 Microcontroller"; + case EM_68HC08: return "Motorola MC68HC08 Microcontroller"; + case EM_68HC05: return "Motorola MC68HC05 Microcontroller"; + case EM_SVX: return "Silicon Graphics SVx"; + case EM_ST19: return "STMicroelectronics ST19 8-bit microcontroller"; + case EM_VAX: return "Digital VAX"; + case EM_AVR_OLD: + case EM_AVR: return "Atmel AVR 8-bit microcontroller"; + case EM_CRIS: return "Axis Communications 32-bit embedded processor"; + case EM_JAVELIN: return "Infineon Technologies 32-bit embedded cpu"; + case EM_FIREPATH: return "Element 14 64-bit DSP processor"; + case EM_ZSP: return "LSI Logic's 16-bit DSP processor"; + case EM_MMIX: return "Donald Knuth's educational 64-bit processor"; + case EM_HUANY: return "Harvard Universitys's machine-independent object format"; + case EM_PRISM: return "Vitesse Prism"; + case EM_X86_64: return "Advanced Micro Devices X86-64"; + case EM_S390_OLD: + case EM_S390: return "IBM S/390"; + case EM_XSTORMY16: return "Sanyo Xstormy16 CPU core"; + case EM_OPENRISC: + case EM_OR32: return "OpenRISC"; + case EM_DLX: return "OpenDLX"; + case EM_IP2K_OLD: + case EM_IP2K: return "Ubicom IP2xxx 8-bit microcontrollers"; + case EM_IQ2000: return "Vitesse IQ2000"; + case EM_XTENSA_OLD: + case EM_XTENSA: return "Tensilica Xtensa Processor"; + default: + sprintf (buff, _(": %x"), e_machine); + return buff; + } +} + +static void +decode_ARM_machine_flags (e_flags, buf) + unsigned e_flags; + char buf[]; +{ + unsigned eabi; + int unknown = 0; + + eabi = EF_ARM_EABI_VERSION (e_flags); + e_flags &= ~ EF_ARM_EABIMASK; + + /* Handle "generic" ARM flags. */ + if (e_flags & EF_ARM_RELEXEC) + { + strcat (buf, ", relocatable executable"); + e_flags &= ~ EF_ARM_RELEXEC; + } + + if (e_flags & EF_ARM_HASENTRY) + { + strcat (buf, ", has entry point"); + e_flags &= ~ EF_ARM_HASENTRY; + } + + /* Now handle EABI specific flags. */ + switch (eabi) + { + default: + strcat (buf, ", "); + if (e_flags) + unknown = 1; + break; + + case EF_ARM_EABI_VER1: + strcat (buf, ", Version1 EABI"); + while (e_flags) + { + unsigned flag; + + /* Process flags one bit at a time. */ + flag = e_flags & - e_flags; + e_flags &= ~ flag; + + switch (flag) + { + case EF_ARM_SYMSARESORTED: /* Conflicts with EF_ARM_INTERWORK. */ + strcat (buf, ", sorted symbol tables"); + break; + + default: + unknown = 1; + break; + } + } + break; + + case EF_ARM_EABI_VER2: + strcat (buf, ", Version2 EABI"); + while (e_flags) + { + unsigned flag; + + /* Process flags one bit at a time. */ + flag = e_flags & - e_flags; + e_flags &= ~ flag; + + switch (flag) + { + case EF_ARM_SYMSARESORTED: /* Conflicts with EF_ARM_INTERWORK. */ + strcat (buf, ", sorted symbol tables"); + break; + + case EF_ARM_DYNSYMSUSESEGIDX: + strcat (buf, ", dynamic symbols use segment index"); + break; + + case EF_ARM_MAPSYMSFIRST: + strcat (buf, ", mapping symbols precede others"); + break; + + default: + unknown = 1; + break; + } + } + break; + + case EF_ARM_EABI_UNKNOWN: + strcat (buf, ", GNU EABI"); + while (e_flags) + { + unsigned flag; + + /* Process flags one bit at a time. */ + flag = e_flags & - e_flags; + e_flags &= ~ flag; + + switch (flag) + { + case EF_ARM_INTERWORK: + strcat (buf, ", interworking enabled"); + break; + + case EF_ARM_APCS_26: + strcat (buf, ", uses APCS/26"); + break; + + case EF_ARM_APCS_FLOAT: + strcat (buf, ", uses APCS/float"); + break; + + case EF_ARM_PIC: + strcat (buf, ", position independent"); + break; + + case EF_ARM_ALIGN8: + strcat (buf, ", 8 bit structure alignment"); + break; + + case EF_ARM_NEW_ABI: + strcat (buf, ", uses new ABI"); + break; + + case EF_ARM_OLD_ABI: + strcat (buf, ", uses old ABI"); + break; + + case EF_ARM_SOFT_FLOAT: + strcat (buf, ", software FP"); + break; + + case EF_ARM_MAVERICK_FLOAT: + strcat (buf, ", Maverick FP"); + break; + + default: + unknown = 1; + break; + } + } + } + + if (unknown) + strcat (buf,", "); +} + +static char * +get_machine_flags (e_flags, e_machine) + unsigned e_flags; + unsigned e_machine; +{ + static char buf[1024]; + + buf[0] = '\0'; + + if (e_flags) + { + switch (e_machine) + { + default: + break; + + case EM_ARM: + decode_ARM_machine_flags (e_flags, buf); + break; + + case EM_68K: + if (e_flags & EF_CPU32) + strcat (buf, ", cpu32"); + if (e_flags & EF_M68000) + strcat (buf, ", m68000"); + break; + + case EM_PPC: + if (e_flags & EF_PPC_EMB) + strcat (buf, ", emb"); + + if (e_flags & EF_PPC_RELOCATABLE) + strcat (buf, ", relocatable"); + + if (e_flags & EF_PPC_RELOCATABLE_LIB) + strcat (buf, ", relocatable-lib"); + break; + + case EM_V850: + case EM_CYGNUS_V850: + switch (e_flags & EF_V850_ARCH) + { + case E_V850E_ARCH: + strcat (buf, ", v850e"); + break; + case E_V850_ARCH: + strcat (buf, ", v850"); + break; + default: + strcat (buf, ", unknown v850 architecture variant"); + break; + } + break; + + case EM_M32R: + case EM_CYGNUS_M32R: + if ((e_flags & EF_M32R_ARCH) == E_M32R_ARCH) + strcat (buf, ", m32r"); + + break; + + case EM_MIPS: + case EM_MIPS_RS3_LE: + if (e_flags & EF_MIPS_NOREORDER) + strcat (buf, ", noreorder"); + + if (e_flags & EF_MIPS_PIC) + strcat (buf, ", pic"); + + if (e_flags & EF_MIPS_CPIC) + strcat (buf, ", cpic"); + + if (e_flags & EF_MIPS_UCODE) + strcat (buf, ", ugen_reserved"); + + if (e_flags & EF_MIPS_ABI2) + strcat (buf, ", abi2"); + + if (e_flags & EF_MIPS_OPTIONS_FIRST) + strcat (buf, ", odk first"); + + if (e_flags & EF_MIPS_32BITMODE) + strcat (buf, ", 32bitmode"); + + switch ((e_flags & EF_MIPS_MACH)) + { + case E_MIPS_MACH_3900: strcat (buf, ", 3900"); break; + case E_MIPS_MACH_4010: strcat (buf, ", 4010"); break; + case E_MIPS_MACH_4100: strcat (buf, ", 4100"); break; + case E_MIPS_MACH_4111: strcat (buf, ", 4111"); break; + case E_MIPS_MACH_4120: strcat (buf, ", 4120"); break; + case E_MIPS_MACH_4650: strcat (buf, ", 4650"); break; + case E_MIPS_MACH_5400: strcat (buf, ", 5400"); break; + case E_MIPS_MACH_5500: strcat (buf, ", 5500"); break; + case E_MIPS_MACH_SB1: strcat (buf, ", sb1"); break; + case 0: + /* We simply ignore the field in this case to avoid confusion: + MIPS ELF does not specify EF_MIPS_MACH, it is a GNU + extension. */ + break; + default: strcat (buf, ", unknown CPU"); break; + } + + switch ((e_flags & EF_MIPS_ABI)) + { + case E_MIPS_ABI_O32: strcat (buf, ", o32"); break; + case E_MIPS_ABI_O64: strcat (buf, ", o64"); break; + case E_MIPS_ABI_EABI32: strcat (buf, ", eabi32"); break; + case E_MIPS_ABI_EABI64: strcat (buf, ", eabi64"); break; + case 0: + /* We simply ignore the field in this case to avoid confusion: + MIPS ELF does not specify EF_MIPS_ABI, it is a GNU extension. + This means it is likely to be an o32 file, but not for + sure. */ + break; + default: strcat (buf, ", unknown ABI"); break; + } + + if (e_flags & EF_MIPS_ARCH_ASE_MDMX) + strcat (buf, ", mdmx"); + + if (e_flags & EF_MIPS_ARCH_ASE_M16) + strcat (buf, ", mips16"); + + switch ((e_flags & EF_MIPS_ARCH)) + { + case E_MIPS_ARCH_1: strcat (buf, ", mips1"); break; + case E_MIPS_ARCH_2: strcat (buf, ", mips2"); break; + case E_MIPS_ARCH_3: strcat (buf, ", mips3"); break; + case E_MIPS_ARCH_4: strcat (buf, ", mips4"); break; + case E_MIPS_ARCH_5: strcat (buf, ", mips5"); break; + case E_MIPS_ARCH_32: strcat (buf, ", mips32"); break; + case E_MIPS_ARCH_32R2: strcat (buf, ", mips32r2"); break; + case E_MIPS_ARCH_64: strcat (buf, ", mips64"); break; + default: strcat (buf, ", unknown ISA"); break; + } + + break; + + case EM_SPARCV9: + if (e_flags & EF_SPARC_32PLUS) + strcat (buf, ", v8+"); + + if (e_flags & EF_SPARC_SUN_US1) + strcat (buf, ", ultrasparcI"); + + if (e_flags & EF_SPARC_SUN_US3) + strcat (buf, ", ultrasparcIII"); + + if (e_flags & EF_SPARC_HAL_R1) + strcat (buf, ", halr1"); + + if (e_flags & EF_SPARC_LEDATA) + strcat (buf, ", ledata"); + + if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_TSO) + strcat (buf, ", tso"); + + if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_PSO) + strcat (buf, ", pso"); + + if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_RMO) + strcat (buf, ", rmo"); + break; + + case EM_PARISC: + switch (e_flags & EF_PARISC_ARCH) + { + case EFA_PARISC_1_0: + strcpy (buf, ", PA-RISC 1.0"); + break; + case EFA_PARISC_1_1: + strcpy (buf, ", PA-RISC 1.1"); + break; + case EFA_PARISC_2_0: + strcpy (buf, ", PA-RISC 2.0"); + break; + default: + break; + } + if (e_flags & EF_PARISC_TRAPNIL) + strcat (buf, ", trapnil"); + if (e_flags & EF_PARISC_EXT) + strcat (buf, ", ext"); + if (e_flags & EF_PARISC_LSB) + strcat (buf, ", lsb"); + if (e_flags & EF_PARISC_WIDE) + strcat (buf, ", wide"); + if (e_flags & EF_PARISC_NO_KABP) + strcat (buf, ", no kabp"); + if (e_flags & EF_PARISC_LAZYSWAP) + strcat (buf, ", lazyswap"); + break; + + case EM_PJ: + case EM_PJ_OLD: + if ((e_flags & EF_PICOJAVA_NEWCALLS) == EF_PICOJAVA_NEWCALLS) + strcat (buf, ", new calling convention"); + + if ((e_flags & EF_PICOJAVA_GNUCALLS) == EF_PICOJAVA_GNUCALLS) + strcat (buf, ", gnu calling convention"); + break; + + case EM_IA_64: + if ((e_flags & EF_IA_64_ABI64)) + strcat (buf, ", 64-bit"); + else + strcat (buf, ", 32-bit"); + if ((e_flags & EF_IA_64_REDUCEDFP)) + strcat (buf, ", reduced fp model"); + if ((e_flags & EF_IA_64_NOFUNCDESC_CONS_GP)) + strcat (buf, ", no function descriptors, constant gp"); + else if ((e_flags & EF_IA_64_CONS_GP)) + strcat (buf, ", constant gp"); + if ((e_flags & EF_IA_64_ABSOLUTE)) + strcat (buf, ", absolute"); + break; + + case EM_VAX: + if ((e_flags & EF_VAX_NONPIC)) + strcat (buf, ", non-PIC"); + if ((e_flags & EF_VAX_DFLOAT)) + strcat (buf, ", D-Float"); + if ((e_flags & EF_VAX_GFLOAT)) + strcat (buf, ", G-Float"); + break; + } + } + + return buf; +} + +static const char * +get_mips_segment_type (type) + unsigned long type; +{ + switch (type) + { + case PT_MIPS_REGINFO: + return "REGINFO"; + case PT_MIPS_RTPROC: + return "RTPROC"; + case PT_MIPS_OPTIONS: + return "OPTIONS"; + default: + break; + } + + return NULL; +} + +static const char * +get_parisc_segment_type (type) + unsigned long type; +{ + switch (type) + { + case PT_HP_TLS: return "HP_TLS"; + case PT_HP_CORE_NONE: return "HP_CORE_NONE"; + case PT_HP_CORE_VERSION: return "HP_CORE_VERSION"; + case PT_HP_CORE_KERNEL: return "HP_CORE_KERNEL"; + case PT_HP_CORE_COMM: return "HP_CORE_COMM"; + case PT_HP_CORE_PROC: return "HP_CORE_PROC"; + case PT_HP_CORE_LOADABLE: return "HP_CORE_LOADABLE"; + case PT_HP_CORE_STACK: return "HP_CORE_STACK"; + case PT_HP_CORE_SHM: return "HP_CORE_SHM"; + case PT_HP_CORE_MMF: return "HP_CORE_MMF"; + case PT_HP_PARALLEL: return "HP_PARALLEL"; + case PT_HP_FASTBIND: return "HP_FASTBIND"; + case PT_PARISC_ARCHEXT: return "PARISC_ARCHEXT"; + case PT_PARISC_UNWIND: return "PARISC_UNWIND"; + default: + break; + } + + return NULL; +} + +static const char * +get_ia64_segment_type (type) + unsigned long type; +{ + switch (type) + { + case PT_IA_64_ARCHEXT: return "IA_64_ARCHEXT"; + case PT_IA_64_UNWIND: return "IA_64_UNWIND"; + case PT_HP_TLS: return "HP_TLS"; + case PT_IA_64_HP_OPT_ANOT: return "HP_OPT_ANNOT"; + case PT_IA_64_HP_HSL_ANOT: return "HP_HSL_ANNOT"; + case PT_IA_64_HP_STACK: return "HP_STACK"; + default: + break; + } + + return NULL; +} + +static const char * +get_segment_type (p_type) + unsigned long p_type; +{ + static char buff[32]; + + switch (p_type) + { + case PT_NULL: return "NULL"; + case PT_LOAD: return "LOAD"; + case PT_DYNAMIC: return "DYNAMIC"; + case PT_INTERP: return "INTERP"; + case PT_NOTE: return "NOTE"; + case PT_SHLIB: return "SHLIB"; + case PT_PHDR: return "PHDR"; + case PT_TLS: return "TLS"; + + case PT_GNU_EH_FRAME: + return "GNU_EH_FRAME"; + + default: + if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) + { + const char *result; + + switch (elf_header.e_machine) + { + case EM_MIPS: + case EM_MIPS_RS3_LE: + result = get_mips_segment_type (p_type); + break; + case EM_PARISC: + result = get_parisc_segment_type (p_type); + break; + case EM_IA_64: + result = get_ia64_segment_type (p_type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + sprintf (buff, "LOPROC+%lx", p_type - PT_LOPROC); + } + else if ((p_type >= PT_LOOS) && (p_type <= PT_HIOS)) + { + const char *result; + + switch (elf_header.e_machine) + { + case EM_PARISC: + result = get_parisc_segment_type (p_type); + break; + case EM_IA_64: + result = get_ia64_segment_type (p_type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + sprintf (buff, "LOOS+%lx", p_type - PT_LOOS); + } + else + sprintf (buff, _(": %lx"), p_type); + + return buff; + } +} + +static const char * +get_mips_section_type_name (sh_type) + unsigned int sh_type; +{ + switch (sh_type) + { + case SHT_MIPS_LIBLIST: return "MIPS_LIBLIST"; + case SHT_MIPS_MSYM: return "MIPS_MSYM"; + case SHT_MIPS_CONFLICT: return "MIPS_CONFLICT"; + case SHT_MIPS_GPTAB: return "MIPS_GPTAB"; + case SHT_MIPS_UCODE: return "MIPS_UCODE"; + case SHT_MIPS_DEBUG: return "MIPS_DEBUG"; + case SHT_MIPS_REGINFO: return "MIPS_REGINFO"; + case SHT_MIPS_PACKAGE: return "MIPS_PACKAGE"; + case SHT_MIPS_PACKSYM: return "MIPS_PACKSYM"; + case SHT_MIPS_RELD: return "MIPS_RELD"; + case SHT_MIPS_IFACE: return "MIPS_IFACE"; + case SHT_MIPS_CONTENT: return "MIPS_CONTENT"; + case SHT_MIPS_OPTIONS: return "MIPS_OPTIONS"; + case SHT_MIPS_SHDR: return "MIPS_SHDR"; + case SHT_MIPS_FDESC: return "MIPS_FDESC"; + case SHT_MIPS_EXTSYM: return "MIPS_EXTSYM"; + case SHT_MIPS_DENSE: return "MIPS_DENSE"; + case SHT_MIPS_PDESC: return "MIPS_PDESC"; + case SHT_MIPS_LOCSYM: return "MIPS_LOCSYM"; + case SHT_MIPS_AUXSYM: return "MIPS_AUXSYM"; + case SHT_MIPS_OPTSYM: return "MIPS_OPTSYM"; + case SHT_MIPS_LOCSTR: return "MIPS_LOCSTR"; + case SHT_MIPS_LINE: return "MIPS_LINE"; + case SHT_MIPS_RFDESC: return "MIPS_RFDESC"; + case SHT_MIPS_DELTASYM: return "MIPS_DELTASYM"; + case SHT_MIPS_DELTAINST: return "MIPS_DELTAINST"; + case SHT_MIPS_DELTACLASS: return "MIPS_DELTACLASS"; + case SHT_MIPS_DWARF: return "MIPS_DWARF"; + case SHT_MIPS_DELTADECL: return "MIPS_DELTADECL"; + case SHT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB"; + case SHT_MIPS_EVENTS: return "MIPS_EVENTS"; + case SHT_MIPS_TRANSLATE: return "MIPS_TRANSLATE"; + case SHT_MIPS_PIXIE: return "MIPS_PIXIE"; + case SHT_MIPS_XLATE: return "MIPS_XLATE"; + case SHT_MIPS_XLATE_DEBUG: return "MIPS_XLATE_DEBUG"; + case SHT_MIPS_WHIRL: return "MIPS_WHIRL"; + case SHT_MIPS_EH_REGION: return "MIPS_EH_REGION"; + case SHT_MIPS_XLATE_OLD: return "MIPS_XLATE_OLD"; + case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION"; + default: + break; + } + return NULL; +} + +static const char * +get_parisc_section_type_name (sh_type) + unsigned int sh_type; +{ + switch (sh_type) + { + case SHT_PARISC_EXT: return "PARISC_EXT"; + case SHT_PARISC_UNWIND: return "PARISC_UNWIND"; + case SHT_PARISC_DOC: return "PARISC_DOC"; + default: + break; + } + return NULL; +} + +static const char * +get_ia64_section_type_name (sh_type) + unsigned int sh_type; +{ + /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */ + if ((sh_type & 0xFF000000) == SHT_IA_64_LOPSREG) + return get_osabi_name ((sh_type & 0x00FF0000) >> 16); + + switch (sh_type) + { + case SHT_IA_64_EXT: return "IA_64_EXT"; + case SHT_IA_64_UNWIND: return "IA_64_UNWIND"; + case SHT_IA_64_PRIORITY_INIT: return "IA_64_PRIORITY_INIT"; + default: + break; + } + return NULL; +} + +static const char * +get_section_type_name (sh_type) + unsigned int sh_type; +{ + static char buff[32]; + + switch (sh_type) + { + case SHT_NULL: return "NULL"; + case SHT_PROGBITS: return "PROGBITS"; + case SHT_SYMTAB: return "SYMTAB"; + case SHT_STRTAB: return "STRTAB"; + case SHT_RELA: return "RELA"; + case SHT_HASH: return "HASH"; + case SHT_DYNAMIC: return "DYNAMIC"; + case SHT_NOTE: return "NOTE"; + case SHT_NOBITS: return "NOBITS"; + case SHT_REL: return "REL"; + case SHT_SHLIB: return "SHLIB"; + case SHT_DYNSYM: return "DYNSYM"; + case SHT_INIT_ARRAY: return "INIT_ARRAY"; + case SHT_FINI_ARRAY: return "FINI_ARRAY"; + case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY"; + case SHT_GROUP: return "GROUP"; + case SHT_SYMTAB_SHNDX: return "SYMTAB SECTION INDICIES"; + case SHT_GNU_verdef: return "VERDEF"; + case SHT_GNU_verneed: return "VERNEED"; + case SHT_GNU_versym: return "VERSYM"; + case 0x6ffffff0: return "VERSYM"; + case 0x6ffffffc: return "VERDEF"; + case 0x7ffffffd: return "AUXILIARY"; + case 0x7fffffff: return "FILTER"; + case SHT_GNU_LIBLIST: return "GNU_LIBLIST"; + + default: + if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC)) + { + const char *result; + + switch (elf_header.e_machine) + { + case EM_MIPS: + case EM_MIPS_RS3_LE: + result = get_mips_section_type_name (sh_type); + break; + case EM_PARISC: + result = get_parisc_section_type_name (sh_type); + break; + case EM_IA_64: + result = get_ia64_section_type_name (sh_type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + sprintf (buff, "LOPROC+%x", sh_type - SHT_LOPROC); + } + else if ((sh_type >= SHT_LOOS) && (sh_type <= SHT_HIOS)) + sprintf (buff, "LOOS+%x", sh_type - SHT_LOOS); + else if ((sh_type >= SHT_LOUSER) && (sh_type <= SHT_HIUSER)) + sprintf (buff, "LOUSER+%x", sh_type - SHT_LOUSER); + else + sprintf (buff, _(": %x"), sh_type); + + return buff; + } +} + +#define OPTION_DEBUG_DUMP 512 + +struct option options[] = +{ + {"all", no_argument, 0, 'a'}, + {"file-header", no_argument, 0, 'h'}, + {"program-headers", no_argument, 0, 'l'}, + {"headers", no_argument, 0, 'e'}, + {"histogram", no_argument, 0, 'I'}, + {"segments", no_argument, 0, 'l'}, + {"sections", no_argument, 0, 'S'}, + {"section-headers", no_argument, 0, 'S'}, + {"symbols", no_argument, 0, 's'}, + {"syms", no_argument, 0, 's'}, + {"relocs", no_argument, 0, 'r'}, + {"notes", no_argument, 0, 'n'}, + {"dynamic", no_argument, 0, 'd'}, + {"arch-specific", no_argument, 0, 'A'}, + {"version-info", no_argument, 0, 'V'}, + {"use-dynamic", no_argument, 0, 'D'}, + {"hex-dump", required_argument, 0, 'x'}, + {"debug-dump", optional_argument, 0, OPTION_DEBUG_DUMP}, + {"unwind", no_argument, 0, 'u'}, +#ifdef SUPPORT_DISASSEMBLY + {"instruction-dump", required_argument, 0, 'i'}, +#endif + + {"version", no_argument, 0, 'v'}, + {"wide", no_argument, 0, 'W'}, + {"help", no_argument, 0, 'H'}, + {0, no_argument, 0, 0} +}; + +static void +usage () +{ + fprintf (stdout, _("Usage: readelf elf-file(s)\n")); + fprintf (stdout, _(" Display information about the contents of ELF format files\n")); + fprintf (stdout, _(" Options are:\n\ + -a --all Equivalent to: -h -l -S -s -r -d -V -A -I\n\ + -h --file-header Display the ELF file header\n\ + -l --program-headers Display the program headers\n\ + --segments An alias for --program-headers\n\ + -S --section-headers Display the sections' header\n\ + --sections An alias for --section-headers\n\ + -e --headers Equivalent to: -h -l -S\n\ + -s --syms Display the symbol table\n\ + --symbols An alias for --syms\n\ + -n --notes Display the core notes (if present)\n\ + -r --relocs Display the relocations (if present)\n\ + -u --unwind Display the unwind info (if present)\n\ + -d --dynamic Display the dynamic segment (if present)\n\ + -V --version-info Display the version sections (if present)\n\ + -A --arch-specific Display architecture specific information (if any).\n\ + -D --use-dynamic Use the dynamic section info when displaying symbols\n\ + -x --hex-dump= Dump the contents of section \n\ + -w[liaprmfFso] or\n\ + --debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=str,=loc]\n\ + Display the contents of DWARF2 debug sections\n")); +#ifdef SUPPORT_DISASSEMBLY + fprintf (stdout, _("\ + -i --instruction-dump=\n\ + Disassemble the contents of section \n")); +#endif + fprintf (stdout, _("\ + -I --histogram Display histogram of bucket list lengths\n\ + -W --wide Allow output width to exceed 80 characters\n\ + -H --help Display this information\n\ + -v --version Display the version number of readelf\n")); + fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO); + + exit (0); +} + +static void +request_dump (section, type) + unsigned int section; + int type; +{ + if (section >= num_dump_sects) + { + char *new_dump_sects; + + new_dump_sects = (char *) calloc (section + 1, 1); + + if (new_dump_sects == NULL) + error (_("Out of memory allocating dump request table.")); + else + { + /* Copy current flag settings. */ + memcpy (new_dump_sects, dump_sects, num_dump_sects); + + free (dump_sects); + + dump_sects = new_dump_sects; + num_dump_sects = section + 1; + } + } + + if (dump_sects) + dump_sects[section] |= type; + + return; +} + +static void +parse_args (argc, argv) + int argc; + char **argv; +{ + int c; + + if (argc < 2) + usage (); + + while ((c = getopt_long + (argc, argv, "ersuahnldSDAIw::x:i:vVWH", options, NULL)) != EOF) + { + char *cp; + int section; + + switch (c) + { + case 0: + /* Long options. */ + break; + case 'H': + usage (); + break; + + case 'a': + do_syms++; + do_reloc++; + do_unwind++; + do_dynamic++; + do_header++; + do_sections++; + do_segments++; + do_version++; + do_histogram++; + do_arch++; + do_notes++; + break; + case 'e': + do_header++; + do_sections++; + do_segments++; + break; + case 'A': + do_arch++; + break; + case 'D': + do_using_dynamic++; + break; + case 'r': + do_reloc++; + break; + case 'u': + do_unwind++; + break; + case 'h': + do_header++; + break; + case 'l': + do_segments++; + break; + case 's': + do_syms++; + break; + case 'S': + do_sections++; + break; + case 'd': + do_dynamic++; + break; + case 'I': + do_histogram++; + break; + case 'n': + do_notes++; + break; + case 'x': + do_dump++; + section = strtoul (optarg, & cp, 0); + if (! *cp && section >= 0) + { + request_dump (section, HEX_DUMP); + break; + } + goto oops; + case 'w': + do_dump++; + if (optarg == 0) + do_debugging = 1; + else + { + unsigned int index = 0; + + do_debugging = 0; + + while (optarg[index]) + switch (optarg[index++]) + { + case 'i': + case 'I': + do_debug_info = 1; + break; + + case 'a': + case 'A': + do_debug_abbrevs = 1; + break; + + case 'l': + case 'L': + do_debug_lines = 1; + break; + + case 'p': + case 'P': + do_debug_pubnames = 1; + break; + + case 'r': + case 'R': + do_debug_aranges = 1; + break; + + case 'F': + do_debug_frames_interp = 1; + case 'f': + do_debug_frames = 1; + break; + + case 'm': + case 'M': + do_debug_macinfo = 1; + break; + + case 's': + case 'S': + do_debug_str = 1; + break; + + case 'o': + case 'O': + do_debug_loc = 1; + break; + + default: + warn (_("Unrecognized debug option '%s'\n"), optarg); + break; + } + } + break; + case OPTION_DEBUG_DUMP: + do_dump++; + if (optarg == 0) + do_debugging = 1; + else + { + static const char *debug_dump_opt[] + = { "line", "info", "abbrev", "pubnames", "ranges", + "macro", "frames", "frames-interp", "str", "loc", NULL }; + unsigned int index; + const char *p; + + do_debugging = 0; + + p = optarg; + while (*p) + { + for (index = 0; debug_dump_opt[index]; index++) + { + size_t len = strlen (debug_dump_opt[index]); + + if (strncmp (p, debug_dump_opt[index], len) == 0 + && (p[len] == ',' || p[len] == '\0')) + { + switch (p[0]) + { + case 'i': + do_debug_info = 1; + break; + + case 'a': + do_debug_abbrevs = 1; + break; + + case 'l': + if (p[1] == 'i') + do_debug_lines = 1; + else + do_debug_loc = 1; + break; + + case 'p': + do_debug_pubnames = 1; + break; + + case 'r': + do_debug_aranges = 1; + break; + + case 'f': + if (len > 6) + do_debug_frames_interp = 1; + do_debug_frames = 1; + break; + + case 'm': + do_debug_macinfo = 1; + break; + + case 's': + do_debug_str = 1; + break; + } + + p += len; + break; + } + } + + if (debug_dump_opt[index] == NULL) + { + warn (_("Unrecognized debug option '%s'\n"), p); + p = strchr (p, ','); + if (p == NULL) + break; + } + + if (*p == ',') + p++; + } + } + break; +#ifdef SUPPORT_DISASSEMBLY + case 'i': + do_dump++; + section = strtoul (optarg, & cp, 0); + if (! *cp && section >= 0) + { + request_dump (section, DISASS_DUMP); + break; + } + goto oops; +#endif + case 'v': + print_version (program_name); + break; + case 'V': + do_version++; + break; + case 'W': + do_wide++; + break; + default: + oops: + /* xgettext:c-format */ + error (_("Invalid option '-%c'\n"), c); + /* Drop through. */ + case '?': + usage (); + } + } + + if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections + && !do_segments && !do_header && !do_dump && !do_version + && !do_histogram && !do_debugging && !do_arch && !do_notes) + usage (); + else if (argc < 3) + { + warn (_("Nothing to do.\n")); + usage(); + } +} + +static const char * +get_elf_class (elf_class) + unsigned int elf_class; +{ + static char buff[32]; + + switch (elf_class) + { + case ELFCLASSNONE: return _("none"); + case ELFCLASS32: return "ELF32"; + case ELFCLASS64: return "ELF64"; + default: + sprintf (buff, _(""), elf_class); + return buff; + } +} + +static const char * +get_data_encoding (encoding) + unsigned int encoding; +{ + static char buff[32]; + + switch (encoding) + { + case ELFDATANONE: return _("none"); + case ELFDATA2LSB: return _("2's complement, little endian"); + case ELFDATA2MSB: return _("2's complement, big endian"); + default: + sprintf (buff, _(""), encoding); + return buff; + } +} + +static const char * +get_osabi_name (osabi) + unsigned int osabi; +{ + static char buff[32]; + + switch (osabi) + { + case ELFOSABI_NONE: return "UNIX - System V"; + case ELFOSABI_HPUX: return "UNIX - HP-UX"; + case ELFOSABI_NETBSD: return "UNIX - NetBSD"; + case ELFOSABI_LINUX: return "UNIX - Linux"; + case ELFOSABI_HURD: return "GNU/Hurd"; + case ELFOSABI_SOLARIS: return "UNIX - Solaris"; + case ELFOSABI_AIX: return "UNIX - AIX"; + case ELFOSABI_IRIX: return "UNIX - IRIX"; + case ELFOSABI_FREEBSD: return "UNIX - FreeBSD"; + case ELFOSABI_TRU64: return "UNIX - TRU64"; + case ELFOSABI_MODESTO: return "Novell - Modesto"; + case ELFOSABI_OPENBSD: return "UNIX - OpenBSD"; + case ELFOSABI_OPENVMS: return "VMS - OpenVMS"; + case ELFOSABI_NSK: return "HP - Non-Stop Kernel"; + case ELFOSABI_AROS: return "Amiga Research OS"; + case ELFOSABI_STANDALONE: return _("Standalone App"); + case ELFOSABI_ARM: return "ARM"; + default: + sprintf (buff, _(""), osabi); + return buff; + } +} + +/* Decode the data held in 'elf_header'. */ + +static int +process_file_header () +{ + if ( elf_header.e_ident[EI_MAG0] != ELFMAG0 + || elf_header.e_ident[EI_MAG1] != ELFMAG1 + || elf_header.e_ident[EI_MAG2] != ELFMAG2 + || elf_header.e_ident[EI_MAG3] != ELFMAG3) + { + error + (_("Not an ELF file - it has the wrong magic bytes at the start\n")); + return 0; + } + + if (do_header) + { + int i; + + printf (_("ELF Header:\n")); + printf (_(" Magic: ")); + for (i = 0; i < EI_NIDENT; i++) + printf ("%2.2x ", elf_header.e_ident[i]); + printf ("\n"); + printf (_(" Class: %s\n"), + get_elf_class (elf_header.e_ident[EI_CLASS])); + printf (_(" Data: %s\n"), + get_data_encoding (elf_header.e_ident[EI_DATA])); + printf (_(" Version: %d %s\n"), + elf_header.e_ident[EI_VERSION], + (elf_header.e_ident[EI_VERSION] == EV_CURRENT + ? "(current)" + : (elf_header.e_ident[EI_VERSION] != EV_NONE + ? "" + : ""))); + printf (_(" OS/ABI: %s\n"), + get_osabi_name (elf_header.e_ident[EI_OSABI])); + printf (_(" ABI Version: %d\n"), + elf_header.e_ident[EI_ABIVERSION]); + printf (_(" Type: %s\n"), + get_file_type (elf_header.e_type)); + printf (_(" Machine: %s\n"), + get_machine_name (elf_header.e_machine)); + printf (_(" Version: 0x%lx\n"), + (unsigned long) elf_header.e_version); + + printf (_(" Entry point address: ")); + print_vma ((bfd_vma) elf_header.e_entry, PREFIX_HEX); + printf (_("\n Start of program headers: ")); + print_vma ((bfd_vma) elf_header.e_phoff, DEC); + printf (_(" (bytes into file)\n Start of section headers: ")); + print_vma ((bfd_vma) elf_header.e_shoff, DEC); + printf (_(" (bytes into file)\n")); + + printf (_(" Flags: 0x%lx%s\n"), + (unsigned long) elf_header.e_flags, + get_machine_flags (elf_header.e_flags, elf_header.e_machine)); + printf (_(" Size of this header: %ld (bytes)\n"), + (long) elf_header.e_ehsize); + printf (_(" Size of program headers: %ld (bytes)\n"), + (long) elf_header.e_phentsize); + printf (_(" Number of program headers: %ld\n"), + (long) elf_header.e_phnum); + printf (_(" Size of section headers: %ld (bytes)\n"), + (long) elf_header.e_shentsize); + printf (_(" Number of section headers: %ld"), + (long) elf_header.e_shnum); + if (section_headers != NULL && elf_header.e_shnum == 0) + printf (" (%ld)", (long) section_headers[0].sh_size); + putc ('\n', stdout); + printf (_(" Section header string table index: %ld"), + (long) elf_header.e_shstrndx); + if (section_headers != NULL && elf_header.e_shstrndx == SHN_XINDEX) + printf (" (%ld)", (long) section_headers[0].sh_link); + putc ('\n', stdout); + } + + if (section_headers != NULL) + { + if (elf_header.e_shnum == 0) + elf_header.e_shnum = section_headers[0].sh_size; + if (elf_header.e_shstrndx == SHN_XINDEX) + elf_header.e_shstrndx = section_headers[0].sh_link; + free (section_headers); + section_headers = NULL; + } + + return 1; +} + + +static int +get_32bit_program_headers (file, program_headers) + FILE *file; + Elf_Internal_Phdr *program_headers; +{ + Elf32_External_Phdr *phdrs; + Elf32_External_Phdr *external; + Elf_Internal_Phdr *internal; + unsigned int i; + + phdrs = ((Elf32_External_Phdr *) + get_data (NULL, file, elf_header.e_phoff, + elf_header.e_phentsize * elf_header.e_phnum, + _("program headers"))); + if (!phdrs) + return 0; + + for (i = 0, internal = program_headers, external = phdrs; + i < elf_header.e_phnum; + i++, internal++, external++) + { + internal->p_type = BYTE_GET (external->p_type); + internal->p_offset = BYTE_GET (external->p_offset); + internal->p_vaddr = BYTE_GET (external->p_vaddr); + internal->p_paddr = BYTE_GET (external->p_paddr); + internal->p_filesz = BYTE_GET (external->p_filesz); + internal->p_memsz = BYTE_GET (external->p_memsz); + internal->p_flags = BYTE_GET (external->p_flags); + internal->p_align = BYTE_GET (external->p_align); + } + + free (phdrs); + + return 1; +} + +static int +get_64bit_program_headers (file, program_headers) + FILE *file; + Elf_Internal_Phdr *program_headers; +{ + Elf64_External_Phdr *phdrs; + Elf64_External_Phdr *external; + Elf_Internal_Phdr *internal; + unsigned int i; + + phdrs = ((Elf64_External_Phdr *) + get_data (NULL, file, elf_header.e_phoff, + elf_header.e_phentsize * elf_header.e_phnum, + _("program headers"))); + if (!phdrs) + return 0; + + for (i = 0, internal = program_headers, external = phdrs; + i < elf_header.e_phnum; + i++, internal++, external++) + { + internal->p_type = BYTE_GET (external->p_type); + internal->p_flags = BYTE_GET (external->p_flags); + internal->p_offset = BYTE_GET8 (external->p_offset); + internal->p_vaddr = BYTE_GET8 (external->p_vaddr); + internal->p_paddr = BYTE_GET8 (external->p_paddr); + internal->p_filesz = BYTE_GET8 (external->p_filesz); + internal->p_memsz = BYTE_GET8 (external->p_memsz); + internal->p_align = BYTE_GET8 (external->p_align); + } + + free (phdrs); + + return 1; +} + +/* Returns 1 if the program headers were loaded. */ + +static int +process_program_headers (file) + FILE *file; +{ + Elf_Internal_Phdr *program_headers; + Elf_Internal_Phdr *segment; + unsigned int i; + + if (elf_header.e_phnum == 0) + { + if (do_segments) + printf (_("\nThere are no program headers in this file.\n")); + return 0; + } + + if (do_segments && !do_header) + { + printf (_("\nElf file type is %s\n"), get_file_type (elf_header.e_type)); + printf (_("Entry point ")); + print_vma ((bfd_vma) elf_header.e_entry, PREFIX_HEX); + printf (_("\nThere are %d program headers, starting at offset "), + elf_header.e_phnum); + print_vma ((bfd_vma) elf_header.e_phoff, DEC); + printf ("\n"); + } + + program_headers = (Elf_Internal_Phdr *) malloc + (elf_header.e_phnum * sizeof (Elf_Internal_Phdr)); + + if (program_headers == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + if (is_32bit_elf) + i = get_32bit_program_headers (file, program_headers); + else + i = get_64bit_program_headers (file, program_headers); + + if (i == 0) + { + free (program_headers); + return 0; + } + + if (do_segments) + { + if (elf_header.e_phnum > 1) + printf (_("\nProgram Headers:\n")); + else + printf (_("\nProgram Headers:\n")); + + if (is_32bit_elf) + printf + (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); + else if (do_wide) + printf + (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); + else + { + printf + (_(" Type Offset VirtAddr PhysAddr\n")); + printf + (_(" FileSiz MemSiz Flags Align\n")); + } + } + + loadaddr = -1; + dynamic_addr = 0; + dynamic_size = 0; + + for (i = 0, segment = program_headers; + i < elf_header.e_phnum; + i++, segment++) + { + if (do_segments) + { + printf (" %-14.14s ", get_segment_type (segment->p_type)); + + if (is_32bit_elf) + { + printf ("0x%6.6lx ", (unsigned long) segment->p_offset); + printf ("0x%8.8lx ", (unsigned long) segment->p_vaddr); + printf ("0x%8.8lx ", (unsigned long) segment->p_paddr); + printf ("0x%5.5lx ", (unsigned long) segment->p_filesz); + printf ("0x%5.5lx ", (unsigned long) segment->p_memsz); + printf ("%c%c%c ", + (segment->p_flags & PF_R ? 'R' : ' '), + (segment->p_flags & PF_W ? 'W' : ' '), + (segment->p_flags & PF_X ? 'E' : ' ')); + printf ("%#lx", (unsigned long) segment->p_align); + } + else if (do_wide) + { + if ((unsigned long) segment->p_offset == segment->p_offset) + printf ("0x%6.6lx ", (unsigned long) segment->p_offset); + else + { + print_vma (segment->p_offset, FULL_HEX); + putchar (' '); + } + + print_vma (segment->p_vaddr, FULL_HEX); + putchar (' '); + print_vma (segment->p_paddr, FULL_HEX); + putchar (' '); + + if ((unsigned long) segment->p_filesz == segment->p_filesz) + printf ("0x%6.6lx ", (unsigned long) segment->p_filesz); + else + { + print_vma (segment->p_filesz, FULL_HEX); + putchar (' '); + } + + if ((unsigned long) segment->p_memsz == segment->p_memsz) + printf ("0x%6.6lx", (unsigned long) segment->p_memsz); + else + { + print_vma (segment->p_offset, FULL_HEX); + } + + printf (" %c%c%c ", + (segment->p_flags & PF_R ? 'R' : ' '), + (segment->p_flags & PF_W ? 'W' : ' '), + (segment->p_flags & PF_X ? 'E' : ' ')); + + if ((unsigned long) segment->p_align == segment->p_align) + printf ("%#lx", (unsigned long) segment->p_align); + else + { + print_vma (segment->p_align, PREFIX_HEX); + } + } + else + { + print_vma (segment->p_offset, FULL_HEX); + putchar (' '); + print_vma (segment->p_vaddr, FULL_HEX); + putchar (' '); + print_vma (segment->p_paddr, FULL_HEX); + printf ("\n "); + print_vma (segment->p_filesz, FULL_HEX); + putchar (' '); + print_vma (segment->p_memsz, FULL_HEX); + printf (" %c%c%c ", + (segment->p_flags & PF_R ? 'R' : ' '), + (segment->p_flags & PF_W ? 'W' : ' '), + (segment->p_flags & PF_X ? 'E' : ' ')); + print_vma (segment->p_align, HEX); + } + } + + switch (segment->p_type) + { + case PT_LOAD: + if (loadaddr == -1) + { + unsigned long align_mask = -segment->p_align; + + if (align_mask == 0) + --align_mask; + loadaddr = ((segment->p_vaddr & align_mask) + - (segment->p_offset & align_mask)); + } + break; + + case PT_DYNAMIC: + if (dynamic_addr) + error (_("more than one dynamic segment\n")); + + dynamic_addr = segment->p_offset; + dynamic_size = segment->p_filesz; + break; + + case PT_INTERP: + if (fseek (file, (long) segment->p_offset, SEEK_SET)) + error (_("Unable to find program interpreter name\n")); + else + { + program_interpreter[0] = 0; + fscanf (file, "%63s", program_interpreter); + + if (do_segments) + printf (_("\n [Requesting program interpreter: %s]"), + program_interpreter); + } + break; + } + + if (do_segments) + putc ('\n', stdout); + } + + if (loadaddr == -1) + { + /* Very strange. */ + loadaddr = 0; + } + + if (do_segments && section_headers != NULL) + { + printf (_("\n Section to Segment mapping:\n")); + printf (_(" Segment Sections...\n")); + + assert (string_table != NULL); + + for (i = 0; i < elf_header.e_phnum; i++) + { + unsigned int j; + Elf_Internal_Shdr *section; + + segment = program_headers + i; + section = section_headers; + + printf (" %2.2d ", i); + + for (j = 1; j < elf_header.e_shnum; j++, section++) + { + if (section->sh_size > 0 + /* Compare allocated sections by VMA, unallocated + sections by file offset. */ + && (section->sh_flags & SHF_ALLOC + ? (section->sh_addr >= segment->p_vaddr + && section->sh_addr + section->sh_size + <= segment->p_vaddr + segment->p_memsz) + : ((bfd_vma) section->sh_offset >= segment->p_offset + && (section->sh_offset + section->sh_size + <= segment->p_offset + segment->p_filesz)))) + printf ("%s ", SECTION_NAME (section)); + } + + putc ('\n',stdout); + } + } + + free (program_headers); + + return 1; +} + + +static int +get_32bit_section_headers (file, num) + FILE *file; + unsigned int num; +{ + Elf32_External_Shdr *shdrs; + Elf_Internal_Shdr *internal; + unsigned int i; + + shdrs = ((Elf32_External_Shdr *) + get_data (NULL, file, elf_header.e_shoff, + elf_header.e_shentsize * num, + _("section headers"))); + if (!shdrs) + return 0; + + section_headers = ((Elf_Internal_Shdr *) + malloc (num * sizeof (Elf_Internal_Shdr))); + + if (section_headers == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + for (i = 0, internal = section_headers; + i < num; + i++, internal++) + { + internal->sh_name = BYTE_GET (shdrs[i].sh_name); + internal->sh_type = BYTE_GET (shdrs[i].sh_type); + internal->sh_flags = BYTE_GET (shdrs[i].sh_flags); + internal->sh_addr = BYTE_GET (shdrs[i].sh_addr); + internal->sh_offset = BYTE_GET (shdrs[i].sh_offset); + internal->sh_size = BYTE_GET (shdrs[i].sh_size); + internal->sh_link = BYTE_GET (shdrs[i].sh_link); + internal->sh_info = BYTE_GET (shdrs[i].sh_info); + internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign); + internal->sh_entsize = BYTE_GET (shdrs[i].sh_entsize); + } + + free (shdrs); + + return 1; +} + +static int +get_64bit_section_headers (file, num) + FILE *file; + unsigned int num; +{ + Elf64_External_Shdr *shdrs; + Elf_Internal_Shdr *internal; + unsigned int i; + + shdrs = ((Elf64_External_Shdr *) + get_data (NULL, file, elf_header.e_shoff, + elf_header.e_shentsize * num, + _("section headers"))); + if (!shdrs) + return 0; + + section_headers = ((Elf_Internal_Shdr *) + malloc (num * sizeof (Elf_Internal_Shdr))); + + if (section_headers == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + for (i = 0, internal = section_headers; + i < num; + i++, internal++) + { + internal->sh_name = BYTE_GET (shdrs[i].sh_name); + internal->sh_type = BYTE_GET (shdrs[i].sh_type); + internal->sh_flags = BYTE_GET8 (shdrs[i].sh_flags); + internal->sh_addr = BYTE_GET8 (shdrs[i].sh_addr); + internal->sh_size = BYTE_GET8 (shdrs[i].sh_size); + internal->sh_entsize = BYTE_GET8 (shdrs[i].sh_entsize); + internal->sh_link = BYTE_GET (shdrs[i].sh_link); + internal->sh_info = BYTE_GET (shdrs[i].sh_info); + internal->sh_offset = BYTE_GET (shdrs[i].sh_offset); + internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign); + } + + free (shdrs); + + return 1; +} + +static Elf_Internal_Sym * +get_32bit_elf_symbols (file, section) + FILE *file; + Elf_Internal_Shdr *section; +{ + unsigned long number; + Elf32_External_Sym *esyms; + Elf_External_Sym_Shndx *shndx; + Elf_Internal_Sym *isyms; + Elf_Internal_Sym *psym; + unsigned int j; + + esyms = ((Elf32_External_Sym *) + get_data (NULL, file, section->sh_offset, + section->sh_size, _("symbols"))); + if (!esyms) + return NULL; + + shndx = NULL; + if (symtab_shndx_hdr != NULL + && (symtab_shndx_hdr->sh_link + == (unsigned long) SECTION_HEADER_NUM (section - section_headers))) + { + shndx = ((Elf_External_Sym_Shndx *) + get_data (NULL, file, symtab_shndx_hdr->sh_offset, + symtab_shndx_hdr->sh_size, _("symtab shndx"))); + if (!shndx) + { + free (esyms); + return NULL; + } + } + + number = section->sh_size / section->sh_entsize; + isyms = (Elf_Internal_Sym *) malloc (number * sizeof (Elf_Internal_Sym)); + + if (isyms == NULL) + { + error (_("Out of memory\n")); + if (shndx) + free (shndx); + free (esyms); + return NULL; + } + + for (j = 0, psym = isyms; + j < number; + j++, psym++) + { + psym->st_name = BYTE_GET (esyms[j].st_name); + psym->st_value = BYTE_GET (esyms[j].st_value); + psym->st_size = BYTE_GET (esyms[j].st_size); + psym->st_shndx = BYTE_GET (esyms[j].st_shndx); + if (psym->st_shndx == SHN_XINDEX && shndx != NULL) + psym->st_shndx + = byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j])); + psym->st_info = BYTE_GET (esyms[j].st_info); + psym->st_other = BYTE_GET (esyms[j].st_other); + } + + if (shndx) + free (shndx); + free (esyms); + + return isyms; +} + +static Elf_Internal_Sym * +get_64bit_elf_symbols (file, section) + FILE *file; + Elf_Internal_Shdr *section; +{ + unsigned long number; + Elf64_External_Sym *esyms; + Elf_External_Sym_Shndx *shndx; + Elf_Internal_Sym *isyms; + Elf_Internal_Sym *psym; + unsigned int j; + + esyms = ((Elf64_External_Sym *) + get_data (NULL, file, section->sh_offset, + section->sh_size, _("symbols"))); + if (!esyms) + return NULL; + + shndx = NULL; + if (symtab_shndx_hdr != NULL + && (symtab_shndx_hdr->sh_link + == (unsigned long) SECTION_HEADER_NUM (section - section_headers))) + { + shndx = ((Elf_External_Sym_Shndx *) + get_data (NULL, file, symtab_shndx_hdr->sh_offset, + symtab_shndx_hdr->sh_size, _("symtab shndx"))); + if (!shndx) + { + free (esyms); + return NULL; + } + } + + number = section->sh_size / section->sh_entsize; + isyms = (Elf_Internal_Sym *) malloc (number * sizeof (Elf_Internal_Sym)); + + if (isyms == NULL) + { + error (_("Out of memory\n")); + if (shndx) + free (shndx); + free (esyms); + return NULL; + } + + for (j = 0, psym = isyms; + j < number; + j++, psym++) + { + psym->st_name = BYTE_GET (esyms[j].st_name); + psym->st_info = BYTE_GET (esyms[j].st_info); + psym->st_other = BYTE_GET (esyms[j].st_other); + psym->st_shndx = BYTE_GET (esyms[j].st_shndx); + if (psym->st_shndx == SHN_XINDEX && shndx != NULL) + psym->st_shndx + = byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j])); + psym->st_value = BYTE_GET8 (esyms[j].st_value); + psym->st_size = BYTE_GET8 (esyms[j].st_size); + } + + if (shndx) + free (shndx); + free (esyms); + + return isyms; +} + +static const char * +get_elf_section_flags (sh_flags) + bfd_vma sh_flags; +{ + static char buff[32]; + + *buff = 0; + + while (sh_flags) + { + bfd_vma flag; + + flag = sh_flags & - sh_flags; + sh_flags &= ~ flag; + + switch (flag) + { + case SHF_WRITE: strcat (buff, "W"); break; + case SHF_ALLOC: strcat (buff, "A"); break; + case SHF_EXECINSTR: strcat (buff, "X"); break; + case SHF_MERGE: strcat (buff, "M"); break; + case SHF_STRINGS: strcat (buff, "S"); break; + case SHF_INFO_LINK: strcat (buff, "I"); break; + case SHF_LINK_ORDER: strcat (buff, "L"); break; + case SHF_OS_NONCONFORMING: strcat (buff, "O"); break; + case SHF_GROUP: strcat (buff, "G"); break; + case SHF_TLS: strcat (buff, "T"); break; + + default: + if (flag & SHF_MASKOS) + { + strcat (buff, "o"); + sh_flags &= ~ SHF_MASKOS; + } + else if (flag & SHF_MASKPROC) + { + strcat (buff, "p"); + sh_flags &= ~ SHF_MASKPROC; + } + else + strcat (buff, "x"); + break; + } + } + + return buff; +} + +static int +process_section_headers (file) + FILE *file; +{ + Elf_Internal_Shdr *section; + unsigned int i; + + section_headers = NULL; + + if (elf_header.e_shnum == 0) + { + if (do_sections) + printf (_("\nThere are no sections in this file.\n")); + + return 1; + } + + if (do_sections && !do_header) + printf (_("There are %d section headers, starting at offset 0x%lx:\n"), + elf_header.e_shnum, (unsigned long) elf_header.e_shoff); + + if (is_32bit_elf) + { + if (! get_32bit_section_headers (file, elf_header.e_shnum)) + return 0; + } + else if (! get_64bit_section_headers (file, elf_header.e_shnum)) + return 0; + + /* Read in the string table, so that we have names to display. */ + section = SECTION_HEADER (elf_header.e_shstrndx); + + if (section->sh_size != 0) + { + string_table = (char *) get_data (NULL, file, section->sh_offset, + section->sh_size, _("string table")); + + string_table_length = section->sh_size; + } + + /* Scan the sections for the dynamic symbol table + and dynamic string table and debug sections. */ + dynamic_symbols = NULL; + dynamic_strings = NULL; + dynamic_syminfo = NULL; + symtab_shndx_hdr = NULL; + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + char *name = SECTION_NAME (section); + + if (section->sh_type == SHT_DYNSYM) + { + if (dynamic_symbols != NULL) + { + error (_("File contains multiple dynamic symbol tables\n")); + continue; + } + + num_dynamic_syms = section->sh_size / section->sh_entsize; + dynamic_symbols = GET_ELF_SYMBOLS (file, section); + } + else if (section->sh_type == SHT_STRTAB + && strcmp (name, ".dynstr") == 0) + { + if (dynamic_strings != NULL) + { + error (_("File contains multiple dynamic string tables\n")); + continue; + } + + dynamic_strings = (char *) get_data (NULL, file, section->sh_offset, + section->sh_size, + _("dynamic strings")); + } + else if (section->sh_type == SHT_SYMTAB_SHNDX) + { + if (symtab_shndx_hdr != NULL) + { + error (_("File contains multiple symtab shndx tables\n")); + continue; + } + symtab_shndx_hdr = section; + } + else if ((do_debugging || do_debug_info || do_debug_abbrevs + || do_debug_lines || do_debug_pubnames || do_debug_aranges + || do_debug_frames || do_debug_macinfo || do_debug_str + || do_debug_loc) + && strncmp (name, ".debug_", 7) == 0) + { + name += 7; + + if (do_debugging + || (do_debug_info && (strcmp (name, "info") == 0)) + || (do_debug_abbrevs && (strcmp (name, "abbrev") == 0)) + || (do_debug_lines && (strcmp (name, "line") == 0)) + || (do_debug_pubnames && (strcmp (name, "pubnames") == 0)) + || (do_debug_aranges && (strcmp (name, "aranges") == 0)) + || (do_debug_frames && (strcmp (name, "frame") == 0)) + || (do_debug_macinfo && (strcmp (name, "macinfo") == 0)) + || (do_debug_str && (strcmp (name, "str") == 0)) + || (do_debug_loc && (strcmp (name, "loc") == 0)) + ) + request_dump (i, DEBUG_DUMP); + } + /* linkonce section to be combined with .debug_info at link time. */ + else if ((do_debugging || do_debug_info) + && strncmp (name, ".gnu.linkonce.wi.", 17) == 0) + request_dump (i, DEBUG_DUMP); + else if (do_debug_frames && strcmp (name, ".eh_frame") == 0) + request_dump (i, DEBUG_DUMP); + } + + if (! do_sections) + return 1; + + if (elf_header.e_shnum > 1) + printf (_("\nSection Headers:\n")); + else + printf (_("\nSection Header:\n")); + + if (is_32bit_elf) + printf + (_(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n")); + else if (do_wide) + printf + (_(" [Nr] Name Type Address Off Size ES Flg Lk Inf Al\n")); + else + { + printf (_(" [Nr] Name Type Address Offset\n")); + printf (_(" Size EntSize Flags Link Info Align\n")); + } + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + printf (" [%2u] %-17.17s %-15.15s ", + SECTION_HEADER_NUM (i), + SECTION_NAME (section), + get_section_type_name (section->sh_type)); + + if (is_32bit_elf) + { + print_vma (section->sh_addr, LONG_HEX); + + printf ( " %6.6lx %6.6lx %2.2lx", + (unsigned long) section->sh_offset, + (unsigned long) section->sh_size, + (unsigned long) section->sh_entsize); + + printf (" %3s ", get_elf_section_flags (section->sh_flags)); + + printf ("%2ld %3lx %2ld\n", + (unsigned long) section->sh_link, + (unsigned long) section->sh_info, + (unsigned long) section->sh_addralign); + } + else if (do_wide) + { + print_vma (section->sh_addr, LONG_HEX); + + if ((long) section->sh_offset == section->sh_offset) + printf (" %6.6lx", (unsigned long) section->sh_offset); + else + { + putchar (' '); + print_vma (section->sh_offset, LONG_HEX); + } + + if ((unsigned long) section->sh_size == section->sh_size) + printf (" %6.6lx", (unsigned long) section->sh_size); + else + { + putchar (' '); + print_vma (section->sh_size, LONG_HEX); + } + + if ((unsigned long) section->sh_entsize == section->sh_entsize) + printf (" %2.2lx", (unsigned long) section->sh_entsize); + else + { + putchar (' '); + print_vma (section->sh_entsize, LONG_HEX); + } + + printf (" %3s ", get_elf_section_flags (section->sh_flags)); + + printf ("%2ld %3lx ", + (unsigned long) section->sh_link, + (unsigned long) section->sh_info); + + if ((unsigned long) section->sh_addralign == section->sh_addralign) + printf ("%2ld\n", (unsigned long) section->sh_addralign); + else + { + print_vma (section->sh_addralign, DEC); + putchar ('\n'); + } + } + else + { + putchar (' '); + print_vma (section->sh_addr, LONG_HEX); + if ((long) section->sh_offset == section->sh_offset) + printf (" %8.8lx", (unsigned long) section->sh_offset); + else + { + printf (" "); + print_vma (section->sh_offset, LONG_HEX); + } + printf ("\n "); + print_vma (section->sh_size, LONG_HEX); + printf (" "); + print_vma (section->sh_entsize, LONG_HEX); + + printf (" %3s ", get_elf_section_flags (section->sh_flags)); + + printf (" %2ld %3lx %ld\n", + (unsigned long) section->sh_link, + (unsigned long) section->sh_info, + (unsigned long) section->sh_addralign); + } + } + + printf (_("Key to Flags:\n\ + W (write), A (alloc), X (execute), M (merge), S (strings)\n\ + I (info), L (link order), G (group), x (unknown)\n\ + O (extra OS processing required) o (OS specific), p (processor specific)\n")); + + return 1; +} + +struct +{ + const char *name; + int reloc; + int size; + int rela; +} dynamic_relocations [] = +{ + { "REL", DT_REL, DT_RELSZ, FALSE }, + { "RELA", DT_RELA, DT_RELASZ, TRUE }, + { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN } +}; + +/* Process the reloc section. */ +static int +process_relocs (file) + FILE *file; +{ + unsigned long rel_size; + unsigned long rel_offset; + + + if (!do_reloc) + return 1; + + if (do_using_dynamic) + { + int is_rela; + const char *name; + int has_dynamic_reloc; + unsigned int i; + + has_dynamic_reloc = 0; + + for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++) + { + is_rela = dynamic_relocations [i].rela; + name = dynamic_relocations [i].name; + rel_size = dynamic_info [dynamic_relocations [i].size]; + rel_offset = dynamic_info [dynamic_relocations [i].reloc]; + + has_dynamic_reloc |= rel_size; + + if (is_rela == UNKNOWN) + { + if (dynamic_relocations [i].reloc == DT_JMPREL) + switch (dynamic_info[DT_PLTREL]) + { + case DT_REL: + is_rela = FALSE; + break; + case DT_RELA: + is_rela = TRUE; + break; + } + } + + if (rel_size) + { + printf + (_("\n'%s' relocation section at offset 0x%lx contains %ld bytes:\n"), + name, rel_offset, rel_size); + + dump_relocations (file, rel_offset - loadaddr, rel_size, + dynamic_symbols, num_dynamic_syms, + dynamic_strings, is_rela); + } + } + + if (! has_dynamic_reloc) + printf (_("\nThere are no dynamic relocations in this file.\n")); + } + else + { + Elf_Internal_Shdr *section; + unsigned long i; + int found = 0; + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + if ( section->sh_type != SHT_RELA + && section->sh_type != SHT_REL) + continue; + + rel_offset = section->sh_offset; + rel_size = section->sh_size; + + if (rel_size) + { + Elf_Internal_Shdr *strsec; + Elf_Internal_Sym *symtab; + char *strtab; + int is_rela; + unsigned long nsyms; + + printf (_("\nRelocation section ")); + + if (string_table == NULL) + printf ("%d", section->sh_name); + else + printf (_("'%s'"), SECTION_NAME (section)); + + printf (_(" at offset 0x%lx contains %lu entries:\n"), + rel_offset, (unsigned long) (rel_size / section->sh_entsize)); + + symtab = NULL; + strtab = NULL; + nsyms = 0; + if (section->sh_link) + { + Elf_Internal_Shdr *symsec; + + symsec = SECTION_HEADER (section->sh_link); + nsyms = symsec->sh_size / symsec->sh_entsize; + symtab = GET_ELF_SYMBOLS (file, symsec); + + if (symtab == NULL) + continue; + + strsec = SECTION_HEADER (symsec->sh_link); + + strtab = (char *) get_data (NULL, file, strsec->sh_offset, + strsec->sh_size, + _("string table")); + } + is_rela = section->sh_type == SHT_RELA; + + dump_relocations (file, rel_offset, rel_size, + symtab, nsyms, strtab, is_rela); + + if (strtab) + free (strtab); + if (symtab) + free (symtab); + + found = 1; + } + } + + if (! found) + printf (_("\nThere are no relocations in this file.\n")); + } + + return 1; +} + +#include "unwind-ia64.h" + +/* An absolute address consists of a section and an offset. If the + section is NULL, the offset itself is the address, otherwise, the + address equals to LOAD_ADDRESS(section) + offset. */ + +struct absaddr + { + unsigned short section; + bfd_vma offset; + }; + +struct unw_aux_info + { + struct unw_table_entry + { + struct absaddr start; + struct absaddr end; + struct absaddr info; + } + *table; /* Unwind table. */ + unsigned long table_len; /* Length of unwind table. */ + unsigned char *info; /* Unwind info. */ + unsigned long info_size; /* Size of unwind info. */ + bfd_vma info_addr; /* starting address of unwind info. */ + bfd_vma seg_base; /* Starting address of segment. */ + Elf_Internal_Sym *symtab; /* The symbol table. */ + unsigned long nsyms; /* Number of symbols. */ + char *strtab; /* The string table. */ + unsigned long strtab_size; /* Size of string table. */ + }; + +static void find_symbol_for_address + PARAMS ((struct unw_aux_info *, struct absaddr, const char **, bfd_vma *)); +static void dump_ia64_unwind + PARAMS ((struct unw_aux_info *)); +static int slurp_ia64_unwind_table + PARAMS ((FILE *, struct unw_aux_info *, Elf_Internal_Shdr *)); + +static void +find_symbol_for_address (aux, addr, symname, offset) + struct unw_aux_info *aux; + struct absaddr addr; + const char **symname; + bfd_vma *offset; +{ + bfd_vma dist = (bfd_vma) 0x100000; + Elf_Internal_Sym *sym, *best = NULL; + unsigned long i; + + for (i = 0, sym = aux->symtab; i < aux->nsyms; ++i, ++sym) + { + if (ELF_ST_TYPE (sym->st_info) == STT_FUNC + && sym->st_name != 0 + && (addr.section == SHN_UNDEF || addr.section == sym->st_shndx) + && addr.offset >= sym->st_value + && addr.offset - sym->st_value < dist) + { + best = sym; + dist = addr.offset - sym->st_value; + if (!dist) + break; + } + } + if (best) + { + *symname = (best->st_name >= aux->strtab_size + ? "" : aux->strtab + best->st_name); + *offset = dist; + return; + } + *symname = NULL; + *offset = addr.offset; +} + +static void +dump_ia64_unwind (aux) + struct unw_aux_info *aux; +{ + bfd_vma addr_size; + struct unw_table_entry *tp; + int in_body; + + addr_size = is_32bit_elf ? 4 : 8; + + for (tp = aux->table; tp < aux->table + aux->table_len; ++tp) + { + bfd_vma stamp; + bfd_vma offset; + const unsigned char *dp; + const unsigned char *head; + const char *procname; + + find_symbol_for_address (aux, tp->start, &procname, &offset); + + fputs ("\n<", stdout); + + if (procname) + { + fputs (procname, stdout); + + if (offset) + printf ("+%lx", (unsigned long) offset); + } + + fputs (">: [", stdout); + print_vma (tp->start.offset, PREFIX_HEX); + fputc ('-', stdout); + print_vma (tp->end.offset, PREFIX_HEX); + printf ("], info at +0x%lx\n", + (unsigned long) (tp->info.offset - aux->seg_base)); + + head = aux->info + (tp->info.offset - aux->info_addr); + stamp = BYTE_GET8 ((unsigned char *) head); + + printf (" v%u, flags=0x%lx (%s%s), len=%lu bytes\n", + (unsigned) UNW_VER (stamp), + (unsigned long) ((stamp & UNW_FLAG_MASK) >> 32), + UNW_FLAG_EHANDLER (stamp) ? " ehandler" : "", + UNW_FLAG_UHANDLER (stamp) ? " uhandler" : "", + (unsigned long) (addr_size * UNW_LENGTH (stamp))); + + if (UNW_VER (stamp) != 1) + { + printf ("\tUnknown version.\n"); + continue; + } + + in_body = 0; + for (dp = head + 8; dp < head + 8 + addr_size * UNW_LENGTH (stamp);) + dp = unw_decode (dp, in_body, & in_body); + } +} + +static int +slurp_ia64_unwind_table (file, aux, sec) + FILE *file; + struct unw_aux_info *aux; + Elf_Internal_Shdr *sec; +{ + unsigned long size, addr_size, nrelas, i; + Elf_Internal_Phdr *prog_hdrs, *seg; + struct unw_table_entry *tep; + Elf_Internal_Shdr *relsec; + Elf_Internal_Rela *rela, *rp; + unsigned char *table, *tp; + Elf_Internal_Sym *sym; + const char *relname; + int result; + + addr_size = is_32bit_elf ? 4 : 8; + + /* First, find the starting address of the segment that includes + this section: */ + + if (elf_header.e_phnum) + { + prog_hdrs = (Elf_Internal_Phdr *) + xmalloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr)); + + if (is_32bit_elf) + result = get_32bit_program_headers (file, prog_hdrs); + else + result = get_64bit_program_headers (file, prog_hdrs); + + if (!result) + { + free (prog_hdrs); + return 0; + } + + for (seg = prog_hdrs; seg < prog_hdrs + elf_header.e_phnum; ++seg) + { + if (seg->p_type != PT_LOAD) + continue; + + if (sec->sh_addr >= seg->p_vaddr + && (sec->sh_addr + sec->sh_size <= seg->p_vaddr + seg->p_memsz)) + { + aux->seg_base = seg->p_vaddr; + break; + } + } + + free (prog_hdrs); + } + + /* Second, build the unwind table from the contents of the unwind section: */ + size = sec->sh_size; + table = (char *) get_data (NULL, file, sec->sh_offset, + size, _("unwind table")); + if (!table) + return 0; + + tep = aux->table = xmalloc (size / (3 * addr_size) * sizeof (aux->table[0])); + for (tp = table; tp < table + size; tp += 3 * addr_size, ++tep) + { + tep->start.section = SHN_UNDEF; + tep->end.section = SHN_UNDEF; + tep->info.section = SHN_UNDEF; + if (is_32bit_elf) + { + tep->start.offset = byte_get ((unsigned char *) tp + 0, 4); + tep->end.offset = byte_get ((unsigned char *) tp + 4, 4); + tep->info.offset = byte_get ((unsigned char *) tp + 8, 4); + } + else + { + tep->start.offset = BYTE_GET8 ((unsigned char *) tp + 0); + tep->end.offset = BYTE_GET8 ((unsigned char *) tp + 8); + tep->info.offset = BYTE_GET8 ((unsigned char *) tp + 16); + } + tep->start.offset += aux->seg_base; + tep->end.offset += aux->seg_base; + tep->info.offset += aux->seg_base; + } + free (table); + + /* Third, apply any relocations to the unwind table: */ + + for (relsec = section_headers; + relsec < section_headers + elf_header.e_shnum; + ++relsec) + { + if (relsec->sh_type != SHT_RELA + || SECTION_HEADER (relsec->sh_info) != sec) + continue; + + if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size, + & rela, & nrelas)) + return 0; + + for (rp = rela; rp < rela + nrelas; ++rp) + { + if (is_32bit_elf) + { + relname = elf_ia64_reloc_type (ELF32_R_TYPE (rp->r_info)); + sym = aux->symtab + ELF32_R_SYM (rp->r_info); + + if (ELF32_ST_TYPE (sym->st_info) != STT_SECTION) + { + warn (_("Skipping unexpected symbol type %u\n"), + ELF32_ST_TYPE (sym->st_info)); + continue; + } + } + else + { + relname = elf_ia64_reloc_type (ELF64_R_TYPE (rp->r_info)); + sym = aux->symtab + ELF64_R_SYM (rp->r_info); + + if (ELF64_ST_TYPE (sym->st_info) != STT_SECTION) + { + warn (_("Skipping unexpected symbol type %u\n"), + ELF64_ST_TYPE (sym->st_info)); + continue; + } + } + + if (strncmp (relname, "R_IA64_SEGREL", 13) != 0) + { + warn (_("Skipping unexpected relocation type %s\n"), relname); + continue; + } + + i = rp->r_offset / (3 * addr_size); + + switch (rp->r_offset/addr_size % 3) + { + case 0: + aux->table[i].start.section = sym->st_shndx; + aux->table[i].start.offset += rp->r_addend; + break; + case 1: + aux->table[i].end.section = sym->st_shndx; + aux->table[i].end.offset += rp->r_addend; + break; + case 2: + aux->table[i].info.section = sym->st_shndx; + aux->table[i].info.offset += rp->r_addend; + break; + default: + break; + } + } + + free (rela); + } + + aux->table_len = size / (3 * addr_size); + return 1; +} + +static int +process_unwind (file) + FILE *file; +{ + Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec; + unsigned long i, addr_size, unwcount = 0, unwstart = 0; + struct unw_aux_info aux; + + if (!do_unwind) + return 1; + + if (elf_header.e_machine != EM_IA_64) + { + printf (_("\nThere are no unwind sections in this file.\n")); + return 1; + } + + memset (& aux, 0, sizeof (aux)); + + addr_size = is_32bit_elf ? 4 : 8; + + for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) + { + if (sec->sh_type == SHT_SYMTAB) + { + aux.nsyms = sec->sh_size / sec->sh_entsize; + aux.symtab = GET_ELF_SYMBOLS (file, sec); + + strsec = SECTION_HEADER (sec->sh_link); + aux.strtab_size = strsec->sh_size; + aux.strtab = (char *) get_data (NULL, file, strsec->sh_offset, + aux.strtab_size, _("string table")); + } + else if (sec->sh_type == SHT_IA_64_UNWIND) + unwcount++; + } + + if (!unwcount) + printf (_("\nThere are no unwind sections in this file.\n")); + + while (unwcount-- > 0) + { + char *suffix; + size_t len, len2; + + for (i = unwstart, sec = section_headers + unwstart; + i < elf_header.e_shnum; ++i, ++sec) + if (sec->sh_type == SHT_IA_64_UNWIND) + { + unwsec = sec; + break; + } + + unwstart = i + 1; + len = sizeof (ELF_STRING_ia64_unwind_once) - 1; + + if (strncmp (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once, + len) == 0) + { + /* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO */ + len2 = sizeof (ELF_STRING_ia64_unwind_info_once) - 1; + suffix = SECTION_NAME (unwsec) + len; + for (i = 0, sec = section_headers; i < elf_header.e_shnum; + ++i, ++sec) + if (strncmp (SECTION_NAME (sec), + ELF_STRING_ia64_unwind_info_once, len2) == 0 + && strcmp (SECTION_NAME (sec) + len2, suffix) == 0) + break; + } + else + { + /* .IA_64.unwindFOO -> .IA_64.unwind_infoFOO + .IA_64.unwind or BAR -> .IA_64.unwind_info */ + len = sizeof (ELF_STRING_ia64_unwind) - 1; + len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1; + suffix = ""; + if (strncmp (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind, + len) == 0) + suffix = SECTION_NAME (unwsec) + len; + for (i = 0, sec = section_headers; i < elf_header.e_shnum; + ++i, ++sec) + if (strncmp (SECTION_NAME (sec), + ELF_STRING_ia64_unwind_info, len2) == 0 + && strcmp (SECTION_NAME (sec) + len2, suffix) == 0) + break; + } + + if (i == elf_header.e_shnum) + { + printf (_("\nCould not find unwind info section for ")); + + if (string_table == NULL) + printf ("%d", unwsec->sh_name); + else + printf (_("'%s'"), SECTION_NAME (unwsec)); + } + else + { + aux.info_size = sec->sh_size; + aux.info_addr = sec->sh_addr; + aux.info = (char *) get_data (NULL, file, sec->sh_offset, + aux.info_size, _("unwind info")); + + printf (_("\nUnwind section ")); + + if (string_table == NULL) + printf ("%d", unwsec->sh_name); + else + printf (_("'%s'"), SECTION_NAME (unwsec)); + + printf (_(" at offset 0x%lx contains %lu entries:\n"), + (unsigned long) unwsec->sh_offset, + (unsigned long) (unwsec->sh_size / (3 * addr_size))); + + (void) slurp_ia64_unwind_table (file, & aux, unwsec); + + if (aux.table_len > 0) + dump_ia64_unwind (& aux); + + if (aux.table) + free ((char *) aux.table); + if (aux.info) + free ((char *) aux.info); + aux.table = NULL; + aux.info = NULL; + } + } + + if (aux.symtab) + free (aux.symtab); + if (aux.strtab) + free ((char *) aux.strtab); + + return 1; +} + +static void +dynamic_segment_mips_val (entry) + Elf_Internal_Dyn *entry; +{ + switch (entry->d_tag) + { + case DT_MIPS_FLAGS: + if (entry->d_un.d_val == 0) + printf ("NONE\n"); + else + { + static const char * opts[] = + { + "QUICKSTART", "NOTPOT", "NO_LIBRARY_REPLACEMENT", + "NO_MOVE", "SGI_ONLY", "GUARANTEE_INIT", "DELTA_C_PLUS_PLUS", + "GUARANTEE_START_INIT", "PIXIE", "DEFAULT_DELAY_LOAD", + "REQUICKSTART", "REQUICKSTARTED", "CORD", "NO_UNRES_UNDEF", + "RLD_ORDER_SAFE" + }; + unsigned int cnt; + int first = 1; + for (cnt = 0; cnt < NUM_ELEM (opts); ++cnt) + if (entry->d_un.d_val & (1 << cnt)) + { + printf ("%s%s", first ? "" : " ", opts[cnt]); + first = 0; + } + puts (""); + } + break; + + case DT_MIPS_IVERSION: + if (dynamic_strings != NULL) + printf ("Interface Version: %s\n", + dynamic_strings + entry->d_un.d_val); + else + printf ("%ld\n", (long) entry->d_un.d_ptr); + break; + + case DT_MIPS_TIME_STAMP: + { + char timebuf[20]; + struct tm *tmp; + + time_t time = entry->d_un.d_val; + tmp = gmtime (&time); + sprintf (timebuf, "%04u-%02u-%02uT%02u:%02u:%02u", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + printf ("Time Stamp: %s\n", timebuf); + } + break; + + case DT_MIPS_RLD_VERSION: + case DT_MIPS_LOCAL_GOTNO: + case DT_MIPS_CONFLICTNO: + case DT_MIPS_LIBLISTNO: + case DT_MIPS_SYMTABNO: + case DT_MIPS_UNREFEXTNO: + case DT_MIPS_HIPAGENO: + case DT_MIPS_DELTA_CLASS_NO: + case DT_MIPS_DELTA_INSTANCE_NO: + case DT_MIPS_DELTA_RELOC_NO: + case DT_MIPS_DELTA_SYM_NO: + case DT_MIPS_DELTA_CLASSSYM_NO: + case DT_MIPS_COMPACT_SIZE: + printf ("%ld\n", (long) entry->d_un.d_ptr); + break; + + default: + printf ("%#lx\n", (long) entry->d_un.d_ptr); + } +} + + +static void +dynamic_segment_parisc_val (entry) + Elf_Internal_Dyn *entry; +{ + switch (entry->d_tag) + { + case DT_HP_DLD_FLAGS: + { + static struct + { + long int bit; + const char *str; + } + flags[] = + { + { DT_HP_DEBUG_PRIVATE, "HP_DEBUG_PRIVATE" }, + { DT_HP_DEBUG_CALLBACK, "HP_DEBUG_CALLBACK" }, + { DT_HP_DEBUG_CALLBACK_BOR, "HP_DEBUG_CALLBACK_BOR" }, + { DT_HP_NO_ENVVAR, "HP_NO_ENVVAR" }, + { DT_HP_BIND_NOW, "HP_BIND_NOW" }, + { DT_HP_BIND_NONFATAL, "HP_BIND_NONFATAL" }, + { DT_HP_BIND_VERBOSE, "HP_BIND_VERBOSE" }, + { DT_HP_BIND_RESTRICTED, "HP_BIND_RESTRICTED" }, + { DT_HP_BIND_SYMBOLIC, "HP_BIND_SYMBOLIC" }, + { DT_HP_RPATH_FIRST, "HP_RPATH_FIRST" }, + { DT_HP_BIND_DEPTH_FIRST, "HP_BIND_DEPTH_FIRST" } + }; + int first = 1; + size_t cnt; + bfd_vma val = entry->d_un.d_val; + + for (cnt = 0; cnt < sizeof (flags) / sizeof (flags[0]); ++cnt) + if (val & flags[cnt].bit) + { + if (! first) + putchar (' '); + fputs (flags[cnt].str, stdout); + first = 0; + val ^= flags[cnt].bit; + } + + if (val != 0 || first) + { + if (! first) + putchar (' '); + print_vma (val, HEX); + } + } + break; + + default: + print_vma (entry->d_un.d_ptr, PREFIX_HEX); + break; + } + putchar ('\n'); +} + +static void +dynamic_segment_ia64_val (entry) + Elf_Internal_Dyn *entry; +{ + switch (entry->d_tag) + { + case DT_IA_64_PLT_RESERVE: + /* First 3 bytes reserved. */ + print_vma (entry->d_un.d_ptr, PREFIX_HEX); + printf (" -- "); + print_vma (entry->d_un.d_ptr + (3 * 8), PREFIX_HEX); + printf ("\n"); + } +} + +static int +get_32bit_dynamic_segment (file) + FILE *file; +{ + Elf32_External_Dyn *edyn; + Elf_Internal_Dyn *entry; + bfd_size_type i; + + edyn = (Elf32_External_Dyn *) get_data (NULL, file, dynamic_addr, + dynamic_size, _("dynamic segment")); + if (!edyn) + return 0; + + /* SGI's ELF has more than one section in the DYNAMIC segment. Determine + how large this .dynamic is now. We can do this even before the byte + swapping since the DT_NULL tag is recognizable. */ + dynamic_size = 0; + while (*(Elf32_Word *) edyn[dynamic_size++].d_tag != DT_NULL) + ; + + dynamic_segment = (Elf_Internal_Dyn *) + malloc (dynamic_size * sizeof (Elf_Internal_Dyn)); + + if (dynamic_segment == NULL) + { + error (_("Out of memory\n")); + free (edyn); + return 0; + } + + for (i = 0, entry = dynamic_segment; + i < dynamic_size; + i++, entry++) + { + entry->d_tag = BYTE_GET (edyn[i].d_tag); + entry->d_un.d_val = BYTE_GET (edyn[i].d_un.d_val); + } + + free (edyn); + + return 1; +} + +static int +get_64bit_dynamic_segment (file) + FILE *file; +{ + Elf64_External_Dyn *edyn; + Elf_Internal_Dyn *entry; + bfd_size_type i; + + edyn = (Elf64_External_Dyn *) get_data (NULL, file, dynamic_addr, + dynamic_size, _("dynamic segment")); + if (!edyn) + return 0; + + /* SGI's ELF has more than one section in the DYNAMIC segment. Determine + how large this .dynamic is now. We can do this even before the byte + swapping since the DT_NULL tag is recognizable. */ + dynamic_size = 0; + while (*(bfd_vma *) edyn[dynamic_size++].d_tag != DT_NULL) + ; + + dynamic_segment = (Elf_Internal_Dyn *) + malloc (dynamic_size * sizeof (Elf_Internal_Dyn)); + + if (dynamic_segment == NULL) + { + error (_("Out of memory\n")); + free (edyn); + return 0; + } + + for (i = 0, entry = dynamic_segment; + i < dynamic_size; + i++, entry++) + { + entry->d_tag = BYTE_GET8 (edyn[i].d_tag); + entry->d_un.d_val = BYTE_GET8 (edyn[i].d_un.d_val); + } + + free (edyn); + + return 1; +} + +static const char * +get_dynamic_flags (flags) + bfd_vma flags; +{ + static char buff[128]; + char *p = buff; + + *p = '\0'; + while (flags) + { + bfd_vma flag; + + flag = flags & - flags; + flags &= ~ flag; + + if (p != buff) + *p++ = ' '; + + switch (flag) + { + case DF_ORIGIN: strcpy (p, "ORIGIN"); break; + case DF_SYMBOLIC: strcpy (p, "SYMBOLIC"); break; + case DF_TEXTREL: strcpy (p, "TEXTREL"); break; + case DF_BIND_NOW: strcpy (p, "BIND_NOW"); break; + case DF_STATIC_TLS: strcpy (p, "STATIC_TLS"); break; + default: strcpy (p, "unknown"); break; + } + + p = strchr (p, '\0'); + } + return buff; +} + +/* Parse and display the contents of the dynamic segment. */ +static int +process_dynamic_segment (file) + FILE *file; +{ + Elf_Internal_Dyn *entry; + bfd_size_type i; + + if (dynamic_size == 0) + { + if (do_dynamic) + printf (_("\nThere is no dynamic segment in this file.\n")); + + return 1; + } + + if (is_32bit_elf) + { + if (! get_32bit_dynamic_segment (file)) + return 0; + } + else if (! get_64bit_dynamic_segment (file)) + return 0; + + /* Find the appropriate symbol table. */ + if (dynamic_symbols == NULL) + { + for (i = 0, entry = dynamic_segment; + i < dynamic_size; + ++i, ++entry) + { + Elf_Internal_Shdr section; + + if (entry->d_tag != DT_SYMTAB) + continue; + + dynamic_info[DT_SYMTAB] = entry->d_un.d_val; + + /* Since we do not know how big the symbol table is, + we default to reading in the entire file (!) and + processing that. This is overkill, I know, but it + should work. */ + section.sh_offset = entry->d_un.d_val - loadaddr; + + if (fseek (file, 0, SEEK_END)) + error (_("Unable to seek to end of file!")); + + section.sh_size = ftell (file) - section.sh_offset; + if (is_32bit_elf) + section.sh_entsize = sizeof (Elf32_External_Sym); + else + section.sh_entsize = sizeof (Elf64_External_Sym); + + num_dynamic_syms = section.sh_size / section.sh_entsize; + if (num_dynamic_syms < 1) + { + error (_("Unable to determine the number of symbols to load\n")); + continue; + } + + dynamic_symbols = GET_ELF_SYMBOLS (file, §ion); + } + } + + /* Similarly find a string table. */ + if (dynamic_strings == NULL) + { + for (i = 0, entry = dynamic_segment; + i < dynamic_size; + ++i, ++entry) + { + unsigned long offset; + long str_tab_len; + + if (entry->d_tag != DT_STRTAB) + continue; + + dynamic_info[DT_STRTAB] = entry->d_un.d_val; + + /* Since we do not know how big the string table is, + we default to reading in the entire file (!) and + processing that. This is overkill, I know, but it + should work. */ + + offset = entry->d_un.d_val - loadaddr; + if (fseek (file, 0, SEEK_END)) + error (_("Unable to seek to end of file\n")); + str_tab_len = ftell (file) - offset; + + if (str_tab_len < 1) + { + error + (_("Unable to determine the length of the dynamic string table\n")); + continue; + } + + dynamic_strings = (char *) get_data (NULL, file, offset, str_tab_len, + _("dynamic string table")); + break; + } + } + + /* And find the syminfo section if available. */ + if (dynamic_syminfo == NULL) + { + unsigned long syminsz = 0; + + for (i = 0, entry = dynamic_segment; + i < dynamic_size; + ++i, ++entry) + { + if (entry->d_tag == DT_SYMINENT) + { + /* Note: these braces are necessary to avoid a syntax + error from the SunOS4 C compiler. */ + assert (sizeof (Elf_External_Syminfo) == entry->d_un.d_val); + } + else if (entry->d_tag == DT_SYMINSZ) + syminsz = entry->d_un.d_val; + else if (entry->d_tag == DT_SYMINFO) + dynamic_syminfo_offset = entry->d_un.d_val - loadaddr; + } + + if (dynamic_syminfo_offset != 0 && syminsz != 0) + { + Elf_External_Syminfo *extsyminfo; + Elf_Internal_Syminfo *syminfo; + + /* There is a syminfo section. Read the data. */ + extsyminfo = ((Elf_External_Syminfo *) + get_data (NULL, file, dynamic_syminfo_offset, + syminsz, _("symbol information"))); + if (!extsyminfo) + return 0; + + dynamic_syminfo = (Elf_Internal_Syminfo *) malloc (syminsz); + if (dynamic_syminfo == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + dynamic_syminfo_nent = syminsz / sizeof (Elf_External_Syminfo); + for (i = 0, syminfo = dynamic_syminfo; i < dynamic_syminfo_nent; + ++i, ++syminfo) + { + syminfo->si_boundto = BYTE_GET (extsyminfo[i].si_boundto); + syminfo->si_flags = BYTE_GET (extsyminfo[i].si_flags); + } + + free (extsyminfo); + } + } + + if (do_dynamic && dynamic_addr) + printf (_("\nDynamic segment at offset 0x%lx contains %ld entries:\n"), + dynamic_addr, (long) dynamic_size); + if (do_dynamic) + printf (_(" Tag Type Name/Value\n")); + + for (i = 0, entry = dynamic_segment; + i < dynamic_size; + i++, entry++) + { + if (do_dynamic) + { + const char *dtype; + + putchar (' '); + print_vma (entry->d_tag, FULL_HEX); + dtype = get_dynamic_type (entry->d_tag); + printf (" (%s)%*s", dtype, + ((is_32bit_elf ? 27 : 19) + - (int) strlen (dtype)), + " "); + } + + switch (entry->d_tag) + { + case DT_FLAGS: + if (do_dynamic) + puts (get_dynamic_flags (entry->d_un.d_val)); + break; + + case DT_AUXILIARY: + case DT_FILTER: + case DT_CONFIG: + case DT_DEPAUDIT: + case DT_AUDIT: + if (do_dynamic) + { + switch (entry->d_tag) + { + case DT_AUXILIARY: + printf (_("Auxiliary library")); + break; + + case DT_FILTER: + printf (_("Filter library")); + break; + + case DT_CONFIG: + printf (_("Configuration file")); + break; + + case DT_DEPAUDIT: + printf (_("Dependency audit library")); + break; + + case DT_AUDIT: + printf (_("Audit library")); + break; + } + + if (dynamic_strings) + printf (": [%s]\n", dynamic_strings + entry->d_un.d_val); + else + { + printf (": "); + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); + } + } + break; + + case DT_FEATURE: + if (do_dynamic) + { + printf (_("Flags:")); + + if (entry->d_un.d_val == 0) + printf (_(" None\n")); + else + { + unsigned long int val = entry->d_un.d_val; + + if (val & DTF_1_PARINIT) + { + printf (" PARINIT"); + val ^= DTF_1_PARINIT; + } + if (val & DTF_1_CONFEXP) + { + printf (" CONFEXP"); + val ^= DTF_1_CONFEXP; + } + if (val != 0) + printf (" %lx", val); + puts (""); + } + } + break; + + case DT_POSFLAG_1: + if (do_dynamic) + { + printf (_("Flags:")); + + if (entry->d_un.d_val == 0) + printf (_(" None\n")); + else + { + unsigned long int val = entry->d_un.d_val; + + if (val & DF_P1_LAZYLOAD) + { + printf (" LAZYLOAD"); + val ^= DF_P1_LAZYLOAD; + } + if (val & DF_P1_GROUPPERM) + { + printf (" GROUPPERM"); + val ^= DF_P1_GROUPPERM; + } + if (val != 0) + printf (" %lx", val); + puts (""); + } + } + break; + + case DT_FLAGS_1: + if (do_dynamic) + { + printf (_("Flags:")); + if (entry->d_un.d_val == 0) + printf (_(" None\n")); + else + { + unsigned long int val = entry->d_un.d_val; + + if (val & DF_1_NOW) + { + printf (" NOW"); + val ^= DF_1_NOW; + } + if (val & DF_1_GLOBAL) + { + printf (" GLOBAL"); + val ^= DF_1_GLOBAL; + } + if (val & DF_1_GROUP) + { + printf (" GROUP"); + val ^= DF_1_GROUP; + } + if (val & DF_1_NODELETE) + { + printf (" NODELETE"); + val ^= DF_1_NODELETE; + } + if (val & DF_1_LOADFLTR) + { + printf (" LOADFLTR"); + val ^= DF_1_LOADFLTR; + } + if (val & DF_1_INITFIRST) + { + printf (" INITFIRST"); + val ^= DF_1_INITFIRST; + } + if (val & DF_1_NOOPEN) + { + printf (" NOOPEN"); + val ^= DF_1_NOOPEN; + } + if (val & DF_1_ORIGIN) + { + printf (" ORIGIN"); + val ^= DF_1_ORIGIN; + } + if (val & DF_1_DIRECT) + { + printf (" DIRECT"); + val ^= DF_1_DIRECT; + } + if (val & DF_1_TRANS) + { + printf (" TRANS"); + val ^= DF_1_TRANS; + } + if (val & DF_1_INTERPOSE) + { + printf (" INTERPOSE"); + val ^= DF_1_INTERPOSE; + } + if (val & DF_1_NODEFLIB) + { + printf (" NODEFLIB"); + val ^= DF_1_NODEFLIB; + } + if (val & DF_1_NODUMP) + { + printf (" NODUMP"); + val ^= DF_1_NODUMP; + } + if (val & DF_1_CONLFAT) + { + printf (" CONLFAT"); + val ^= DF_1_CONLFAT; + } + if (val != 0) + printf (" %lx", val); + puts (""); + } + } + break; + + case DT_PLTREL: + dynamic_info[entry->d_tag] = entry->d_un.d_val; + if (do_dynamic) + puts (get_dynamic_type (entry->d_un.d_val)); + break; + + case DT_NULL : + case DT_NEEDED : + case DT_PLTGOT : + case DT_HASH : + case DT_STRTAB : + case DT_SYMTAB : + case DT_RELA : + case DT_INIT : + case DT_FINI : + case DT_SONAME : + case DT_RPATH : + case DT_SYMBOLIC: + case DT_REL : + case DT_DEBUG : + case DT_TEXTREL : + case DT_JMPREL : + case DT_RUNPATH : + dynamic_info[entry->d_tag] = entry->d_un.d_val; + + if (do_dynamic) + { + char *name; + + if (dynamic_strings == NULL) + name = NULL; + else + name = dynamic_strings + entry->d_un.d_val; + + if (name) + { + switch (entry->d_tag) + { + case DT_NEEDED: + printf (_("Shared library: [%s]"), name); + + if (strcmp (name, program_interpreter) == 0) + printf (_(" program interpreter")); + break; + + case DT_SONAME: + printf (_("Library soname: [%s]"), name); + break; + + case DT_RPATH: + printf (_("Library rpath: [%s]"), name); + break; + + case DT_RUNPATH: + printf (_("Library runpath: [%s]"), name); + break; + + default: + print_vma (entry->d_un.d_val, PREFIX_HEX); + break; + } + } + else + print_vma (entry->d_un.d_val, PREFIX_HEX); + + putchar ('\n'); + } + break; + + case DT_PLTRELSZ: + case DT_RELASZ : + case DT_STRSZ : + case DT_RELSZ : + case DT_RELAENT : + case DT_SYMENT : + case DT_RELENT : + dynamic_info[entry->d_tag] = entry->d_un.d_val; + case DT_PLTPADSZ: + case DT_MOVEENT : + case DT_MOVESZ : + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_GNU_CONFLICTSZ: + case DT_GNU_LIBLISTSZ: + if (do_dynamic) + { + print_vma (entry->d_un.d_val, UNSIGNED); + printf (" (bytes)\n"); + } + break; + + case DT_VERDEFNUM: + case DT_VERNEEDNUM: + case DT_RELACOUNT: + case DT_RELCOUNT: + if (do_dynamic) + { + print_vma (entry->d_un.d_val, UNSIGNED); + putchar ('\n'); + } + break; + + case DT_SYMINSZ: + case DT_SYMINENT: + case DT_SYMINFO: + case DT_USED: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + if (do_dynamic) + { + if (dynamic_strings != NULL && entry->d_tag == DT_USED) + { + char *name; + + name = dynamic_strings + entry->d_un.d_val; + + if (*name) + { + printf (_("Not needed object: [%s]\n"), name); + break; + } + } + + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); + } + break; + + case DT_BIND_NOW: + /* The value of this entry is ignored. */ + if (do_dynamic) + putchar ('\n'); + break; + + case DT_GNU_PRELINKED: + if (do_dynamic) + { + struct tm *tmp; + time_t time = entry->d_un.d_val; + + tmp = gmtime (&time); + printf ("%04u-%02u-%02uT%02u:%02u:%02u\n", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + } + break; + + default: + if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM)) + version_info[DT_VERSIONTAGIDX (entry->d_tag)] = + entry->d_un.d_val; + + if (do_dynamic) + { + switch (elf_header.e_machine) + { + case EM_MIPS: + case EM_MIPS_RS3_LE: + dynamic_segment_mips_val (entry); + break; + case EM_PARISC: + dynamic_segment_parisc_val (entry); + break; + case EM_IA_64: + dynamic_segment_ia64_val (entry); + break; + default: + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); + } + } + break; + } + } + + return 1; +} + +static char * +get_ver_flags (flags) + unsigned int flags; +{ + static char buff[32]; + + buff[0] = 0; + + if (flags == 0) + return _("none"); + + if (flags & VER_FLG_BASE) + strcat (buff, "BASE "); + + if (flags & VER_FLG_WEAK) + { + if (flags & VER_FLG_BASE) + strcat (buff, "| "); + + strcat (buff, "WEAK "); + } + + if (flags & ~(VER_FLG_BASE | VER_FLG_WEAK)) + strcat (buff, "| "); + + return buff; +} + +/* Display the contents of the version sections. */ +static int +process_version_sections (file) + FILE *file; +{ + Elf_Internal_Shdr *section; + unsigned i; + int found = 0; + + if (! do_version) + return 1; + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + switch (section->sh_type) + { + case SHT_GNU_verdef: + { + Elf_External_Verdef *edefs; + unsigned int idx; + unsigned int cnt; + + found = 1; + + printf + (_("\nVersion definition section '%s' contains %ld entries:\n"), + SECTION_NAME (section), section->sh_info); + + printf (_(" Addr: 0x")); + printf_vma (section->sh_addr); + printf (_(" Offset: %#08lx Link: %lx (%s)\n"), + (unsigned long) section->sh_offset, section->sh_link, + SECTION_NAME (SECTION_HEADER (section->sh_link))); + + edefs = ((Elf_External_Verdef *) + get_data (NULL, file, section->sh_offset, + section->sh_size, + _("version definition section"))); + if (!edefs) + break; + + for (idx = cnt = 0; cnt < section->sh_info; ++cnt) + { + char *vstart; + Elf_External_Verdef *edef; + Elf_Internal_Verdef ent; + Elf_External_Verdaux *eaux; + Elf_Internal_Verdaux aux; + int j; + int isum; + + vstart = ((char *) edefs) + idx; + + edef = (Elf_External_Verdef *) vstart; + + ent.vd_version = BYTE_GET (edef->vd_version); + ent.vd_flags = BYTE_GET (edef->vd_flags); + ent.vd_ndx = BYTE_GET (edef->vd_ndx); + ent.vd_cnt = BYTE_GET (edef->vd_cnt); + ent.vd_hash = BYTE_GET (edef->vd_hash); + ent.vd_aux = BYTE_GET (edef->vd_aux); + ent.vd_next = BYTE_GET (edef->vd_next); + + printf (_(" %#06x: Rev: %d Flags: %s"), + idx, ent.vd_version, get_ver_flags (ent.vd_flags)); + + printf (_(" Index: %d Cnt: %d "), + ent.vd_ndx, ent.vd_cnt); + + vstart += ent.vd_aux; + + eaux = (Elf_External_Verdaux *) vstart; + + aux.vda_name = BYTE_GET (eaux->vda_name); + aux.vda_next = BYTE_GET (eaux->vda_next); + + if (dynamic_strings) + printf (_("Name: %s\n"), dynamic_strings + aux.vda_name); + else + printf (_("Name index: %ld\n"), aux.vda_name); + + isum = idx + ent.vd_aux; + + for (j = 1; j < ent.vd_cnt; j++) + { + isum += aux.vda_next; + vstart += aux.vda_next; + + eaux = (Elf_External_Verdaux *) vstart; + + aux.vda_name = BYTE_GET (eaux->vda_name); + aux.vda_next = BYTE_GET (eaux->vda_next); + + if (dynamic_strings) + printf (_(" %#06x: Parent %d: %s\n"), + isum, j, dynamic_strings + aux.vda_name); + else + printf (_(" %#06x: Parent %d, name index: %ld\n"), + isum, j, aux.vda_name); + } + + idx += ent.vd_next; + } + + free (edefs); + } + break; + + case SHT_GNU_verneed: + { + Elf_External_Verneed *eneed; + unsigned int idx; + unsigned int cnt; + + found = 1; + + printf (_("\nVersion needs section '%s' contains %ld entries:\n"), + SECTION_NAME (section), section->sh_info); + + printf (_(" Addr: 0x")); + printf_vma (section->sh_addr); + printf (_(" Offset: %#08lx Link to section: %ld (%s)\n"), + (unsigned long) section->sh_offset, section->sh_link, + SECTION_NAME (SECTION_HEADER (section->sh_link))); + + eneed = ((Elf_External_Verneed *) + get_data (NULL, file, section->sh_offset, + section->sh_size, _("version need section"))); + if (!eneed) + break; + + for (idx = cnt = 0; cnt < section->sh_info; ++cnt) + { + Elf_External_Verneed *entry; + Elf_Internal_Verneed ent; + int j; + int isum; + char *vstart; + + vstart = ((char *) eneed) + idx; + + entry = (Elf_External_Verneed *) vstart; + + ent.vn_version = BYTE_GET (entry->vn_version); + ent.vn_cnt = BYTE_GET (entry->vn_cnt); + ent.vn_file = BYTE_GET (entry->vn_file); + ent.vn_aux = BYTE_GET (entry->vn_aux); + ent.vn_next = BYTE_GET (entry->vn_next); + + printf (_(" %#06x: Version: %d"), idx, ent.vn_version); + + if (dynamic_strings) + printf (_(" File: %s"), dynamic_strings + ent.vn_file); + else + printf (_(" File: %lx"), ent.vn_file); + + printf (_(" Cnt: %d\n"), ent.vn_cnt); + + vstart += ent.vn_aux; + + for (j = 0, isum = idx + ent.vn_aux; j < ent.vn_cnt; ++j) + { + Elf_External_Vernaux *eaux; + Elf_Internal_Vernaux aux; + + eaux = (Elf_External_Vernaux *) vstart; + + aux.vna_hash = BYTE_GET (eaux->vna_hash); + aux.vna_flags = BYTE_GET (eaux->vna_flags); + aux.vna_other = BYTE_GET (eaux->vna_other); + aux.vna_name = BYTE_GET (eaux->vna_name); + aux.vna_next = BYTE_GET (eaux->vna_next); + + if (dynamic_strings) + printf (_(" %#06x: Name: %s"), + isum, dynamic_strings + aux.vna_name); + else + printf (_(" %#06x: Name index: %lx"), + isum, aux.vna_name); + + printf (_(" Flags: %s Version: %d\n"), + get_ver_flags (aux.vna_flags), aux.vna_other); + + isum += aux.vna_next; + vstart += aux.vna_next; + } + + idx += ent.vn_next; + } + + free (eneed); + } + break; + + case SHT_GNU_versym: + { + Elf_Internal_Shdr *link_section; + int total; + int cnt; + unsigned char *edata; + unsigned short *data; + char *strtab; + Elf_Internal_Sym *symbols; + Elf_Internal_Shdr *string_sec; + + link_section = SECTION_HEADER (section->sh_link); + total = section->sh_size / section->sh_entsize; + + found = 1; + + symbols = GET_ELF_SYMBOLS (file, link_section); + + string_sec = SECTION_HEADER (link_section->sh_link); + + strtab = (char *) get_data (NULL, file, string_sec->sh_offset, + string_sec->sh_size, + _("version string table")); + if (!strtab) + break; + + printf (_("\nVersion symbols section '%s' contains %d entries:\n"), + SECTION_NAME (section), total); + + printf (_(" Addr: ")); + printf_vma (section->sh_addr); + printf (_(" Offset: %#08lx Link: %lx (%s)\n"), + (unsigned long) section->sh_offset, section->sh_link, + SECTION_NAME (link_section)); + + edata = + ((unsigned char *) + get_data (NULL, file, + version_info[DT_VERSIONTAGIDX (DT_VERSYM)] - loadaddr, + total * sizeof (short), _("version symbol data"))); + if (!edata) + { + free (strtab); + break; + } + + data = (unsigned short *) malloc (total * sizeof (short)); + + for (cnt = total; cnt --;) + data[cnt] = byte_get (edata + cnt * sizeof (short), + sizeof (short)); + + free (edata); + + for (cnt = 0; cnt < total; cnt += 4) + { + int j, nn; + int check_def, check_need; + char *name; + + printf (" %03x:", cnt); + + for (j = 0; (j < 4) && (cnt + j) < total; ++j) + switch (data[cnt + j]) + { + case 0: + fputs (_(" 0 (*local*) "), stdout); + break; + + case 1: + fputs (_(" 1 (*global*) "), stdout); + break; + + default: + nn = printf ("%4x%c", data[cnt + j] & 0x7fff, + data[cnt + j] & 0x8000 ? 'h' : ' '); + + check_def = 1; + check_need = 1; + if (SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type + != SHT_NOBITS) + { + if (symbols[cnt + j].st_shndx == SHN_UNDEF) + check_def = 0; + else + check_need = 0; + } + + if (check_need + && version_info[DT_VERSIONTAGIDX (DT_VERNEED)]) + { + Elf_Internal_Verneed ivn; + unsigned long offset; + + offset = version_info[DT_VERSIONTAGIDX (DT_VERNEED)] + - loadaddr; + + do + { + Elf_Internal_Vernaux ivna; + Elf_External_Verneed evn; + Elf_External_Vernaux evna; + unsigned long a_off; + + get_data (&evn, file, offset, sizeof (evn), + _("version need")); + + ivn.vn_aux = BYTE_GET (evn.vn_aux); + ivn.vn_next = BYTE_GET (evn.vn_next); + + a_off = offset + ivn.vn_aux; + + do + { + get_data (&evna, file, a_off, sizeof (evna), + _("version need aux (2)")); + + ivna.vna_next = BYTE_GET (evna.vna_next); + ivna.vna_other = BYTE_GET (evna.vna_other); + + a_off += ivna.vna_next; + } + while (ivna.vna_other != data[cnt + j] + && ivna.vna_next != 0); + + if (ivna.vna_other == data[cnt + j]) + { + ivna.vna_name = BYTE_GET (evna.vna_name); + + name = strtab + ivna.vna_name; + nn += printf ("(%s%-*s", + name, + 12 - (int) strlen (name), + ")"); + check_def = 0; + break; + } + + offset += ivn.vn_next; + } + while (ivn.vn_next); + } + + if (check_def && data[cnt + j] != 0x8001 + && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) + { + Elf_Internal_Verdef ivd; + Elf_External_Verdef evd; + unsigned long offset; + + offset = (version_info[DT_VERSIONTAGIDX (DT_VERDEF)] + - loadaddr); + + do + { + get_data (&evd, file, offset, sizeof (evd), + _("version def")); + + ivd.vd_next = BYTE_GET (evd.vd_next); + ivd.vd_ndx = BYTE_GET (evd.vd_ndx); + + offset += ivd.vd_next; + } + while (ivd.vd_ndx != (data[cnt + j] & 0x7fff) + && ivd.vd_next != 0); + + if (ivd.vd_ndx == (data[cnt + j] & 0x7fff)) + { + Elf_External_Verdaux evda; + Elf_Internal_Verdaux ivda; + + ivd.vd_aux = BYTE_GET (evd.vd_aux); + + get_data (&evda, file, + offset - ivd.vd_next + ivd.vd_aux, + sizeof (evda), _("version def aux")); + + ivda.vda_name = BYTE_GET (evda.vda_name); + + name = strtab + ivda.vda_name; + nn += printf ("(%s%-*s", + name, + 12 - (int) strlen (name), + ")"); + } + } + + if (nn < 18) + printf ("%*c", 18 - nn, ' '); + } + + putchar ('\n'); + } + + free (data); + free (strtab); + free (symbols); + } + break; + + default: + break; + } + } + + if (! found) + printf (_("\nNo version information found in this file.\n")); + + return 1; +} + +static const char * +get_symbol_binding (binding) + unsigned int binding; +{ + static char buff[32]; + + switch (binding) + { + case STB_LOCAL: return "LOCAL"; + case STB_GLOBAL: return "GLOBAL"; + case STB_WEAK: return "WEAK"; + default: + if (binding >= STB_LOPROC && binding <= STB_HIPROC) + sprintf (buff, _(": %d"), binding); + else if (binding >= STB_LOOS && binding <= STB_HIOS) + sprintf (buff, _(": %d"), binding); + else + sprintf (buff, _(": %d"), binding); + return buff; + } +} + +static const char * +get_symbol_type (type) + unsigned int type; +{ + static char buff[32]; + + switch (type) + { + case STT_NOTYPE: return "NOTYPE"; + case STT_OBJECT: return "OBJECT"; + case STT_FUNC: return "FUNC"; + case STT_SECTION: return "SECTION"; + case STT_FILE: return "FILE"; + case STT_COMMON: return "COMMON"; + case STT_TLS: return "TLS"; + default: + if (type >= STT_LOPROC && type <= STT_HIPROC) + { + if (elf_header.e_machine == EM_ARM && type == STT_ARM_TFUNC) + return "THUMB_FUNC"; + + if (elf_header.e_machine == EM_SPARCV9 && type == STT_REGISTER) + return "REGISTER"; + + if (elf_header.e_machine == EM_PARISC && type == STT_PARISC_MILLI) + return "PARISC_MILLI"; + + sprintf (buff, _(": %d"), type); + } + else if (type >= STT_LOOS && type <= STT_HIOS) + { + if (elf_header.e_machine == EM_PARISC) + { + if (type == STT_HP_OPAQUE) + return "HP_OPAQUE"; + if (type == STT_HP_STUB) + return "HP_STUB"; + } + + sprintf (buff, _(": %d"), type); + } + else + sprintf (buff, _(": %d"), type); + return buff; + } +} + +static const char * +get_symbol_visibility (visibility) + unsigned int visibility; +{ + switch (visibility) + { + case STV_DEFAULT: return "DEFAULT"; + case STV_INTERNAL: return "INTERNAL"; + case STV_HIDDEN: return "HIDDEN"; + case STV_PROTECTED: return "PROTECTED"; + default: abort (); + } +} + +static const char * +get_symbol_index_type (type) + unsigned int type; +{ + static char buff[32]; + + switch (type) + { + case SHN_UNDEF: return "UND"; + case SHN_ABS: return "ABS"; + case SHN_COMMON: return "COM"; + default: + if (type >= SHN_LOPROC && type <= SHN_HIPROC) + sprintf (buff, "PRC[0x%04x]", type); + else if (type >= SHN_LOOS && type <= SHN_HIOS) + sprintf (buff, "OS [0x%04x]", type); + else if (type >= SHN_LORESERVE && type <= SHN_HIRESERVE) + sprintf (buff, "RSV[0x%04x]", type); + else + sprintf (buff, "%3d", type); + break; + } + + return buff; +} + +static int * +get_dynamic_data (file, number) + FILE *file; + unsigned int number; +{ + unsigned char *e_data; + int *i_data; + + e_data = (unsigned char *) malloc (number * 4); + + if (e_data == NULL) + { + error (_("Out of memory\n")); + return NULL; + } + + if (fread (e_data, 4, number, file) != number) + { + error (_("Unable to read in dynamic data\n")); + return NULL; + } + + i_data = (int *) malloc (number * sizeof (*i_data)); + + if (i_data == NULL) + { + error (_("Out of memory\n")); + free (e_data); + return NULL; + } + + while (number--) + i_data[number] = byte_get (e_data + number * 4, 4); + + free (e_data); + + return i_data; +} + +/* Dump the symbol table. */ +static int +process_symbol_table (file) + FILE *file; +{ + Elf_Internal_Shdr *section; + unsigned char nb[4]; + unsigned char nc[4]; + int nbuckets = 0; + int nchains = 0; + int *buckets = NULL; + int *chains = NULL; + + if (! do_syms && !do_histogram) + return 1; + + if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL) + || do_histogram)) + { + if (fseek (file, dynamic_info[DT_HASH] - loadaddr, SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information")); + return 0; + } + + if (fread (nb, sizeof (nb), 1, file) != 1) + { + error (_("Failed to read in number of buckets\n")); + return 0; + } + + if (fread (nc, sizeof (nc), 1, file) != 1) + { + error (_("Failed to read in number of chains\n")); + return 0; + } + + nbuckets = byte_get (nb, 4); + nchains = byte_get (nc, 4); + + buckets = get_dynamic_data (file, nbuckets); + chains = get_dynamic_data (file, nchains); + + if (buckets == NULL || chains == NULL) + return 0; + } + + if (do_syms + && dynamic_info[DT_HASH] && do_using_dynamic && dynamic_strings != NULL) + { + int hn; + int si; + + printf (_("\nSymbol table for image:\n")); + if (is_32bit_elf) + printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); + else + printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); + + for (hn = 0; hn < nbuckets; hn++) + { + if (! buckets[hn]) + continue; + + for (si = buckets[hn]; si < nchains && si > 0; si = chains[si]) + { + Elf_Internal_Sym *psym; + + psym = dynamic_symbols + si; + + printf (" %3d %3d: ", si, hn); + print_vma (psym->st_value, LONG_HEX); + putchar (' ' ); + print_vma (psym->st_size, DEC_5); + + printf (" %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info))); + printf (" %6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); + printf (" %3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); + printf (" %3.3s ", get_symbol_index_type (psym->st_shndx)); + print_symbol (25, dynamic_strings + psym->st_name); + putchar ('\n'); + } + } + } + else if (do_syms && !do_using_dynamic) + { + unsigned int i; + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + unsigned int si; + char *strtab; + Elf_Internal_Sym *symtab; + Elf_Internal_Sym *psym; + + + if ( section->sh_type != SHT_SYMTAB + && section->sh_type != SHT_DYNSYM) + continue; + + printf (_("\nSymbol table '%s' contains %lu entries:\n"), + SECTION_NAME (section), + (unsigned long) (section->sh_size / section->sh_entsize)); + if (is_32bit_elf) + printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); + else + printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); + + symtab = GET_ELF_SYMBOLS (file, section); + if (symtab == NULL) + continue; + + if (section->sh_link == elf_header.e_shstrndx) + strtab = string_table; + else + { + Elf_Internal_Shdr *string_sec; + + string_sec = SECTION_HEADER (section->sh_link); + + strtab = (char *) get_data (NULL, file, string_sec->sh_offset, + string_sec->sh_size, + _("string table")); + } + + for (si = 0, psym = symtab; + si < section->sh_size / section->sh_entsize; + si++, psym++) + { + printf ("%6d: ", si); + print_vma (psym->st_value, LONG_HEX); + putchar (' '); + print_vma (psym->st_size, DEC_5); + printf (" %-7s", get_symbol_type (ELF_ST_TYPE (psym->st_info))); + printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); + printf (" %-3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); + printf (" %4s ", get_symbol_index_type (psym->st_shndx)); + print_symbol (25, strtab + psym->st_name); + + if (section->sh_type == SHT_DYNSYM && + version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0) + { + unsigned char data[2]; + unsigned short vers_data; + unsigned long offset; + int is_nobits; + int check_def; + + offset = version_info[DT_VERSIONTAGIDX (DT_VERSYM)] + - loadaddr; + + get_data (&data, file, offset + si * sizeof (vers_data), + sizeof (data), _("version data")); + + vers_data = byte_get (data, 2); + + is_nobits = (SECTION_HEADER (psym->st_shndx)->sh_type + == SHT_NOBITS); + + check_def = (psym->st_shndx != SHN_UNDEF); + + if ((vers_data & 0x8000) || vers_data > 1) + { + if (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] + && (is_nobits || ! check_def)) + { + Elf_External_Verneed evn; + Elf_Internal_Verneed ivn; + Elf_Internal_Vernaux ivna; + + /* We must test both. */ + offset = (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] + - loadaddr); + + do + { + unsigned long vna_off; + + get_data (&evn, file, offset, sizeof (evn), + _("version need")); + + ivn.vn_aux = BYTE_GET (evn.vn_aux); + ivn.vn_next = BYTE_GET (evn.vn_next); + + vna_off = offset + ivn.vn_aux; + + do + { + Elf_External_Vernaux evna; + + get_data (&evna, file, vna_off, + sizeof (evna), + _("version need aux (3)")); + + ivna.vna_other = BYTE_GET (evna.vna_other); + ivna.vna_next = BYTE_GET (evna.vna_next); + ivna.vna_name = BYTE_GET (evna.vna_name); + + vna_off += ivna.vna_next; + } + while (ivna.vna_other != vers_data + && ivna.vna_next != 0); + + if (ivna.vna_other == vers_data) + break; + + offset += ivn.vn_next; + } + while (ivn.vn_next != 0); + + if (ivna.vna_other == vers_data) + { + printf ("@%s (%d)", + strtab + ivna.vna_name, ivna.vna_other); + check_def = 0; + } + else if (! is_nobits) + error (_("bad dynamic symbol")); + else + check_def = 1; + } + + if (check_def) + { + if (vers_data != 0x8001 + && version_info[DT_VERSIONTAGIDX (DT_VERDEF)]) + { + Elf_Internal_Verdef ivd; + Elf_Internal_Verdaux ivda; + Elf_External_Verdaux evda; + unsigned long offset; + + offset + = (version_info[DT_VERSIONTAGIDX (DT_VERDEF)] + - loadaddr); + + do + { + Elf_External_Verdef evd; + + get_data (&evd, file, offset, sizeof (evd), + _("version def")); + + ivd.vd_ndx = BYTE_GET (evd.vd_ndx); + ivd.vd_aux = BYTE_GET (evd.vd_aux); + ivd.vd_next = BYTE_GET (evd.vd_next); + + offset += ivd.vd_next; + } + while (ivd.vd_ndx != (vers_data & 0x7fff) + && ivd.vd_next != 0); + + offset -= ivd.vd_next; + offset += ivd.vd_aux; + + get_data (&evda, file, offset, sizeof (evda), + _("version def aux")); + + ivda.vda_name = BYTE_GET (evda.vda_name); + + if (psym->st_name != ivda.vda_name) + printf ((vers_data & 0x8000) + ? "@%s" : "@@%s", + strtab + ivda.vda_name); + } + } + } + } + + putchar ('\n'); + } + + free (symtab); + if (strtab != string_table) + free (strtab); + } + } + else if (do_syms) + printf + (_("\nDynamic symbol information is not available for displaying symbols.\n")); + + if (do_histogram && buckets != NULL) + { + int *lengths; + int *counts; + int hn; + int si; + int maxlength = 0; + int nzero_counts = 0; + int nsyms = 0; + + printf (_("\nHistogram for bucket list length (total of %d buckets):\n"), + nbuckets); + printf (_(" Length Number %% of total Coverage\n")); + + lengths = (int *) calloc (nbuckets, sizeof (int)); + if (lengths == NULL) + { + error (_("Out of memory")); + return 0; + } + for (hn = 0; hn < nbuckets; ++hn) + { + if (! buckets[hn]) + continue; + + for (si = buckets[hn]; si > 0 && si < nchains; si = chains[si]) + { + ++nsyms; + if (maxlength < ++lengths[hn]) + ++maxlength; + } + } + + counts = (int *) calloc (maxlength + 1, sizeof (int)); + if (counts == NULL) + { + error (_("Out of memory")); + return 0; + } + + for (hn = 0; hn < nbuckets; ++hn) + ++counts[lengths[hn]]; + + if (nbuckets > 0) + { + printf (" 0 %-10d (%5.1f%%)\n", + counts[0], (counts[0] * 100.0) / nbuckets); + for (si = 1; si <= maxlength; ++si) + { + nzero_counts += counts[si] * si; + printf ("%7d %-10d (%5.1f%%) %5.1f%%\n", + si, counts[si], (counts[si] * 100.0) / nbuckets, + (nzero_counts * 100.0) / nsyms); + } + } + + free (counts); + free (lengths); + } + + if (buckets != NULL) + { + free (buckets); + free (chains); + } + + return 1; +} + +static int +process_syminfo (file) + FILE *file ATTRIBUTE_UNUSED; +{ + unsigned int i; + + if (dynamic_syminfo == NULL + || !do_dynamic) + /* No syminfo, this is ok. */ + return 1; + + /* There better should be a dynamic symbol section. */ + if (dynamic_symbols == NULL || dynamic_strings == NULL) + return 0; + + if (dynamic_addr) + printf (_("\nDynamic info segment at offset 0x%lx contains %d entries:\n"), + dynamic_syminfo_offset, dynamic_syminfo_nent); + + printf (_(" Num: Name BoundTo Flags\n")); + for (i = 0; i < dynamic_syminfo_nent; ++i) + { + unsigned short int flags = dynamic_syminfo[i].si_flags; + + printf ("%4d: ", i); + print_symbol (30, dynamic_strings + dynamic_symbols[i].st_name); + putchar (' '); + + switch (dynamic_syminfo[i].si_boundto) + { + case SYMINFO_BT_SELF: + fputs ("SELF ", stdout); + break; + case SYMINFO_BT_PARENT: + fputs ("PARENT ", stdout); + break; + default: + if (dynamic_syminfo[i].si_boundto > 0 + && dynamic_syminfo[i].si_boundto < dynamic_size) + { + print_symbol (10, + dynamic_strings + + (dynamic_segment + [dynamic_syminfo[i].si_boundto].d_un.d_val)); + putchar (' ' ); + } + else + printf ("%-10d ", dynamic_syminfo[i].si_boundto); + break; + } + + if (flags & SYMINFO_FLG_DIRECT) + printf (" DIRECT"); + if (flags & SYMINFO_FLG_PASSTHRU) + printf (" PASSTHRU"); + if (flags & SYMINFO_FLG_COPY) + printf (" COPY"); + if (flags & SYMINFO_FLG_LAZYLOAD) + printf (" LAZYLOAD"); + + puts (""); + } + + return 1; +} + +#ifdef SUPPORT_DISASSEMBLY +static void +disassemble_section (section, file) + Elf_Internal_Shdr *section; + FILE *file; +{ + printf (_("\nAssembly dump of section %s\n"), + SECTION_NAME (section)); + + /* XXX -- to be done --- XXX */ + + return 1; +} +#endif + +static int +dump_section (section, file) + Elf_Internal_Shdr *section; + FILE *file; +{ + bfd_size_type bytes; + bfd_vma addr; + unsigned char *data; + unsigned char *start; + + bytes = section->sh_size; + + if (bytes == 0) + { + printf (_("\nSection '%s' has no data to dump.\n"), + SECTION_NAME (section)); + return 0; + } + else + printf (_("\nHex dump of section '%s':\n"), SECTION_NAME (section)); + + addr = section->sh_addr; + + start = (unsigned char *) get_data (NULL, file, section->sh_offset, bytes, + _("section data")); + if (!start) + return 0; + + data = start; + + while (bytes) + { + int j; + int k; + int lbytes; + + lbytes = (bytes > 16 ? 16 : bytes); + + printf (" 0x%8.8lx ", (unsigned long) addr); + + switch (elf_header.e_ident[EI_DATA]) + { + default: + case ELFDATA2LSB: + for (j = 15; j >= 0; j --) + { + if (j < lbytes) + printf ("%2.2x", data[j]); + else + printf (" "); + + if (!(j & 0x3)) + printf (" "); + } + break; + + case ELFDATA2MSB: + for (j = 0; j < 16; j++) + { + if (j < lbytes) + printf ("%2.2x", data[j]); + else + printf (" "); + + if ((j & 3) == 3) + printf (" "); + } + break; + } + + for (j = 0; j < lbytes; j++) + { + k = data[j]; + if (k >= ' ' && k < 0x80) + printf ("%c", k); + else + printf ("."); + } + + putchar ('\n'); + + data += lbytes; + addr += lbytes; + bytes -= lbytes; + } + + free (start); + + return 1; +} + + +static unsigned long int +read_leb128 (data, length_return, sign) + unsigned char *data; + int *length_return; + int sign; +{ + unsigned long int result = 0; + unsigned int num_read = 0; + int shift = 0; + unsigned char byte; + + do + { + byte = *data++; + num_read++; + + result |= (byte & 0x7f) << shift; + + shift += 7; + + } + while (byte & 0x80); + + if (length_return != NULL) + *length_return = num_read; + + if (sign && (shift < 32) && (byte & 0x40)) + result |= -1 << shift; + + return result; +} + +typedef struct State_Machine_Registers +{ + unsigned long address; + unsigned int file; + unsigned int line; + unsigned int column; + int is_stmt; + int basic_block; + int end_sequence; +/* This variable hold the number of the last entry seen + in the File Table. */ + unsigned int last_file_entry; +} SMR; + +static SMR state_machine_regs; + +static void +reset_state_machine (is_stmt) + int is_stmt; +{ + state_machine_regs.address = 0; + state_machine_regs.file = 1; + state_machine_regs.line = 1; + state_machine_regs.column = 0; + state_machine_regs.is_stmt = is_stmt; + state_machine_regs.basic_block = 0; + state_machine_regs.end_sequence = 0; + state_machine_regs.last_file_entry = 0; +} + +/* Handled an extend line op. Returns true if this is the end + of sequence. */ +static int +process_extended_line_op (data, is_stmt, pointer_size) + unsigned char *data; + int is_stmt; + int pointer_size; +{ + unsigned char op_code; + int bytes_read; + unsigned int len; + unsigned char *name; + unsigned long adr; + + len = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + + if (len == 0) + { + warn (_("badly formed extended line op encountered!\n")); + return bytes_read; + } + + len += bytes_read; + op_code = *data++; + + printf (_(" Extended opcode %d: "), op_code); + + switch (op_code) + { + case DW_LNE_end_sequence: + printf (_("End of Sequence\n\n")); + reset_state_machine (is_stmt); + break; + + case DW_LNE_set_address: + adr = byte_get (data, pointer_size); + printf (_("set Address to 0x%lx\n"), adr); + state_machine_regs.address = adr; + break; + + case DW_LNE_define_file: + printf (_(" define new File Table entry\n")); + printf (_(" Entry\tDir\tTime\tSize\tName\n")); + + printf (_(" %d\t"), ++state_machine_regs.last_file_entry); + name = data; + data += strlen ((char *) data) + 1; + printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); + data += bytes_read; + printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); + data += bytes_read; + printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); + printf (_("%s\n\n"), name); + break; + + default: + printf (_("UNKNOWN: length %d\n"), len - bytes_read); + break; + } + + return len; +} + +/* Size of pointers in the .debug_line section. This information is not + really present in that section. It's obtained before dumping the debug + sections by doing some pre-scan of the .debug_info section. */ +static int debug_line_pointer_size = 4; + +static int +display_debug_lines (section, start, file) + Elf_Internal_Shdr *section; + unsigned char * start; + FILE *file ATTRIBUTE_UNUSED; +{ + unsigned char *hdrptr; + DWARF2_Internal_LineInfo info; + unsigned char *standard_opcodes; + unsigned char *data = start; + unsigned char *end = start + section->sh_size; + unsigned char *end_of_sequence; + int i; + int offset_size; + int initial_length_size; + + printf (_("\nDump of debug contents of section %s:\n\n"), + SECTION_NAME (section)); + + while (data < end) + { + hdrptr = data; + + /* Check the length of the block. */ + info.li_length = byte_get (hdrptr, 4); + hdrptr += 4; + + if (info.li_length == 0xffffffff) + { + /* This section is 64-bit DWARF 3. */ + info.li_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } + + if (info.li_length + initial_length_size > section->sh_size) + { + warn + (_("The line info appears to be corrupt - the section is too small\n")); + return 0; + } + + /* Check its version number. */ + info.li_version = byte_get (hdrptr, 2); + hdrptr += 2; + if (info.li_version != 2 && info.li_version != 3) + { + warn (_("Only DWARF version 2 and 3 line info is currently supported.\n")); + return 0; + } + + info.li_prologue_length = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + info.li_min_insn_length = byte_get (hdrptr, 1); + hdrptr++; + info.li_default_is_stmt = byte_get (hdrptr, 1); + hdrptr++; + info.li_line_base = byte_get (hdrptr, 1); + hdrptr++; + info.li_line_range = byte_get (hdrptr, 1); + hdrptr++; + info.li_opcode_base = byte_get (hdrptr, 1); + hdrptr++; + + /* Sign extend the line base field. */ + info.li_line_base <<= 24; + info.li_line_base >>= 24; + + printf (_(" Length: %ld\n"), info.li_length); + printf (_(" DWARF Version: %d\n"), info.li_version); + printf (_(" Prologue Length: %d\n"), info.li_prologue_length); + printf (_(" Minimum Instruction Length: %d\n"), info.li_min_insn_length); + printf (_(" Initial value of 'is_stmt': %d\n"), info.li_default_is_stmt); + printf (_(" Line Base: %d\n"), info.li_line_base); + printf (_(" Line Range: %d\n"), info.li_line_range); + printf (_(" Opcode Base: %d\n"), info.li_opcode_base); + + end_of_sequence = data + info.li_length + initial_length_size; + + reset_state_machine (info.li_default_is_stmt); + + /* Display the contents of the Opcodes table. */ + standard_opcodes = hdrptr; + + printf (_("\n Opcodes:\n")); + + for (i = 1; i < info.li_opcode_base; i++) + printf (_(" Opcode %d has %d args\n"), i, standard_opcodes[i - 1]); + + /* Display the contents of the Directory table. */ + data = standard_opcodes + info.li_opcode_base - 1; + + if (*data == 0) + printf (_("\n The Directory Table is empty.\n")); + else + { + printf (_("\n The Directory Table:\n")); + + while (*data != 0) + { + printf (_(" %s\n"), data); + + data += strlen ((char *) data) + 1; + } + } + + /* Skip the NUL at the end of the table. */ + data++; + + /* Display the contents of the File Name table. */ + if (*data == 0) + printf (_("\n The File Name Table is empty.\n")); + else + { + printf (_("\n The File Name Table:\n")); + printf (_(" Entry\tDir\tTime\tSize\tName\n")); + + while (*data != 0) + { + unsigned char *name; + int bytes_read; + + printf (_(" %d\t"), ++state_machine_regs.last_file_entry); + name = data; + + data += strlen ((char *) data) + 1; + + printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); + data += bytes_read; + printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); + data += bytes_read; + printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); + data += bytes_read; + printf (_("%s\n"), name); + } + } + + /* Skip the NUL at the end of the table. */ + data++; + + /* Now display the statements. */ + printf (_("\n Line Number Statements:\n")); + + + while (data < end_of_sequence) + { + unsigned char op_code; + int adv; + int bytes_read; + + op_code = *data++; + + if (op_code >= info.li_opcode_base) + { + op_code -= info.li_opcode_base; + adv = (op_code / info.li_line_range) * info.li_min_insn_length; + state_machine_regs.address += adv; + printf (_(" Special opcode %d: advance Address by %d to 0x%lx"), + op_code, adv, state_machine_regs.address); + adv = (op_code % info.li_line_range) + info.li_line_base; + state_machine_regs.line += adv; + printf (_(" and Line by %d to %d\n"), + adv, state_machine_regs.line); + } + else switch (op_code) + { + case DW_LNS_extended_op: + data += process_extended_line_op (data, info.li_default_is_stmt, + debug_line_pointer_size); + break; + + case DW_LNS_copy: + printf (_(" Copy\n")); + break; + + case DW_LNS_advance_pc: + adv = info.li_min_insn_length * read_leb128 (data, & bytes_read, 0); + data += bytes_read; + state_machine_regs.address += adv; + printf (_(" Advance PC by %d to %lx\n"), adv, + state_machine_regs.address); + break; + + case DW_LNS_advance_line: + adv = read_leb128 (data, & bytes_read, 1); + data += bytes_read; + state_machine_regs.line += adv; + printf (_(" Advance Line by %d to %d\n"), adv, + state_machine_regs.line); + break; + + case DW_LNS_set_file: + adv = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + printf (_(" Set File Name to entry %d in the File Name Table\n"), + adv); + state_machine_regs.file = adv; + break; + + case DW_LNS_set_column: + adv = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + printf (_(" Set column to %d\n"), adv); + state_machine_regs.column = adv; + break; + + case DW_LNS_negate_stmt: + adv = state_machine_regs.is_stmt; + adv = ! adv; + printf (_(" Set is_stmt to %d\n"), adv); + state_machine_regs.is_stmt = adv; + break; + + case DW_LNS_set_basic_block: + printf (_(" Set basic block\n")); + state_machine_regs.basic_block = 1; + break; + + case DW_LNS_const_add_pc: + adv = (((255 - info.li_opcode_base) / info.li_line_range) + * info.li_min_insn_length); + state_machine_regs.address += adv; + printf (_(" Advance PC by constant %d to 0x%lx\n"), adv, + state_machine_regs.address); + break; + + case DW_LNS_fixed_advance_pc: + adv = byte_get (data, 2); + data += 2; + state_machine_regs.address += adv; + printf (_(" Advance PC by fixed size amount %d to 0x%lx\n"), + adv, state_machine_regs.address); + break; + + case DW_LNS_set_prologue_end: + printf (_(" Set prologue_end to true\n")); + break; + + case DW_LNS_set_epilogue_begin: + printf (_(" Set epilogue_begin to true\n")); + break; + + case DW_LNS_set_isa: + adv = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + printf (_(" Set ISA to %d\n"), adv); + break; + + default: + printf (_(" Unknown opcode %d with operands: "), op_code); + { + int i; + for (i = standard_opcodes[op_code - 1]; i > 0 ; --i) + { + printf ("0x%lx%s", read_leb128 (data, &bytes_read, 0), + i == 1 ? "" : ", "); + data += bytes_read; + } + putchar ('\n'); + } + break; + } + } + putchar ('\n'); + } + + return 1; +} + +static int +display_debug_pubnames (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start; + FILE *file ATTRIBUTE_UNUSED; +{ + DWARF2_Internal_PubNames pubnames; + unsigned char *end; + + end = start + section->sh_size; + + printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section)); + + while (start < end) + { + unsigned char *data; + unsigned long offset; + int offset_size, initial_length_size; + + data = start; + + pubnames.pn_length = byte_get (data, 4); + data += 4; + if (pubnames.pn_length == 0xffffffff) + { + pubnames.pn_length = byte_get (data, 8); + data += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } + + pubnames.pn_version = byte_get (data, 2); + data += 2; + pubnames.pn_offset = byte_get (data, offset_size); + data += offset_size; + pubnames.pn_size = byte_get (data, offset_size); + data += offset_size; + + start += pubnames.pn_length + initial_length_size; + + if (pubnames.pn_version != 2 && pubnames.pn_version != 3) + { + static int warned = 0; + + if (! warned) + { + warn (_("Only DWARF 2 and 3 pubnames are currently supported\n")); + warned = 1; + } + + continue; + } + + printf (_(" Length: %ld\n"), + pubnames.pn_length); + printf (_(" Version: %d\n"), + pubnames.pn_version); + printf (_(" Offset into .debug_info section: %ld\n"), + pubnames.pn_offset); + printf (_(" Size of area in .debug_info section: %ld\n"), + pubnames.pn_size); + + printf (_("\n Offset\tName\n")); + + do + { + offset = byte_get (data, offset_size); + + if (offset != 0) + { + data += offset_size; + printf (" %ld\t\t%s\n", offset, data); + data += strlen ((char *) data) + 1; + } + } + while (offset != 0); + } + + printf ("\n"); + return 1; +} + +static char * +get_TAG_name (tag) + unsigned long tag; +{ + switch (tag) + { + case DW_TAG_padding: return "DW_TAG_padding"; + case DW_TAG_array_type: return "DW_TAG_array_type"; + case DW_TAG_class_type: return "DW_TAG_class_type"; + case DW_TAG_entry_point: return "DW_TAG_entry_point"; + case DW_TAG_enumeration_type: return "DW_TAG_enumeration_type"; + case DW_TAG_formal_parameter: return "DW_TAG_formal_parameter"; + case DW_TAG_imported_declaration: return "DW_TAG_imported_declaration"; + case DW_TAG_label: return "DW_TAG_label"; + case DW_TAG_lexical_block: return "DW_TAG_lexical_block"; + case DW_TAG_member: return "DW_TAG_member"; + case DW_TAG_pointer_type: return "DW_TAG_pointer_type"; + case DW_TAG_reference_type: return "DW_TAG_reference_type"; + case DW_TAG_compile_unit: return "DW_TAG_compile_unit"; + case DW_TAG_string_type: return "DW_TAG_string_type"; + case DW_TAG_structure_type: return "DW_TAG_structure_type"; + case DW_TAG_subroutine_type: return "DW_TAG_subroutine_type"; + case DW_TAG_typedef: return "DW_TAG_typedef"; + case DW_TAG_union_type: return "DW_TAG_union_type"; + case DW_TAG_unspecified_parameters: return "DW_TAG_unspecified_parameters"; + case DW_TAG_variant: return "DW_TAG_variant"; + case DW_TAG_common_block: return "DW_TAG_common_block"; + case DW_TAG_common_inclusion: return "DW_TAG_common_inclusion"; + case DW_TAG_inheritance: return "DW_TAG_inheritance"; + case DW_TAG_inlined_subroutine: return "DW_TAG_inlined_subroutine"; + case DW_TAG_module: return "DW_TAG_module"; + case DW_TAG_ptr_to_member_type: return "DW_TAG_ptr_to_member_type"; + case DW_TAG_set_type: return "DW_TAG_set_type"; + case DW_TAG_subrange_type: return "DW_TAG_subrange_type"; + case DW_TAG_with_stmt: return "DW_TAG_with_stmt"; + case DW_TAG_access_declaration: return "DW_TAG_access_declaration"; + case DW_TAG_base_type: return "DW_TAG_base_type"; + case DW_TAG_catch_block: return "DW_TAG_catch_block"; + case DW_TAG_const_type: return "DW_TAG_const_type"; + case DW_TAG_constant: return "DW_TAG_constant"; + case DW_TAG_enumerator: return "DW_TAG_enumerator"; + case DW_TAG_file_type: return "DW_TAG_file_type"; + case DW_TAG_friend: return "DW_TAG_friend"; + case DW_TAG_namelist: return "DW_TAG_namelist"; + case DW_TAG_namelist_item: return "DW_TAG_namelist_item"; + case DW_TAG_packed_type: return "DW_TAG_packed_type"; + case DW_TAG_subprogram: return "DW_TAG_subprogram"; + case DW_TAG_template_type_param: return "DW_TAG_template_type_param"; + case DW_TAG_template_value_param: return "DW_TAG_template_value_param"; + case DW_TAG_thrown_type: return "DW_TAG_thrown_type"; + case DW_TAG_try_block: return "DW_TAG_try_block"; + case DW_TAG_variant_part: return "DW_TAG_variant_part"; + case DW_TAG_variable: return "DW_TAG_variable"; + case DW_TAG_volatile_type: return "DW_TAG_volatile_type"; + case DW_TAG_MIPS_loop: return "DW_TAG_MIPS_loop"; + case DW_TAG_format_label: return "DW_TAG_format_label"; + case DW_TAG_function_template: return "DW_TAG_function_template"; + case DW_TAG_class_template: return "DW_TAG_class_template"; + /* DWARF 2.1 values. */ + case DW_TAG_dwarf_procedure: return "DW_TAG_dwarf_procedure"; + case DW_TAG_restrict_type: return "DW_TAG_restrict_type"; + case DW_TAG_interface_type: return "DW_TAG_interface_type"; + case DW_TAG_namespace: return "DW_TAG_namespace"; + case DW_TAG_imported_module: return "DW_TAG_imported_module"; + case DW_TAG_unspecified_type: return "DW_TAG_unspecified_type"; + case DW_TAG_partial_unit: return "DW_TAG_partial_unit"; + case DW_TAG_imported_unit: return "DW_TAG_imported_unit"; + /* UPC values. */ + case DW_TAG_upc_shared_type: return "DW_TAG_upc_shared_type"; + case DW_TAG_upc_strict_type: return "DW_TAG_upc_strict_type"; + case DW_TAG_upc_relaxed_type: return "DW_TAG_upc_relaxed_type"; + default: + { + static char buffer[100]; + + sprintf (buffer, _("Unknown TAG value: %lx"), tag); + return buffer; + } + } +} + +static char * +get_AT_name (attribute) + unsigned long attribute; +{ + switch (attribute) + { + case DW_AT_sibling: return "DW_AT_sibling"; + case DW_AT_location: return "DW_AT_location"; + case DW_AT_name: return "DW_AT_name"; + case DW_AT_ordering: return "DW_AT_ordering"; + case DW_AT_subscr_data: return "DW_AT_subscr_data"; + case DW_AT_byte_size: return "DW_AT_byte_size"; + case DW_AT_bit_offset: return "DW_AT_bit_offset"; + case DW_AT_bit_size: return "DW_AT_bit_size"; + case DW_AT_element_list: return "DW_AT_element_list"; + case DW_AT_stmt_list: return "DW_AT_stmt_list"; + case DW_AT_low_pc: return "DW_AT_low_pc"; + case DW_AT_high_pc: return "DW_AT_high_pc"; + case DW_AT_language: return "DW_AT_language"; + case DW_AT_member: return "DW_AT_member"; + case DW_AT_discr: return "DW_AT_discr"; + case DW_AT_discr_value: return "DW_AT_discr_value"; + case DW_AT_visibility: return "DW_AT_visibility"; + case DW_AT_import: return "DW_AT_import"; + case DW_AT_string_length: return "DW_AT_string_length"; + case DW_AT_common_reference: return "DW_AT_common_reference"; + case DW_AT_comp_dir: return "DW_AT_comp_dir"; + case DW_AT_const_value: return "DW_AT_const_value"; + case DW_AT_containing_type: return "DW_AT_containing_type"; + case DW_AT_default_value: return "DW_AT_default_value"; + case DW_AT_inline: return "DW_AT_inline"; + case DW_AT_is_optional: return "DW_AT_is_optional"; + case DW_AT_lower_bound: return "DW_AT_lower_bound"; + case DW_AT_producer: return "DW_AT_producer"; + case DW_AT_prototyped: return "DW_AT_prototyped"; + case DW_AT_return_addr: return "DW_AT_return_addr"; + case DW_AT_start_scope: return "DW_AT_start_scope"; + case DW_AT_stride_size: return "DW_AT_stride_size"; + case DW_AT_upper_bound: return "DW_AT_upper_bound"; + case DW_AT_abstract_origin: return "DW_AT_abstract_origin"; + case DW_AT_accessibility: return "DW_AT_accessibility"; + case DW_AT_address_class: return "DW_AT_address_class"; + case DW_AT_artificial: return "DW_AT_artificial"; + case DW_AT_base_types: return "DW_AT_base_types"; + case DW_AT_calling_convention: return "DW_AT_calling_convention"; + case DW_AT_count: return "DW_AT_count"; + case DW_AT_data_member_location: return "DW_AT_data_member_location"; + case DW_AT_decl_column: return "DW_AT_decl_column"; + case DW_AT_decl_file: return "DW_AT_decl_file"; + case DW_AT_decl_line: return "DW_AT_decl_line"; + case DW_AT_declaration: return "DW_AT_declaration"; + case DW_AT_discr_list: return "DW_AT_discr_list"; + case DW_AT_encoding: return "DW_AT_encoding"; + case DW_AT_external: return "DW_AT_external"; + case DW_AT_frame_base: return "DW_AT_frame_base"; + case DW_AT_friend: return "DW_AT_friend"; + case DW_AT_identifier_case: return "DW_AT_identifier_case"; + case DW_AT_macro_info: return "DW_AT_macro_info"; + case DW_AT_namelist_items: return "DW_AT_namelist_items"; + case DW_AT_priority: return "DW_AT_priority"; + case DW_AT_segment: return "DW_AT_segment"; + case DW_AT_specification: return "DW_AT_specification"; + case DW_AT_static_link: return "DW_AT_static_link"; + case DW_AT_type: return "DW_AT_type"; + case DW_AT_use_location: return "DW_AT_use_location"; + case DW_AT_variable_parameter: return "DW_AT_variable_parameter"; + case DW_AT_virtuality: return "DW_AT_virtuality"; + case DW_AT_vtable_elem_location: return "DW_AT_vtable_elem_location"; + /* DWARF 2.1 values. */ + case DW_AT_allocated: return "DW_AT_allocated"; + case DW_AT_associated: return "DW_AT_associated"; + case DW_AT_data_location: return "DW_AT_data_location"; + case DW_AT_stride: return "DW_AT_stride"; + case DW_AT_entry_pc: return "DW_AT_entry_pc"; + case DW_AT_use_UTF8: return "DW_AT_use_UTF8"; + case DW_AT_extension: return "DW_AT_extension"; + case DW_AT_ranges: return "DW_AT_ranges"; + case DW_AT_trampoline: return "DW_AT_trampoline"; + case DW_AT_call_column: return "DW_AT_call_column"; + case DW_AT_call_file: return "DW_AT_call_file"; + case DW_AT_call_line: return "DW_AT_call_line"; + /* SGI/MIPS extensions. */ + case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; + case DW_AT_MIPS_loop_begin: return "DW_AT_MIPS_loop_begin"; + case DW_AT_MIPS_tail_loop_begin: return "DW_AT_MIPS_tail_loop_begin"; + case DW_AT_MIPS_epilog_begin: return "DW_AT_MIPS_epilog_begin"; + case DW_AT_MIPS_loop_unroll_factor: return "DW_AT_MIPS_loop_unroll_factor"; + case DW_AT_MIPS_software_pipeline_depth: + return "DW_AT_MIPS_software_pipeline_depth"; + case DW_AT_MIPS_linkage_name: return "DW_AT_MIPS_linkage_name"; + case DW_AT_MIPS_stride: return "DW_AT_MIPS_stride"; + case DW_AT_MIPS_abstract_name: return "DW_AT_MIPS_abstract_name"; + case DW_AT_MIPS_clone_origin: return "DW_AT_MIPS_clone_origin"; + case DW_AT_MIPS_has_inlines: return "DW_AT_MIPS_has_inlines"; + /* GNU extensions. */ + case DW_AT_sf_names: return "DW_AT_sf_names"; + case DW_AT_src_info: return "DW_AT_src_info"; + case DW_AT_mac_info: return "DW_AT_mac_info"; + case DW_AT_src_coords: return "DW_AT_src_coords"; + case DW_AT_body_begin: return "DW_AT_body_begin"; + case DW_AT_body_end: return "DW_AT_body_end"; + case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; + /* UPC extension. */ + case DW_AT_upc_threads_scaled: return "DW_AT_upc_threads_scaled"; + default: + { + static char buffer[100]; + + sprintf (buffer, _("Unknown AT value: %lx"), attribute); + return buffer; + } + } +} + +static char * +get_FORM_name (form) + unsigned long form; +{ + switch (form) + { + case DW_FORM_addr: return "DW_FORM_addr"; + case DW_FORM_block2: return "DW_FORM_block2"; + case DW_FORM_block4: return "DW_FORM_block4"; + case DW_FORM_data2: return "DW_FORM_data2"; + case DW_FORM_data4: return "DW_FORM_data4"; + case DW_FORM_data8: return "DW_FORM_data8"; + case DW_FORM_string: return "DW_FORM_string"; + case DW_FORM_block: return "DW_FORM_block"; + case DW_FORM_block1: return "DW_FORM_block1"; + case DW_FORM_data1: return "DW_FORM_data1"; + case DW_FORM_flag: return "DW_FORM_flag"; + case DW_FORM_sdata: return "DW_FORM_sdata"; + case DW_FORM_strp: return "DW_FORM_strp"; + case DW_FORM_udata: return "DW_FORM_udata"; + case DW_FORM_ref_addr: return "DW_FORM_ref_addr"; + case DW_FORM_ref1: return "DW_FORM_ref1"; + case DW_FORM_ref2: return "DW_FORM_ref2"; + case DW_FORM_ref4: return "DW_FORM_ref4"; + case DW_FORM_ref8: return "DW_FORM_ref8"; + case DW_FORM_ref_udata: return "DW_FORM_ref_udata"; + case DW_FORM_indirect: return "DW_FORM_indirect"; + default: + { + static char buffer[100]; + + sprintf (buffer, _("Unknown FORM value: %lx"), form); + return buffer; + } + } +} + +/* FIXME: There are better and more effiecint ways to handle + these structures. For now though, I just want something that + is simple to implement. */ +typedef struct abbrev_attr +{ + unsigned long attribute; + unsigned long form; + struct abbrev_attr *next; +} +abbrev_attr; + +typedef struct abbrev_entry +{ + unsigned long entry; + unsigned long tag; + int children; + struct abbrev_attr *first_attr; + struct abbrev_attr *last_attr; + struct abbrev_entry *next; +} +abbrev_entry; + +static abbrev_entry *first_abbrev = NULL; +static abbrev_entry *last_abbrev = NULL; + +static void +free_abbrevs () +{ + abbrev_entry *abbrev; + + for (abbrev = first_abbrev; abbrev;) + { + abbrev_entry *next = abbrev->next; + abbrev_attr *attr; + + for (attr = abbrev->first_attr; attr;) + { + abbrev_attr *next = attr->next; + + free (attr); + attr = next; + } + + free (abbrev); + abbrev = next; + } + + last_abbrev = first_abbrev = NULL; +} + +static void +add_abbrev (number, tag, children) + unsigned long number; + unsigned long tag; + int children; +{ + abbrev_entry *entry; + + entry = (abbrev_entry *) malloc (sizeof (*entry)); + + if (entry == NULL) + /* ugg */ + return; + + entry->entry = number; + entry->tag = tag; + entry->children = children; + entry->first_attr = NULL; + entry->last_attr = NULL; + entry->next = NULL; + + if (first_abbrev == NULL) + first_abbrev = entry; + else + last_abbrev->next = entry; + + last_abbrev = entry; +} + +static void +add_abbrev_attr (attribute, form) + unsigned long attribute; + unsigned long form; +{ + abbrev_attr *attr; + + attr = (abbrev_attr *) malloc (sizeof (*attr)); + + if (attr == NULL) + /* ugg */ + return; + + attr->attribute = attribute; + attr->form = form; + attr->next = NULL; + + if (last_abbrev->first_attr == NULL) + last_abbrev->first_attr = attr; + else + last_abbrev->last_attr->next = attr; + + last_abbrev->last_attr = attr; +} + +/* Processes the (partial) contents of a .debug_abbrev section. + Returns NULL if the end of the section was encountered. + Returns the address after the last byte read if the end of + an abbreviation set was found. */ + +static unsigned char * +process_abbrev_section (start, end) + unsigned char *start; + unsigned char *end; +{ + if (first_abbrev != NULL) + return NULL; + + while (start < end) + { + int bytes_read; + unsigned long entry; + unsigned long tag; + unsigned long attribute; + int children; + + entry = read_leb128 (start, & bytes_read, 0); + start += bytes_read; + + /* A single zero is supposed to end the section according + to the standard. If there's more, then signal that to + the caller. */ + if (entry == 0) + return start == end ? NULL : start; + + tag = read_leb128 (start, & bytes_read, 0); + start += bytes_read; + + children = *start++; + + add_abbrev (entry, tag, children); + + do + { + unsigned long form; + + attribute = read_leb128 (start, & bytes_read, 0); + start += bytes_read; + + form = read_leb128 (start, & bytes_read, 0); + start += bytes_read; + + if (attribute != 0) + add_abbrev_attr (attribute, form); + } + while (attribute != 0); + } + + return NULL; +} + + +static int +display_debug_macinfo (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start; + FILE *file ATTRIBUTE_UNUSED; +{ + unsigned char *end = start + section->sh_size; + unsigned char *curr = start; + unsigned int bytes_read; + enum dwarf_macinfo_record_type op; + + printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section)); + + while (curr < end) + { + unsigned int lineno; + const char *string; + + op = *curr; + curr++; + + switch (op) + { + case DW_MACINFO_start_file: + { + unsigned int filenum; + + lineno = read_leb128 (curr, & bytes_read, 0); + curr += bytes_read; + filenum = read_leb128 (curr, & bytes_read, 0); + curr += bytes_read; + + printf (_(" DW_MACINFO_start_file - lineno: %d filenum: %d\n"), lineno, filenum); + } + break; + + case DW_MACINFO_end_file: + printf (_(" DW_MACINFO_end_file\n")); + break; + + case DW_MACINFO_define: + lineno = read_leb128 (curr, & bytes_read, 0); + curr += bytes_read; + string = curr; + curr += strlen (string) + 1; + printf (_(" DW_MACINFO_define - lineno : %d macro : %s\n"), lineno, string); + break; + + case DW_MACINFO_undef: + lineno = read_leb128 (curr, & bytes_read, 0); + curr += bytes_read; + string = curr; + curr += strlen (string) + 1; + printf (_(" DW_MACINFO_undef - lineno : %d macro : %s\n"), lineno, string); + break; + + case DW_MACINFO_vendor_ext: + { + unsigned int constant; + + constant = read_leb128 (curr, & bytes_read, 0); + curr += bytes_read; + string = curr; + curr += strlen (string) + 1; + printf (_(" DW_MACINFO_vendor_ext - constant : %d string : %s\n"), constant, string); + } + break; + } + } + + return 1; +} + + +static int +display_debug_abbrev (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start; + FILE *file ATTRIBUTE_UNUSED; +{ + abbrev_entry *entry; + unsigned char *end = start + section->sh_size; + + printf (_("Contents of the %s section:\n\n"), SECTION_NAME (section)); + + do + { + start = process_abbrev_section (start, end); + + if (first_abbrev == NULL) + continue; + + printf (_(" Number TAG\n")); + + for (entry = first_abbrev; entry; entry = entry->next) + { + abbrev_attr *attr; + + printf (_(" %ld %s [%s]\n"), + entry->entry, + get_TAG_name (entry->tag), + entry->children ? _("has children") : _("no children")); + + for (attr = entry->first_attr; attr; attr = attr->next) + { + printf (_(" %-18s %s\n"), + get_AT_name (attr->attribute), + get_FORM_name (attr->form)); + } + } + + free_abbrevs (); + } + while (start); + + printf ("\n"); + + return 1; +} + + +static unsigned char * +display_block (data, length) + unsigned char *data; + unsigned long length; +{ + printf (_(" %lu byte block: "), length); + + while (length --) + printf ("%lx ", (unsigned long) byte_get (data++, 1)); + + return data; +} + +static void +decode_location_expression (data, pointer_size, length) + unsigned char * data; + unsigned int pointer_size; + unsigned long length; +{ + unsigned op; + int bytes_read; + unsigned long uvalue; + unsigned char *end = data + length; + + while (data < end) + { + op = *data++; + + switch (op) + { + case DW_OP_addr: + printf ("DW_OP_addr: %lx", + (unsigned long) byte_get (data, pointer_size)); + data += pointer_size; + break; + case DW_OP_deref: + printf ("DW_OP_deref"); + break; + case DW_OP_const1u: + printf ("DW_OP_const1u: %lu", (unsigned long) byte_get (data++, 1)); + break; + case DW_OP_const1s: + printf ("DW_OP_const1s: %ld", (long) byte_get (data++, 1)); + break; + case DW_OP_const2u: + printf ("DW_OP_const2u: %lu", (unsigned long) byte_get (data, 2)); + data += 2; + break; + case DW_OP_const2s: + printf ("DW_OP_const2s: %ld", (long) byte_get (data, 2)); + data += 2; + break; + case DW_OP_const4u: + printf ("DW_OP_const4u: %lu", (unsigned long) byte_get (data, 4)); + data += 4; + break; + case DW_OP_const4s: + printf ("DW_OP_const4s: %ld", (long) byte_get (data, 4)); + data += 4; + break; + case DW_OP_const8u: + printf ("DW_OP_const8u: %lu %lu", (unsigned long) byte_get (data, 4), + (unsigned long) byte_get (data + 4, 4)); + data += 8; + break; + case DW_OP_const8s: + printf ("DW_OP_const8s: %ld %ld", (long) byte_get (data, 4), + (long) byte_get (data + 4, 4)); + data += 8; + break; + case DW_OP_constu: + printf ("DW_OP_constu: %lu", read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + case DW_OP_consts: + printf ("DW_OP_consts: %ld", read_leb128 (data, &bytes_read, 1)); + data += bytes_read; + break; + case DW_OP_dup: + printf ("DW_OP_dup"); + break; + case DW_OP_drop: + printf ("DW_OP_drop"); + break; + case DW_OP_over: + printf ("DW_OP_over"); + break; + case DW_OP_pick: + printf ("DW_OP_pick: %ld", (unsigned long) byte_get (data++, 1)); + break; + case DW_OP_swap: + printf ("DW_OP_swap"); + break; + case DW_OP_rot: + printf ("DW_OP_rot"); + break; + case DW_OP_xderef: + printf ("DW_OP_xderef"); + break; + case DW_OP_abs: + printf ("DW_OP_abs"); + break; + case DW_OP_and: + printf ("DW_OP_and"); + break; + case DW_OP_div: + printf ("DW_OP_div"); + break; + case DW_OP_minus: + printf ("DW_OP_minus"); + break; + case DW_OP_mod: + printf ("DW_OP_mod"); + break; + case DW_OP_mul: + printf ("DW_OP_mul"); + break; + case DW_OP_neg: + printf ("DW_OP_neg"); + break; + case DW_OP_not: + printf ("DW_OP_not"); + break; + case DW_OP_or: + printf ("DW_OP_or"); + break; + case DW_OP_plus: + printf ("DW_OP_plus"); + break; + case DW_OP_plus_uconst: + printf ("DW_OP_plus_uconst: %lu", + read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + case DW_OP_shl: + printf ("DW_OP_shl"); + break; + case DW_OP_shr: + printf ("DW_OP_shr"); + break; + case DW_OP_shra: + printf ("DW_OP_shra"); + break; + case DW_OP_xor: + printf ("DW_OP_xor"); + break; + case DW_OP_bra: + printf ("DW_OP_bra: %ld", (long) byte_get (data, 2)); + data += 2; + break; + case DW_OP_eq: + printf ("DW_OP_eq"); + break; + case DW_OP_ge: + printf ("DW_OP_ge"); + break; + case DW_OP_gt: + printf ("DW_OP_gt"); + break; + case DW_OP_le: + printf ("DW_OP_le"); + break; + case DW_OP_lt: + printf ("DW_OP_lt"); + break; + case DW_OP_ne: + printf ("DW_OP_ne"); + break; + case DW_OP_skip: + printf ("DW_OP_skip: %ld", (long) byte_get (data, 2)); + data += 2; + break; + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + printf ("DW_OP_lit%d", op - DW_OP_lit0); + break; + + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + printf ("DW_OP_reg%d", op - DW_OP_reg0); + break; + + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + printf ("DW_OP_breg%d: %ld", op - DW_OP_breg0, + read_leb128 (data, &bytes_read, 1)); + data += bytes_read; + break; + + case DW_OP_regx: + printf ("DW_OP_regx: %lu", read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + case DW_OP_fbreg: + printf ("DW_OP_fbreg: %ld", read_leb128 (data, &bytes_read, 1)); + data += bytes_read; + break; + case DW_OP_bregx: + uvalue = read_leb128 (data, &bytes_read, 0); + data += bytes_read; + printf ("DW_OP_bregx: %lu %ld", uvalue, + read_leb128 (data, &bytes_read, 1)); + data += bytes_read; + break; + case DW_OP_piece: + printf ("DW_OP_piece: %lu", read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + case DW_OP_deref_size: + printf ("DW_OP_deref_size: %ld", (long) byte_get (data++, 1)); + break; + case DW_OP_xderef_size: + printf ("DW_OP_xderef_size: %ld", (long) byte_get (data++, 1)); + break; + case DW_OP_nop: + printf ("DW_OP_nop"); + break; + + /* DWARF 3 extensions. */ + case DW_OP_push_object_address: + printf ("DW_OP_push_object_address"); + break; + case DW_OP_call2: + printf ("DW_OP_call2: <%lx>", (long) byte_get (data, 2)); + data += 2; + break; + case DW_OP_call4: + printf ("DW_OP_call4: <%lx>", (long) byte_get (data, 4)); + data += 4; + break; + case DW_OP_call_ref: + printf ("DW_OP_call_ref"); + break; + + /* GNU extensions. */ + case DW_OP_GNU_push_tls_address: + printf ("DW_OP_GNU_push_tls_address"); + break; + + default: + if (op >= DW_OP_lo_user + && op <= DW_OP_hi_user) + printf (_("(User defined location op)")); + else + printf (_("(Unknown location op)")); + /* No way to tell where the next op is, so just bail. */ + return; + } + + /* Separate the ops. */ + if (data < end) + printf ("; "); + } +} + +static const char *debug_loc_contents; +static bfd_vma debug_loc_size; + +static void +load_debug_loc (file) + FILE *file; +{ + Elf_Internal_Shdr *sec; + unsigned int i; + + /* If it is already loaded, do nothing. */ + if (debug_loc_contents != NULL) + return; + + /* Locate the .debug_loc section. */ + for (i = 0, sec = section_headers; + i < elf_header.e_shnum; + i++, sec++) + if (strcmp (SECTION_NAME (sec), ".debug_loc") == 0) + break; + + if (i == elf_header.e_shnum || sec->sh_size == 0) + return; + + debug_loc_size = sec->sh_size; + + debug_loc_contents = ((char *) + get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_loc section data"))); +} + +static void +free_debug_loc () +{ + if (debug_loc_contents == NULL) + return; + + free ((char *) debug_loc_contents); + debug_loc_contents = NULL; + debug_loc_size = 0; +} + + +static int +display_debug_loc (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start; + FILE *file ATTRIBUTE_UNUSED; +{ + unsigned char *section_end; + unsigned long bytes; + unsigned char *section_begin = start; + bfd_vma addr; + + addr = section->sh_addr; + bytes = section->sh_size; + section_end = start + bytes; + + if (bytes == 0) + { + printf (_("\nThe .debug_loc section is empty.\n")); + return 0; + } + + printf (_("Contents of the .debug_loc section:\n\n")); + printf (_("\n Offset Begin End Expression\n")); + + while (start < section_end) + { + unsigned long begin; + unsigned long end; + unsigned short length; + unsigned long offset; + + offset = start - section_begin; + + while (1) + { + /* Normally, the lists in the debug_loc section are related to a + given compilation unit, and thus, we would use the pointer size + of that compilation unit. However, since we are displaying it + seperately here, we either have to store pointer sizes of all + compilation units, or assume they don't change. We assume, + like the debug_line display, that it doesn't change. */ + begin = byte_get (start, debug_line_pointer_size); + start += debug_line_pointer_size; + end = byte_get (start, debug_line_pointer_size); + start += debug_line_pointer_size; + + if (begin == 0 && end == 0) + break; + + /* For now, skip any base address specifiers. */ + if (begin == 0xffffffff) + continue; + + begin += addr; + end += addr; + + length = byte_get (start, 2); + start += 2; + + printf (" %8.8lx %8.8lx %8.8lx (", offset, begin, end); + decode_location_expression (start, debug_line_pointer_size, length); + printf (")\n"); + + start += length; + } + printf ("\n"); + } + return 1; +} + +static const char *debug_str_contents; +static bfd_vma debug_str_size; + +static void +load_debug_str (file) + FILE *file; +{ + Elf_Internal_Shdr *sec; + unsigned int i; + + /* If it is already loaded, do nothing. */ + if (debug_str_contents != NULL) + return; + + /* Locate the .debug_str section. */ + for (i = 0, sec = section_headers; + i < elf_header.e_shnum; + i++, sec++) + if (strcmp (SECTION_NAME (sec), ".debug_str") == 0) + break; + + if (i == elf_header.e_shnum || sec->sh_size == 0) + return; + + debug_str_size = sec->sh_size; + + debug_str_contents = ((char *) + get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_str section data"))); +} + +static void +free_debug_str () +{ + if (debug_str_contents == NULL) + return; + + free ((char *) debug_str_contents); + debug_str_contents = NULL; + debug_str_size = 0; +} + +static const char * +fetch_indirect_string (offset) + unsigned long offset; +{ + if (debug_str_contents == NULL) + return _(""); + + if (offset > debug_str_size) + return _(""); + + return debug_str_contents + offset; +} + +static int +display_debug_str (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start; + FILE *file ATTRIBUTE_UNUSED; +{ + unsigned long bytes; + bfd_vma addr; + + addr = section->sh_addr; + bytes = section->sh_size; + + if (bytes == 0) + { + printf (_("\nThe .debug_str section is empty.\n")); + return 0; + } + + printf (_("Contents of the .debug_str section:\n\n")); + + while (bytes) + { + int j; + int k; + int lbytes; + + lbytes = (bytes > 16 ? 16 : bytes); + + printf (" 0x%8.8lx ", (unsigned long) addr); + + for (j = 0; j < 16; j++) + { + if (j < lbytes) + printf ("%2.2x", start[j]); + else + printf (" "); + + if ((j & 3) == 3) + printf (" "); + } + + for (j = 0; j < lbytes; j++) + { + k = start[j]; + if (k >= ' ' && k < 0x80) + printf ("%c", k); + else + printf ("."); + } + + putchar ('\n'); + + start += lbytes; + addr += lbytes; + bytes -= lbytes; + } + + return 1; +} + +static unsigned char * +read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size, + offset_size, dwarf_version) + unsigned long attribute; + unsigned long form; + unsigned char *data; + unsigned long cu_offset; + unsigned long pointer_size; + unsigned long offset_size; + int dwarf_version; +{ + unsigned long uvalue = 0; + unsigned char *block_start = NULL; + int bytes_read; + + switch (form) + { + default: + break; + + case DW_FORM_ref_addr: + if (dwarf_version == 2) + { + uvalue = byte_get (data, pointer_size); + data += pointer_size; + } + else if (dwarf_version == 3) + { + uvalue = byte_get (data, offset_size); + data += offset_size; + } + else + { + error (_("Internal error: DWARF version is not 2 or 3.\n")); + } + break; + + case DW_FORM_addr: + uvalue = byte_get (data, pointer_size); + data += pointer_size; + break; + + case DW_FORM_strp: + uvalue = byte_get (data, offset_size); + data += offset_size; + break; + + case DW_FORM_ref1: + case DW_FORM_flag: + case DW_FORM_data1: + uvalue = byte_get (data++, 1); + break; + + case DW_FORM_ref2: + case DW_FORM_data2: + uvalue = byte_get (data, 2); + data += 2; + break; + + case DW_FORM_ref4: + case DW_FORM_data4: + uvalue = byte_get (data, 4); + data += 4; + break; + + case DW_FORM_sdata: + uvalue = read_leb128 (data, & bytes_read, 1); + data += bytes_read; + break; + + case DW_FORM_ref_udata: + case DW_FORM_udata: + uvalue = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + break; + + case DW_FORM_indirect: + form = read_leb128 (data, & bytes_read, 0); + data += bytes_read; + printf (" %s", get_FORM_name (form)); + return read_and_display_attr_value (attribute, form, data, cu_offset, + pointer_size, offset_size, + dwarf_version); + } + + switch (form) + { + case DW_FORM_ref_addr: + printf (" <#%lx>", uvalue); + break; + + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref_udata: + printf (" <%lx>", uvalue + cu_offset); + break; + + case DW_FORM_addr: + printf (" %#lx", uvalue); + + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_sdata: + case DW_FORM_udata: + printf (" %ld", uvalue); + break; + + case DW_FORM_ref8: + case DW_FORM_data8: + uvalue = byte_get (data, 4); + printf (" %lx", uvalue); + printf (" %lx", (unsigned long) byte_get (data + 4, 4)); + data += 8; + break; + + case DW_FORM_string: + printf (" %s", data); + data += strlen ((char *) data) + 1; + break; + + case DW_FORM_block: + uvalue = read_leb128 (data, & bytes_read, 0); + block_start = data + bytes_read; + data = display_block (block_start, uvalue); + break; + + case DW_FORM_block1: + uvalue = byte_get (data, 1); + block_start = data + 1; + data = display_block (block_start, uvalue); + break; + + case DW_FORM_block2: + uvalue = byte_get (data, 2); + block_start = data + 2; + data = display_block (block_start, uvalue); + break; + + case DW_FORM_block4: + uvalue = byte_get (data, 4); + block_start = data + 4; + data = display_block (block_start, uvalue); + break; + + case DW_FORM_strp: + printf (_(" (indirect string, offset: 0x%lx): %s"), + uvalue, fetch_indirect_string (uvalue)); + break; + + case DW_FORM_indirect: + /* Handled above. */ + break; + + default: + warn (_("Unrecognized form: %d\n"), form); + break; + } + + /* For some attributes we can display futher information. */ + + printf ("\t"); + + switch (attribute) + { + case DW_AT_inline: + switch (uvalue) + { + case DW_INL_not_inlined: + printf (_("(not inlined)")); + break; + case DW_INL_inlined: + printf (_("(inlined)")); + break; + case DW_INL_declared_not_inlined: + printf (_("(declared as inline but ignored)")); + break; + case DW_INL_declared_inlined: + printf (_("(declared as inline and inlined)")); + break; + default: + printf (_(" (Unknown inline attribute value: %lx)"), uvalue); + break; + } + break; + + case DW_AT_language: + switch (uvalue) + { + case DW_LANG_C: printf ("(non-ANSI C)"); break; + case DW_LANG_C89: printf ("(ANSI C)"); break; + case DW_LANG_C_plus_plus: printf ("(C++)"); break; + case DW_LANG_Fortran77: printf ("(FORTRAN 77)"); break; + case DW_LANG_Fortran90: printf ("(Fortran 90)"); break; + case DW_LANG_Modula2: printf ("(Modula 2)"); break; + case DW_LANG_Pascal83: printf ("(ANSI Pascal)"); break; + case DW_LANG_Ada83: printf ("(Ada)"); break; + case DW_LANG_Cobol74: printf ("(Cobol 74)"); break; + case DW_LANG_Cobol85: printf ("(Cobol 85)"); break; + /* DWARF 2.1 values. */ + case DW_LANG_C99: printf ("(ANSI C99)"); break; + case DW_LANG_Ada95: printf ("(ADA 95)"); break; + case DW_LANG_Fortran95: printf ("(Fortran 95)"); break; + /* MIPS extension. */ + case DW_LANG_Mips_Assembler: printf ("(MIPS assembler)"); break; + /* UPC extension. */ + case DW_LANG_Upc: printf ("(Unified Parallel C)"); break; + default: + printf ("(Unknown: %lx)", uvalue); + break; + } + break; + + case DW_AT_encoding: + switch (uvalue) + { + case DW_ATE_void: printf ("(void)"); break; + case DW_ATE_address: printf ("(machine address)"); break; + case DW_ATE_boolean: printf ("(boolean)"); break; + case DW_ATE_complex_float: printf ("(complex float)"); break; + case DW_ATE_float: printf ("(float)"); break; + case DW_ATE_signed: printf ("(signed)"); break; + case DW_ATE_signed_char: printf ("(signed char)"); break; + case DW_ATE_unsigned: printf ("(unsigned)"); break; + case DW_ATE_unsigned_char: printf ("(unsigned char)"); break; + /* DWARF 2.1 value. */ + case DW_ATE_imaginary_float: printf ("(imaginary float)"); break; + default: + if (uvalue >= DW_ATE_lo_user + && uvalue <= DW_ATE_hi_user) + printf ("(user defined type)"); + else + printf ("(unknown type)"); + break; + } + break; + + case DW_AT_accessibility: + switch (uvalue) + { + case DW_ACCESS_public: printf ("(public)"); break; + case DW_ACCESS_protected: printf ("(protected)"); break; + case DW_ACCESS_private: printf ("(private)"); break; + default: + printf ("(unknown accessibility)"); + break; + } + break; + + case DW_AT_visibility: + switch (uvalue) + { + case DW_VIS_local: printf ("(local)"); break; + case DW_VIS_exported: printf ("(exported)"); break; + case DW_VIS_qualified: printf ("(qualified)"); break; + default: printf ("(unknown visibility)"); break; + } + break; + + case DW_AT_virtuality: + switch (uvalue) + { + case DW_VIRTUALITY_none: printf ("(none)"); break; + case DW_VIRTUALITY_virtual: printf ("(virtual)"); break; + case DW_VIRTUALITY_pure_virtual:printf ("(pure_virtual)"); break; + default: printf ("(unknown virtuality)"); break; + } + break; + + case DW_AT_identifier_case: + switch (uvalue) + { + case DW_ID_case_sensitive: printf ("(case_sensitive)"); break; + case DW_ID_up_case: printf ("(up_case)"); break; + case DW_ID_down_case: printf ("(down_case)"); break; + case DW_ID_case_insensitive: printf ("(case_insensitive)"); break; + default: printf ("(unknown case)"); break; + } + break; + + case DW_AT_calling_convention: + switch (uvalue) + { + case DW_CC_normal: printf ("(normal)"); break; + case DW_CC_program: printf ("(program)"); break; + case DW_CC_nocall: printf ("(nocall)"); break; + default: + if (uvalue >= DW_CC_lo_user + && uvalue <= DW_CC_hi_user) + printf ("(user defined)"); + else + printf ("(unknown convention)"); + } + break; + + case DW_AT_ordering: + switch (uvalue) + { + case -1: printf ("(undefined)"); break; + case 0: printf ("(row major)"); break; + case 1: printf ("(column major)"); break; + } + break; + + case DW_AT_frame_base: + case DW_AT_location: + case DW_AT_data_member_location: + case DW_AT_vtable_elem_location: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_data_location: + case DW_AT_stride: + case DW_AT_upper_bound: + case DW_AT_lower_bound: + if (block_start) + { + printf ("("); + decode_location_expression (block_start, pointer_size, uvalue); + printf (")"); + } + else if (form == DW_FORM_data4 || form == DW_FORM_data8) + { + printf ("("); + printf ("location list"); + printf (")"); + } + break; + + default: + break; + } + + return data; +} + +static unsigned char * +read_and_display_attr (attribute, form, data, cu_offset, pointer_size, + offset_size, dwarf_version) + unsigned long attribute; + unsigned long form; + unsigned char *data; + unsigned long cu_offset; + unsigned long pointer_size; + unsigned long offset_size; + int dwarf_version; +{ + printf (" %-18s:", get_AT_name (attribute)); + data = read_and_display_attr_value (attribute, form, data, cu_offset, + pointer_size, offset_size, dwarf_version); + printf ("\n"); + return data; +} + +static int +display_debug_info (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start; + FILE *file; +{ + unsigned char *end = start + section->sh_size; + unsigned char *section_begin = start; + + printf (_("The section %s contains:\n\n"), SECTION_NAME (section)); + + load_debug_str (file); + load_debug_loc (file); + + while (start < end) + { + DWARF2_Internal_CompUnit compunit; + Elf_Internal_Shdr *relsec; + unsigned char *hdrptr; + unsigned char *cu_abbrev_offset_ptr; + unsigned char *tags; + unsigned int i; + int level; + unsigned long cu_offset; + int offset_size; + int initial_length_size; + + hdrptr = start; + + compunit.cu_length = byte_get (hdrptr, 4); + hdrptr += 4; + + if (compunit.cu_length == 0xffffffff) + { + compunit.cu_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } + + compunit.cu_version = byte_get (hdrptr, 2); + hdrptr += 2; + + /* Apply addends of RELA relocations. */ + for (relsec = section_headers; + relsec < section_headers + elf_header.e_shnum; + ++relsec) + { + unsigned long nrelas; + Elf_Internal_Rela *rela, *rp; + Elf_Internal_Shdr *symsec; + Elf_Internal_Sym *symtab; + Elf_Internal_Sym *sym; + + if (relsec->sh_type != SHT_RELA + || SECTION_HEADER (relsec->sh_info) != section + || relsec->sh_size == 0) + continue; + + if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size, + & rela, & nrelas)) + return 0; + + symsec = SECTION_HEADER (relsec->sh_link); + symtab = GET_ELF_SYMBOLS (file, symsec); + + for (rp = rela; rp < rela + nrelas; ++rp) + { + unsigned char *loc; + + if (rp->r_offset >= (bfd_vma) (hdrptr - section_begin) + && section->sh_size > (bfd_vma) offset_size + && rp->r_offset <= section->sh_size - offset_size) + loc = section_begin + rp->r_offset; + else + continue; + + if (is_32bit_elf) + { + sym = symtab + ELF32_R_SYM (rp->r_info); + + if (ELF32_R_SYM (rp->r_info) != 0 + && ELF32_ST_TYPE (sym->st_info) != STT_SECTION) + { + warn (_("Skipping unexpected symbol type %u\n"), + ELF32_ST_TYPE (sym->st_info)); + continue; + } + } + else + { + sym = symtab + ELF64_R_SYM (rp->r_info); + + if (ELF64_R_SYM (rp->r_info) != 0 + && ELF64_ST_TYPE (sym->st_info) != STT_SECTION) + { + warn (_("Skipping unexpected symbol type %u\n"), + ELF64_ST_TYPE (sym->st_info)); + continue; + } + } + + byte_put (loc, rp->r_addend, offset_size); + } + + free (rela); + break; + } + + cu_abbrev_offset_ptr = hdrptr; + compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + + compunit.cu_pointer_size = byte_get (hdrptr, 1); + hdrptr += 1; + + tags = hdrptr; + cu_offset = start - section_begin; + start += compunit.cu_length + initial_length_size; + + printf (_(" Compilation Unit @ %lx:\n"), cu_offset); + printf (_(" Length: %ld\n"), compunit.cu_length); + printf (_(" Version: %d\n"), compunit.cu_version); + printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset); + printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size); + + if (compunit.cu_version != 2 && compunit.cu_version != 3) + { + warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n")); + continue; + } + + free_abbrevs (); + + /* Read in the abbrevs used by this compilation unit. */ + { + Elf_Internal_Shdr *sec; + unsigned char *begin; + + /* Locate the .debug_abbrev section and process it. */ + for (i = 0, sec = section_headers; + i < elf_header.e_shnum; + i++, sec++) + if (strcmp (SECTION_NAME (sec), ".debug_abbrev") == 0) + break; + + if (i == elf_header.e_shnum || sec->sh_size == 0) + { + warn (_("Unable to locate .debug_abbrev section!\n")); + return 0; + } + + begin = ((unsigned char *) + get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_abbrev section data"))); + if (!begin) + return 0; + + process_abbrev_section (begin + compunit.cu_abbrev_offset, + begin + sec->sh_size); + + free (begin); + } + + level = 0; + while (tags < start) + { + int bytes_read; + unsigned long abbrev_number; + abbrev_entry *entry; + abbrev_attr *attr; + + abbrev_number = read_leb128 (tags, & bytes_read, 0); + tags += bytes_read; + + /* A null DIE marks the end of a list of children. */ + if (abbrev_number == 0) + { + --level; + continue; + } + + /* Scan through the abbreviation list until we reach the + correct entry. */ + for (entry = first_abbrev; + entry && entry->entry != abbrev_number; + entry = entry->next) + continue; + + if (entry == NULL) + { + warn (_("Unable to locate entry %lu in the abbreviation table\n"), + abbrev_number); + return 0; + } + + printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"), + level, + (unsigned long) (tags - section_begin - bytes_read), + abbrev_number, + get_TAG_name (entry->tag)); + + for (attr = entry->first_attr; attr; attr = attr->next) + tags = read_and_display_attr (attr->attribute, + attr->form, + tags, cu_offset, + compunit.cu_pointer_size, + offset_size, + compunit.cu_version); + + if (entry->children) + ++level; + } + } + + free_debug_str (); + free_debug_loc (); + + printf ("\n"); + + return 1; +} + +static int +display_debug_aranges (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start; + FILE *file ATTRIBUTE_UNUSED; +{ + unsigned char *end = start + section->sh_size; + + printf (_("The section %s contains:\n\n"), SECTION_NAME (section)); + + while (start < end) + { + unsigned char *hdrptr; + DWARF2_Internal_ARange arange; + unsigned char *ranges; + unsigned long length; + unsigned long address; + int excess; + int offset_size; + int initial_length_size; + + hdrptr = start; + + arange.ar_length = byte_get (hdrptr, 4); + hdrptr += 4; + + if (arange.ar_length == 0xffffffff) + { + arange.ar_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } + + arange.ar_version = byte_get (hdrptr, 2); + hdrptr += 2; + + arange.ar_info_offset = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + + arange.ar_pointer_size = byte_get (hdrptr, 1); + hdrptr += 1; + + arange.ar_segment_size = byte_get (hdrptr, 1); + hdrptr += 1; + + if (arange.ar_version != 2 && arange.ar_version != 3) + { + warn (_("Only DWARF 2 and 3 aranges are currently supported.\n")); + break; + } + + printf (_(" Length: %ld\n"), arange.ar_length); + printf (_(" Version: %d\n"), arange.ar_version); + printf (_(" Offset into .debug_info: %lx\n"), arange.ar_info_offset); + printf (_(" Pointer Size: %d\n"), arange.ar_pointer_size); + printf (_(" Segment Size: %d\n"), arange.ar_segment_size); + + printf (_("\n Address Length\n")); + + ranges = hdrptr; + + /* Must pad to an alignment boundary that is twice the pointer size. */ + excess = (hdrptr - start) % (2 * arange.ar_pointer_size); + if (excess) + ranges += (2 * arange.ar_pointer_size) - excess; + + for (;;) + { + address = byte_get (ranges, arange.ar_pointer_size); + + ranges += arange.ar_pointer_size; + + length = byte_get (ranges, arange.ar_pointer_size); + + ranges += arange.ar_pointer_size; + + /* A pair of zeros marks the end of the list. */ + if (address == 0 && length == 0) + break; + + printf (" %8.8lx %lu\n", address, length); + } + + start += arange.ar_length + initial_length_size; + } + + printf ("\n"); + + return 1; +} + +typedef struct Frame_Chunk +{ + struct Frame_Chunk *next; + unsigned char *chunk_start; + int ncols; + /* DW_CFA_{undefined,same_value,offset,register,unreferenced} */ + short int *col_type; + int *col_offset; + char *augmentation; + unsigned int code_factor; + int data_factor; + unsigned long pc_begin; + unsigned long pc_range; + int cfa_reg; + int cfa_offset; + int ra; + unsigned char fde_encoding; + unsigned char cfa_exp; +} +Frame_Chunk; + +/* A marker for a col_type that means this column was never referenced + in the frame info. */ +#define DW_CFA_unreferenced (-1) + +static void frame_need_space PARAMS ((Frame_Chunk *, int)); +static void frame_display_row PARAMS ((Frame_Chunk *, int *, int *)); +static int size_of_encoded_value PARAMS ((int)); + +static void +frame_need_space (fc, reg) + Frame_Chunk *fc; + int reg; +{ + int prev = fc->ncols; + + if (reg < fc->ncols) + return; + + fc->ncols = reg + 1; + fc->col_type = (short int *) xrealloc (fc->col_type, + fc->ncols * sizeof (short int)); + fc->col_offset = (int *) xrealloc (fc->col_offset, + fc->ncols * sizeof (int)); + + while (prev < fc->ncols) + { + fc->col_type[prev] = DW_CFA_unreferenced; + fc->col_offset[prev] = 0; + prev++; + } +} + +static void +frame_display_row (fc, need_col_headers, max_regs) + Frame_Chunk *fc; + int *need_col_headers; + int *max_regs; +{ + int r; + char tmp[100]; + + if (*max_regs < fc->ncols) + *max_regs = fc->ncols; + + if (*need_col_headers) + { + *need_col_headers = 0; + + printf (" LOC CFA "); + + for (r = 0; r < *max_regs; r++) + if (fc->col_type[r] != DW_CFA_unreferenced) + { + if (r == fc->ra) + printf ("ra "); + else + printf ("r%-4d", r); + } + + printf ("\n"); + } + + printf ("%08lx ", fc->pc_begin); + if (fc->cfa_exp) + strcpy (tmp, "exp"); + else + sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset); + printf ("%-8s ", tmp); + + for (r = 0; r < fc->ncols; r++) + { + if (fc->col_type[r] != DW_CFA_unreferenced) + { + switch (fc->col_type[r]) + { + case DW_CFA_undefined: + strcpy (tmp, "u"); + break; + case DW_CFA_same_value: + strcpy (tmp, "s"); + break; + case DW_CFA_offset: + sprintf (tmp, "c%+d", fc->col_offset[r]); + break; + case DW_CFA_register: + sprintf (tmp, "r%d", fc->col_offset[r]); + break; + case DW_CFA_expression: + strcpy (tmp, "exp"); + break; + default: + strcpy (tmp, "n/a"); + break; + } + printf ("%-5s", tmp); + } + } + printf ("\n"); +} + +static int +size_of_encoded_value (encoding) + int encoding; +{ + switch (encoding & 0x7) + { + default: /* ??? */ + case 0: return is_32bit_elf ? 4 : 8; + case 2: return 2; + case 3: return 4; + case 4: return 8; + } +} + +#define GET(N) byte_get (start, N); start += N +#define LEB() read_leb128 (start, & length_return, 0); start += length_return +#define SLEB() read_leb128 (start, & length_return, 1); start += length_return + +static int +display_debug_frames (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start; + FILE *file ATTRIBUTE_UNUSED; +{ + unsigned char *end = start + section->sh_size; + unsigned char *section_start = start; + Frame_Chunk *chunks = 0; + Frame_Chunk *remembered_state = 0; + Frame_Chunk *rs; + int is_eh = (strcmp (SECTION_NAME (section), ".eh_frame") == 0); + int length_return; + int max_regs = 0; + int addr_size = is_32bit_elf ? 4 : 8; + + printf (_("The section %s contains:\n"), SECTION_NAME (section)); + + while (start < end) + { + unsigned char *saved_start; + unsigned char *block_end; + unsigned long length; + unsigned long cie_id; + Frame_Chunk *fc; + Frame_Chunk *cie; + int need_col_headers = 1; + unsigned char *augmentation_data = NULL; + unsigned long augmentation_data_len = 0; + int encoded_ptr_size = addr_size; + int offset_size; + int initial_length_size; + + saved_start = start; + length = byte_get (start, 4); start += 4; + + if (length == 0) + { + printf ("\n%08lx ZERO terminator\n\n", + (unsigned long)(saved_start - section_start)); + return 1; + } + + if (length == 0xffffffff) + { + length = byte_get (start, 8); + start += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; + } + + block_end = saved_start + length + initial_length_size; + cie_id = byte_get (start, offset_size); start += offset_size; + + if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID)) + { + int version; + + fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); + memset (fc, 0, sizeof (Frame_Chunk)); + + fc->next = chunks; + chunks = fc; + fc->chunk_start = saved_start; + fc->ncols = 0; + fc->col_type = (short int *) xmalloc (sizeof (short int)); + fc->col_offset = (int *) xmalloc (sizeof (int)); + frame_need_space (fc, max_regs-1); + + version = *start++; + + fc->augmentation = start; + start = strchr (start, '\0') + 1; + + if (fc->augmentation[0] == 'z') + { + fc->code_factor = LEB (); + fc->data_factor = SLEB (); + fc->ra = byte_get (start, 1); start += 1; + augmentation_data_len = LEB (); + augmentation_data = start; + start += augmentation_data_len; + } + else if (strcmp (fc->augmentation, "eh") == 0) + { + start += addr_size; + fc->code_factor = LEB (); + fc->data_factor = SLEB (); + fc->ra = byte_get (start, 1); start += 1; + } + else + { + fc->code_factor = LEB (); + fc->data_factor = SLEB (); + fc->ra = byte_get (start, 1); start += 1; + } + cie = fc; + + if (do_debug_frames_interp) + printf ("\n%08lx %08lx %08lx CIE \"%s\" cf=%d df=%d ra=%d\n", + (unsigned long)(saved_start - section_start), length, cie_id, + fc->augmentation, fc->code_factor, fc->data_factor, + fc->ra); + else + { + printf ("\n%08lx %08lx %08lx CIE\n", + (unsigned long)(saved_start - section_start), length, cie_id); + printf (" Version: %d\n", version); + printf (" Augmentation: \"%s\"\n", fc->augmentation); + printf (" Code alignment factor: %u\n", fc->code_factor); + printf (" Data alignment factor: %d\n", fc->data_factor); + printf (" Return address column: %d\n", fc->ra); + + if (augmentation_data_len) + { + unsigned long i; + printf (" Augmentation data: "); + for (i = 0; i < augmentation_data_len; ++i) + printf (" %02x", augmentation_data[i]); + putchar ('\n'); + } + putchar ('\n'); + } + + if (augmentation_data_len) + { + unsigned char *p, *q; + p = fc->augmentation + 1; + q = augmentation_data; + + while (1) + { + if (*p == 'L') + q++; + else if (*p == 'P') + q += 1 + size_of_encoded_value (*q); + else if (*p == 'R') + fc->fde_encoding = *q++; + else + break; + p++; + } + + if (fc->fde_encoding) + encoded_ptr_size = size_of_encoded_value (fc->fde_encoding); + } + + frame_need_space (fc, fc->ra); + } + else + { + unsigned char *look_for; + static Frame_Chunk fde_fc; + + fc = & fde_fc; + memset (fc, 0, sizeof (Frame_Chunk)); + + look_for = is_eh ? start - 4 - cie_id : section_start + cie_id; + + for (cie = chunks; cie ; cie = cie->next) + if (cie->chunk_start == look_for) + break; + + if (!cie) + { + warn ("Invalid CIE pointer %08lx in FDE at %08lx\n", + cie_id, saved_start); + start = block_end; + fc->ncols = 0; + fc->col_type = (short int *) xmalloc (sizeof (short int)); + fc->col_offset = (int *) xmalloc (sizeof (int)); + frame_need_space (fc, max_regs - 1); + cie = fc; + fc->augmentation = ""; + fc->fde_encoding = 0; + } + else + { + fc->ncols = cie->ncols; + fc->col_type = (short int *) xmalloc (fc->ncols * sizeof (short int)); + fc->col_offset = (int *) xmalloc (fc->ncols * sizeof (int)); + memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int)); + memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int)); + fc->augmentation = cie->augmentation; + fc->code_factor = cie->code_factor; + fc->data_factor = cie->data_factor; + fc->cfa_reg = cie->cfa_reg; + fc->cfa_offset = cie->cfa_offset; + fc->ra = cie->ra; + frame_need_space (fc, max_regs-1); + fc->fde_encoding = cie->fde_encoding; + } + + if (fc->fde_encoding) + encoded_ptr_size = size_of_encoded_value (fc->fde_encoding); + + fc->pc_begin = byte_get (start, encoded_ptr_size); + if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel) + fc->pc_begin += section->sh_addr + (start - section_start); + start += encoded_ptr_size; + fc->pc_range = byte_get (start, encoded_ptr_size); + start += encoded_ptr_size; + + if (cie->augmentation[0] == 'z') + { + augmentation_data_len = LEB (); + augmentation_data = start; + start += augmentation_data_len; + } + + printf ("\n%08lx %08lx %08lx FDE cie=%08lx pc=%08lx..%08lx\n", + (unsigned long)(saved_start - section_start), length, cie_id, + (unsigned long)(cie->chunk_start - section_start), + fc->pc_begin, fc->pc_begin + fc->pc_range); + if (! do_debug_frames_interp && augmentation_data_len) + { + unsigned long i; + printf (" Augmentation data: "); + for (i = 0; i < augmentation_data_len; ++i) + printf (" %02x", augmentation_data[i]); + putchar ('\n'); + putchar ('\n'); + } + } + + /* At this point, fc is the current chunk, cie (if any) is set, and we're + about to interpret instructions for the chunk. */ + + if (do_debug_frames_interp) + { + /* Start by making a pass over the chunk, allocating storage + and taking note of what registers are used. */ + unsigned char *tmp = start; + + while (start < block_end) + { + unsigned op, opa; + unsigned long reg, tmp; + + op = *start++; + opa = op & 0x3f; + if (op & 0xc0) + op &= 0xc0; + + /* Warning: if you add any more cases to this switch, be + sure to add them to the corresponding switch below. */ + switch (op) + { + case DW_CFA_advance_loc: + break; + case DW_CFA_offset: + LEB (); + frame_need_space (fc, opa); + fc->col_type[opa] = DW_CFA_undefined; + break; + case DW_CFA_restore: + frame_need_space (fc, opa); + fc->col_type[opa] = DW_CFA_undefined; + break; + case DW_CFA_set_loc: + start += encoded_ptr_size; + break; + case DW_CFA_advance_loc1: + start += 1; + break; + case DW_CFA_advance_loc2: + start += 2; + break; + case DW_CFA_advance_loc4: + start += 4; + break; + case DW_CFA_offset_extended: + reg = LEB (); LEB (); + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + break; + case DW_CFA_restore_extended: + reg = LEB (); + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + break; + case DW_CFA_undefined: + reg = LEB (); + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + break; + case DW_CFA_same_value: + reg = LEB (); + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + break; + case DW_CFA_register: + reg = LEB (); LEB (); + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + break; + case DW_CFA_def_cfa: + LEB (); LEB (); + break; + case DW_CFA_def_cfa_register: + LEB (); + break; + case DW_CFA_def_cfa_offset: + LEB (); + break; + case DW_CFA_def_cfa_expression: + tmp = LEB (); + start += tmp; + break; + case DW_CFA_expression: + reg = LEB (); + tmp = LEB (); + start += tmp; + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + break; + case DW_CFA_offset_extended_sf: + reg = LEB (); SLEB (); + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + break; + case DW_CFA_def_cfa_sf: + LEB (); SLEB (); + break; + case DW_CFA_def_cfa_offset_sf: + SLEB (); + break; + case DW_CFA_MIPS_advance_loc8: + start += 8; + break; + case DW_CFA_GNU_args_size: + LEB (); + break; + case DW_CFA_GNU_negative_offset_extended: + reg = LEB (); LEB (); + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + + default: + break; + } + } + start = tmp; + } + + /* Now we know what registers are used, make a second pass over + the chunk, this time actually printing out the info. */ + + while (start < block_end) + { + unsigned op, opa; + unsigned long ul, reg, roffs; + long l, ofs; + bfd_vma vma; + + op = *start++; + opa = op & 0x3f; + if (op & 0xc0) + op &= 0xc0; + + /* Warning: if you add any more cases to this switch, be + sure to add them to the corresponding switch above. */ + switch (op) + { + case DW_CFA_advance_loc: + if (do_debug_frames_interp) + frame_display_row (fc, &need_col_headers, &max_regs); + else + printf (" DW_CFA_advance_loc: %d to %08lx\n", + opa * fc->code_factor, + fc->pc_begin + opa * fc->code_factor); + fc->pc_begin += opa * fc->code_factor; + break; + + case DW_CFA_offset: + roffs = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_offset: r%d at cfa%+ld\n", + opa, roffs * fc->data_factor); + fc->col_type[opa] = DW_CFA_offset; + fc->col_offset[opa] = roffs * fc->data_factor; + break; + + case DW_CFA_restore: + if (! do_debug_frames_interp) + printf (" DW_CFA_restore: r%d\n", opa); + fc->col_type[opa] = cie->col_type[opa]; + fc->col_offset[opa] = cie->col_offset[opa]; + break; + + case DW_CFA_set_loc: + vma = byte_get (start, encoded_ptr_size); + if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel) + vma += section->sh_addr + (start - section_start); + start += encoded_ptr_size; + if (do_debug_frames_interp) + frame_display_row (fc, &need_col_headers, &max_regs); + else + printf (" DW_CFA_set_loc: %08lx\n", (unsigned long)vma); + fc->pc_begin = vma; + break; + + case DW_CFA_advance_loc1: + ofs = byte_get (start, 1); start += 1; + if (do_debug_frames_interp) + frame_display_row (fc, &need_col_headers, &max_regs); + else + printf (" DW_CFA_advance_loc1: %ld to %08lx\n", + ofs * fc->code_factor, + fc->pc_begin + ofs * fc->code_factor); + fc->pc_begin += ofs * fc->code_factor; + break; + + case DW_CFA_advance_loc2: + ofs = byte_get (start, 2); start += 2; + if (do_debug_frames_interp) + frame_display_row (fc, &need_col_headers, &max_regs); + else + printf (" DW_CFA_advance_loc2: %ld to %08lx\n", + ofs * fc->code_factor, + fc->pc_begin + ofs * fc->code_factor); + fc->pc_begin += ofs * fc->code_factor; + break; + + case DW_CFA_advance_loc4: + ofs = byte_get (start, 4); start += 4; + if (do_debug_frames_interp) + frame_display_row (fc, &need_col_headers, &max_regs); + else + printf (" DW_CFA_advance_loc4: %ld to %08lx\n", + ofs * fc->code_factor, + fc->pc_begin + ofs * fc->code_factor); + fc->pc_begin += ofs * fc->code_factor; + break; + + case DW_CFA_offset_extended: + reg = LEB (); + roffs = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_offset_extended: r%ld at cfa%+ld\n", + reg, roffs * fc->data_factor); + fc->col_type[reg] = DW_CFA_offset; + fc->col_offset[reg] = roffs * fc->data_factor; + break; + + case DW_CFA_restore_extended: + reg = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_restore_extended: r%ld\n", reg); + fc->col_type[reg] = cie->col_type[reg]; + fc->col_offset[reg] = cie->col_offset[reg]; + break; + + case DW_CFA_undefined: + reg = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_undefined: r%ld\n", reg); + fc->col_type[reg] = DW_CFA_undefined; + fc->col_offset[reg] = 0; + break; + + case DW_CFA_same_value: + reg = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_same_value: r%ld\n", reg); + fc->col_type[reg] = DW_CFA_same_value; + fc->col_offset[reg] = 0; + break; + + case DW_CFA_register: + reg = LEB (); + roffs = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_register: r%ld\n", reg); + fc->col_type[reg] = DW_CFA_register; + fc->col_offset[reg] = roffs; + break; + + case DW_CFA_remember_state: + if (! do_debug_frames_interp) + printf (" DW_CFA_remember_state\n"); + rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); + rs->ncols = fc->ncols; + rs->col_type = (short int *) xmalloc (rs->ncols * sizeof (short int)); + rs->col_offset = (int *) xmalloc (rs->ncols * sizeof (int)); + memcpy (rs->col_type, fc->col_type, rs->ncols); + memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int)); + rs->next = remembered_state; + remembered_state = rs; + break; + + case DW_CFA_restore_state: + if (! do_debug_frames_interp) + printf (" DW_CFA_restore_state\n"); + rs = remembered_state; + remembered_state = rs->next; + frame_need_space (fc, rs->ncols-1); + memcpy (fc->col_type, rs->col_type, rs->ncols); + memcpy (fc->col_offset, rs->col_offset, rs->ncols * sizeof (int)); + free (rs->col_type); + free (rs->col_offset); + free (rs); + break; + + case DW_CFA_def_cfa: + fc->cfa_reg = LEB (); + fc->cfa_offset = LEB (); + fc->cfa_exp = 0; + if (! do_debug_frames_interp) + printf (" DW_CFA_def_cfa: r%d ofs %d\n", + fc->cfa_reg, fc->cfa_offset); + break; + + case DW_CFA_def_cfa_register: + fc->cfa_reg = LEB (); + fc->cfa_exp = 0; + if (! do_debug_frames_interp) + printf (" DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg); + break; + + case DW_CFA_def_cfa_offset: + fc->cfa_offset = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_def_cfa_offset: %d\n", fc->cfa_offset); + break; + + case DW_CFA_nop: + if (! do_debug_frames_interp) + printf (" DW_CFA_nop\n"); + break; + + case DW_CFA_def_cfa_expression: + ul = LEB (); + if (! do_debug_frames_interp) + { + printf (" DW_CFA_def_cfa_expression ("); + decode_location_expression (start, addr_size, ul); + printf (")\n"); + } + fc->cfa_exp = 1; + start += ul; + break; + + case DW_CFA_expression: + reg = LEB (); + ul = LEB (); + if (! do_debug_frames_interp) + { + printf (" DW_CFA_expression: r%ld (", reg); + decode_location_expression (start, addr_size, ul); + printf (")\n"); + } + fc->col_type[reg] = DW_CFA_expression; + start += ul; + break; + + case DW_CFA_offset_extended_sf: + reg = LEB (); + l = SLEB (); + frame_need_space (fc, reg); + if (! do_debug_frames_interp) + printf (" DW_CFA_offset_extended_sf: r%ld at cfa%+ld\n", + reg, l * fc->data_factor); + fc->col_type[reg] = DW_CFA_offset; + fc->col_offset[reg] = l * fc->data_factor; + break; + + case DW_CFA_def_cfa_sf: + fc->cfa_reg = LEB (); + fc->cfa_offset = SLEB (); + fc->cfa_exp = 0; + if (! do_debug_frames_interp) + printf (" DW_CFA_def_cfa_sf: r%d ofs %d\n", + fc->cfa_reg, fc->cfa_offset); + break; + + case DW_CFA_def_cfa_offset_sf: + fc->cfa_offset = SLEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset); + break; + + case DW_CFA_MIPS_advance_loc8: + ofs = byte_get (start, 8); start += 8; + if (do_debug_frames_interp) + frame_display_row (fc, &need_col_headers, &max_regs); + else + printf (" DW_CFA_MIPS_advance_loc8: %ld to %08lx\n", + ofs * fc->code_factor, + fc->pc_begin + ofs * fc->code_factor); + fc->pc_begin += ofs * fc->code_factor; + break; + + case DW_CFA_GNU_window_save: + if (! do_debug_frames_interp) + printf (" DW_CFA_GNU_window_save\n"); + break; + + case DW_CFA_GNU_args_size: + ul = LEB (); + if (! do_debug_frames_interp) + printf (" DW_CFA_GNU_args_size: %ld\n", ul); + break; + + case DW_CFA_GNU_negative_offset_extended: + reg = LEB (); + l = - LEB (); + frame_need_space (fc, reg); + if (! do_debug_frames_interp) + printf (" DW_CFA_GNU_negative_offset_extended: r%ld at cfa%+ld\n", + reg, l * fc->data_factor); + fc->col_type[reg] = DW_CFA_offset; + fc->col_offset[reg] = l * fc->data_factor; + break; + + default: + fprintf (stderr, "unsupported or unknown DW_CFA_%d\n", op); + start = block_end; + } + } + + if (do_debug_frames_interp) + frame_display_row (fc, &need_col_headers, &max_regs); + + start = block_end; + } + + printf ("\n"); + + return 1; +} + +#undef GET +#undef LEB +#undef SLEB + +static int +display_debug_not_supported (section, start, file) + Elf_Internal_Shdr *section; + unsigned char *start ATTRIBUTE_UNUSED; + FILE *file ATTRIBUTE_UNUSED; +{ + printf (_("Displaying the debug contents of section %s is not yet supported.\n"), + SECTION_NAME (section)); + + return 1; +} + +/* Pre-scan the .debug_info section to record the size of address. + When dumping the .debug_line, we use that size information, assuming + that all compilation units have the same address size. */ +static int +prescan_debug_info (section, start, file) + Elf_Internal_Shdr *section ATTRIBUTE_UNUSED; + unsigned char *start; + FILE *file ATTRIBUTE_UNUSED; +{ + unsigned long length; + + /* Read the first 4 bytes. For a 32-bit DWARF section, this will + be the length. For a 64-bit DWARF section, it'll be the escape + code 0xffffffff followed by an 8 byte length. For the purposes + of this prescan, we don't care about the actual length, but the + presence of the escape bytes does affect the location of the byte + which describes the address size. */ + length = byte_get (start, 4); + + if (length == 0xffffffff) + { + /* For 64-bit DWARF, the 1-byte address_size field is 22 bytes + from the start of the section. This is computed as follows: + + unit_length: 12 bytes + version: 2 bytes + debug_abbrev_offset: 8 bytes + ----------------------------- + Total: 22 bytes */ + + debug_line_pointer_size = byte_get (start + 22, 1); + } + else + { + /* For 32-bit DWARF, the 1-byte address_size field is 10 bytes from + the start of the section: + unit_length: 4 bytes + version: 2 bytes + debug_abbrev_offset: 4 bytes + ----------------------------- + Total: 10 bytes */ + + debug_line_pointer_size = byte_get (start + 10, 1); + } + return 0; +} + + /* A structure containing the name of a debug section and a pointer + to a function that can decode it. The third field is a prescan + function to be run over the section before displaying any of the + sections. */ +struct +{ + const char *const name; + int (*display) PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); + int (*prescan) PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); +} +debug_displays[] = +{ + { ".debug_abbrev", display_debug_abbrev, NULL }, + { ".debug_aranges", display_debug_aranges, NULL }, + { ".debug_frame", display_debug_frames, NULL }, + { ".debug_info", display_debug_info, prescan_debug_info }, + { ".debug_line", display_debug_lines, NULL }, + { ".debug_pubnames", display_debug_pubnames, NULL }, + { ".eh_frame", display_debug_frames, NULL }, + { ".debug_macinfo", display_debug_macinfo, NULL }, + { ".debug_str", display_debug_str, NULL }, + { ".debug_loc", display_debug_loc, NULL }, + { ".debug_pubtypes", display_debug_not_supported, NULL }, + { ".debug_ranges", display_debug_not_supported, NULL }, + { ".debug_static_func", display_debug_not_supported, NULL }, + { ".debug_static_vars", display_debug_not_supported, NULL }, + { ".debug_types", display_debug_not_supported, NULL }, + { ".debug_weaknames", display_debug_not_supported, NULL } +}; + +static int +display_debug_section (section, file) + Elf_Internal_Shdr *section; + FILE *file; +{ + char *name = SECTION_NAME (section); + bfd_size_type length; + unsigned char *start; + int i; + + length = section->sh_size; + if (length == 0) + { + printf (_("\nSection '%s' has no debugging data.\n"), name); + return 0; + } + + start = (unsigned char *) get_data (NULL, file, section->sh_offset, length, + _("debug section data")); + if (!start) + return 0; + + /* See if we know how to display the contents of this section. */ + if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0) + name = ".debug_info"; + + for (i = NUM_ELEM (debug_displays); i--;) + if (strcmp (debug_displays[i].name, name) == 0) + { + debug_displays[i].display (section, start, file); + break; + } + + if (i == -1) + printf (_("Unrecognized debug section: %s\n"), name); + + free (start); + + /* If we loaded in the abbrev section at some point, + we must release it here. */ + free_abbrevs (); + + return 1; +} + +static int +process_section_contents (file) + FILE *file; +{ + Elf_Internal_Shdr *section; + unsigned int i; + + if (! do_dump) + return 1; + + /* Pre-scan the debug sections to find some debug information not + present in some of them. For the .debug_line, we must find out the + size of address (specified in .debug_info and .debug_aranges). */ + for (i = 0, section = section_headers; + i < elf_header.e_shnum && i < num_dump_sects; + i++, section++) + { + char *name = SECTION_NAME (section); + int j; + + if (section->sh_size == 0) + continue; + + /* See if there is some pre-scan operation for this section. */ + for (j = NUM_ELEM (debug_displays); j--;) + if (strcmp (debug_displays[j].name, name) == 0) + { + if (debug_displays[j].prescan != NULL) + { + bfd_size_type length; + unsigned char *start; + + length = section->sh_size; + start = ((unsigned char *) + get_data (NULL, file, section->sh_offset, length, + _("debug section data"))); + if (!start) + return 0; + + debug_displays[j].prescan (section, start, file); + free (start); + } + + break; + } + } + + for (i = 0, section = section_headers; + i < elf_header.e_shnum && i < num_dump_sects; + i++, section++) + { +#ifdef SUPPORT_DISASSEMBLY + if (dump_sects[i] & DISASS_DUMP) + disassemble_section (section, file); +#endif + if (dump_sects[i] & HEX_DUMP) + dump_section (section, file); + + if (dump_sects[i] & DEBUG_DUMP) + display_debug_section (section, file); + } + + if (i < num_dump_sects) + warn (_("Some sections were not dumped because they do not exist!\n")); + + return 1; +} + +static void +process_mips_fpe_exception (mask) + int mask; +{ + if (mask) + { + int first = 1; + if (mask & OEX_FPU_INEX) + fputs ("INEX", stdout), first = 0; + if (mask & OEX_FPU_UFLO) + printf ("%sUFLO", first ? "" : "|"), first = 0; + if (mask & OEX_FPU_OFLO) + printf ("%sOFLO", first ? "" : "|"), first = 0; + if (mask & OEX_FPU_DIV0) + printf ("%sDIV0", first ? "" : "|"), first = 0; + if (mask & OEX_FPU_INVAL) + printf ("%sINVAL", first ? "" : "|"); + } + else + fputs ("0", stdout); +} + +static int +process_mips_specific (file) + FILE *file; +{ + Elf_Internal_Dyn *entry; + size_t liblist_offset = 0; + size_t liblistno = 0; + size_t conflictsno = 0; + size_t options_offset = 0; + size_t conflicts_offset = 0; + + /* We have a lot of special sections. Thanks SGI! */ + if (dynamic_segment == NULL) + /* No information available. */ + return 0; + + for (entry = dynamic_segment; entry->d_tag != DT_NULL; ++entry) + switch (entry->d_tag) + { + case DT_MIPS_LIBLIST: + liblist_offset = entry->d_un.d_val - loadaddr; + break; + case DT_MIPS_LIBLISTNO: + liblistno = entry->d_un.d_val; + break; + case DT_MIPS_OPTIONS: + options_offset = entry->d_un.d_val - loadaddr; + break; + case DT_MIPS_CONFLICT: + conflicts_offset = entry->d_un.d_val - loadaddr; + break; + case DT_MIPS_CONFLICTNO: + conflictsno = entry->d_un.d_val; + break; + default: + break; + } + + if (liblist_offset != 0 && liblistno != 0 && do_dynamic) + { + Elf32_External_Lib *elib; + size_t cnt; + + elib = ((Elf32_External_Lib *) + get_data (NULL, file, liblist_offset, + liblistno * sizeof (Elf32_External_Lib), + _("liblist"))); + if (elib) + { + printf ("\nSection '.liblist' contains %lu entries:\n", + (unsigned long) liblistno); + fputs (" Library Time Stamp Checksum Version Flags\n", + stdout); + + for (cnt = 0; cnt < liblistno; ++cnt) + { + Elf32_Lib liblist; + time_t time; + char timebuf[20]; + struct tm *tmp; + + liblist.l_name = BYTE_GET (elib[cnt].l_name); + time = BYTE_GET (elib[cnt].l_time_stamp); + liblist.l_checksum = BYTE_GET (elib[cnt].l_checksum); + liblist.l_version = BYTE_GET (elib[cnt].l_version); + liblist.l_flags = BYTE_GET (elib[cnt].l_flags); + + tmp = gmtime (&time); + sprintf (timebuf, "%04u-%02u-%02uT%02u:%02u:%02u", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + printf ("%3lu: ", (unsigned long) cnt); + print_symbol (20, dynamic_strings + liblist.l_name); + printf (" %s %#10lx %-7ld", timebuf, liblist.l_checksum, + liblist.l_version); + + if (liblist.l_flags == 0) + puts (" NONE"); + else + { + static const struct + { + const char *name; + int bit; + } + l_flags_vals[] = + { + { " EXACT_MATCH", LL_EXACT_MATCH }, + { " IGNORE_INT_VER", LL_IGNORE_INT_VER }, + { " REQUIRE_MINOR", LL_REQUIRE_MINOR }, + { " EXPORTS", LL_EXPORTS }, + { " DELAY_LOAD", LL_DELAY_LOAD }, + { " DELTA", LL_DELTA } + }; + int flags = liblist.l_flags; + size_t fcnt; + + for (fcnt = 0; + fcnt < sizeof (l_flags_vals) / sizeof (l_flags_vals[0]); + ++fcnt) + if ((flags & l_flags_vals[fcnt].bit) != 0) + { + fputs (l_flags_vals[fcnt].name, stdout); + flags ^= l_flags_vals[fcnt].bit; + } + if (flags != 0) + printf (" %#x", (unsigned int) flags); + + puts (""); + } + } + + free (elib); + } + } + + if (options_offset != 0) + { + Elf_External_Options *eopt; + Elf_Internal_Shdr *sect = section_headers; + Elf_Internal_Options *iopt; + Elf_Internal_Options *option; + size_t offset; + int cnt; + + /* Find the section header so that we get the size. */ + while (sect->sh_type != SHT_MIPS_OPTIONS) + ++sect; + + eopt = (Elf_External_Options *) get_data (NULL, file, options_offset, + sect->sh_size, _("options")); + if (eopt) + { + iopt = ((Elf_Internal_Options *) + malloc ((sect->sh_size / sizeof (eopt)) * sizeof (*iopt))); + if (iopt == NULL) + { + error (_("Out of memory")); + return 0; + } + + offset = cnt = 0; + option = iopt; + + while (offset < sect->sh_size) + { + Elf_External_Options *eoption; + + eoption = (Elf_External_Options *) ((char *) eopt + offset); + + option->kind = BYTE_GET (eoption->kind); + option->size = BYTE_GET (eoption->size); + option->section = BYTE_GET (eoption->section); + option->info = BYTE_GET (eoption->info); + + offset += option->size; + + ++option; + ++cnt; + } + + printf (_("\nSection '%s' contains %d entries:\n"), + SECTION_NAME (sect), cnt); + + option = iopt; + + while (cnt-- > 0) + { + size_t len; + + switch (option->kind) + { + case ODK_NULL: + /* This shouldn't happen. */ + printf (" NULL %d %lx", option->section, option->info); + break; + case ODK_REGINFO: + printf (" REGINFO "); + if (elf_header.e_machine == EM_MIPS) + { + /* 32bit form. */ + Elf32_External_RegInfo *ereg; + Elf32_RegInfo reginfo; + + ereg = (Elf32_External_RegInfo *) (option + 1); + reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask); + reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]); + reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]); + reginfo.ri_cprmask[2] = BYTE_GET (ereg->ri_cprmask[2]); + reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]); + reginfo.ri_gp_value = BYTE_GET (ereg->ri_gp_value); + + printf ("GPR %08lx GP 0x%lx\n", + reginfo.ri_gprmask, + (unsigned long) reginfo.ri_gp_value); + printf (" CPR0 %08lx CPR1 %08lx CPR2 %08lx CPR3 %08lx\n", + reginfo.ri_cprmask[0], reginfo.ri_cprmask[1], + reginfo.ri_cprmask[2], reginfo.ri_cprmask[3]); + } + else + { + /* 64 bit form. */ + Elf64_External_RegInfo *ereg; + Elf64_Internal_RegInfo reginfo; + + ereg = (Elf64_External_RegInfo *) (option + 1); + reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask); + reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]); + reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]); + reginfo.ri_cprmask[2] = BYTE_GET (ereg->ri_cprmask[2]); + reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]); + reginfo.ri_gp_value = BYTE_GET8 (ereg->ri_gp_value); + + printf ("GPR %08lx GP 0x", + reginfo.ri_gprmask); + printf_vma (reginfo.ri_gp_value); + printf ("\n"); + + printf (" CPR0 %08lx CPR1 %08lx CPR2 %08lx CPR3 %08lx\n", + reginfo.ri_cprmask[0], reginfo.ri_cprmask[1], + reginfo.ri_cprmask[2], reginfo.ri_cprmask[3]); + } + ++option; + continue; + case ODK_EXCEPTIONS: + fputs (" EXCEPTIONS fpe_min(", stdout); + process_mips_fpe_exception (option->info & OEX_FPU_MIN); + fputs (") fpe_max(", stdout); + process_mips_fpe_exception ((option->info & OEX_FPU_MAX) >> 8); + fputs (")", stdout); + + if (option->info & OEX_PAGE0) + fputs (" PAGE0", stdout); + if (option->info & OEX_SMM) + fputs (" SMM", stdout); + if (option->info & OEX_FPDBUG) + fputs (" FPDBUG", stdout); + if (option->info & OEX_DISMISS) + fputs (" DISMISS", stdout); + break; + case ODK_PAD: + fputs (" PAD ", stdout); + if (option->info & OPAD_PREFIX) + fputs (" PREFIX", stdout); + if (option->info & OPAD_POSTFIX) + fputs (" POSTFIX", stdout); + if (option->info & OPAD_SYMBOL) + fputs (" SYMBOL", stdout); + break; + case ODK_HWPATCH: + fputs (" HWPATCH ", stdout); + if (option->info & OHW_R4KEOP) + fputs (" R4KEOP", stdout); + if (option->info & OHW_R8KPFETCH) + fputs (" R8KPFETCH", stdout); + if (option->info & OHW_R5KEOP) + fputs (" R5KEOP", stdout); + if (option->info & OHW_R5KCVTL) + fputs (" R5KCVTL", stdout); + break; + case ODK_FILL: + fputs (" FILL ", stdout); + /* XXX Print content of info word? */ + break; + case ODK_TAGS: + fputs (" TAGS ", stdout); + /* XXX Print content of info word? */ + break; + case ODK_HWAND: + fputs (" HWAND ", stdout); + if (option->info & OHWA0_R4KEOP_CHECKED) + fputs (" R4KEOP_CHECKED", stdout); + if (option->info & OHWA0_R4KEOP_CLEAN) + fputs (" R4KEOP_CLEAN", stdout); + break; + case ODK_HWOR: + fputs (" HWOR ", stdout); + if (option->info & OHWA0_R4KEOP_CHECKED) + fputs (" R4KEOP_CHECKED", stdout); + if (option->info & OHWA0_R4KEOP_CLEAN) + fputs (" R4KEOP_CLEAN", stdout); + break; + case ODK_GP_GROUP: + printf (" GP_GROUP %#06lx self-contained %#06lx", + option->info & OGP_GROUP, + (option->info & OGP_SELF) >> 16); + break; + case ODK_IDENT: + printf (" IDENT %#06lx self-contained %#06lx", + option->info & OGP_GROUP, + (option->info & OGP_SELF) >> 16); + break; + default: + /* This shouldn't happen. */ + printf (" %3d ??? %d %lx", + option->kind, option->section, option->info); + break; + } + + len = sizeof (*eopt); + while (len < option->size) + if (((char *) option)[len] >= ' ' + && ((char *) option)[len] < 0x7f) + printf ("%c", ((char *) option)[len++]); + else + printf ("\\%03o", ((char *) option)[len++]); + + fputs ("\n", stdout); + ++option; + } + + free (eopt); + } + } + + if (conflicts_offset != 0 && conflictsno != 0) + { + Elf32_Conflict *iconf; + size_t cnt; + + if (dynamic_symbols == NULL) + { + error (_("conflict list found without a dynamic symbol table")); + return 0; + } + + iconf = (Elf32_Conflict *) malloc (conflictsno * sizeof (*iconf)); + if (iconf == NULL) + { + error (_("Out of memory")); + return 0; + } + + if (is_32bit_elf) + { + Elf32_External_Conflict *econf32; + + econf32 = ((Elf32_External_Conflict *) + get_data (NULL, file, conflicts_offset, + conflictsno * sizeof (*econf32), + _("conflict"))); + if (!econf32) + return 0; + + for (cnt = 0; cnt < conflictsno; ++cnt) + iconf[cnt] = BYTE_GET (econf32[cnt]); + + free (econf32); + } + else + { + Elf64_External_Conflict *econf64; + + econf64 = ((Elf64_External_Conflict *) + get_data (NULL, file, conflicts_offset, + conflictsno * sizeof (*econf64), + _("conflict"))); + if (!econf64) + return 0; + + for (cnt = 0; cnt < conflictsno; ++cnt) + iconf[cnt] = BYTE_GET (econf64[cnt]); + + free (econf64); + } + + printf (_("\nSection '.conflict' contains %ld entries:\n"), + (long) conflictsno); + puts (_(" Num: Index Value Name")); + + for (cnt = 0; cnt < conflictsno; ++cnt) + { + Elf_Internal_Sym *psym = & dynamic_symbols[iconf[cnt]]; + + printf ("%5lu: %8lu ", (unsigned long) cnt, iconf[cnt]); + print_vma (psym->st_value, FULL_HEX); + putchar (' '); + print_symbol (25, dynamic_strings + psym->st_name); + putchar ('\n'); + } + + free (iconf); + } + + return 1; +} + +static int +process_gnu_liblist (file) + FILE *file; +{ + Elf_Internal_Shdr *section, *string_sec; + Elf32_External_Lib *elib; + char *strtab; + size_t cnt; + unsigned i; + + if (! do_arch) + return 0; + + for (i = 0, section = section_headers; + i < elf_header.e_shnum; + i++, section++) + { + switch (section->sh_type) + { + case SHT_GNU_LIBLIST: + elib = ((Elf32_External_Lib *) + get_data (NULL, file, section->sh_offset, section->sh_size, + _("liblist"))); + + if (elib == NULL) + break; + string_sec = SECTION_HEADER (section->sh_link); + + strtab = (char *) get_data (NULL, file, string_sec->sh_offset, + string_sec->sh_size, + _("liblist string table")); + + if (strtab == NULL + || section->sh_entsize != sizeof (Elf32_External_Lib)) + { + free (elib); + break; + } + + printf (_("\nLibrary list section '%s' contains %lu entries:\n"), + SECTION_NAME (section), + (long) (section->sh_size / sizeof (Elf32_External_Lib))); + + puts (" Library Time Stamp Checksum Version Flags"); + + for (cnt = 0; cnt < section->sh_size / sizeof (Elf32_External_Lib); + ++cnt) + { + Elf32_Lib liblist; + time_t time; + char timebuf[20]; + struct tm *tmp; + + liblist.l_name = BYTE_GET (elib[cnt].l_name); + time = BYTE_GET (elib[cnt].l_time_stamp); + liblist.l_checksum = BYTE_GET (elib[cnt].l_checksum); + liblist.l_version = BYTE_GET (elib[cnt].l_version); + liblist.l_flags = BYTE_GET (elib[cnt].l_flags); + + tmp = gmtime (&time); + sprintf (timebuf, "%04u-%02u-%02uT%02u:%02u:%02u", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); + + printf ("%3lu: ", (unsigned long) cnt); + if (do_wide) + printf ("%-20s", strtab + liblist.l_name); + else + printf ("%-20.20s", strtab + liblist.l_name); + printf (" %s %#010lx %-7ld %-7ld\n", timebuf, liblist.l_checksum, + liblist.l_version, liblist.l_flags); + } + + free (elib); + } + } + + return 1; +} + +static const char * +get_note_type (e_type) + unsigned e_type; +{ + static char buff[64]; + + switch (e_type) + { + case NT_PRSTATUS: return _("NT_PRSTATUS (prstatus structure)"); + case NT_FPREGSET: return _("NT_FPREGSET (floating point registers)"); + case NT_PRPSINFO: return _("NT_PRPSINFO (prpsinfo structure)"); + case NT_TASKSTRUCT: return _("NT_TASKSTRUCT (task structure)"); + case NT_PRXFPREG: return _("NT_PRXFPREG (user_xfpregs structure)"); + case NT_PSTATUS: return _("NT_PSTATUS (pstatus structure)"); + case NT_FPREGS: return _("NT_FPREGS (floating point registers)"); + case NT_PSINFO: return _("NT_PSINFO (psinfo structure)"); + case NT_LWPSTATUS: return _("NT_LWPSTATUS (lwpstatus_t structure)"); + case NT_LWPSINFO: return _("NT_LWPSINFO (lwpsinfo_t structure)"); + case NT_WIN32PSTATUS: return _("NT_WIN32PSTATUS (win32_pstatus structure)"); + default: + sprintf (buff, _("Unknown note type: (0x%08x)"), e_type); + return buff; + } +} + +static const char * +get_netbsd_elfcore_note_type (e_type) + unsigned e_type; +{ + static char buff[64]; + + if (e_type == NT_NETBSDCORE_PROCINFO) + { + /* NetBSD core "procinfo" structure. */ + return _("NetBSD procinfo structure"); + } + + /* As of Jan 2002 there are no other machine-independent notes + defined for NetBSD core files. If the note type is less + than the start of the machine-dependent note types, we don't + understand it. */ + + if (e_type < NT_NETBSDCORE_FIRSTMACH) + { + sprintf (buff, _("Unknown note type: (0x%08x)"), e_type); + return buff; + } + + switch (elf_header.e_machine) + { + /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 + and PT_GETFPREGS == mach+2. */ + + case EM_OLD_ALPHA: + case EM_ALPHA: + case EM_SPARC: + case EM_SPARC32PLUS: + case EM_SPARCV9: + switch (e_type) + { + case NT_NETBSDCORE_FIRSTMACH+0: + return _("PT_GETREGS (reg structure)"); + case NT_NETBSDCORE_FIRSTMACH+2: + return _("PT_GETFPREGS (fpreg structure)"); + default: + break; + } + break; + + /* On all other arch's, PT_GETREGS == mach+1 and + PT_GETFPREGS == mach+3. */ + default: + switch (e_type) + { + case NT_NETBSDCORE_FIRSTMACH+1: + return _("PT_GETREGS (reg structure)"); + case NT_NETBSDCORE_FIRSTMACH+3: + return _("PT_GETFPREGS (fpreg structure)"); + default: + break; + } + } + + sprintf (buff, _("PT_FIRSTMACH+%d"), e_type - NT_NETBSDCORE_FIRSTMACH); + return buff; +} + +/* Note that by the ELF standard, the name field is already null byte + terminated, and namesz includes the terminating null byte. + I.E. the value of namesz for the name "FSF" is 4. + + If the value of namesz is zero, there is no name present. */ +static int +process_note (pnote) + Elf_Internal_Note *pnote; +{ + const char *nt; + + if (pnote->namesz == 0) + { + /* If there is no note name, then use the default set of + note type strings. */ + nt = get_note_type (pnote->type); + } + else if (strncmp (pnote->namedata, "NetBSD-CORE", 11) == 0) + { + /* NetBSD-specific core file notes. */ + nt = get_netbsd_elfcore_note_type (pnote->type); + } + else + { + /* Don't recognize this note name; just use the default set of + note type strings. */ + nt = get_note_type (pnote->type); + } + + printf (" %s\t\t0x%08lx\t%s\n", + pnote->namesz ? pnote->namedata : "(NONE)", + pnote->descsz, nt); + return 1; +} + + +static int +process_corefile_note_segment (file, offset, length) + FILE *file; + bfd_vma offset; + bfd_vma length; +{ + Elf_External_Note *pnotes; + Elf_External_Note *external; + int res = 1; + + if (length <= 0) + return 0; + + pnotes = (Elf_External_Note *) get_data (NULL, file, offset, length, + _("notes")); + if (!pnotes) + return 0; + + external = pnotes; + + printf (_("\nNotes at offset 0x%08lx with length 0x%08lx:\n"), + (unsigned long) offset, (unsigned long) length); + printf (_(" Owner\t\tData size\tDescription\n")); + + while (external < (Elf_External_Note *)((char *) pnotes + length)) + { + Elf_External_Note *next; + Elf_Internal_Note inote; + char *temp = NULL; + + inote.type = BYTE_GET (external->type); + inote.namesz = BYTE_GET (external->namesz); + inote.namedata = external->name; + inote.descsz = BYTE_GET (external->descsz); + inote.descdata = inote.namedata + align_power (inote.namesz, 2); + inote.descpos = offset + (inote.descdata - (char *) pnotes); + + next = (Elf_External_Note *)(inote.descdata + align_power (inote.descsz, 2)); + + if (((char *) next) > (((char *) pnotes) + length)) + { + warn (_("corrupt note found at offset %x into core notes\n"), + ((char *) external) - ((char *) pnotes)); + warn (_(" type: %x, namesize: %08lx, descsize: %08lx\n"), + inote.type, inote.namesz, inote.descsz); + break; + } + + external = next; + + /* Verify that name is null terminated. It appears that at least + one version of Linux (RedHat 6.0) generates corefiles that don't + comply with the ELF spec by failing to include the null byte in + namesz. */ + if (inote.namedata[inote.namesz] != '\0') + { + temp = malloc (inote.namesz + 1); + + if (temp == NULL) + { + error (_("Out of memory\n")); + res = 0; + break; + } + + strncpy (temp, inote.namedata, inote.namesz); + temp[inote.namesz] = 0; + + /* warn (_("'%s' NOTE name not properly null terminated\n"), temp); */ + inote.namedata = temp; + } + + res &= process_note (& inote); + + if (temp != NULL) + { + free (temp); + temp = NULL; + } + } + + free (pnotes); + + return res; +} + +static int +process_corefile_note_segments (file) + FILE *file; +{ + Elf_Internal_Phdr *program_headers; + Elf_Internal_Phdr *segment; + unsigned int i; + int res = 1; + + program_headers = (Elf_Internal_Phdr *) malloc + (elf_header.e_phnum * sizeof (Elf_Internal_Phdr)); + + if (program_headers == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + if (is_32bit_elf) + i = get_32bit_program_headers (file, program_headers); + else + i = get_64bit_program_headers (file, program_headers); + + if (i == 0) + { + free (program_headers); + return 0; + } + + for (i = 0, segment = program_headers; + i < elf_header.e_phnum; + i++, segment++) + { + if (segment->p_type == PT_NOTE) + res &= process_corefile_note_segment (file, + (bfd_vma) segment->p_offset, + (bfd_vma) segment->p_filesz); + } + + free (program_headers); + + return res; +} + +static int +process_corefile_contents (file) + FILE *file; +{ + /* If we have not been asked to display the notes then do nothing. */ + if (! do_notes) + return 1; + + /* If file is not a core file then exit. */ + if (elf_header.e_type != ET_CORE) + return 1; + + /* No program headers means no NOTE segment. */ + if (elf_header.e_phnum == 0) + { + printf (_("No note segments present in the core file.\n")); + return 1; + } + + return process_corefile_note_segments (file); +} + +static int +process_arch_specific (file) + FILE *file; +{ + if (! do_arch) + return 1; + + switch (elf_header.e_machine) + { + case EM_MIPS: + case EM_MIPS_RS3_LE: + return process_mips_specific (file); + break; + default: + break; + } + return 1; +} + +static int +get_file_header (file) + FILE *file; +{ + /* Read in the identity array. */ + if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1) + return 0; + + /* Determine how to read the rest of the header. */ + switch (elf_header.e_ident[EI_DATA]) + { + default: /* fall through */ + case ELFDATANONE: /* fall through */ + case ELFDATA2LSB: + byte_get = byte_get_little_endian; + byte_put = byte_put_little_endian; + break; + case ELFDATA2MSB: + byte_get = byte_get_big_endian; + byte_put = byte_put_big_endian; + break; + } + + /* For now we only support 32 bit and 64 bit ELF files. */ + is_32bit_elf = (elf_header.e_ident[EI_CLASS] != ELFCLASS64); + + /* Read in the rest of the header. */ + if (is_32bit_elf) + { + Elf32_External_Ehdr ehdr32; + + if (fread (ehdr32.e_type, sizeof (ehdr32) - EI_NIDENT, 1, file) != 1) + return 0; + + elf_header.e_type = BYTE_GET (ehdr32.e_type); + elf_header.e_machine = BYTE_GET (ehdr32.e_machine); + elf_header.e_version = BYTE_GET (ehdr32.e_version); + elf_header.e_entry = BYTE_GET (ehdr32.e_entry); + elf_header.e_phoff = BYTE_GET (ehdr32.e_phoff); + elf_header.e_shoff = BYTE_GET (ehdr32.e_shoff); + elf_header.e_flags = BYTE_GET (ehdr32.e_flags); + elf_header.e_ehsize = BYTE_GET (ehdr32.e_ehsize); + elf_header.e_phentsize = BYTE_GET (ehdr32.e_phentsize); + elf_header.e_phnum = BYTE_GET (ehdr32.e_phnum); + elf_header.e_shentsize = BYTE_GET (ehdr32.e_shentsize); + elf_header.e_shnum = BYTE_GET (ehdr32.e_shnum); + elf_header.e_shstrndx = BYTE_GET (ehdr32.e_shstrndx); + } + else + { + Elf64_External_Ehdr ehdr64; + + /* If we have been compiled with sizeof (bfd_vma) == 4, then + we will not be able to cope with the 64bit data found in + 64 ELF files. Detect this now and abort before we start + overwritting things. */ + if (sizeof (bfd_vma) < 8) + { + error (_("This instance of readelf has been built without support for a\n\ +64 bit data type and so it cannot read 64 bit ELF files.\n")); + return 0; + } + + if (fread (ehdr64.e_type, sizeof (ehdr64) - EI_NIDENT, 1, file) != 1) + return 0; + + elf_header.e_type = BYTE_GET (ehdr64.e_type); + elf_header.e_machine = BYTE_GET (ehdr64.e_machine); + elf_header.e_version = BYTE_GET (ehdr64.e_version); + elf_header.e_entry = BYTE_GET8 (ehdr64.e_entry); + elf_header.e_phoff = BYTE_GET8 (ehdr64.e_phoff); + elf_header.e_shoff = BYTE_GET8 (ehdr64.e_shoff); + elf_header.e_flags = BYTE_GET (ehdr64.e_flags); + elf_header.e_ehsize = BYTE_GET (ehdr64.e_ehsize); + elf_header.e_phentsize = BYTE_GET (ehdr64.e_phentsize); + elf_header.e_phnum = BYTE_GET (ehdr64.e_phnum); + elf_header.e_shentsize = BYTE_GET (ehdr64.e_shentsize); + elf_header.e_shnum = BYTE_GET (ehdr64.e_shnum); + elf_header.e_shstrndx = BYTE_GET (ehdr64.e_shstrndx); + } + + if (elf_header.e_shoff) + { + /* There may be some extensions in the first section header. Don't + bomb if we can't read it. */ + if (is_32bit_elf) + get_32bit_section_headers (file, 1); + else + get_64bit_section_headers (file, 1); + } + + return 1; +} + +static int +process_file (file_name) + char *file_name; +{ + FILE *file; + struct stat statbuf; + unsigned int i; + + if (stat (file_name, & statbuf) < 0) + { + error (_("Cannot stat input file %s.\n"), file_name); + return 1; + } + + file = fopen (file_name, "rb"); + if (file == NULL) + { + error (_("Input file %s not found.\n"), file_name); + return 1; + } + + if (! get_file_header (file)) + { + error (_("%s: Failed to read file header\n"), file_name); + fclose (file); + return 1; + } + + /* Initialise per file variables. */ + for (i = NUM_ELEM (version_info); i--;) + version_info[i] = 0; + + for (i = NUM_ELEM (dynamic_info); i--;) + dynamic_info[i] = 0; + + /* Process the file. */ + if (show_name) + printf (_("\nFile: %s\n"), file_name); + + if (! process_file_header ()) + { + fclose (file); + return 1; + } + + if (! process_section_headers (file)) + { + /* Without loaded section headers we + cannot process lots of things. */ + do_unwind = do_version = do_dump = do_arch = 0; + + if (! do_using_dynamic) + do_syms = do_reloc = 0; + } + + if (process_program_headers (file)) + process_dynamic_segment (file); + + process_relocs (file); + + process_unwind (file); + + process_symbol_table (file); + + process_syminfo (file); + + process_version_sections (file); + + process_section_contents (file); + + process_corefile_contents (file); + + process_gnu_liblist (file); + + process_arch_specific (file); + + fclose (file); + + if (section_headers) + { + free (section_headers); + section_headers = NULL; + } + + if (string_table) + { + free (string_table); + string_table = NULL; + string_table_length = 0; + } + + if (dynamic_strings) + { + free (dynamic_strings); + dynamic_strings = NULL; + } + + if (dynamic_symbols) + { + free (dynamic_symbols); + dynamic_symbols = NULL; + num_dynamic_syms = 0; + } + + if (dynamic_syminfo) + { + free (dynamic_syminfo); + dynamic_syminfo = NULL; + } + + return 0; +} + +#ifdef SUPPORT_DISASSEMBLY +/* Needed by the i386 disassembler. For extra credit, someone could + fix this so that we insert symbolic addresses here, esp for GOT/PLT + symbols. */ + +void +print_address (unsigned int addr, FILE *outfile) +{ + fprintf (outfile,"0x%8.8x", addr); +} + +/* Needed by the i386 disassembler. */ +void +db_task_printsym (unsigned int addr) +{ + print_address (addr, stderr); +} +#endif + +int main PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char **argv; +{ + int err; + char *cmdline_dump_sects = NULL; + unsigned num_cmdline_dump_sects = 0; + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + parse_args (argc, argv); + + if (optind < (argc - 1)) + show_name = 1; + + /* When processing more than one file remember the dump requests + issued on command line to reset them after each file. */ + if (optind + 1 < argc && dump_sects != NULL) + { + cmdline_dump_sects = malloc (num_dump_sects); + if (cmdline_dump_sects == NULL) + error (_("Out of memory allocating dump request table.")); + else + { + memcpy (cmdline_dump_sects, dump_sects, num_dump_sects); + num_cmdline_dump_sects = num_dump_sects; + } + } + + err = 0; + while (optind < argc) + { + err |= process_file (argv[optind++]); + + /* Reset dump requests. */ + if (optind < argc && dump_sects != NULL) + { + num_dump_sects = num_cmdline_dump_sects; + if (num_cmdline_dump_sects > 0) + memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); + } + } + + if (dump_sects != NULL) + free (dump_sects); + if (cmdline_dump_sects != NULL) + free (cmdline_dump_sects); + + return err; +} diff --git a/contrib/binutils-2.14/binutils/rename.c b/contrib/binutils-2.14/binutils/rename.c new file mode 100644 index 0000000000..0ccaedc963 --- /dev/null +++ b/contrib/binutils-2.14/binutils/rename.c @@ -0,0 +1,221 @@ +/* rename.c -- rename a file, preserving symlinks. + Copyright 1999, 2002 Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "bfd.h" +#include "bucomm.h" + +#include + +#ifdef HAVE_GOOD_UTIME_H +#include +#else /* ! HAVE_GOOD_UTIME_H */ +#ifdef HAVE_UTIMES +#include +#endif /* HAVE_UTIMES */ +#endif /* ! HAVE_GOOD_UTIME_H */ + +/* We need to open the file in binary modes on system where that makes + a difference. */ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static int simple_copy + PARAMS ((const char *, const char *)); + +/* The number of bytes to copy at once. */ +#define COPY_BUF 8192 + +/* Copy file FROM to file TO, performing no translations. + Return 0 if ok, -1 if error. */ + +static int +simple_copy (from, to) + const char *from; + const char *to; +{ + int fromfd, tofd, nread; + int saved; + char buf[COPY_BUF]; + + fromfd = open (from, O_RDONLY | O_BINARY); + if (fromfd < 0) + return -1; +#ifdef O_CREAT + tofd = open (to, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0777); +#else + tofd = creat (to, 0777); +#endif + if (tofd < 0) + { + saved = errno; + close (fromfd); + errno = saved; + return -1; + } + while ((nread = read (fromfd, buf, sizeof buf)) > 0) + { + if (write (tofd, buf, nread) != nread) + { + saved = errno; + close (fromfd); + close (tofd); + errno = saved; + return -1; + } + } + saved = errno; + close (fromfd); + close (tofd); + if (nread < 0) + { + errno = saved; + return -1; + } + return 0; +} + +/* Set the times of the file DESTINATION to be the same as those in + STATBUF. */ + +void +set_times (destination, statbuf) + const char *destination; + const struct stat *statbuf; +{ + int result; + + { +#ifdef HAVE_GOOD_UTIME_H + struct utimbuf tb; + + tb.actime = statbuf->st_atime; + tb.modtime = statbuf->st_mtime; + result = utime (destination, &tb); +#else /* ! HAVE_GOOD_UTIME_H */ +#ifndef HAVE_UTIMES + long tb[2]; + + tb[0] = statbuf->st_atime; + tb[1] = statbuf->st_mtime; + result = utime (destination, tb); +#else /* HAVE_UTIMES */ + struct timeval tv[2]; + + tv[0].tv_sec = statbuf->st_atime; + tv[0].tv_usec = 0; + tv[1].tv_sec = statbuf->st_mtime; + tv[1].tv_usec = 0; + result = utimes (destination, tv); +#endif /* HAVE_UTIMES */ +#endif /* ! HAVE_GOOD_UTIME_H */ + } + + if (result != 0) + non_fatal (_("%s: cannot set time: %s"), destination, strerror (errno)); +} + +#ifndef S_ISLNK +#ifdef S_IFLNK +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#else +#define S_ISLNK(m) 0 +#define lstat stat +#endif +#endif + +/* Rename FROM to TO, copying if TO is a link. + Return 0 if ok, -1 if error. */ + +int +smart_rename (from, to, preserve_dates) + const char *from; + const char *to; + int preserve_dates; +{ + bfd_boolean exists; + struct stat s; + int ret = 0; + + exists = lstat (to, &s) == 0; + +#if defined (_WIN32) && !defined (__CYGWIN32__) + /* Win32, unlike unix, will not erase `to' in `rename(from, to)' but + fail instead. Also, chown is not present. */ + + if (exists) + remove (to); + + ret = rename (from, to); + if (ret != 0) + { + /* We have to clean up here. */ + + non_fatal (_("%s: rename: %s"), to, strerror (errno)); + unlink (from); + } +#else + /* Use rename only if TO is not a symbolic link and has + only one hard link. */ + if (! exists || (!S_ISLNK (s.st_mode) && s.st_nlink == 1)) + { + ret = rename (from, to); + if (ret == 0) + { + if (exists) + { + /* Try to preserve the permission bits and ownership of + TO. First get the mode right except for the setuid + bit. Then change the ownership. Then fix the setuid + bit. We do the chmod before the chown because if the + chown succeeds, and we are a normal user, we won't be + able to do the chmod afterward. We don't bother to + fix the setuid bit first because that might introduce + a fleeting security problem, and because the chown + will clear the setuid bit anyhow. We only fix the + setuid bit if the chown succeeds, because we don't + want to introduce an unexpected setuid file owned by + the user running objcopy. */ + chmod (to, s.st_mode & 0777); + if (chown (to, s.st_uid, s.st_gid) >= 0) + chmod (to, s.st_mode & 07777); + } + } + else + { + /* We have to clean up here. */ + non_fatal (_("%s: rename: %s"), to, strerror (errno)); + unlink (from); + } + } + else + { + ret = simple_copy (from, to); + if (ret != 0) + non_fatal (_("%s: simple_copy: %s"), to, strerror (errno)); + + if (preserve_dates) + set_times (to, &s); + unlink (from); + } +#endif /* _WIN32 && !__CYGWIN32__ */ + + return ret; +} diff --git a/contrib/binutils-2.14/binutils/size.c b/contrib/binutils-2.14/binutils/size.c new file mode 100644 index 0000000000..5e4c9ed6ba --- /dev/null +++ b/contrib/binutils-2.14/binutils/size.c @@ -0,0 +1,592 @@ +/* size.c -- report size of various sections of an executable file. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002 Free Software Foundation, Inc. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Extensions/incompatibilities: + o - BSD output has filenames at the end. + o - BSD output can appear in different radicies. + o - SysV output has less redundant whitespace. Filename comes at end. + o - SysV output doesn't show VMA which is always the same as the PMA. + o - We also handle core files. + o - We also handle archives. + If you write shell scripts which manipulate this info then you may be + out of luck; there's no --compatibility or --pedantic option. */ + +#include "bfd.h" +#include "bucomm.h" +#include "libiberty.h" +#include "getopt.h" + +#ifndef BSD_DEFAULT +#define BSD_DEFAULT 1 +#endif + +/* Program options. */ + +enum + { + decimal, octal, hex + } +radix = decimal; + +int berkeley_format = BSD_DEFAULT; /* 0 means use AT&T-style output. */ +int show_version = 0; +int show_help = 0; +int show_totals = 0; + +static bfd_size_type total_bsssize; +static bfd_size_type total_datasize; +static bfd_size_type total_textsize; + +/* Program exit status. */ +int return_code = 0; + +static char *target = NULL; + +/* Static declarations. */ + +static void usage PARAMS ((FILE *, int)); +static void display_file PARAMS ((char *)); +static void display_bfd PARAMS ((bfd *)); +static void display_archive PARAMS ((bfd *)); +static int size_number PARAMS ((bfd_size_type)); +#if 0 +static void lprint_number PARAMS ((int, bfd_size_type)); +#endif +static void rprint_number PARAMS ((int, bfd_size_type)); +static void print_berkeley_format PARAMS ((bfd *)); +static void sysv_internal_sizer PARAMS ((bfd *, asection *, PTR)); +static void sysv_internal_printer PARAMS ((bfd *, asection *, PTR)); +static void print_sysv_format PARAMS ((bfd *)); +static void print_sizes PARAMS ((bfd * file)); +static void berkeley_sum PARAMS ((bfd *, sec_ptr, PTR)); + +static void +usage (stream, status) + FILE *stream; + int status; +{ + fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name); + fprintf (stream, _(" Displays the sizes of sections inside binary files\n")); + fprintf (stream, _(" If no input file(s) are specified, a.out is assumed\n")); + fprintf (stream, _(" The options are:\n\ + -A|-B --format={sysv|berkeley} Select output style (default is %s)\n\ + -o|-d|-x --radix={8|10|16} Display numbers in octal, decimal or hex\n\ + -t --totals Display the total sizes (Berkeley only)\n\ + --target= Set the binary file format\n\ + -h --help Display this information\n\ + -v --version Display the program's version\n\ +\n"), +#if BSD_DEFAULT + "berkeley" +#else + "sysv" +#endif +); + list_supported_targets (program_name, stream); + if (status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); + exit (status); +} + +struct option long_options[] = +{ + {"format", required_argument, 0, 200}, + {"radix", required_argument, 0, 201}, + {"target", required_argument, 0, 202}, + {"totals", no_argument, &show_totals, 1}, + {"version", no_argument, &show_version, 1}, + {"help", no_argument, &show_help, 1}, + {0, no_argument, 0, 0} +}; + +int main PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char **argv; +{ + int temp; + int c; + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = *argv; + xmalloc_set_program_name (program_name); + + bfd_init (); + set_default_bfd_target (); + + while ((c = getopt_long (argc, argv, "ABHhVvdfotx", long_options, + (int *) 0)) != EOF) + switch (c) + { + case 200: /* --format */ + switch (*optarg) + { + case 'B': + case 'b': + berkeley_format = 1; + break; + case 'S': + case 's': + berkeley_format = 0; + break; + default: + non_fatal (_("invalid argument to --format: %s"), optarg); + usage (stderr, 1); + } + break; + + case 202: /* --target */ + target = optarg; + break; + + case 201: /* --radix */ +#ifdef ANSI_LIBRARIES + temp = strtol (optarg, NULL, 10); +#else + temp = atol (optarg); +#endif + switch (temp) + { + case 10: + radix = decimal; + break; + case 8: + radix = octal; + break; + case 16: + radix = hex; + break; + default: + non_fatal (_("Invalid radix: %s\n"), optarg); + usage (stderr, 1); + } + break; + + case 'A': + berkeley_format = 0; + break; + case 'B': + berkeley_format = 1; + break; + case 'v': + case 'V': + show_version = 1; + break; + case 'd': + radix = decimal; + break; + case 'x': + radix = hex; + break; + case 'o': + radix = octal; + break; + case 't': + show_totals = 1; + break; + case 'f': /* FIXME : For sysv68, `-f' means `full format', i.e. + `[fname:] M(.text) + N(.data) + O(.bss) + P(.comment) = Q' + where `fname: ' appears only if there are >= 2 input files, + and M, N, O, P, Q are expressed in decimal by default, + hexa or octal if requested by `-x' or `-o'. + Just to make things interesting, Solaris also accepts -f, + which prints out the size of each allocatable section, the + name of the section, and the total of the section sizes. */ + /* For the moment, accept `-f' silently, and ignore it. */ + break; + case 0: + break; + case 'h': + case 'H': + case '?': + usage (stderr, 1); + } + + if (show_version) + print_version ("size"); + if (show_help) + usage (stdout, 0); + + if (optind == argc) + display_file ("a.out"); + else + for (; optind < argc;) + display_file (argv[optind++]); + + if (show_totals && berkeley_format) + { + bfd_size_type total = total_textsize + total_datasize + total_bsssize; + + rprint_number (7, total_textsize); + putchar('\t'); + rprint_number (7, total_datasize); + putchar('\t'); + rprint_number (7, total_bsssize); + printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"), + (unsigned long) total, (unsigned long) total); + fputs ("(TOTALS)\n", stdout); + } + + return return_code; +} + +/* Display stats on file or archive member ABFD. */ + +static void +display_bfd (abfd) + bfd *abfd; +{ + char **matching; + + if (bfd_check_format (abfd, bfd_archive)) + /* An archive within an archive. */ + return; + + if (bfd_check_format_matches (abfd, bfd_object, &matching)) + { + print_sizes (abfd); + printf ("\n"); + return; + } + + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + bfd_nonfatal (bfd_get_filename (abfd)); + list_matching_formats (matching); + free (matching); + return_code = 3; + return; + } + + if (bfd_check_format_matches (abfd, bfd_core, &matching)) + { + const char *core_cmd; + + print_sizes (abfd); + fputs (" (core file", stdout); + + core_cmd = bfd_core_file_failing_command (abfd); + if (core_cmd) + printf (" invoked as %s", core_cmd); + + puts (")\n"); + return; + } + + bfd_nonfatal (bfd_get_filename (abfd)); + + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + { + list_matching_formats (matching); + free (matching); + } + + return_code = 3; +} + +static void +display_archive (file) + bfd *file; +{ + bfd *arfile = (bfd *) NULL; + bfd *last_arfile = (bfd *) NULL; + + for (;;) + { + bfd_set_error (bfd_error_no_error); + + arfile = bfd_openr_next_archived_file (file, arfile); + if (arfile == NULL) + { + if (bfd_get_error () != bfd_error_no_more_archived_files) + { + bfd_nonfatal (bfd_get_filename (file)); + return_code = 2; + } + break; + } + + display_bfd (arfile); + + if (last_arfile != NULL) + bfd_close (last_arfile); + last_arfile = arfile; + } + + if (last_arfile != NULL) + bfd_close (last_arfile); +} + +static void +display_file (filename) + char *filename; +{ + bfd *file = bfd_openr (filename, target); + + if (file == NULL) + { + bfd_nonfatal (filename); + return_code = 1; + return; + } + + if (bfd_check_format (file, bfd_archive)) + display_archive (file); + else + display_bfd (file); + + if (!bfd_close (file)) + { + bfd_nonfatal (filename); + return_code = 1; + return; + } +} + +/* This is what lexical functions are for. */ + +static int +size_number (num) + bfd_size_type num; +{ + char buffer[40]; + + sprintf (buffer, + (radix == decimal ? "%lu" : + ((radix == octal) ? "0%lo" : "0x%lx")), + (unsigned long) num); + + return strlen (buffer); +} + +#if 0 + +/* This is not used. */ + +static void +lprint_number (width, num) + int width; + bfd_size_type num; +{ + char buffer[40]; + + sprintf (buffer, + (radix == decimal ? "%lu" : + ((radix == octal) ? "0%lo" : "0x%lx")), + (unsigned long) num); + + printf ("%-*s", width, buffer); +} + +#endif + +static void +rprint_number (width, num) + int width; + bfd_size_type num; +{ + char buffer[40]; + + sprintf (buffer, + (radix == decimal ? "%lu" : + ((radix == octal) ? "0%lo" : "0x%lx")), + (unsigned long) num); + + printf ("%*s", width, buffer); +} + +static bfd_size_type bsssize; +static bfd_size_type datasize; +static bfd_size_type textsize; + +static void +berkeley_sum (abfd, sec, ignore) + bfd *abfd ATTRIBUTE_UNUSED; + sec_ptr sec; + PTR ignore ATTRIBUTE_UNUSED; +{ + flagword flags; + bfd_size_type size; + + flags = bfd_get_section_flags (abfd, sec); + if ((flags & SEC_ALLOC) == 0) + return; + + size = bfd_get_section_size_before_reloc (sec); + if ((flags & SEC_CODE) != 0 || (flags & SEC_READONLY) != 0) + textsize += size; + else if ((flags & SEC_HAS_CONTENTS) != 0) + datasize += size; + else + bsssize += size; +} + +static void +print_berkeley_format (abfd) + bfd *abfd; +{ + static int files_seen = 0; + bfd_size_type total; + + bsssize = 0; + datasize = 0; + textsize = 0; + + bfd_map_over_sections (abfd, berkeley_sum, (PTR) NULL); + + if (files_seen++ == 0) +#if 0 + /* Intel doesn't like bss/stk because they don't have core files. */ + puts ((radix == octal) ? " text\t data\tbss/stk\t oct\t hex\tfilename" : + " text\t data\tbss/stk\t dec\t hex\tfilename"); +#else + puts ((radix == octal) ? " text\t data\t bss\t oct\t hex\tfilename" : + " text\t data\t bss\t dec\t hex\tfilename"); +#endif + + total = textsize + datasize + bsssize; + + if (show_totals) + { + total_textsize += textsize; + total_datasize += datasize; + total_bsssize += bsssize; + } + + rprint_number (7, textsize); + putchar ('\t'); + rprint_number (7, datasize); + putchar ('\t'); + rprint_number (7, bsssize); + printf (((radix == octal) ? "\t%7lo\t%7lx\t" : "\t%7lu\t%7lx\t"), + (unsigned long) total, (unsigned long) total); + + fputs (bfd_get_filename (abfd), stdout); + + if (bfd_my_archive (abfd)) + printf (" (ex %s)", bfd_get_filename (bfd_my_archive (abfd))); +} + +/* I REALLY miss lexical functions! */ +bfd_size_type svi_total = 0; +bfd_vma svi_maxvma = 0; +int svi_namelen = 0; +int svi_vmalen = 0; +int svi_sizelen = 0; + +static void +sysv_internal_sizer (file, sec, ignore) + bfd *file ATTRIBUTE_UNUSED; + sec_ptr sec; + PTR ignore ATTRIBUTE_UNUSED; +{ + bfd_size_type size = bfd_section_size (file, sec); + + if ( ! bfd_is_abs_section (sec) + && ! bfd_is_com_section (sec) + && ! bfd_is_und_section (sec)) + { + int namelen = strlen (bfd_section_name (file, sec)); + + if (namelen > svi_namelen) + svi_namelen = namelen; + + svi_total += size; + + if (bfd_section_vma (file, sec) > svi_maxvma) + svi_maxvma = bfd_section_vma (file, sec); + } +} + +static void +sysv_internal_printer (file, sec, ignore) + bfd *file ATTRIBUTE_UNUSED; + sec_ptr sec; + PTR ignore ATTRIBUTE_UNUSED; +{ + bfd_size_type size = bfd_section_size (file, sec); + + if ( ! bfd_is_abs_section (sec) + && ! bfd_is_com_section (sec) + && ! bfd_is_und_section (sec)) + { + svi_total += size; + + printf ("%-*s ", svi_namelen, bfd_section_name (file, sec)); + rprint_number (svi_sizelen, size); + printf (" "); + rprint_number (svi_vmalen, bfd_section_vma (file, sec)); + printf ("\n"); + } +} + +static void +print_sysv_format (file) + bfd *file; +{ + /* Size all of the columns. */ + svi_total = 0; + svi_maxvma = 0; + svi_namelen = 0; + bfd_map_over_sections (file, sysv_internal_sizer, (PTR) NULL); + svi_vmalen = size_number ((bfd_size_type)svi_maxvma); + + if ((size_t) svi_vmalen < sizeof ("addr") - 1) + svi_vmalen = sizeof ("addr")-1; + + svi_sizelen = size_number (svi_total); + if ((size_t) svi_sizelen < sizeof ("size") - 1) + svi_sizelen = sizeof ("size")-1; + + svi_total = 0; + printf ("%s ", bfd_get_filename (file)); + + if (bfd_my_archive (file)) + printf (" (ex %s)", bfd_get_filename (bfd_my_archive (file))); + + printf (":\n%-*s %*s %*s\n", svi_namelen, "section", + svi_sizelen, "size", svi_vmalen, "addr"); + + bfd_map_over_sections (file, sysv_internal_printer, (PTR) NULL); + + printf ("%-*s ", svi_namelen, "Total"); + rprint_number (svi_sizelen, svi_total); + printf ("\n\n"); +} + +static void +print_sizes (file) + bfd *file; +{ + if (berkeley_format) + print_berkeley_format (file); + else + print_sysv_format (file); +} diff --git a/contrib/binutils-2.14/binutils/stabs.c b/contrib/binutils-2.14/binutils/stabs.c new file mode 100644 index 0000000000..91eff59ffa --- /dev/null +++ b/contrib/binutils-2.14/binutils/stabs.c @@ -0,0 +1,5204 @@ +/* stabs.c -- Parse stabs debugging information + Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file contains code which parses stabs debugging information. + The organization of this code is based on the gdb stabs reading + code. The job it does is somewhat different, because it is not + trying to identify the correct address for anything. */ + +#include + +#include "bfd.h" +#include "bucomm.h" +#include "libiberty.h" +#include "safe-ctype.h" +#include "demangle.h" +#include "debug.h" +#include "budbg.h" +#include "filenames.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" + +/* The number of predefined XCOFF types. */ + +#define XCOFF_TYPE_COUNT 34 + +/* This structure is used as a handle so that the stab parsing doesn't + need to use any static variables. */ + +struct stab_handle +{ + /* The BFD. */ + bfd *abfd; + /* TRUE if this is stabs in sections. */ + bfd_boolean sections; + /* The symbol table. */ + asymbol **syms; + /* The number of symbols. */ + long symcount; + /* The accumulated file name string. */ + char *so_string; + /* The value of the last N_SO symbol. */ + bfd_vma so_value; + /* The value of the start of the file, so that we can handle file + relative N_LBRAC and N_RBRAC symbols. */ + bfd_vma file_start_offset; + /* The offset of the start of the function, so that we can handle + function relative N_LBRAC and N_RBRAC symbols. */ + bfd_vma function_start_offset; + /* The version number of gcc which compiled the current compilation + unit, 0 if not compiled by gcc. */ + int gcc_compiled; + /* Whether an N_OPT symbol was seen that was not generated by gcc, + so that we can detect the SunPRO compiler. */ + bfd_boolean n_opt_found; + /* The main file name. */ + char *main_filename; + /* A stack of unfinished N_BINCL files. */ + struct bincl_file *bincl_stack; + /* A list of finished N_BINCL files. */ + struct bincl_file *bincl_list; + /* Whether we are inside a function or not. */ + bfd_boolean within_function; + /* The address of the end of the function, used if we have seen an + N_FUN symbol while in a function. This is -1 if we have not seen + an N_FUN (the normal case). */ + bfd_vma function_end; + /* The depth of block nesting. */ + int block_depth; + /* List of pending variable definitions. */ + struct stab_pending_var *pending; + /* Number of files for which we have types. */ + unsigned int files; + /* Lists of types per file. */ + struct stab_types **file_types; + /* Predefined XCOFF types. */ + debug_type xcoff_types[XCOFF_TYPE_COUNT]; + /* Undefined tags. */ + struct stab_tag *tags; + /* Set by parse_stab_type if it sees a structure defined as a cross + reference to itself. Reset by parse_stab_type otherwise. */ + bfd_boolean self_crossref; +}; + +/* A list of these structures is used to hold pending variable + definitions seen before the N_LBRAC of a block. */ + +struct stab_pending_var +{ + /* Next pending variable definition. */ + struct stab_pending_var *next; + /* Name. */ + const char *name; + /* Type. */ + debug_type type; + /* Kind. */ + enum debug_var_kind kind; + /* Value. */ + bfd_vma val; +}; + +/* A list of these structures is used to hold the types for a single + file. */ + +struct stab_types +{ + /* Next set of slots for this file. */ + struct stab_types *next; + /* Types indexed by type number. */ +#define STAB_TYPES_SLOTS (16) + debug_type types[STAB_TYPES_SLOTS]; +}; + +/* We keep a list of undefined tags that we encounter, so that we can + fill them in if the tag is later defined. */ + +struct stab_tag +{ + /* Next undefined tag. */ + struct stab_tag *next; + /* Tag name. */ + const char *name; + /* Type kind. */ + enum debug_type_kind kind; + /* Slot to hold real type when we discover it. If we don't, we fill + in an undefined tag type. */ + debug_type slot; + /* Indirect type we have created to point at slot. */ + debug_type type; +}; + +static char *savestring + PARAMS ((const char *, int)); +static bfd_vma parse_number + PARAMS ((const char **, bfd_boolean *)); +static void bad_stab + PARAMS ((const char *)); +static void warn_stab + PARAMS ((const char *, const char *)); +static bfd_boolean parse_stab_string + PARAMS ((PTR, struct stab_handle *, int, int, bfd_vma, const char *)); +static debug_type parse_stab_type + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + debug_type **)); +static bfd_boolean parse_stab_type_number + PARAMS ((const char **, int *)); +static debug_type parse_stab_range_type + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + const int *)); +static debug_type parse_stab_sun_builtin_type + PARAMS ((PTR, const char **)); +static debug_type parse_stab_sun_floating_type + PARAMS ((PTR, const char **)); +static debug_type parse_stab_enum_type + PARAMS ((PTR, const char **)); +static debug_type parse_stab_struct_type + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + bfd_boolean, const int *)); +static bfd_boolean parse_stab_baseclasses + PARAMS ((PTR, struct stab_handle *, const char **, debug_baseclass **)); +static bfd_boolean parse_stab_struct_fields + PARAMS ((PTR, struct stab_handle *, const char **, debug_field **, + bfd_boolean *)); +static bfd_boolean parse_stab_cpp_abbrev + PARAMS ((PTR, struct stab_handle *, const char **, debug_field *)); +static bfd_boolean parse_stab_one_struct_field + PARAMS ((PTR, struct stab_handle *, const char **, const char *, + debug_field *, bfd_boolean *)); +static bfd_boolean parse_stab_members + PARAMS ((PTR, struct stab_handle *, const char *, const char **, + const int *, debug_method **)); +static debug_type parse_stab_argtypes + PARAMS ((PTR, struct stab_handle *, debug_type, const char *, const char *, + debug_type, const char *, bfd_boolean, bfd_boolean, const char **)); +static bfd_boolean parse_stab_tilde_field + PARAMS ((PTR, struct stab_handle *, const char **, const int *, + debug_type *, bfd_boolean *)); +static debug_type parse_stab_array_type + PARAMS ((PTR, struct stab_handle *, const char **, bfd_boolean)); +static void push_bincl + PARAMS ((struct stab_handle *, const char *, bfd_vma)); +static const char *pop_bincl + PARAMS ((struct stab_handle *)); +static bfd_boolean find_excl + PARAMS ((struct stab_handle *, const char *, bfd_vma)); +static bfd_boolean stab_record_variable + PARAMS ((PTR, struct stab_handle *, const char *, debug_type, + enum debug_var_kind, bfd_vma)); +static bfd_boolean stab_emit_pending_vars + PARAMS ((PTR, struct stab_handle *)); +static debug_type *stab_find_slot + PARAMS ((struct stab_handle *, const int *)); +static debug_type stab_find_type + PARAMS ((PTR, struct stab_handle *, const int *)); +static bfd_boolean stab_record_type + PARAMS ((PTR, struct stab_handle *, const int *, debug_type)); +static debug_type stab_xcoff_builtin_type + PARAMS ((PTR, struct stab_handle *, int)); +static debug_type stab_find_tagged_type + PARAMS ((PTR, struct stab_handle *, const char *, int, + enum debug_type_kind)); +static debug_type *stab_demangle_argtypes + PARAMS ((PTR, struct stab_handle *, const char *, bfd_boolean *, + unsigned int)); + +/* Save a string in memory. */ + +static char * +savestring (start, len) + const char *start; + int len; +{ + char *ret; + + ret = (char *) xmalloc (len + 1); + memcpy (ret, start, len); + ret[len] = '\0'; + return ret; +} + +/* Read a number from a string. */ + +static bfd_vma +parse_number (pp, poverflow) + const char **pp; + bfd_boolean *poverflow; +{ + unsigned long ul; + const char *orig; + + if (poverflow != NULL) + *poverflow = FALSE; + + orig = *pp; + + errno = 0; + ul = strtoul (*pp, (char **) pp, 0); + if (ul + 1 != 0 || errno == 0) + { + /* If bfd_vma is larger than unsigned long, and the number is + meant to be negative, we have to make sure that we sign + extend properly. */ + if (*orig == '-') + return (bfd_vma) (bfd_signed_vma) (long) ul; + return (bfd_vma) ul; + } + + /* Note that even though strtoul overflowed, it should have set *pp + to the end of the number, which is where we want it. */ + if (sizeof (bfd_vma) > sizeof (unsigned long)) + { + const char *p; + bfd_boolean neg; + int base; + bfd_vma over, lastdig; + bfd_boolean overflow; + bfd_vma v; + + /* Our own version of strtoul, for a bfd_vma. */ + p = orig; + + neg = FALSE; + if (*p == '+') + ++p; + else if (*p == '-') + { + neg = TRUE; + ++p; + } + + base = 10; + if (*p == '0') + { + if (p[1] == 'x' || p[1] == 'X') + { + base = 16; + p += 2; + } + else + { + base = 8; + ++p; + } + } + + over = ((bfd_vma) (bfd_signed_vma) -1) / (bfd_vma) base; + lastdig = ((bfd_vma) (bfd_signed_vma) -1) % (bfd_vma) base; + + overflow = FALSE; + v = 0; + while (1) + { + int d; + + d = *p++; + if (ISDIGIT (d)) + d -= '0'; + else if (ISUPPER (d)) + d -= 'A'; + else if (ISLOWER (d)) + d -= 'a'; + else + break; + + if (d >= base) + break; + + if (v > over || (v == over && (bfd_vma) d > lastdig)) + { + overflow = TRUE; + break; + } + } + + if (! overflow) + { + if (neg) + v = - v; + return v; + } + } + + /* If we get here, the number is too large to represent in a + bfd_vma. */ + if (poverflow != NULL) + *poverflow = TRUE; + else + warn_stab (orig, _("numeric overflow")); + + return 0; +} + +/* Give an error for a bad stab string. */ + +static void +bad_stab (p) + const char *p; +{ + fprintf (stderr, _("Bad stab: %s\n"), p); +} + +/* Warn about something in a stab string. */ + +static void +warn_stab (p, err) + const char *p; + const char *err; +{ + fprintf (stderr, _("Warning: %s: %s\n"), err, p); +} + +/* Create a handle to parse stabs symbols with. */ + +PTR +start_stab (dhandle, abfd, sections, syms, symcount) + PTR dhandle ATTRIBUTE_UNUSED; + bfd *abfd; + bfd_boolean sections; + asymbol **syms; + long symcount; +{ + struct stab_handle *ret; + + ret = (struct stab_handle *) xmalloc (sizeof *ret); + memset (ret, 0, sizeof *ret); + ret->abfd = abfd; + ret->sections = sections; + ret->syms = syms; + ret->symcount = symcount; + ret->files = 1; + ret->file_types = (struct stab_types **) xmalloc (sizeof *ret->file_types); + ret->file_types[0] = NULL; + ret->function_end = (bfd_vma) -1; + return (PTR) ret; +} + +/* When we have processed all the stabs information, we need to go + through and fill in all the undefined tags. */ + +bfd_boolean +finish_stab (dhandle, handle) + PTR dhandle; + PTR handle; +{ + struct stab_handle *info = (struct stab_handle *) handle; + struct stab_tag *st; + + if (info->within_function) + { + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, info->function_end)) + return FALSE; + info->within_function = FALSE; + info->function_end = (bfd_vma) -1; + } + + for (st = info->tags; st != NULL; st = st->next) + { + enum debug_type_kind kind; + + kind = st->kind; + if (kind == DEBUG_KIND_ILLEGAL) + kind = DEBUG_KIND_STRUCT; + st->slot = debug_make_undefined_tagged_type (dhandle, st->name, kind); + if (st->slot == DEBUG_TYPE_NULL) + return FALSE; + } + + return TRUE; +} + +/* Handle a single stabs symbol. */ + +bfd_boolean +parse_stab (dhandle, handle, type, desc, value, string) + PTR dhandle; + PTR handle; + int type; + int desc; + bfd_vma value; + const char *string; +{ + struct stab_handle *info = (struct stab_handle *) handle; + + /* gcc will emit two N_SO strings per compilation unit, one for the + directory name and one for the file name. We just collect N_SO + strings as we see them, and start the new compilation unit when + we see a non N_SO symbol. */ + if (info->so_string != NULL + && (type != N_SO || *string == '\0' || value != info->so_value)) + { + if (! debug_set_filename (dhandle, info->so_string)) + return FALSE; + info->main_filename = info->so_string; + + info->gcc_compiled = 0; + info->n_opt_found = FALSE; + + /* Generally, for stabs in the symbol table, the N_LBRAC and + N_RBRAC symbols are relative to the N_SO symbol value. */ + if (! info->sections) + info->file_start_offset = info->so_value; + + /* We need to reset the mapping from type numbers to types. We + can't free the old mapping, because of the use of + debug_make_indirect_type. */ + info->files = 1; + info->file_types = ((struct stab_types **) + xmalloc (sizeof *info->file_types)); + info->file_types[0] = NULL; + + info->so_string = NULL; + + /* Now process whatever type we just got. */ + } + + switch (type) + { + case N_FN: + case N_FN_SEQ: + break; + + case N_LBRAC: + /* Ignore extra outermost context from SunPRO cc and acc. */ + if (info->n_opt_found && desc == 1) + break; + + if (! info->within_function) + { + fprintf (stderr, _("N_LBRAC not within function\n")); + return FALSE; + } + + /* Start an inner lexical block. */ + if (! debug_start_block (dhandle, + (value + + info->file_start_offset + + info->function_start_offset))) + return FALSE; + + /* Emit any pending variable definitions. */ + if (! stab_emit_pending_vars (dhandle, info)) + return FALSE; + + ++info->block_depth; + break; + + case N_RBRAC: + /* Ignore extra outermost context from SunPRO cc and acc. */ + if (info->n_opt_found && desc == 1) + break; + + /* We shouldn't have any pending variable definitions here, but, + if we do, we probably need to emit them before closing the + block. */ + if (! stab_emit_pending_vars (dhandle, info)) + return FALSE; + + /* End an inner lexical block. */ + if (! debug_end_block (dhandle, + (value + + info->file_start_offset + + info->function_start_offset))) + return FALSE; + + --info->block_depth; + if (info->block_depth < 0) + { + fprintf (stderr, _("Too many N_RBRACs\n")); + return FALSE; + } + break; + + case N_SO: + /* This always ends a function. */ + if (info->within_function) + { + bfd_vma endval; + + endval = value; + if (*string != '\0' + && info->function_end != (bfd_vma) -1 + && info->function_end < endval) + endval = info->function_end; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, endval)) + return FALSE; + info->within_function = FALSE; + info->function_end = (bfd_vma) -1; + } + + /* An empty string is emitted by gcc at the end of a compilation + unit. */ + if (*string == '\0') + return TRUE; + + /* Just accumulate strings until we see a non N_SO symbol. If + the string starts with a directory separator or some other + form of absolute path specification, we discard the previously + accumulated strings. */ + if (info->so_string == NULL) + info->so_string = xstrdup (string); + else + { + char *f; + + f = info->so_string; + + if (IS_ABSOLUTE_PATH (string)) + info->so_string = xstrdup (string); + else + info->so_string = concat (info->so_string, string, + (const char *) NULL); + free (f); + } + + info->so_value = value; + + break; + + case N_SOL: + /* Start an include file. */ + if (! debug_start_source (dhandle, string)) + return FALSE; + break; + + case N_BINCL: + /* Start an include file which may be replaced. */ + push_bincl (info, string, value); + if (! debug_start_source (dhandle, string)) + return FALSE; + break; + + case N_EINCL: + /* End an N_BINCL include. */ + if (! debug_start_source (dhandle, pop_bincl (info))) + return FALSE; + break; + + case N_EXCL: + /* This is a duplicate of a header file named by N_BINCL which + was eliminated by the linker. */ + if (! find_excl (info, string, value)) + return FALSE; + break; + + case N_SLINE: + if (! debug_record_line (dhandle, desc, + value + (info->within_function + ? info->function_start_offset : 0))) + return FALSE; + break; + + case N_BCOMM: + if (! debug_start_common_block (dhandle, string)) + return FALSE; + break; + + case N_ECOMM: + if (! debug_end_common_block (dhandle, string)) + return FALSE; + break; + + case N_FUN: + if (*string == '\0') + { + if (info->within_function) + { + /* This always marks the end of a function; we don't + need to worry about info->function_end. */ + if (info->sections) + value += info->function_start_offset; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, value)) + return FALSE; + info->within_function = FALSE; + info->function_end = (bfd_vma) -1; + } + break; + } + + /* A const static symbol in the .text section will have an N_FUN + entry. We need to use these to mark the end of the function, + in case we are looking at gcc output before it was changed to + always emit an empty N_FUN. We can't call debug_end_function + here, because it might be a local static symbol. */ + if (info->within_function + && (info->function_end == (bfd_vma) -1 + || value < info->function_end)) + info->function_end = value; + + /* Fall through. */ + /* FIXME: gdb checks the string for N_STSYM, N_LCSYM or N_ROSYM + symbols, and if it does not start with :S, gdb relocates the + value to the start of the section. gcc always seems to use + :S, so we don't worry about this. */ + /* Fall through. */ + default: + { + const char *colon; + + colon = strchr (string, ':'); + if (colon != NULL + && (colon[1] == 'f' || colon[1] == 'F')) + { + if (info->within_function) + { + bfd_vma endval; + + endval = value; + if (info->function_end != (bfd_vma) -1 + && info->function_end < endval) + endval = info->function_end; + if (! stab_emit_pending_vars (dhandle, info) + || ! debug_end_function (dhandle, endval)) + return FALSE; + info->function_end = (bfd_vma) -1; + } + /* For stabs in sections, line numbers and block addresses + are offsets from the start of the function. */ + if (info->sections) + info->function_start_offset = value; + info->within_function = TRUE; + } + + if (! parse_stab_string (dhandle, info, type, desc, value, string)) + return FALSE; + } + break; + + case N_OPT: + if (string != NULL && strcmp (string, "gcc2_compiled.") == 0) + info->gcc_compiled = 2; + else if (string != NULL && strcmp (string, "gcc_compiled.") == 0) + info->gcc_compiled = 1; + else + info->n_opt_found = TRUE; + break; + + case N_OBJ: + case N_ENDM: + case N_MAIN: + case N_WARNING: + break; + } + + return TRUE; +} + +/* Parse the stabs string. */ + +static bfd_boolean +parse_stab_string (dhandle, info, stabtype, desc, value, string) + PTR dhandle; + struct stab_handle *info; + int stabtype; + int desc; + bfd_vma value; + const char *string; +{ + const char *p; + char *name; + int type; + debug_type dtype; + bfd_boolean synonym; + bfd_boolean self_crossref; + unsigned int lineno; + debug_type *slot; + + p = strchr (string, ':'); + if (p == NULL) + return TRUE; + + while (p[1] == ':') + { + p += 2; + p = strchr (p, ':'); + if (p == NULL) + { + bad_stab (string); + return FALSE; + } + } + + /* GCC 2.x puts the line number in desc. SunOS apparently puts in + the number of bytes occupied by a type or object, which we + ignore. */ + if (info->gcc_compiled >= 2) + lineno = desc; + else + lineno = 0; + + /* FIXME: Sometimes the special C++ names start with '.'. */ + name = NULL; + if (string[0] == '$') + { + switch (string[1]) + { + case 't': + name = "this"; + break; + case 'v': + /* Was: name = "vptr"; */ + break; + case 'e': + name = "eh_throw"; + break; + case '_': + /* This was an anonymous type that was never fixed up. */ + break; + case 'X': + /* SunPRO (3.0 at least) static variable encoding. */ + break; + default: + warn_stab (string, _("unknown C++ encoded name")); + break; + } + } + + if (name == NULL) + { + if (p == string || (string[0] == ' ' && p == string + 1)) + name = NULL; + else + name = savestring (string, p - string); + } + + ++p; + if (ISDIGIT (*p) || *p == '(' || *p == '-') + type = 'l'; + else + type = *p++; + + switch (type) + { + case 'c': + /* c is a special case, not followed by a type-number. + SYMBOL:c=iVALUE for an integer constant symbol. + SYMBOL:c=rVALUE for a floating constant symbol. + SYMBOL:c=eTYPE,INTVALUE for an enum constant symbol. + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + if (*p != '=') + { + bad_stab (string); + return FALSE; + } + ++p; + switch (*p++) + { + case 'r': + /* Floating point constant. */ + if (! debug_record_float_const (dhandle, name, atof (p))) + return FALSE; + break; + case 'i': + /* Integer constant. */ + /* Defining integer constants this way is kind of silly, + since 'e' constants allows the compiler to give not only + the value, but the type as well. C has at least int, + long, unsigned int, and long long as constant types; + other languages probably should have at least unsigned as + well as signed constants. */ + if (! debug_record_int_const (dhandle, name, atoi (p))) + return FALSE; + break; + case 'e': + /* SYMBOL:c=eTYPE,INTVALUE for a constant symbol whose value + can be represented as integral. + e.g. "b:c=e6,0" for "const b = blob1" + (where type 6 is defined by "blobs:t6=eblob1:0,blob2:1,;"). */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + &p, (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (*p != ',') + { + bad_stab (string); + return FALSE; + } + if (! debug_record_typed_const (dhandle, name, dtype, atoi (p))) + return FALSE; + break; + default: + bad_stab (string); + return FALSE; + } + + break; + + case 'C': + /* The name of a caught exception. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + &p, (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_label (dhandle, name, dtype, value)) + return FALSE; + break; + + case 'f': + case 'F': + /* A function definition. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_function (dhandle, name, dtype, type == 'F', value)) + return FALSE; + + /* Sun acc puts declared types of arguments here. We don't care + about their actual types (FIXME -- we should remember the whole + function prototype), but the list may define some new types + that we have to remember, so we must scan it now. */ + while (*p == ';') + { + ++p; + if (parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL) + == DEBUG_TYPE_NULL) + return FALSE; + } + + break; + + case 'G': + { + char leading; + long c; + asymbol **ps; + + /* A global symbol. The value must be extracted from the + symbol table. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + leading = bfd_get_symbol_leading_char (info->abfd); + for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps) + { + const char *n; + + n = bfd_asymbol_name (*ps); + if (leading != '\0' && *n == leading) + ++n; + if (*n == *name && strcmp (n, name) == 0) + break; + } + if (c > 0) + value = bfd_asymbol_value (*ps); + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL, + value)) + return FALSE; + } + break; + + /* This case is faked by a conditional above, when there is no + code letter in the dbx data. Dbx data never actually + contains 'l'. */ + case 'l': + case 's': + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, + value)) + return FALSE; + break; + + case 'p': + /* A function parameter. */ + if (*p != 'F') + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + else + { + /* pF is a two-letter code that means a function parameter in + Fortran. The type-number specifies the type of the return + value. Translate it into a pointer-to-function type. */ + ++p; + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype != DEBUG_TYPE_NULL) + { + debug_type ftype; + + ftype = debug_make_function_type (dhandle, dtype, + (debug_type *) NULL, FALSE); + dtype = debug_make_pointer_type (dhandle, ftype); + } + } + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_STACK, + value)) + return FALSE; + + /* FIXME: At this point gdb considers rearranging the parameter + address on a big endian machine if it is smaller than an int. + We have no way to do that, since we don't really know much + about the target. */ + break; + + case 'P': + if (stabtype == N_FUN) + { + /* Prototype of a function referenced by this file. */ + while (*p == ';') + { + ++p; + if (parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL) + == DEBUG_TYPE_NULL) + return FALSE; + } + break; + } + /* Fall through. */ + case 'R': + /* Parameter which is in a register. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REG, + value)) + return FALSE; + break; + + case 'r': + /* Register variable (either global or local). */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_REGISTER, + value)) + return FALSE; + + /* FIXME: At this point gdb checks to combine pairs of 'p' and + 'r' stabs into a single 'P' stab. */ + break; + + case 'S': + /* Static symbol at top level of file. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_STATIC, + value)) + return FALSE; + break; + + case 't': + /* A typedef. */ + dtype = parse_stab_type (dhandle, info, name, &p, &slot); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (name == NULL) + { + /* A nameless type. Nothing to do. */ + return TRUE; + } + + dtype = debug_name_type (dhandle, name, dtype); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + + if (slot != NULL) + *slot = dtype; + + break; + + case 'T': + /* Struct, union, or enum tag. For GNU C++, this can be be followed + by 't' which means we are typedef'ing it as well. */ + if (*p != 't') + { + synonym = FALSE; + /* FIXME: gdb sets synonym to TRUE if the current language + is C++. */ + } + else + { + synonym = TRUE; + ++p; + } + + dtype = parse_stab_type (dhandle, info, name, &p, &slot); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (name == NULL) + return TRUE; + + /* INFO->SELF_CROSSREF is set by parse_stab_type if this type is + a cross reference to itself. These are generated by some + versions of g++. */ + self_crossref = info->self_crossref; + + dtype = debug_tag_type (dhandle, name, dtype); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (slot != NULL) + *slot = dtype; + + /* See if we have a cross reference to this tag which we can now + fill in. Avoid filling in a cross reference to ourselves, + because that would lead to circular debugging information. */ + if (! self_crossref) + { + register struct stab_tag **pst; + + for (pst = &info->tags; *pst != NULL; pst = &(*pst)->next) + { + if ((*pst)->name[0] == name[0] + && strcmp ((*pst)->name, name) == 0) + { + (*pst)->slot = dtype; + *pst = (*pst)->next; + break; + } + } + } + + if (synonym) + { + dtype = debug_name_type (dhandle, name, dtype); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + + if (slot != NULL) + *slot = dtype; + } + + break; + + case 'V': + /* Static symbol of local scope */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + /* FIXME: gdb checks os9k_stabs here. */ + if (! stab_record_variable (dhandle, info, name, dtype, + DEBUG_LOCAL_STATIC, value)) + return FALSE; + break; + + case 'v': + /* Reference parameter. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REFERENCE, + value)) + return FALSE; + break; + + case 'a': + /* Reference parameter which is in a register. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! debug_record_parameter (dhandle, name, dtype, DEBUG_PARM_REF_REG, + value)) + return FALSE; + break; + + case 'X': + /* This is used by Sun FORTRAN for "function result value". + Sun claims ("dbx and dbxtool interfaces", 2nd ed) + that Pascal uses it too, but when I tried it Pascal used + "x:3" (local symbol) instead. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, &p, + (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return FALSE; + if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_LOCAL, + value)) + return FALSE; + break; + + default: + bad_stab (string); + return FALSE; + } + + /* FIXME: gdb converts structure values to structure pointers in a + couple of cases, depending upon the target. */ + + return TRUE; +} + +/* Parse a stabs type. The typename argument is non-NULL if this is a + typedef or a tag definition. The pp argument points to the stab + string, and is updated. The slotp argument points to a place to + store the slot used if the type is being defined. */ + +static debug_type +parse_stab_type (dhandle, info, typename, pp, slotp) + PTR dhandle; + struct stab_handle *info; + const char *typename; + const char **pp; + debug_type **slotp; +{ + const char *orig; + int typenums[2]; + int size; + bfd_boolean stringp; + int descriptor; + debug_type dtype; + + if (slotp != NULL) + *slotp = NULL; + + orig = *pp; + + size = -1; + stringp = FALSE; + + info->self_crossref = FALSE; + + /* Read type number if present. The type number may be omitted. + for instance in a two-dimensional array declared with type + "ar1;1;10;ar1;1;10;4". */ + if (! ISDIGIT (**pp) && **pp != '(' && **pp != '-') + { + /* 'typenums=' not present, type is anonymous. Read and return + the definition, but don't put it in the type vector. */ + typenums[0] = typenums[1] = -1; + } + else + { + if (! parse_stab_type_number (pp, typenums)) + return DEBUG_TYPE_NULL; + + if (**pp != '=') + /* Type is not being defined here. Either it already + exists, or this is a forward reference to it. */ + return stab_find_type (dhandle, info, typenums); + + /* Only set the slot if the type is being defined. This means + that the mapping from type numbers to types will only record + the name of the typedef which defines a type. If we don't do + this, then something like + typedef int foo; + int i; + will record that i is of type foo. Unfortunately, stabs + information is ambiguous about variable types. For this code, + typedef int foo; + int i; + foo j; + the stabs information records both i and j as having the same + type. This could be fixed by patching the compiler. */ + if (slotp != NULL && typenums[0] >= 0 && typenums[1] >= 0) + *slotp = stab_find_slot (info, typenums); + + /* Type is being defined here. */ + /* Skip the '='. */ + ++*pp; + + while (**pp == '@') + { + const char *p = *pp + 1; + const char *attr; + + if (ISDIGIT (*p) || *p == '(' || *p == '-') + /* Member type. */ + break; + + /* Type attributes. */ + attr = p; + + for (; *p != ';'; ++p) + { + if (*p == '\0') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + } + *pp = p + 1; + + switch (*attr) + { + case 's': + size = atoi (attr + 1); + size /= 8; /* Size is in bits. We store it in bytes. */ + if (size <= 0) + size = -1; + break; + + case 'S': + stringp = TRUE; + break; + + default: + /* Ignore unrecognized type attributes, so future + compilers can invent new ones. */ + break; + } + } + } + + descriptor = **pp; + ++*pp; + + switch (descriptor) + { + case 'x': + { + enum debug_type_kind code; + const char *q1, *q2, *p; + + /* A cross reference to another type. */ + switch (**pp) + { + case 's': + code = DEBUG_KIND_STRUCT; + break; + case 'u': + code = DEBUG_KIND_UNION; + break; + case 'e': + code = DEBUG_KIND_ENUM; + break; + default: + /* Complain and keep going, so compilers can invent new + cross-reference types. */ + warn_stab (orig, _("unrecognized cross reference type")); + code = DEBUG_KIND_STRUCT; + break; + } + ++*pp; + + q1 = strchr (*pp, '<'); + p = strchr (*pp, ':'); + if (p == NULL) + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + if (q1 != NULL && p > q1 && p[1] == ':') + { + int nest = 0; + + for (q2 = q1; *q2 != '\0'; ++q2) + { + if (*q2 == '<') + ++nest; + else if (*q2 == '>') + --nest; + else if (*q2 == ':' && nest == 0) + break; + } + p = q2; + if (*p != ':') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + } + + /* Some versions of g++ can emit stabs like + fleep:T20=xsfleep: + which define structures in terms of themselves. We need to + tell the caller to avoid building a circular structure. */ + if (typename != NULL + && strncmp (typename, *pp, p - *pp) == 0 + && typename[p - *pp] == '\0') + info->self_crossref = TRUE; + + dtype = stab_find_tagged_type (dhandle, info, *pp, p - *pp, code); + + *pp = p + 1; + } + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '(': + { + const char *hold; + int xtypenums[2]; + + /* This type is defined as another type. */ + (*pp)--; + hold = *pp; + + /* Peek ahead at the number to detect void. */ + if (! parse_stab_type_number (pp, xtypenums)) + return DEBUG_TYPE_NULL; + + if (typenums[0] == xtypenums[0] && typenums[1] == xtypenums[1]) + { + /* This type is being defined as itself, which means that + it is void. */ + dtype = debug_make_void_type (dhandle); + } + else + { + *pp = hold; + + /* Go back to the number and have parse_stab_type get it. + This means that we can deal with something like + t(1,2)=(3,4)=... which the Lucid compiler uses. */ + dtype = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (dtype == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + } + + if (typenums[0] != -1) + { + if (! stab_record_type (dhandle, info, typenums, dtype)) + return DEBUG_TYPE_NULL; + } + + break; + } + + case '*': + dtype = debug_make_pointer_type (dhandle, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, + (debug_type **) NULL)); + break; + + case '&': + /* Reference to another type. */ + dtype = (debug_make_reference_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL))); + break; + + case 'f': + /* Function returning another type. */ + /* FIXME: gdb checks os9k_stabs here. */ + dtype = (debug_make_function_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL), + (debug_type *) NULL, FALSE)); + break; + + case 'k': + /* Const qualifier on some type (Sun). */ + /* FIXME: gdb accepts 'c' here if os9k_stabs. */ + dtype = debug_make_const_type (dhandle, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, + (debug_type **) NULL)); + break; + + case 'B': + /* Volatile qual on some type (Sun). */ + /* FIXME: gdb accepts 'i' here if os9k_stabs. */ + dtype = (debug_make_volatile_type + (dhandle, + parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL))); + break; + + case '@': + /* Offset (class & variable) type. This is used for a pointer + relative to an object. */ + { + debug_type domain; + debug_type memtype; + + /* Member type. */ + + domain = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (domain == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + if (**pp != ',') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + memtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (memtype == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + dtype = debug_make_offset_type (dhandle, domain, memtype); + } + break; + + case '#': + /* Method (class & fn) type. */ + if (**pp == '#') + { + debug_type return_type; + + ++*pp; + return_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (return_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + dtype = debug_make_method_type (dhandle, return_type, + DEBUG_TYPE_NULL, + (debug_type *) NULL, FALSE); + } + else + { + debug_type domain; + debug_type return_type; + debug_type *args; + unsigned int n; + unsigned int alloc; + bfd_boolean varargs; + + domain = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (domain == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + if (**pp != ',') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + return_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (return_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + alloc = 10; + args = (debug_type *) xmalloc (alloc * sizeof *args); + n = 0; + while (**pp != ';') + { + if (**pp != ',') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + if (n + 1 >= alloc) + { + alloc += 10; + args = ((debug_type *) + xrealloc ((PTR) args, alloc * sizeof *args)); + } + + args[n] = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (args[n] == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + ++n; + } + ++*pp; + + /* If the last type is not void, then this function takes a + variable number of arguments. Otherwise, we must strip + the void type. */ + if (n == 0 + || debug_get_type_kind (dhandle, args[n - 1]) != DEBUG_KIND_VOID) + varargs = TRUE; + else + { + --n; + varargs = FALSE; + } + + args[n] = DEBUG_TYPE_NULL; + + dtype = debug_make_method_type (dhandle, return_type, domain, args, + varargs); + } + break; + + case 'r': + /* Range type. */ + dtype = parse_stab_range_type (dhandle, info, typename, pp, typenums); + break; + + case 'b': + /* FIXME: gdb checks os9k_stabs here. */ + /* Sun ACC builtin int type. */ + dtype = parse_stab_sun_builtin_type (dhandle, pp); + break; + + case 'R': + /* Sun ACC builtin float type. */ + dtype = parse_stab_sun_floating_type (dhandle, pp); + break; + + case 'e': + /* Enumeration type. */ + dtype = parse_stab_enum_type (dhandle, pp); + break; + + case 's': + case 'u': + /* Struct or union type. */ + dtype = parse_stab_struct_type (dhandle, info, typename, pp, + descriptor == 's', typenums); + break; + + case 'a': + /* Array type. */ + if (**pp != 'r') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + dtype = parse_stab_array_type (dhandle, info, pp, stringp); + break; + + case 'S': + dtype = debug_make_set_type (dhandle, + parse_stab_type (dhandle, info, + (const char *) NULL, + pp, + (debug_type **) NULL), + stringp); + break; + + default: + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + + if (dtype == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + if (typenums[0] != -1) + { + if (! stab_record_type (dhandle, info, typenums, dtype)) + return DEBUG_TYPE_NULL; + } + + if (size != -1) + { + if (! debug_record_type_size (dhandle, dtype, (unsigned int) size)) + return DEBUG_TYPE_NULL; + } + + return dtype; +} + +/* Read a number by which a type is referred to in dbx data, or + perhaps read a pair (FILENUM, TYPENUM) in parentheses. Just a + single number N is equivalent to (0,N). Return the two numbers by + storing them in the vector TYPENUMS. */ + +static bfd_boolean +parse_stab_type_number (pp, typenums) + const char **pp; + int *typenums; +{ + const char *orig; + + orig = *pp; + + if (**pp != '(') + { + typenums[0] = 0; + typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL); + } + else + { + ++*pp; + typenums[0] = (int) parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ',') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + typenums[1] = (int) parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ')') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + } + + return TRUE; +} + +/* Parse a range type. */ + +static debug_type +parse_stab_range_type (dhandle, info, typename, pp, typenums) + PTR dhandle; + struct stab_handle *info; + const char *typename; + const char **pp; + const int *typenums; +{ + const char *orig; + int rangenums[2]; + bfd_boolean self_subrange; + debug_type index_type; + const char *s2, *s3; + bfd_signed_vma n2, n3; + bfd_boolean ov2, ov3; + + orig = *pp; + + index_type = DEBUG_TYPE_NULL; + + /* First comes a type we are a subrange of. + In C it is usually 0, 1 or the type being defined. */ + if (! parse_stab_type_number (pp, rangenums)) + return DEBUG_TYPE_NULL; + + self_subrange = (rangenums[0] == typenums[0] + && rangenums[1] == typenums[1]); + + if (**pp == '=') + { + *pp = orig; + index_type = parse_stab_type (dhandle, info, (const char *) NULL, + pp, (debug_type **) NULL); + if (index_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + } + + if (**pp == ';') + ++*pp; + + /* The remaining two operands are usually lower and upper bounds of + the range. But in some special cases they mean something else. */ + s2 = *pp; + n2 = parse_number (pp, &ov2); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + s3 = *pp; + n3 = parse_number (pp, &ov3); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + if (ov2 || ov3) + { + /* gcc will emit range stabs for long long types. Handle this + as a special case. FIXME: This needs to be more general. */ +#define LLLOW "01000000000000000000000;" +#define LLHIGH "0777777777777777777777;" +#define ULLHIGH "01777777777777777777777;" + if (index_type == DEBUG_TYPE_NULL) + { + if (strncmp (s2, LLLOW, sizeof LLLOW - 1) == 0 + && strncmp (s3, LLHIGH, sizeof LLHIGH - 1) == 0) + return debug_make_int_type (dhandle, 8, FALSE); + if (! ov2 + && n2 == 0 + && strncmp (s3, ULLHIGH, sizeof ULLHIGH - 1) == 0) + return debug_make_int_type (dhandle, 8, TRUE); + } + + warn_stab (orig, _("numeric overflow")); + } + + if (index_type == DEBUG_TYPE_NULL) + { + /* A type defined as a subrange of itself, with both bounds 0, + is void. */ + if (self_subrange && n2 == 0 && n3 == 0) + return debug_make_void_type (dhandle); + + /* A type defined as a subrange of itself, with n2 positive and + n3 zero, is a complex type, and n2 is the number of bytes. */ + if (self_subrange && n3 == 0 && n2 > 0) + return debug_make_complex_type (dhandle, n2); + + /* If n3 is zero and n2 is positive, this is a floating point + type, and n2 is the number of bytes. */ + if (n3 == 0 && n2 > 0) + return debug_make_float_type (dhandle, n2); + + /* If the upper bound is -1, this is an unsigned int. */ + if (n2 == 0 && n3 == -1) + { + /* When gcc is used with -gstabs, but not -gstabs+, it will emit + long long int:t6=r1;0;-1; + long long unsigned int:t7=r1;0;-1; + We hack here to handle this reasonably. */ + if (typename != NULL) + { + if (strcmp (typename, "long long int") == 0) + return debug_make_int_type (dhandle, 8, FALSE); + else if (strcmp (typename, "long long unsigned int") == 0) + return debug_make_int_type (dhandle, 8, TRUE); + } + /* FIXME: The size here really depends upon the target. */ + return debug_make_int_type (dhandle, 4, TRUE); + } + + /* A range of 0 to 127 is char. */ + if (self_subrange && n2 == 0 && n3 == 127) + return debug_make_int_type (dhandle, 1, FALSE); + + /* FIXME: gdb checks for the language CHILL here. */ + + if (n2 == 0) + { + if (n3 < 0) + return debug_make_int_type (dhandle, - n3, TRUE); + else if (n3 == 0xff) + return debug_make_int_type (dhandle, 1, TRUE); + else if (n3 == 0xffff) + return debug_make_int_type (dhandle, 2, TRUE); + else if (n3 == (bfd_signed_vma) 0xffffffff) + return debug_make_int_type (dhandle, 4, TRUE); +#ifdef BFD64 + else if (n3 == ((((bfd_signed_vma) 0xffffffff) << 32) | 0xffffffff)) + return debug_make_int_type (dhandle, 8, TRUE); +#endif + } + else if (n3 == 0 + && n2 < 0 + && (self_subrange || n2 == -8)) + return debug_make_int_type (dhandle, - n2, TRUE); + else if (n2 == - n3 - 1 || n2 == n3 + 1) + { + if (n3 == 0x7f) + return debug_make_int_type (dhandle, 1, FALSE); + else if (n3 == 0x7fff) + return debug_make_int_type (dhandle, 2, FALSE); + else if (n3 == 0x7fffffff) + return debug_make_int_type (dhandle, 4, FALSE); +#ifdef BFD64 + else if (n3 == ((((bfd_vma) 0x7fffffff) << 32) | 0xffffffff)) + return debug_make_int_type (dhandle, 8, FALSE); +#endif + } + } + + /* At this point I don't have the faintest idea how to deal with a + self_subrange type; I'm going to assume that this is used as an + idiom, and that all of them are special cases. So . . . */ + if (self_subrange) + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + + index_type = stab_find_type (dhandle, info, rangenums); + if (index_type == DEBUG_TYPE_NULL) + { + /* Does this actually ever happen? Is that why we are worrying + about dealing with it rather than just calling error_type? */ + warn_stab (orig, _("missing index type")); + index_type = debug_make_int_type (dhandle, 4, FALSE); + } + + return debug_make_range_type (dhandle, index_type, n2, n3); +} + +/* Sun's ACC uses a somewhat saner method for specifying the builtin + typedefs in every file (for int, long, etc): + + type = b ; ; + signed = u or s. Possible c in addition to u or s (for char?). + offset = offset from high order bit to start bit of type. + width is # bytes in object of this type, nbits is # bits in type. + + The width/offset stuff appears to be for small objects stored in + larger ones (e.g. `shorts' in `int' registers). We ignore it for now, + FIXME. */ + +static debug_type +parse_stab_sun_builtin_type (dhandle, pp) + PTR dhandle; + const char **pp; +{ + const char *orig; + bfd_boolean unsignedp; + bfd_vma bits; + + orig = *pp; + + switch (**pp) + { + case 's': + unsignedp = FALSE; + break; + case 'u': + unsignedp = TRUE; + break; + default: + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + /* For some odd reason, all forms of char put a c here. This is strange + because no other type has this honor. We can safely ignore this because + we actually determine 'char'acterness by the number of bits specified in + the descriptor. */ + if (**pp == 'c') + ++*pp; + + /* The first number appears to be the number of bytes occupied + by this type, except that unsigned short is 4 instead of 2. + Since this information is redundant with the third number, + we will ignore it. */ + (void) parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + /* The second number is always 0, so ignore it too. */ + (void) parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + /* The third number is the number of bits for this type. */ + bits = parse_number (pp, (bfd_boolean *) NULL); + + /* The type *should* end with a semicolon. If it are embedded + in a larger type the semicolon may be the only way to know where + the type ends. If this type is at the end of the stabstring we + can deal with the omitted semicolon (but we don't have to like + it). Don't bother to complain(), Sun's compiler omits the semicolon + for "void". */ + if (**pp == ';') + ++*pp; + + if (bits == 0) + return debug_make_void_type (dhandle); + + return debug_make_int_type (dhandle, bits / 8, unsignedp); +} + +/* Parse a builtin floating type generated by the Sun compiler. */ + +static debug_type +parse_stab_sun_floating_type (dhandle, pp) + PTR dhandle; + const char **pp; +{ + const char *orig; + bfd_vma details; + bfd_vma bytes; + + orig = *pp; + + /* The first number has more details about the type, for example + FN_COMPLEX. */ + details = parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + + /* The second number is the number of bytes occupied by this type */ + bytes = parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + + if (details == NF_COMPLEX + || details == NF_COMPLEX16 + || details == NF_COMPLEX32) + return debug_make_complex_type (dhandle, bytes); + + return debug_make_float_type (dhandle, bytes); +} + +/* Handle an enum type. */ + +static debug_type +parse_stab_enum_type (dhandle, pp) + PTR dhandle; + const char **pp; +{ + const char *orig; + const char **names; + bfd_signed_vma *values; + unsigned int n; + unsigned int alloc; + + orig = *pp; + + /* FIXME: gdb checks os9k_stabs here. */ + + /* The aix4 compiler emits an extra field before the enum members; + my guess is it's a type of some sort. Just ignore it. */ + if (**pp == '-') + { + while (**pp != ':') + ++*pp; + ++*pp; + } + + /* Read the value-names and their values. + The input syntax is NAME:VALUE,NAME:VALUE, and so on. + A semicolon or comma instead of a NAME means the end. */ + alloc = 10; + names = (const char **) xmalloc (alloc * sizeof *names); + values = (bfd_signed_vma *) xmalloc (alloc * sizeof *values); + n = 0; + while (**pp != '\0' && **pp != ';' && **pp != ',') + { + const char *p; + char *name; + bfd_signed_vma val; + + p = *pp; + while (*p != ':') + ++p; + + name = savestring (*pp, p - *pp); + + *pp = p + 1; + val = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ',') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + if (n + 1 >= alloc) + { + alloc += 10; + names = ((const char **) + xrealloc ((PTR) names, alloc * sizeof *names)); + values = ((bfd_signed_vma *) + xrealloc ((PTR) values, alloc * sizeof *values)); + } + + names[n] = name; + values[n] = val; + ++n; + } + + names[n] = NULL; + values[n] = 0; + + if (**pp == ';') + ++*pp; + + return debug_make_enum_type (dhandle, names, values); +} + +/* Read the description of a structure (or union type) and return an object + describing the type. + + PP points to a character pointer that points to the next unconsumed token + in the the stabs string. For example, given stabs "A:T4=s4a:1,0,32;;", + *PP will point to "4a:1,0,32;;". */ + +static debug_type +parse_stab_struct_type (dhandle, info, tagname, pp, structp, typenums) + PTR dhandle; + struct stab_handle *info; + const char *tagname; + const char **pp; + bfd_boolean structp; + const int *typenums; +{ + const char *orig; + bfd_vma size; + debug_baseclass *baseclasses; + debug_field *fields; + bfd_boolean statics; + debug_method *methods; + debug_type vptrbase; + bfd_boolean ownvptr; + + orig = *pp; + + /* Get the size. */ + size = parse_number (pp, (bfd_boolean *) NULL); + + /* Get the other information. */ + if (! parse_stab_baseclasses (dhandle, info, pp, &baseclasses) + || ! parse_stab_struct_fields (dhandle, info, pp, &fields, &statics) + || ! parse_stab_members (dhandle, info, tagname, pp, typenums, &methods) + || ! parse_stab_tilde_field (dhandle, info, pp, typenums, &vptrbase, + &ownvptr)) + return DEBUG_TYPE_NULL; + + if (! statics + && baseclasses == NULL + && methods == NULL + && vptrbase == DEBUG_TYPE_NULL + && ! ownvptr) + return debug_make_struct_type (dhandle, structp, size, fields); + + return debug_make_object_type (dhandle, structp, size, fields, baseclasses, + methods, vptrbase, ownvptr); +} + +/* The stabs for C++ derived classes contain baseclass information which + is marked by a '!' character after the total size. This function is + called when we encounter the baseclass marker, and slurps up all the + baseclass information. + + Immediately following the '!' marker is the number of base classes that + the class is derived from, followed by information for each base class. + For each base class, there are two visibility specifiers, a bit offset + to the base class information within the derived class, a reference to + the type for the base class, and a terminating semicolon. + + A typical example, with two base classes, would be "!2,020,19;0264,21;". + ^^ ^ ^ ^ ^ ^ ^ + Baseclass information marker __________________|| | | | | | | + Number of baseclasses __________________________| | | | | | | + Visibility specifiers (2) ________________________| | | | | | + Offset in bits from start of class _________________| | | | | + Type number for base class ___________________________| | | | + Visibility specifiers (2) _______________________________| | | + Offset in bits from start of class ________________________| | + Type number of base class ____________________________________| + + Return TRUE for success, FALSE for failure. */ + +static bfd_boolean +parse_stab_baseclasses (dhandle, info, pp, retp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + debug_baseclass **retp; +{ + const char *orig; + unsigned int c, i; + debug_baseclass *classes; + + *retp = NULL; + + orig = *pp; + + if (**pp != '!') + { + /* No base classes. */ + return TRUE; + } + ++*pp; + + c = (unsigned int) parse_number (pp, (bfd_boolean *) NULL); + + if (**pp != ',') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + + classes = (debug_baseclass *) xmalloc ((c + 1) * sizeof (**retp)); + + for (i = 0; i < c; i++) + { + bfd_boolean virtual; + enum debug_visibility visibility; + bfd_vma bitpos; + debug_type type; + + switch (**pp) + { + case '0': + virtual = FALSE; + break; + case '1': + virtual = TRUE; + break; + default: + warn_stab (orig, _("unknown virtual character for baseclass")); + virtual = FALSE; + break; + } + ++*pp; + + switch (**pp) + { + case '0': + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + case '1': + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + case '2': + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + default: + warn_stab (orig, _("unknown visibility character for baseclass")); + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + } + ++*pp; + + /* The remaining value is the bit offset of the portion of the + object corresponding to this baseclass. Always zero in the + absence of multiple inheritance. */ + bitpos = parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ',') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (type == DEBUG_TYPE_NULL) + return FALSE; + + classes[i] = debug_make_baseclass (dhandle, type, bitpos, virtual, + visibility); + if (classes[i] == DEBUG_BASECLASS_NULL) + return FALSE; + + if (**pp != ';') + return FALSE; + ++*pp; + } + + classes[i] = DEBUG_BASECLASS_NULL; + + *retp = classes; + + return TRUE; +} + +/* Read struct or class data fields. They have the form: + + NAME : [VISIBILITY] TYPENUM , BITPOS , BITSIZE ; + + At the end, we see a semicolon instead of a field. + + In C++, this may wind up being NAME:?TYPENUM:PHYSNAME; for + a static field. + + The optional VISIBILITY is one of: + + '/0' (VISIBILITY_PRIVATE) + '/1' (VISIBILITY_PROTECTED) + '/2' (VISIBILITY_PUBLIC) + '/9' (VISIBILITY_IGNORE) + + or nothing, for C style fields with public visibility. + + Returns 1 for success, 0 for failure. */ + +static bfd_boolean +parse_stab_struct_fields (dhandle, info, pp, retp, staticsp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + debug_field **retp; + bfd_boolean *staticsp; +{ + const char *orig; + const char *p; + debug_field *fields; + unsigned int c; + unsigned int alloc; + + *retp = NULL; + *staticsp = FALSE; + + orig = *pp; + + c = 0; + alloc = 10; + fields = (debug_field *) xmalloc (alloc * sizeof *fields); + while (**pp != ';') + { + /* FIXME: gdb checks os9k_stabs here. */ + + p = *pp; + + /* Add 1 to c to leave room for NULL pointer at end. */ + if (c + 1 >= alloc) + { + alloc += 10; + fields = ((debug_field *) + xrealloc ((PTR) fields, alloc * sizeof *fields)); + } + + /* If it starts with CPLUS_MARKER it is a special abbreviation, + unless the CPLUS_MARKER is followed by an underscore, in + which case it is just the name of an anonymous type, which we + should handle like any other type name. We accept either '$' + or '.', because a field name can never contain one of these + characters except as a CPLUS_MARKER. */ + + if ((*p == '$' || *p == '.') && p[1] != '_') + { + ++*pp; + if (! parse_stab_cpp_abbrev (dhandle, info, pp, fields + c)) + return FALSE; + ++c; + continue; + } + + /* Look for the ':' that separates the field name from the field + values. Data members are delimited by a single ':', while member + functions are delimited by a pair of ':'s. When we hit the member + functions (if any), terminate scan loop and return. */ + + p = strchr (p, ':'); + if (p == NULL) + { + bad_stab (orig); + return FALSE; + } + + if (p[1] == ':') + break; + + if (! parse_stab_one_struct_field (dhandle, info, pp, p, fields + c, + staticsp)) + return FALSE; + + ++c; + } + + fields[c] = DEBUG_FIELD_NULL; + + *retp = fields; + + return TRUE; +} + +/* Special GNU C++ name. */ + +static bfd_boolean +parse_stab_cpp_abbrev (dhandle, info, pp, retp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + debug_field *retp; +{ + const char *orig; + int cpp_abbrev; + debug_type context; + const char *name; + const char *typename; + debug_type type; + bfd_vma bitpos; + + *retp = DEBUG_FIELD_NULL; + + orig = *pp; + + if (**pp != 'v') + { + bad_stab (*pp); + return FALSE; + } + ++*pp; + + cpp_abbrev = **pp; + ++*pp; + + /* At this point, *pp points to something like "22:23=*22...", where + the type number before the ':' is the "context" and everything + after is a regular type definition. Lookup the type, find it's + name, and construct the field name. */ + + context = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (context == DEBUG_TYPE_NULL) + return FALSE; + + switch (cpp_abbrev) + { + case 'f': + /* $vf -- a virtual function table pointer. */ + name = "_vptr$"; + break; + case 'b': + /* $vb -- a virtual bsomethingorother */ + typename = debug_get_type_name (dhandle, context); + if (typename == NULL) + { + warn_stab (orig, _("unnamed $vb type")); + typename = "FOO"; + } + name = concat ("_vb$", typename, (const char *) NULL); + break; + default: + warn_stab (orig, _("unrecognized C++ abbreviation")); + name = "INVALID_CPLUSPLUS_ABBREV"; + break; + } + + if (**pp != ':') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (**pp != ',') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + + bitpos = parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + + *retp = debug_make_field (dhandle, name, type, bitpos, 0, + DEBUG_VISIBILITY_PRIVATE); + if (*retp == DEBUG_FIELD_NULL) + return FALSE; + + return TRUE; +} + +/* Parse a single field in a struct or union. */ + +static bfd_boolean +parse_stab_one_struct_field (dhandle, info, pp, p, retp, staticsp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + const char *p; + debug_field *retp; + bfd_boolean *staticsp; +{ + const char *orig; + char *name; + enum debug_visibility visibility; + debug_type type; + bfd_vma bitpos; + bfd_vma bitsize; + + orig = *pp; + + /* FIXME: gdb checks ARM_DEMANGLING here. */ + + name = savestring (*pp, p - *pp); + + *pp = p + 1; + + if (**pp != '/') + visibility = DEBUG_VISIBILITY_PUBLIC; + else + { + ++*pp; + switch (**pp) + { + case '0': + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + case '1': + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + case '2': + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + default: + warn_stab (orig, _("unknown visibility character for field")); + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + } + ++*pp; + } + + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (type == DEBUG_TYPE_NULL) + return FALSE; + + if (**pp == ':') + { + char *varname; + + /* This is a static class member. */ + ++*pp; + p = strchr (*pp, ';'); + if (p == NULL) + { + bad_stab (orig); + return FALSE; + } + + varname = savestring (*pp, p - *pp); + + *pp = p + 1; + + *retp = debug_make_static_member (dhandle, name, type, varname, + visibility); + *staticsp = TRUE; + + return TRUE; + } + + if (**pp != ',') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + + bitpos = parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ',') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + + bitsize = parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + + if (bitpos == 0 && bitsize == 0) + { + /* This can happen in two cases: (1) at least for gcc 2.4.5 or + so, it is a field which has been optimized out. The correct + stab for this case is to use VISIBILITY_IGNORE, but that is a + recent invention. (2) It is a 0-size array. For example + union { int num; char str[0]; } foo. Printing "" + for str in "p foo" is OK, since foo.str (and thus foo.str[3]) + will continue to work, and a 0-size array as a whole doesn't + have any contents to print. + + I suspect this probably could also happen with gcc -gstabs + (not -gstabs+) for static fields, and perhaps other C++ + extensions. Hopefully few people use -gstabs with gdb, since + it is intended for dbx compatibility. */ + visibility = DEBUG_VISIBILITY_IGNORE; + } + + /* FIXME: gdb does some stuff here to mark fields as unpacked. */ + + *retp = debug_make_field (dhandle, name, type, bitpos, bitsize, visibility); + + return TRUE; +} + +/* Read member function stabs info for C++ classes. The form of each member + function data is: + + NAME :: TYPENUM[=type definition] ARGS : PHYSNAME ; + + An example with two member functions is: + + afunc1::20=##15;:i;2A.;afunc2::20:i;2A.; + + For the case of overloaded operators, the format is op$::*.funcs, where + $ is the CPLUS_MARKER (usually '$'), `*' holds the place for an operator + name (such as `+=') and `.' marks the end of the operator name. */ + +static bfd_boolean +parse_stab_members (dhandle, info, tagname, pp, typenums, retp) + PTR dhandle; + struct stab_handle *info; + const char *tagname; + const char **pp; + const int *typenums; + debug_method **retp; +{ + const char *orig; + debug_method *methods; + unsigned int c; + unsigned int alloc; + + *retp = NULL; + + orig = *pp; + + alloc = 0; + methods = NULL; + c = 0; + + while (**pp != ';') + { + const char *p; + char *name; + debug_method_variant *variants; + unsigned int cvars; + unsigned int allocvars; + debug_type look_ahead_type; + + p = strchr (*pp, ':'); + if (p == NULL || p[1] != ':') + break; + + /* FIXME: Some systems use something other than '$' here. */ + if ((*pp)[0] != 'o' || (*pp)[1] != 'p' || (*pp)[2] != '$') + { + name = savestring (*pp, p - *pp); + *pp = p + 2; + } + else + { + /* This is a completely wierd case. In order to stuff in the + names that might contain colons (the usual name delimiter), + Mike Tiemann defined a different name format which is + signalled if the identifier is "op$". In that case, the + format is "op$::XXXX." where XXXX is the name. This is + used for names like "+" or "=". YUUUUUUUK! FIXME! */ + *pp = p + 2; + for (p = *pp; *p != '.' && *p != '\0'; p++) + ; + if (*p != '.') + { + bad_stab (orig); + return FALSE; + } + name = savestring (*pp, p - *pp); + *pp = p + 1; + } + + allocvars = 10; + variants = ((debug_method_variant *) + xmalloc (allocvars * sizeof *variants)); + cvars = 0; + + look_ahead_type = DEBUG_TYPE_NULL; + + do + { + debug_type type; + bfd_boolean stub; + char *argtypes; + enum debug_visibility visibility; + bfd_boolean constp, volatilep, staticp; + bfd_vma voffset; + debug_type context; + const char *physname; + bfd_boolean varargs; + + if (look_ahead_type != DEBUG_TYPE_NULL) + { + /* g++ version 1 kludge */ + type = look_ahead_type; + look_ahead_type = DEBUG_TYPE_NULL; + } + else + { + type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (type == DEBUG_TYPE_NULL) + return FALSE; + if (**pp != ':') + { + bad_stab (orig); + return FALSE; + } + } + + ++*pp; + p = strchr (*pp, ';'); + if (p == NULL) + { + bad_stab (orig); + return FALSE; + } + + stub = FALSE; + if (debug_get_type_kind (dhandle, type) == DEBUG_KIND_METHOD + && debug_get_parameter_types (dhandle, type, &varargs) == NULL) + stub = TRUE; + + argtypes = savestring (*pp, p - *pp); + *pp = p + 1; + + switch (**pp) + { + case '0': + visibility = DEBUG_VISIBILITY_PRIVATE; + break; + case '1': + visibility = DEBUG_VISIBILITY_PROTECTED; + break; + default: + visibility = DEBUG_VISIBILITY_PUBLIC; + break; + } + ++*pp; + + constp = FALSE; + volatilep = FALSE; + switch (**pp) + { + case 'A': + /* Normal function. */ + ++*pp; + break; + case 'B': + /* const member function. */ + constp = TRUE; + ++*pp; + break; + case 'C': + /* volatile member function. */ + volatilep = TRUE; + ++*pp; + break; + case 'D': + /* const volatile member function. */ + constp = TRUE; + volatilep = TRUE; + ++*pp; + break; + case '*': + case '?': + case '.': + /* File compiled with g++ version 1; no information. */ + break; + default: + warn_stab (orig, _("const/volatile indicator missing")); + break; + } + + staticp = FALSE; + switch (**pp) + { + case '*': + /* virtual member function, followed by index. The sign + bit is supposedly set to distinguish + pointers-to-methods from virtual function indicies. */ + ++*pp; + voffset = parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + voffset &= 0x7fffffff; + + if (**pp == ';' || *pp == '\0') + { + /* Must be g++ version 1. */ + context = DEBUG_TYPE_NULL; + } + else + { + /* Figure out from whence this virtual function + came. It may belong to virtual function table of + one of its baseclasses. */ + look_ahead_type = parse_stab_type (dhandle, info, + (const char *) NULL, + pp, + (debug_type **) NULL); + if (**pp == ':') + { + /* g++ version 1 overloaded methods. */ + context = DEBUG_TYPE_NULL; + } + else + { + context = look_ahead_type; + look_ahead_type = DEBUG_TYPE_NULL; + if (**pp != ';') + { + bad_stab (orig); + return FALSE; + } + ++*pp; + } + } + break; + + case '?': + /* static member function. */ + ++*pp; + staticp = TRUE; + voffset = 0; + context = DEBUG_TYPE_NULL; + if (strncmp (argtypes, name, strlen (name)) != 0) + stub = TRUE; + break; + + default: + warn_stab (orig, "member function type missing"); + voffset = 0; + context = DEBUG_TYPE_NULL; + break; + + case '.': + ++*pp; + voffset = 0; + context = DEBUG_TYPE_NULL; + break; + } + + /* If the type is not a stub, then the argtypes string is + the physical name of the function. Otherwise the + argtypes string is the mangled form of the argument + types, and the full type and the physical name must be + extracted from them. */ + if (! stub) + physname = argtypes; + else + { + debug_type class_type, return_type; + + class_type = stab_find_type (dhandle, info, typenums); + if (class_type == DEBUG_TYPE_NULL) + return FALSE; + return_type = debug_get_return_type (dhandle, type); + if (return_type == DEBUG_TYPE_NULL) + { + bad_stab (orig); + return FALSE; + } + type = parse_stab_argtypes (dhandle, info, class_type, name, + tagname, return_type, argtypes, + constp, volatilep, &physname); + if (type == DEBUG_TYPE_NULL) + return FALSE; + } + + if (cvars + 1 >= allocvars) + { + allocvars += 10; + variants = ((debug_method_variant *) + xrealloc ((PTR) variants, + allocvars * sizeof *variants)); + } + + if (! staticp) + variants[cvars] = debug_make_method_variant (dhandle, physname, + type, visibility, + constp, volatilep, + voffset, context); + else + variants[cvars] = debug_make_static_method_variant (dhandle, + physname, + type, + visibility, + constp, + volatilep); + if (variants[cvars] == DEBUG_METHOD_VARIANT_NULL) + return FALSE; + + ++cvars; + } + while (**pp != ';' && **pp != '\0'); + + variants[cvars] = DEBUG_METHOD_VARIANT_NULL; + + if (**pp != '\0') + ++*pp; + + if (c + 1 >= alloc) + { + alloc += 10; + methods = ((debug_method *) + xrealloc ((PTR) methods, alloc * sizeof *methods)); + } + + methods[c] = debug_make_method (dhandle, name, variants); + + ++c; + } + + if (methods != NULL) + methods[c] = DEBUG_METHOD_NULL; + + *retp = methods; + + return TRUE; +} + +/* Parse a string representing argument types for a method. Stabs + tries to save space by packing argument types into a mangled + string. This string should give us enough information to extract + both argument types and the physical name of the function, given + the tag name. */ + +static debug_type +parse_stab_argtypes (dhandle, info, class_type, fieldname, tagname, + return_type, argtypes, constp, volatilep, pphysname) + PTR dhandle; + struct stab_handle *info; + debug_type class_type; + const char *fieldname; + const char *tagname; + debug_type return_type; + const char *argtypes; + bfd_boolean constp; + bfd_boolean volatilep; + const char **pphysname; +{ + bfd_boolean is_full_physname_constructor; + bfd_boolean is_constructor; + bfd_boolean is_destructor; + debug_type *args; + bfd_boolean varargs; + unsigned int physname_len = 0; + + /* Constructors are sometimes handled specially. */ + is_full_physname_constructor = ((argtypes[0] == '_' + && argtypes[1] == '_' + && (ISDIGIT (argtypes[2]) + || argtypes[2] == 'Q' + || argtypes[2] == 't')) + || strncmp (argtypes, "__ct", 4) == 0); + + is_constructor = (is_full_physname_constructor + || (tagname != NULL + && strcmp (fieldname, tagname) == 0)); + is_destructor = ((argtypes[0] == '_' + && (argtypes[1] == '$' || argtypes[1] == '.') + && argtypes[2] == '_') + || strncmp (argtypes, "__dt", 4) == 0); + + if (is_destructor || is_full_physname_constructor) + *pphysname = argtypes; + else + { + unsigned int len; + const char *const_prefix; + const char *volatile_prefix; + char buf[20]; + unsigned int mangled_name_len; + char *physname; + + len = tagname == NULL ? 0 : strlen (tagname); + const_prefix = constp ? "C" : ""; + volatile_prefix = volatilep ? "V" : ""; + + if (len == 0) + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + else if (tagname != NULL && strchr (tagname, '<') != NULL) + { + /* Template methods are fully mangled. */ + sprintf (buf, "__%s%s", const_prefix, volatile_prefix); + tagname = NULL; + len = 0; + } + else + sprintf (buf, "__%s%s%d", const_prefix, volatile_prefix, len); + + mangled_name_len = ((is_constructor ? 0 : strlen (fieldname)) + + strlen (buf) + + len + + strlen (argtypes) + + 1); + + if (fieldname[0] == 'o' + && fieldname[1] == 'p' + && (fieldname[2] == '$' || fieldname[2] == '.')) + { + const char *opname; + + opname = cplus_mangle_opname (fieldname + 3, 0); + if (opname == NULL) + { + fprintf (stderr, _("No mangling for \"%s\"\n"), fieldname); + return DEBUG_TYPE_NULL; + } + mangled_name_len += strlen (opname); + physname = (char *) xmalloc (mangled_name_len); + strncpy (physname, fieldname, 3); + strcpy (physname + 3, opname); + } + else + { + physname = (char *) xmalloc (mangled_name_len); + if (is_constructor) + physname[0] = '\0'; + else + strcpy (physname, fieldname); + } + + physname_len = strlen (physname); + strcat (physname, buf); + if (tagname != NULL) + strcat (physname, tagname); + strcat (physname, argtypes); + + *pphysname = physname; + } + + if (*argtypes == '\0' || is_destructor) + { + args = (debug_type *) xmalloc (sizeof *args); + *args = NULL; + return debug_make_method_type (dhandle, return_type, class_type, args, + FALSE); + } + + args = stab_demangle_argtypes (dhandle, info, *pphysname, &varargs, physname_len); + if (args == NULL) + return DEBUG_TYPE_NULL; + + return debug_make_method_type (dhandle, return_type, class_type, args, + varargs); +} + +/* The tail end of stabs for C++ classes that contain a virtual function + pointer contains a tilde, a %, and a type number. + The type number refers to the base class (possibly this class itself) which + contains the vtable pointer for the current class. + + This function is called when we have parsed all the method declarations, + so we can look for the vptr base class info. */ + +static bfd_boolean +parse_stab_tilde_field (dhandle, info, pp, typenums, retvptrbase, retownvptr) + PTR dhandle; + struct stab_handle *info; + const char **pp; + const int *typenums; + debug_type *retvptrbase; + bfd_boolean *retownvptr; +{ + const char *orig; + const char *hold; + int vtypenums[2]; + + *retvptrbase = DEBUG_TYPE_NULL; + *retownvptr = FALSE; + + orig = *pp; + + /* If we are positioned at a ';', then skip it. */ + if (**pp == ';') + ++*pp; + + if (**pp != '~') + return TRUE; + + ++*pp; + + if (**pp == '=' || **pp == '+' || **pp == '-') + { + /* Obsolete flags that used to indicate the presence of + constructors and/or destructors. */ + ++*pp; + } + + if (**pp != '%') + return TRUE; + + ++*pp; + + hold = *pp; + + /* The next number is the type number of the base class (possibly + our own class) which supplies the vtable for this class. */ + if (! parse_stab_type_number (pp, vtypenums)) + return FALSE; + + if (vtypenums[0] == typenums[0] + && vtypenums[1] == typenums[1]) + *retownvptr = TRUE; + else + { + debug_type vtype; + const char *p; + + *pp = hold; + + vtype = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + for (p = *pp; *p != ';' && *p != '\0'; p++) + ; + if (*p != ';') + { + bad_stab (orig); + return FALSE; + } + + *retvptrbase = vtype; + + *pp = p + 1; + } + + return TRUE; +} + +/* Read a definition of an array type. */ + +static debug_type +parse_stab_array_type (dhandle, info, pp, stringp) + PTR dhandle; + struct stab_handle *info; + const char **pp; + bfd_boolean stringp; +{ + const char *orig; + const char *p; + int typenums[2]; + debug_type index_type; + bfd_boolean adjustable; + bfd_signed_vma lower, upper; + debug_type element_type; + + /* Format of an array type: + "ar;lower;upper;". + OS9000: "arlower,upper;". + + Fortran adjustable arrays use Adigits or Tdigits for lower or upper; + for these, produce a type like float[][]. */ + + orig = *pp; + + /* FIXME: gdb checks os9k_stabs here. */ + + /* If the index type is type 0, we take it as int. */ + p = *pp; + if (! parse_stab_type_number (&p, typenums)) + return DEBUG_TYPE_NULL; + if (typenums[0] == 0 && typenums[1] == 0 && **pp != '=') + { + index_type = debug_find_named_type (dhandle, "int"); + if (index_type == DEBUG_TYPE_NULL) + { + index_type = debug_make_int_type (dhandle, 4, FALSE); + if (index_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + } + *pp = p; + } + else + { + index_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + } + + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + adjustable = FALSE; + + if (! ISDIGIT (**pp) && **pp != '-') + { + ++*pp; + adjustable = TRUE; + } + + lower = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + if (! ISDIGIT (**pp) && **pp != '-') + { + ++*pp; + adjustable = TRUE; + } + + upper = (bfd_signed_vma) parse_number (pp, (bfd_boolean *) NULL); + if (**pp != ';') + { + bad_stab (orig); + return DEBUG_TYPE_NULL; + } + ++*pp; + + element_type = parse_stab_type (dhandle, info, (const char *) NULL, pp, + (debug_type **) NULL); + if (element_type == DEBUG_TYPE_NULL) + return DEBUG_TYPE_NULL; + + if (adjustable) + { + lower = 0; + upper = -1; + } + + return debug_make_array_type (dhandle, element_type, index_type, lower, + upper, stringp); +} + +/* This struct holds information about files we have seen using + N_BINCL. */ + +struct bincl_file +{ + /* The next N_BINCL file. */ + struct bincl_file *next; + /* The next N_BINCL on the stack. */ + struct bincl_file *next_stack; + /* The file name. */ + const char *name; + /* The hash value. */ + bfd_vma hash; + /* The file index. */ + unsigned int file; + /* The list of types defined in this file. */ + struct stab_types *file_types; +}; + +/* Start a new N_BINCL file, pushing it onto the stack. */ + +static void +push_bincl (info, name, hash) + struct stab_handle *info; + const char *name; + bfd_vma hash; +{ + struct bincl_file *n; + + n = (struct bincl_file *) xmalloc (sizeof *n); + n->next = info->bincl_list; + n->next_stack = info->bincl_stack; + n->name = name; + n->hash = hash; + n->file = info->files; + n->file_types = NULL; + info->bincl_list = n; + info->bincl_stack = n; + + ++info->files; + info->file_types = ((struct stab_types **) + xrealloc ((PTR) info->file_types, + (info->files + * sizeof *info->file_types))); + info->file_types[n->file] = NULL; +} + +/* Finish an N_BINCL file, at an N_EINCL, popping the name off the + stack. */ + +static const char * +pop_bincl (info) + struct stab_handle *info; +{ + struct bincl_file *o; + + o = info->bincl_stack; + if (o == NULL) + return info->main_filename; + info->bincl_stack = o->next_stack; + + o->file_types = info->file_types[o->file]; + + if (info->bincl_stack == NULL) + return info->main_filename; + return info->bincl_stack->name; +} + +/* Handle an N_EXCL: get the types from the corresponding N_BINCL. */ + +static bfd_boolean +find_excl (info, name, hash) + struct stab_handle *info; + const char *name; + bfd_vma hash; +{ + struct bincl_file *l; + + ++info->files; + info->file_types = ((struct stab_types **) + xrealloc ((PTR) info->file_types, + (info->files + * sizeof *info->file_types))); + + for (l = info->bincl_list; l != NULL; l = l->next) + if (l->hash == hash && strcmp (l->name, name) == 0) + break; + if (l == NULL) + { + warn_stab (name, _("Undefined N_EXCL")); + info->file_types[info->files - 1] = NULL; + return TRUE; + } + + info->file_types[info->files - 1] = l->file_types; + + return TRUE; +} + +/* Handle a variable definition. gcc emits variable definitions for a + block before the N_LBRAC, so we must hold onto them until we see + it. The SunPRO compiler emits variable definitions after the + N_LBRAC, so we can call debug_record_variable immediately. */ + +static bfd_boolean +stab_record_variable (dhandle, info, name, type, kind, val) + PTR dhandle; + struct stab_handle *info; + const char *name; + debug_type type; + enum debug_var_kind kind; + bfd_vma val; +{ + struct stab_pending_var *v; + + if ((kind == DEBUG_GLOBAL || kind == DEBUG_STATIC) + || ! info->within_function + || (info->gcc_compiled == 0 && info->n_opt_found)) + return debug_record_variable (dhandle, name, type, kind, val); + + v = (struct stab_pending_var *) xmalloc (sizeof *v); + memset (v, 0, sizeof *v); + + v->next = info->pending; + v->name = name; + v->type = type; + v->kind = kind; + v->val = val; + info->pending = v; + + return TRUE; +} + +/* Emit pending variable definitions. This is called after we see the + N_LBRAC that starts the block. */ + +static bfd_boolean +stab_emit_pending_vars (dhandle, info) + PTR dhandle; + struct stab_handle *info; +{ + struct stab_pending_var *v; + + v = info->pending; + while (v != NULL) + { + struct stab_pending_var *next; + + if (! debug_record_variable (dhandle, v->name, v->type, v->kind, v->val)) + return FALSE; + + next = v->next; + free (v); + v = next; + } + + info->pending = NULL; + + return TRUE; +} + +/* Find the slot for a type in the database. */ + +static debug_type * +stab_find_slot (info, typenums) + struct stab_handle *info; + const int *typenums; +{ + int filenum; + int index; + struct stab_types **ps; + + filenum = typenums[0]; + index = typenums[1]; + + if (filenum < 0 || (unsigned int) filenum >= info->files) + { + fprintf (stderr, _("Type file number %d out of range\n"), filenum); + return NULL; + } + if (index < 0) + { + fprintf (stderr, _("Type index number %d out of range\n"), index); + return NULL; + } + + ps = info->file_types + filenum; + + while (index >= STAB_TYPES_SLOTS) + { + if (*ps == NULL) + { + *ps = (struct stab_types *) xmalloc (sizeof **ps); + memset (*ps, 0, sizeof **ps); + } + ps = &(*ps)->next; + index -= STAB_TYPES_SLOTS; + } + if (*ps == NULL) + { + *ps = (struct stab_types *) xmalloc (sizeof **ps); + memset (*ps, 0, sizeof **ps); + } + + return (*ps)->types + index; +} + +/* Find a type given a type number. If the type has not been + allocated yet, create an indirect type. */ + +static debug_type +stab_find_type (dhandle, info, typenums) + PTR dhandle; + struct stab_handle *info; + const int *typenums; +{ + debug_type *slot; + + if (typenums[0] == 0 && typenums[1] < 0) + { + /* A negative type number indicates an XCOFF builtin type. */ + return stab_xcoff_builtin_type (dhandle, info, typenums[1]); + } + + slot = stab_find_slot (info, typenums); + if (slot == NULL) + return DEBUG_TYPE_NULL; + + if (*slot == DEBUG_TYPE_NULL) + return debug_make_indirect_type (dhandle, slot, (const char *) NULL); + + return *slot; +} + +/* Record that a given type number refers to a given type. */ + +static bfd_boolean +stab_record_type (dhandle, info, typenums, type) + PTR dhandle ATTRIBUTE_UNUSED; + struct stab_handle *info; + const int *typenums; + debug_type type; +{ + debug_type *slot; + + slot = stab_find_slot (info, typenums); + if (slot == NULL) + return FALSE; + + /* gdb appears to ignore type redefinitions, so we do as well. */ + + *slot = type; + + return TRUE; +} + +/* Return an XCOFF builtin type. */ + +static debug_type +stab_xcoff_builtin_type (dhandle, info, typenum) + PTR dhandle; + struct stab_handle *info; + int typenum; +{ + debug_type rettype; + const char *name; + + if (typenum >= 0 || typenum < -XCOFF_TYPE_COUNT) + { + fprintf (stderr, _("Unrecognized XCOFF type %d\n"), typenum); + return DEBUG_TYPE_NULL; + } + if (info->xcoff_types[-typenum] != NULL) + return info->xcoff_types[-typenum]; + + switch (-typenum) + { + case 1: + /* The size of this and all the other types are fixed, defined + by the debugging format. */ + name = "int"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; + case 2: + name = "char"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; + case 3: + name = "short"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; + case 4: + name = "long"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; + case 5: + name = "unsigned char"; + rettype = debug_make_int_type (dhandle, 1, TRUE); + break; + case 6: + name = "signed char"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; + case 7: + name = "unsigned short"; + rettype = debug_make_int_type (dhandle, 2, TRUE); + break; + case 8: + name = "unsigned int"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + break; + case 9: + name = "unsigned"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + case 10: + name = "unsigned long"; + rettype = debug_make_int_type (dhandle, 4, TRUE); + break; + case 11: + name = "void"; + rettype = debug_make_void_type (dhandle); + break; + case 12: + /* IEEE single precision (32 bit). */ + name = "float"; + rettype = debug_make_float_type (dhandle, 4); + break; + case 13: + /* IEEE double precision (64 bit). */ + name = "double"; + rettype = debug_make_float_type (dhandle, 8); + break; + case 14: + /* This is an IEEE double on the RS/6000, and different machines + with different sizes for "long double" should use different + negative type numbers. See stabs.texinfo. */ + name = "long double"; + rettype = debug_make_float_type (dhandle, 8); + break; + case 15: + name = "integer"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; + case 16: + name = "boolean"; + rettype = debug_make_bool_type (dhandle, 4); + break; + case 17: + name = "short real"; + rettype = debug_make_float_type (dhandle, 4); + break; + case 18: + name = "real"; + rettype = debug_make_float_type (dhandle, 8); + break; + case 19: + /* FIXME */ + name = "stringptr"; + rettype = NULL; + break; + case 20: + /* FIXME */ + name = "character"; + rettype = debug_make_int_type (dhandle, 1, TRUE); + break; + case 21: + name = "logical*1"; + rettype = debug_make_bool_type (dhandle, 1); + break; + case 22: + name = "logical*2"; + rettype = debug_make_bool_type (dhandle, 2); + break; + case 23: + name = "logical*4"; + rettype = debug_make_bool_type (dhandle, 4); + break; + case 24: + name = "logical"; + rettype = debug_make_bool_type (dhandle, 4); + break; + case 25: + /* Complex type consisting of two IEEE single precision values. */ + name = "complex"; + rettype = debug_make_complex_type (dhandle, 8); + break; + case 26: + /* Complex type consisting of two IEEE double precision values. */ + name = "double complex"; + rettype = debug_make_complex_type (dhandle, 16); + break; + case 27: + name = "integer*1"; + rettype = debug_make_int_type (dhandle, 1, FALSE); + break; + case 28: + name = "integer*2"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; + case 29: + name = "integer*4"; + rettype = debug_make_int_type (dhandle, 4, FALSE); + break; + case 30: + /* FIXME */ + name = "wchar"; + rettype = debug_make_int_type (dhandle, 2, FALSE); + break; + case 31: + name = "long long"; + rettype = debug_make_int_type (dhandle, 8, FALSE); + break; + case 32: + name = "unsigned long long"; + rettype = debug_make_int_type (dhandle, 8, TRUE); + break; + case 33: + name = "logical*8"; + rettype = debug_make_bool_type (dhandle, 8); + break; + case 34: + name = "integer*8"; + rettype = debug_make_int_type (dhandle, 8, FALSE); + break; + default: + abort (); + } + + rettype = debug_name_type (dhandle, name, rettype); + + info->xcoff_types[-typenum] = rettype; + + return rettype; +} + +/* Find or create a tagged type. */ + +static debug_type +stab_find_tagged_type (dhandle, info, p, len, kind) + PTR dhandle; + struct stab_handle *info; + const char *p; + int len; + enum debug_type_kind kind; +{ + char *name; + debug_type dtype; + struct stab_tag *st; + + name = savestring (p, len); + + /* We pass DEBUG_KIND_ILLEGAL because we want all tags in the same + namespace. This is right for C, and I don't know how to handle + other languages. FIXME. */ + dtype = debug_find_tagged_type (dhandle, name, DEBUG_KIND_ILLEGAL); + if (dtype != DEBUG_TYPE_NULL) + { + free (name); + return dtype; + } + + /* We need to allocate an entry on the undefined tag list. */ + for (st = info->tags; st != NULL; st = st->next) + { + if (st->name[0] == name[0] + && strcmp (st->name, name) == 0) + { + if (st->kind == DEBUG_KIND_ILLEGAL) + st->kind = kind; + free (name); + break; + } + } + if (st == NULL) + { + st = (struct stab_tag *) xmalloc (sizeof *st); + memset (st, 0, sizeof *st); + + st->next = info->tags; + st->name = name; + st->kind = kind; + st->slot = DEBUG_TYPE_NULL; + st->type = debug_make_indirect_type (dhandle, &st->slot, name); + info->tags = st; + } + + return st->type; +} + +/* In order to get the correct argument types for a stubbed method, we + need to extract the argument types from a C++ mangled string. + Since the argument types can refer back to the return type, this + means that we must demangle the entire physical name. In gdb this + is done by calling cplus_demangle and running the results back + through the C++ expression parser. Since we have no expression + parser, we must duplicate much of the work of cplus_demangle here. + + We assume that GNU style demangling is used, since this is only + done for method stubs, and only g++ should output that form of + debugging information. */ + +/* This structure is used to hold a pointer to type information which + demangling a string. */ + +struct stab_demangle_typestring +{ + /* The start of the type. This is not null terminated. */ + const char *typestring; + /* The length of the type. */ + unsigned int len; +}; + +/* This structure is used to hold information while demangling a + string. */ + +struct stab_demangle_info +{ + /* The debugging information handle. */ + PTR dhandle; + /* The stab information handle. */ + struct stab_handle *info; + /* The array of arguments we are building. */ + debug_type *args; + /* Whether the method takes a variable number of arguments. */ + bfd_boolean varargs; + /* The array of types we have remembered. */ + struct stab_demangle_typestring *typestrings; + /* The number of typestrings. */ + unsigned int typestring_count; + /* The number of typestring slots we have allocated. */ + unsigned int typestring_alloc; +}; + +static void stab_bad_demangle + PARAMS ((const char *)); +static unsigned int stab_demangle_count + PARAMS ((const char **)); +static bfd_boolean stab_demangle_get_count + PARAMS ((const char **, unsigned int *)); +static bfd_boolean stab_demangle_prefix + PARAMS ((struct stab_demangle_info *, const char **, unsigned int)); +static bfd_boolean stab_demangle_function_name + PARAMS ((struct stab_demangle_info *, const char **, const char *)); +static bfd_boolean stab_demangle_signature + PARAMS ((struct stab_demangle_info *, const char **)); +static bfd_boolean stab_demangle_qualified + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static bfd_boolean stab_demangle_template + PARAMS ((struct stab_demangle_info *, const char **, char **)); +static bfd_boolean stab_demangle_class + PARAMS ((struct stab_demangle_info *, const char **, const char **)); +static bfd_boolean stab_demangle_args + PARAMS ((struct stab_demangle_info *, const char **, debug_type **, + bfd_boolean *)); +static bfd_boolean stab_demangle_arg + PARAMS ((struct stab_demangle_info *, const char **, debug_type **, + unsigned int *, unsigned int *)); +static bfd_boolean stab_demangle_type + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static bfd_boolean stab_demangle_fund_type + PARAMS ((struct stab_demangle_info *, const char **, debug_type *)); +static bfd_boolean stab_demangle_remember_type + PARAMS ((struct stab_demangle_info *, const char *, int)); + +/* Warn about a bad demangling. */ + +static void +stab_bad_demangle (s) + const char *s; +{ + fprintf (stderr, _("bad mangled name `%s'\n"), s); +} + +/* Get a count from a stab string. */ + +static unsigned int +stab_demangle_count (pp) + const char **pp; +{ + unsigned int count; + + count = 0; + while (ISDIGIT (**pp)) + { + count *= 10; + count += **pp - '0'; + ++*pp; + } + return count; +} + +/* Require a count in a string. The count may be multiple digits, in + which case it must end in an underscore. */ + +static bfd_boolean +stab_demangle_get_count (pp, pi) + const char **pp; + unsigned int *pi; +{ + if (! ISDIGIT (**pp)) + return FALSE; + + *pi = **pp - '0'; + ++*pp; + if (ISDIGIT (**pp)) + { + unsigned int count; + const char *p; + + count = *pi; + p = *pp; + do + { + count *= 10; + count += *p - '0'; + ++p; + } + while (ISDIGIT (*p)); + if (*p == '_') + { + *pp = p + 1; + *pi = count; + } + } + + return TRUE; +} + +/* This function demangles a physical name, returning a NULL + terminated array of argument types. */ + +static debug_type * +stab_demangle_argtypes (dhandle, info, physname, pvarargs, physname_len) + PTR dhandle; + struct stab_handle *info; + const char *physname; + bfd_boolean *pvarargs; + unsigned int physname_len; +{ + struct stab_demangle_info minfo; + + minfo.dhandle = dhandle; + minfo.info = info; + minfo.args = NULL; + minfo.varargs = FALSE; + minfo.typestring_alloc = 10; + minfo.typestrings = ((struct stab_demangle_typestring *) + xmalloc (minfo.typestring_alloc + * sizeof *minfo.typestrings)); + minfo.typestring_count = 0; + + /* cplus_demangle checks for special GNU mangled forms, but we can't + see any of them in mangled method argument types. */ + + if (! stab_demangle_prefix (&minfo, &physname, physname_len)) + goto error_return; + + if (*physname != '\0') + { + if (! stab_demangle_signature (&minfo, &physname)) + goto error_return; + } + + free (minfo.typestrings); + minfo.typestrings = NULL; + + if (minfo.args == NULL) + fprintf (stderr, _("no argument types in mangled string\n")); + + *pvarargs = minfo.varargs; + return minfo.args; + + error_return: + if (minfo.typestrings != NULL) + free (minfo.typestrings); + return NULL; +} + +/* Demangle the prefix of the mangled name. */ + +static bfd_boolean +stab_demangle_prefix (minfo, pp, physname_len) + struct stab_demangle_info *minfo; + const char **pp; + unsigned int physname_len; +{ + const char *scan; + unsigned int i; + + /* cplus_demangle checks for global constructors and destructors, + but we can't see them in mangled argument types. */ + + if (physname_len) + scan = *pp + physname_len; + else + { + /* Look for `__'. */ + scan = *pp; + do + scan = strchr (scan, '_'); + while (scan != NULL && *++scan != '_'); + + if (scan == NULL) + { + stab_bad_demangle (*pp); + return FALSE; + } + + --scan; + + /* We found `__'; move ahead to the last contiguous `__' pair. */ + i = strspn (scan, "_"); + if (i > 2) + scan += i - 2; + } + + if (scan == *pp + && (ISDIGIT (scan[2]) + || scan[2] == 'Q' + || scan[2] == 't')) + { + /* This is a GNU style constructor name. */ + *pp = scan + 2; + return TRUE; + } + else if (scan == *pp + && ! ISDIGIT (scan[2]) + && scan[2] != 't') + { + /* Look for the `__' that separates the prefix from the + signature. */ + while (*scan == '_') + ++scan; + scan = strstr (scan, "__"); + if (scan == NULL || scan[2] == '\0') + { + stab_bad_demangle (*pp); + return FALSE; + } + + return stab_demangle_function_name (minfo, pp, scan); + } + else if (scan[2] != '\0') + { + /* The name doesn't start with `__', but it does contain `__'. */ + return stab_demangle_function_name (minfo, pp, scan); + } + else + { + stab_bad_demangle (*pp); + return FALSE; + } + /*NOTREACHED*/ +} + +/* Demangle a function name prefix. The scan argument points to the + double underscore which separates the function name from the + signature. */ + +static bfd_boolean +stab_demangle_function_name (minfo, pp, scan) + struct stab_demangle_info *minfo; + const char **pp; + const char *scan; +{ + const char *name; + + /* The string from *pp to scan is the name of the function. We + don't care about the name, since we just looking for argument + types. However, for conversion operators, the name may include a + type which we must remember in order to handle backreferences. */ + + name = *pp; + *pp = scan + 2; + + if (*pp - name >= 5 + && strncmp (name, "type", 4) == 0 + && (name[4] == '$' || name[4] == '.')) + { + const char *tem; + + /* This is a type conversion operator. */ + tem = name + 5; + if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL)) + return FALSE; + } + else if (name[0] == '_' + && name[1] == '_' + && name[2] == 'o' + && name[3] == 'p') + { + const char *tem; + + /* This is a type conversion operator. */ + tem = name + 4; + if (! stab_demangle_type (minfo, &tem, (debug_type *) NULL)) + return FALSE; + } + + return TRUE; +} + +/* Demangle the signature. This is where the argument types are + found. */ + +static bfd_boolean +stab_demangle_signature (minfo, pp) + struct stab_demangle_info *minfo; + const char **pp; +{ + const char *orig; + bfd_boolean expect_func, func_done; + const char *hold; + + orig = *pp; + + expect_func = FALSE; + func_done = FALSE; + hold = NULL; + + while (**pp != '\0') + { + switch (**pp) + { + case 'Q': + hold = *pp; + if (! stab_demangle_qualified (minfo, pp, (debug_type *) NULL) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return FALSE; + expect_func = TRUE; + hold = NULL; + break; + + case 'S': + /* Static member function. FIXME: Can this happen? */ + if (hold == NULL) + hold = *pp; + ++*pp; + break; + + case 'C': + /* Const member function. */ + if (hold == NULL) + hold = *pp; + ++*pp; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (hold == NULL) + hold = *pp; + if (! stab_demangle_class (minfo, pp, (const char **) NULL) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return FALSE; + expect_func = TRUE; + hold = NULL; + break; + + case 'F': + /* Function. I don't know if this actually happens with g++ + output. */ + hold = NULL; + func_done = TRUE; + ++*pp; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return FALSE; + break; + + case 't': + /* Template. */ + if (hold == NULL) + hold = *pp; + if (! stab_demangle_template (minfo, pp, (char **) NULL) + || ! stab_demangle_remember_type (minfo, hold, *pp - hold)) + return FALSE; + hold = NULL; + expect_func = TRUE; + break; + + case '_': + /* At the outermost level, we cannot have a return type + specified, so if we run into another '_' at this point we + are dealing with a mangled name that is either bogus, or + has been mangled by some algorithm we don't know how to + deal with. So just reject the entire demangling. */ + stab_bad_demangle (orig); + return FALSE; + + default: + /* Assume we have stumbled onto the first outermost function + argument token, and start processing args. */ + func_done = TRUE; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return FALSE; + break; + } + + if (expect_func) + { + func_done = TRUE; + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return FALSE; + } + } + + if (! func_done) + { + /* With GNU style demangling, bar__3foo is 'foo::bar(void)', and + bar__3fooi is 'foo::bar(int)'. We get here when we find the + first case, and need to ensure that the '(void)' gets added + to the current declp. */ + if (! stab_demangle_args (minfo, pp, &minfo->args, &minfo->varargs)) + return FALSE; + } + + return TRUE; +} + +/* Demangle a qualified name, such as "Q25Outer5Inner" which is the + mangled form of "Outer::Inner". */ + +static bfd_boolean +stab_demangle_qualified (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + const char *p; + unsigned int qualifiers; + debug_type context; + + orig = *pp; + + switch ((*pp)[1]) + { + case '_': + /* GNU mangled name with more than 9 classes. The count is + preceded by an underscore (to distinguish it from the <= 9 + case) and followed by an underscore. */ + p = *pp + 2; + if (! ISDIGIT (*p) || *p == '0') + { + stab_bad_demangle (orig); + return FALSE; + } + qualifiers = atoi (p); + while (ISDIGIT (*p)) + ++p; + if (*p != '_') + { + stab_bad_demangle (orig); + return FALSE; + } + *pp = p + 1; + break; + + case '1': case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + qualifiers = (*pp)[1] - '0'; + /* Skip an optional underscore after the count. */ + if ((*pp)[2] == '_') + ++*pp; + *pp += 2; + break; + + case '0': + default: + stab_bad_demangle (orig); + return FALSE; + } + + context = DEBUG_TYPE_NULL; + + /* Pick off the names. */ + while (qualifiers-- > 0) + { + if (**pp == '_') + ++*pp; + if (**pp == 't') + { + char *name; + + if (! stab_demangle_template (minfo, pp, + ptype != NULL ? &name : NULL)) + return FALSE; + + if (ptype != NULL) + { + context = stab_find_tagged_type (minfo->dhandle, minfo->info, + name, strlen (name), + DEBUG_KIND_CLASS); + free (name); + if (context == DEBUG_TYPE_NULL) + return FALSE; + } + } + else + { + unsigned int len; + + len = stab_demangle_count (pp); + if (strlen (*pp) < len) + { + stab_bad_demangle (orig); + return FALSE; + } + + if (ptype != NULL) + { + const debug_field *fields; + + fields = NULL; + if (context != DEBUG_TYPE_NULL) + fields = debug_get_fields (minfo->dhandle, context); + + context = DEBUG_TYPE_NULL; + + if (fields != NULL) + { + char *name; + + /* Try to find the type by looking through the + fields of context until we find a field with the + same type. This ought to work for a class + defined within a class, but it won't work for, + e.g., an enum defined within a class. stabs does + not give us enough information to figure out the + latter case. */ + + name = savestring (*pp, len); + + for (; *fields != DEBUG_FIELD_NULL; fields++) + { + debug_type ft; + const char *dn; + + ft = debug_get_field_type (minfo->dhandle, *fields); + if (ft == NULL) + return FALSE; + dn = debug_get_type_name (minfo->dhandle, ft); + if (dn != NULL && strcmp (dn, name) == 0) + { + context = ft; + break; + } + } + + free (name); + } + + if (context == DEBUG_TYPE_NULL) + { + /* We have to fall back on finding the type by name. + If there are more types to come, then this must + be a class. Otherwise, it could be anything. */ + + if (qualifiers == 0) + { + char *name; + + name = savestring (*pp, len); + context = debug_find_named_type (minfo->dhandle, + name); + free (name); + } + + if (context == DEBUG_TYPE_NULL) + { + context = stab_find_tagged_type (minfo->dhandle, + minfo->info, + *pp, len, + (qualifiers == 0 + ? DEBUG_KIND_ILLEGAL + : DEBUG_KIND_CLASS)); + if (context == DEBUG_TYPE_NULL) + return FALSE; + } + } + } + + *pp += len; + } + } + + if (ptype != NULL) + *ptype = context; + + return TRUE; +} + +/* Demangle a template. If PNAME is not NULL, this sets *PNAME to a + string representation of the template. */ + +static bfd_boolean +stab_demangle_template (minfo, pp, pname) + struct stab_demangle_info *minfo; + const char **pp; + char **pname; +{ + const char *orig; + unsigned int r, i; + + orig = *pp; + + ++*pp; + + /* Skip the template name. */ + r = stab_demangle_count (pp); + if (r == 0 || strlen (*pp) < r) + { + stab_bad_demangle (orig); + return FALSE; + } + *pp += r; + + /* Get the size of the parameter list. */ + if (stab_demangle_get_count (pp, &r) == 0) + { + stab_bad_demangle (orig); + return FALSE; + } + + for (i = 0; i < r; i++) + { + if (**pp == 'Z') + { + /* This is a type parameter. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, (debug_type *) NULL)) + return FALSE; + } + else + { + const char *old_p; + bfd_boolean pointerp, realp, integralp, charp, boolp; + bfd_boolean done; + + old_p = *pp; + pointerp = FALSE; + realp = FALSE; + integralp = FALSE; + charp = FALSE; + boolp = FALSE; + done = FALSE; + + /* This is a value parameter. */ + + if (! stab_demangle_type (minfo, pp, (debug_type *) NULL)) + return FALSE; + + while (*old_p != '\0' && ! done) + { + switch (*old_p) + { + case 'P': + case 'p': + case 'R': + pointerp = TRUE; + done = TRUE; + break; + case 'C': /* Const. */ + case 'S': /* Signed. */ + case 'U': /* Unsigned. */ + case 'V': /* Volatile. */ + case 'F': /* Function. */ + case 'M': /* Member function. */ + case 'O': /* ??? */ + ++old_p; + break; + case 'Q': /* Qualified name. */ + integralp = TRUE; + done = TRUE; + break; + case 'T': /* Remembered type. */ + abort (); + case 'v': /* Void. */ + abort (); + case 'x': /* Long long. */ + case 'l': /* Long. */ + case 'i': /* Int. */ + case 's': /* Short. */ + case 'w': /* Wchar_t. */ + integralp = TRUE; + done = TRUE; + break; + case 'b': /* Bool. */ + boolp = TRUE; + done = TRUE; + break; + case 'c': /* Char. */ + charp = TRUE; + done = TRUE; + break; + case 'r': /* Long double. */ + case 'd': /* Double. */ + case 'f': /* Float. */ + realp = TRUE; + done = TRUE; + break; + default: + /* Assume it's a user defined integral type. */ + integralp = TRUE; + done = TRUE; + break; + } + } + + if (integralp) + { + if (**pp == 'm') + ++*pp; + while (ISDIGIT (**pp)) + ++*pp; + } + else if (charp) + { + unsigned int val; + + if (**pp == 'm') + ++*pp; + val = stab_demangle_count (pp); + if (val == 0) + { + stab_bad_demangle (orig); + return FALSE; + } + } + else if (boolp) + { + unsigned int val; + + val = stab_demangle_count (pp); + if (val != 0 && val != 1) + { + stab_bad_demangle (orig); + return FALSE; + } + } + else if (realp) + { + if (**pp == 'm') + ++*pp; + while (ISDIGIT (**pp)) + ++*pp; + if (**pp == '.') + { + ++*pp; + while (ISDIGIT (**pp)) + ++*pp; + } + if (**pp == 'e') + { + ++*pp; + while (ISDIGIT (**pp)) + ++*pp; + } + } + else if (pointerp) + { + unsigned int len; + + if (! stab_demangle_get_count (pp, &len)) + { + stab_bad_demangle (orig); + return FALSE; + } + *pp += len; + } + } + } + + /* We can translate this to a string fairly easily by invoking the + regular demangling routine. */ + if (pname != NULL) + { + char *s1, *s2, *s3, *s4 = NULL; + char *from, *to; + + s1 = savestring (orig, *pp - orig); + + s2 = concat ("NoSuchStrinG__", s1, (const char *) NULL); + + free (s1); + + s3 = cplus_demangle (s2, DMGL_ANSI); + + free (s2); + + if (s3 != NULL) + s4 = strstr (s3, "::NoSuchStrinG"); + if (s3 == NULL || s4 == NULL) + { + stab_bad_demangle (orig); + if (s3 != NULL) + free (s3); + return FALSE; + } + + /* Eliminating all spaces, except those between > characters, + makes it more likely that the demangled name will match the + name which g++ used as the structure name. */ + for (from = to = s3; from != s4; ++from) + if (*from != ' ' + || (from[1] == '>' && from > s3 && from[-1] == '>')) + *to++ = *from; + + *pname = savestring (s3, to - s3); + + free (s3); + } + + return TRUE; +} + +/* Demangle a class name. */ + +static bfd_boolean +stab_demangle_class (minfo, pp, pstart) + struct stab_demangle_info *minfo ATTRIBUTE_UNUSED; + const char **pp; + const char **pstart; +{ + const char *orig; + unsigned int n; + + orig = *pp; + + n = stab_demangle_count (pp); + if (strlen (*pp) < n) + { + stab_bad_demangle (orig); + return FALSE; + } + + if (pstart != NULL) + *pstart = *pp; + + *pp += n; + + return TRUE; +} + +/* Demangle function arguments. If the pargs argument is not NULL, it + is set to a NULL terminated array holding the arguments. */ + +static bfd_boolean +stab_demangle_args (minfo, pp, pargs, pvarargs) + struct stab_demangle_info *minfo; + const char **pp; + debug_type **pargs; + bfd_boolean *pvarargs; +{ + const char *orig; + unsigned int alloc, count; + + orig = *pp; + + alloc = 10; + if (pargs != NULL) + { + *pargs = (debug_type *) xmalloc (alloc * sizeof **pargs); + *pvarargs = FALSE; + } + count = 0; + + while (**pp != '_' && **pp != '\0' && **pp != 'e') + { + if (**pp == 'N' || **pp == 'T') + { + char temptype; + unsigned int r, t; + + temptype = **pp; + ++*pp; + + if (temptype == 'T') + r = 1; + else + { + if (! stab_demangle_get_count (pp, &r)) + { + stab_bad_demangle (orig); + return FALSE; + } + } + + if (! stab_demangle_get_count (pp, &t)) + { + stab_bad_demangle (orig); + return FALSE; + } + + if (t >= minfo->typestring_count) + { + stab_bad_demangle (orig); + return FALSE; + } + while (r-- > 0) + { + const char *tem; + + tem = minfo->typestrings[t].typestring; + if (! stab_demangle_arg (minfo, &tem, pargs, &count, &alloc)) + return FALSE; + } + } + else + { + if (! stab_demangle_arg (minfo, pp, pargs, &count, &alloc)) + return FALSE; + } + } + + if (pargs != NULL) + (*pargs)[count] = DEBUG_TYPE_NULL; + + if (**pp == 'e') + { + if (pargs != NULL) + *pvarargs = TRUE; + ++*pp; + } + + return TRUE; +} + +/* Demangle a single argument. */ + +static bfd_boolean +stab_demangle_arg (minfo, pp, pargs, pcount, palloc) + struct stab_demangle_info *minfo; + const char **pp; + debug_type **pargs; + unsigned int *pcount; + unsigned int *palloc; +{ + const char *start; + debug_type type; + + start = *pp; + if (! stab_demangle_type (minfo, pp, + pargs == NULL ? (debug_type *) NULL : &type) + || ! stab_demangle_remember_type (minfo, start, *pp - start)) + return FALSE; + + if (pargs != NULL) + { + if (type == DEBUG_TYPE_NULL) + return FALSE; + + if (*pcount + 1 >= *palloc) + { + *palloc += 10; + *pargs = ((debug_type *) + xrealloc (*pargs, *palloc * sizeof **pargs)); + } + (*pargs)[*pcount] = type; + ++*pcount; + } + + return TRUE; +} + +/* Demangle a type. If the ptype argument is not NULL, *ptype is set + to the newly allocated type. */ + +static bfd_boolean +stab_demangle_type (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + + orig = *pp; + + switch (**pp) + { + case 'P': + case 'p': + /* A pointer type. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return FALSE; + if (ptype != NULL) + *ptype = debug_make_pointer_type (minfo->dhandle, *ptype); + break; + + case 'R': + /* A reference type. */ + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return FALSE; + if (ptype != NULL) + *ptype = debug_make_reference_type (minfo->dhandle, *ptype); + break; + + case 'A': + /* An array. */ + { + unsigned long high; + + ++*pp; + high = 0; + while (**pp != '\0' && **pp != '_') + { + if (! ISDIGIT (**pp)) + { + stab_bad_demangle (orig); + return FALSE; + } + high *= 10; + high += **pp - '0'; + ++*pp; + } + if (**pp != '_') + { + stab_bad_demangle (orig); + return FALSE; + } + ++*pp; + + if (! stab_demangle_type (minfo, pp, ptype)) + return FALSE; + if (ptype != NULL) + { + debug_type int_type; + + int_type = debug_find_named_type (minfo->dhandle, "int"); + if (int_type == NULL) + int_type = debug_make_int_type (minfo->dhandle, 4, FALSE); + *ptype = debug_make_array_type (minfo->dhandle, *ptype, int_type, + 0, high, FALSE); + } + } + break; + + case 'T': + /* A back reference to a remembered type. */ + { + unsigned int i; + const char *p; + + ++*pp; + if (! stab_demangle_get_count (pp, &i)) + { + stab_bad_demangle (orig); + return FALSE; + } + if (i >= minfo->typestring_count) + { + stab_bad_demangle (orig); + return FALSE; + } + p = minfo->typestrings[i].typestring; + if (! stab_demangle_type (minfo, &p, ptype)) + return FALSE; + } + break; + + case 'F': + /* A function. */ + { + debug_type *args; + bfd_boolean varargs; + + ++*pp; + if (! stab_demangle_args (minfo, pp, + (ptype == NULL + ? (debug_type **) NULL + : &args), + (ptype == NULL + ? (bfd_boolean *) NULL + : &varargs))) + return FALSE; + if (**pp != '_') + { + /* cplus_demangle will accept a function without a return + type, but I don't know when that will happen, or what + to do if it does. */ + stab_bad_demangle (orig); + return FALSE; + } + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return FALSE; + if (ptype != NULL) + *ptype = debug_make_function_type (minfo->dhandle, *ptype, args, + varargs); + + } + break; + + case 'M': + case 'O': + { + bfd_boolean memberp, constp, volatilep; + debug_type class_type = DEBUG_TYPE_NULL; + debug_type *args; + bfd_boolean varargs; + unsigned int n; + const char *name; + + memberp = **pp == 'M'; + constp = FALSE; + volatilep = FALSE; + args = NULL; + varargs = FALSE; + + ++*pp; + if (ISDIGIT (**pp)) + { + n = stab_demangle_count (pp); + if (strlen (*pp) < n) + { + stab_bad_demangle (orig); + return FALSE; + } + name = *pp; + *pp += n; + + if (ptype != NULL) + { + class_type = stab_find_tagged_type (minfo->dhandle, + minfo->info, + name, (int) n, + DEBUG_KIND_CLASS); + if (class_type == DEBUG_TYPE_NULL) + return FALSE; + } + } + else if (**pp == 'Q') + { + if (! stab_demangle_qualified (minfo, pp, + (ptype == NULL + ? (debug_type *) NULL + : &class_type))) + return FALSE; + } + else + { + stab_bad_demangle (orig); + return FALSE; + } + + if (memberp) + { + if (**pp == 'C') + { + constp = TRUE; + ++*pp; + } + else if (**pp == 'V') + { + volatilep = TRUE; + ++*pp; + } + if (**pp != 'F') + { + stab_bad_demangle (orig); + return FALSE; + } + ++*pp; + if (! stab_demangle_args (minfo, pp, + (ptype == NULL + ? (debug_type **) NULL + : &args), + (ptype == NULL + ? (bfd_boolean *) NULL + : &varargs))) + return FALSE; + } + + if (**pp != '_') + { + stab_bad_demangle (orig); + return FALSE; + } + ++*pp; + + if (! stab_demangle_type (minfo, pp, ptype)) + return FALSE; + + if (ptype != NULL) + { + if (! memberp) + *ptype = debug_make_offset_type (minfo->dhandle, class_type, + *ptype); + else + { + /* FIXME: We have no way to record constp or + volatilep. */ + *ptype = debug_make_method_type (minfo->dhandle, *ptype, + class_type, args, varargs); + } + } + } + break; + + case 'G': + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return FALSE; + break; + + case 'C': + ++*pp; + if (! stab_demangle_type (minfo, pp, ptype)) + return FALSE; + if (ptype != NULL) + *ptype = debug_make_const_type (minfo->dhandle, *ptype); + break; + + case 'Q': + { + const char *hold; + + hold = *pp; + if (! stab_demangle_qualified (minfo, pp, ptype)) + return FALSE; + } + break; + + default: + if (! stab_demangle_fund_type (minfo, pp, ptype)) + return FALSE; + break; + } + + return TRUE; +} + +/* Demangle a fundamental type. If the ptype argument is not NULL, + *ptype is set to the newly allocated type. */ + +static bfd_boolean +stab_demangle_fund_type (minfo, pp, ptype) + struct stab_demangle_info *minfo; + const char **pp; + debug_type *ptype; +{ + const char *orig; + bfd_boolean constp, volatilep, unsignedp, signedp; + bfd_boolean done; + + orig = *pp; + + constp = FALSE; + volatilep = FALSE; + unsignedp = FALSE; + signedp = FALSE; + + done = FALSE; + while (! done) + { + switch (**pp) + { + case 'C': + constp = TRUE; + ++*pp; + break; + + case 'U': + unsignedp = TRUE; + ++*pp; + break; + + case 'S': + signedp = TRUE; + ++*pp; + break; + + case 'V': + volatilep = TRUE; + ++*pp; + break; + + default: + done = TRUE; + break; + } + } + + switch (**pp) + { + case '\0': + case '_': + /* cplus_demangle permits this, but I don't know what it means. */ + stab_bad_demangle (orig); + break; + + case 'v': /* void */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "void"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_void_type (minfo->dhandle); + } + ++*pp; + break; + + case 'x': /* long long */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "long long unsigned int" + : "long long int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 8, unsignedp); + } + ++*pp; + break; + + case 'l': /* long */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "long unsigned int" + : "long int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp); + } + ++*pp; + break; + + case 'i': /* int */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "unsigned int" + : "int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 4, unsignedp); + } + ++*pp; + break; + + case 's': /* short */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "short unsigned int" + : "short int")); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 2, unsignedp); + } + ++*pp; + break; + + case 'b': /* bool */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "bool"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_bool_type (minfo->dhandle, 4); + } + ++*pp; + break; + + case 'c': /* char */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, + (unsignedp + ? "unsigned char" + : (signedp + ? "signed char" + : "char"))); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 1, unsignedp); + } + ++*pp; + break; + + case 'w': /* wchar_t */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "__wchar_t"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_int_type (minfo->dhandle, 2, TRUE); + } + ++*pp; + break; + + case 'r': /* long double */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "long double"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 8); + } + ++*pp; + break; + + case 'd': /* double */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "double"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 8); + } + ++*pp; + break; + + case 'f': /* float */ + if (ptype != NULL) + { + *ptype = debug_find_named_type (minfo->dhandle, "float"); + if (*ptype == DEBUG_TYPE_NULL) + *ptype = debug_make_float_type (minfo->dhandle, 4); + } + ++*pp; + break; + + case 'G': + ++*pp; + if (! ISDIGIT (**pp)) + { + stab_bad_demangle (orig); + return FALSE; + } + /* Fall through. */ + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + const char *hold; + + if (! stab_demangle_class (minfo, pp, &hold)) + return FALSE; + if (ptype != NULL) + { + char *name; + + name = savestring (hold, *pp - hold); + *ptype = debug_find_named_type (minfo->dhandle, name); + free (name); + if (*ptype == DEBUG_TYPE_NULL) + { + /* FIXME: It is probably incorrect to assume that + undefined types are tagged types. */ + *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info, + hold, *pp - hold, + DEBUG_KIND_ILLEGAL); + if (*ptype == DEBUG_TYPE_NULL) + return FALSE; + } + } + } + break; + + case 't': + { + char *name; + + if (! stab_demangle_template (minfo, pp, + ptype != NULL ? &name : NULL)) + return FALSE; + if (ptype != NULL) + { + *ptype = stab_find_tagged_type (minfo->dhandle, minfo->info, + name, strlen (name), + DEBUG_KIND_CLASS); + free (name); + if (*ptype == DEBUG_TYPE_NULL) + return FALSE; + } + } + break; + + default: + stab_bad_demangle (orig); + return FALSE; + } + + if (ptype != NULL) + { + if (constp) + *ptype = debug_make_const_type (minfo->dhandle, *ptype); + if (volatilep) + *ptype = debug_make_volatile_type (minfo->dhandle, *ptype); + } + + return TRUE; +} + +/* Remember a type string in a demangled string. */ + +static bfd_boolean +stab_demangle_remember_type (minfo, p, len) + struct stab_demangle_info *minfo; + const char *p; + int len; +{ + if (minfo->typestring_count >= minfo->typestring_alloc) + { + minfo->typestring_alloc += 10; + minfo->typestrings = ((struct stab_demangle_typestring *) + xrealloc (minfo->typestrings, + (minfo->typestring_alloc + * sizeof *minfo->typestrings))); + } + + minfo->typestrings[minfo->typestring_count].typestring = p; + minfo->typestrings[minfo->typestring_count].len = (unsigned int) len; + ++minfo->typestring_count; + + return TRUE; +} diff --git a/contrib/binutils-2.14/binutils/strings.c b/contrib/binutils-2.14/binutils/strings.c new file mode 100644 index 0000000000..b5e88d0586 --- /dev/null +++ b/contrib/binutils-2.14/binutils/strings.c @@ -0,0 +1,675 @@ +/* strings -- print the strings of printable characters in files + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Usage: strings [options] file... + + Options: + --all + -a + - Do not scan only the initialized data section of object files. + + --print-file-name + -f Print the name of the file before each string. + + --bytes=min-len + -n min-len + -min-len Print graphic char sequences, MIN-LEN or more bytes long, + that are followed by a NUL or a newline. Default is 4. + + --radix={o,x,d} + -t {o,x,d} Print the offset within the file before each string, + in octal/hex/decimal. + + -o Like -to. (Some other implementations have -o like -to, + others like -td. We chose one arbitrarily.) + + --encoding={s,S,b,l,B,L} + -e {s,S,b,l,B,L} + Select character encoding: 7-bit-character, 8-bit-character, + bigendian 16-bit, littleendian 16-bit, bigendian 32-bit, + littleendian 32-bit. + + --target=BFDNAME + Specify a non-default object file format. + + --help + -h Print the usage message on the standard output. + + --version + -v Print the program version number. + + Written by Richard Stallman + and David MacKenzie . */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "bfd.h" +#include +#include "getopt.h" +#include +#include "bucomm.h" +#include "libiberty.h" +#include "safe-ctype.h" + +/* Some platforms need to put stdin into binary mode, to read + binary files. */ +#ifdef HAVE_SETMODE +#ifndef O_BINARY +#ifdef _O_BINARY +#define O_BINARY _O_BINARY +#define setmode _setmode +#else +#define O_BINARY 0 +#endif +#endif +#if O_BINARY +#include +#define SET_BINARY(f) do { if (!isatty (f)) setmode (f,O_BINARY); } while (0) +#endif +#endif + +#define STRING_ISGRAPHIC(c) \ + ( (c) >= 0 \ + && (c) <= 255 \ + && ((c) == '\t' || ISPRINT (c) || (encoding == 'S' && (c) > 127))) + +#ifndef errno +extern int errno; +#endif + +/* The BFD section flags that identify an initialized data section. */ +#define DATA_FLAGS (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS) + +#ifdef HAVE_FOPEN64 +typedef off64_t file_off; +#define file_open(s,m) fopen64(s, m) +#else +typedef off_t file_off; +#define file_open(s,m) fopen(s, m) +#endif + +/* Radix for printing addresses (must be 8, 10 or 16). */ +static int address_radix; + +/* Minimum length of sequence of graphic chars to trigger output. */ +static int string_min; + +/* TRUE means print address within file for each string. */ +static bfd_boolean print_addresses; + +/* TRUE means print filename for each string. */ +static bfd_boolean print_filenames; + +/* TRUE means for object files scan only the data section. */ +static bfd_boolean datasection_only; + +/* TRUE if we found an initialized data section in the current file. */ +static bfd_boolean got_a_section; + +/* The BFD object file format. */ +static char *target; + +/* The character encoding format. */ +static char encoding; +static int encoding_bytes; + +static struct option long_options[] = +{ + {"all", no_argument, NULL, 'a'}, + {"print-file-name", no_argument, NULL, 'f'}, + {"bytes", required_argument, NULL, 'n'}, + {"radix", required_argument, NULL, 't'}, + {"encoding", required_argument, NULL, 'e'}, + {"target", required_argument, NULL, 'T'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'v'}, + {NULL, 0, NULL, 0} +}; + +static void strings_a_section + PARAMS ((bfd *, asection *, PTR)); +static bfd_boolean strings_object_file + PARAMS ((const char *)); +static bfd_boolean strings_file + PARAMS ((char *file)); +static int integer_arg + PARAMS ((char *s)); +static void print_strings + PARAMS ((const char *, FILE *, file_off, int, int, char *)); +static void usage + PARAMS ((FILE *, int)); +static long get_char + PARAMS ((FILE *, file_off *, int *, char **)); + +int main + PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char **argv; +{ + int optc; + int exit_status = 0; + bfd_boolean files_given = FALSE; + +#if defined (HAVE_SETLOCALE) + setlocale (LC_ALL, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + program_name = argv[0]; + xmalloc_set_program_name (program_name); + string_min = -1; + print_addresses = FALSE; + print_filenames = FALSE; + datasection_only = TRUE; + target = NULL; + encoding = 's'; + + while ((optc = getopt_long (argc, argv, "afhHn:ot:e:Vv0123456789", + long_options, (int *) 0)) != EOF) + { + switch (optc) + { + case 'a': + datasection_only = FALSE; + break; + + case 'f': + print_filenames = TRUE; + break; + + case 'H': + case 'h': + usage (stdout, 0); + + case 'n': + string_min = integer_arg (optarg); + if (string_min < 1) + fatal (_("invalid number %s"), optarg); + break; + + case 'o': + print_addresses = TRUE; + address_radix = 8; + break; + + case 't': + print_addresses = TRUE; + if (optarg[1] != '\0') + usage (stderr, 1); + switch (optarg[0]) + { + case 'o': + address_radix = 8; + break; + + case 'd': + address_radix = 10; + break; + + case 'x': + address_radix = 16; + break; + + default: + usage (stderr, 1); + } + break; + + case 'T': + target = optarg; + break; + + case 'e': + if (optarg[1] != '\0') + usage (stderr, 1); + encoding = optarg[0]; + break; + + case 'V': + case 'v': + print_version ("strings"); + break; + + case '?': + usage (stderr, 1); + + default: + if (string_min < 0) + string_min = optc - '0'; + else + string_min = string_min * 10 + optc - '0'; + break; + } + } + + if (string_min < 0) + string_min = 4; + + switch (encoding) + { + case 'S': + case 's': + encoding_bytes = 1; + break; + case 'b': + case 'l': + encoding_bytes = 2; + break; + case 'B': + case 'L': + encoding_bytes = 4; + break; + default: + usage (stderr, 1); + } + + bfd_init (); + set_default_bfd_target (); + + if (optind >= argc) + { + datasection_only = FALSE; +#ifdef SET_BINARY + SET_BINARY (fileno (stdin)); +#endif + print_strings ("{standard input}", stdin, 0, 0, 0, (char *) NULL); + files_given = TRUE; + } + else + { + for (; optind < argc; ++optind) + { + if (strcmp (argv[optind], "-") == 0) + datasection_only = FALSE; + else + { + files_given = TRUE; + exit_status |= strings_file (argv[optind]) == FALSE; + } + } + } + + if (!files_given) + usage (stderr, 1); + + return (exit_status); +} + +/* Scan section SECT of the file ABFD, whose printable name is FILE. + If it contains initialized data, + set `got_a_section' and print the strings in it. */ + +static void +strings_a_section (abfd, sect, filearg) + bfd *abfd; + asection *sect; + PTR filearg; +{ + const char *file = (const char *) filearg; + + if ((sect->flags & DATA_FLAGS) == DATA_FLAGS) + { + bfd_size_type sz = bfd_get_section_size_before_reloc (sect); + PTR mem = xmalloc (sz); + + if (bfd_get_section_contents (abfd, sect, mem, (file_ptr) 0, sz)) + { + got_a_section = TRUE; + print_strings (file, (FILE *) NULL, sect->filepos, 0, sz, mem); + } + free (mem); + } +} + +/* Scan all of the sections in FILE, and print the strings + in the initialized data section(s). + + Return TRUE if successful, + FALSE if not (such as if FILE is not an object file). */ + +static bfd_boolean +strings_object_file (file) + const char *file; +{ + bfd *abfd = bfd_openr (file, target); + + if (abfd == NULL) + /* Treat the file as a non-object file. */ + return FALSE; + + /* This call is mainly for its side effect of reading in the sections. + We follow the traditional behavior of `strings' in that we don't + complain if we don't recognize a file to be an object file. */ + if (!bfd_check_format (abfd, bfd_object)) + { + bfd_close (abfd); + return FALSE; + } + + got_a_section = FALSE; + bfd_map_over_sections (abfd, strings_a_section, (PTR) file); + + if (!bfd_close (abfd)) + { + bfd_nonfatal (file); + return FALSE; + } + + return got_a_section; +} + +/* Print the strings in FILE. Return TRUE if ok, FALSE if an error occurs. */ + +static bfd_boolean +strings_file (file) + char *file; +{ + /* If we weren't told to scan the whole file, + try to open it as an object file and only look at + initialized data sections. If that fails, fall back to the + whole file. */ + if (!datasection_only || !strings_object_file (file)) + { + FILE *stream; + + stream = file_open (file, FOPEN_RB); + if (stream == NULL) + { + fprintf (stderr, "%s: ", program_name); + perror (file); + return FALSE; + } + + print_strings (file, stream, (file_off) 0, 0, 0, (char *) 0); + + if (fclose (stream) == EOF) + { + fprintf (stderr, "%s: ", program_name); + perror (file); + return FALSE; + } + } + + return TRUE; +} + +/* Read the next character, return EOF if none available. + Assume that STREAM is positioned so that the next byte read + is at address ADDRESS in the file. + + If STREAM is NULL, do not read from it. + The caller can supply a buffer of characters + to be processed before the data in STREAM. + MAGIC is the address of the buffer and + MAGICCOUNT is how many characters are in it. */ + +static long +get_char (stream, address, magiccount, magic) + FILE *stream; + file_off *address; + int *magiccount; + char **magic; +{ + int c, i; + long r = EOF; + unsigned char buf[4]; + + for (i = 0; i < encoding_bytes; i++) + { + if (*magiccount) + { + (*magiccount)--; + c = *(*magic)++; + } + else + { + if (stream == NULL) + return EOF; +#ifdef HAVE_GETC_UNLOCKED + c = getc_unlocked (stream); +#else + c = getc (stream); +#endif + if (c == EOF) + return EOF; + } + + (*address)++; + buf[i] = c; + } + + switch (encoding) + { + case 'S': + case 's': + r = buf[0]; + break; + case 'b': + r = (buf[0] << 8) | buf[1]; + break; + case 'l': + r = buf[0] | (buf[1] << 8); + break; + case 'B': + r = ((long) buf[0] << 24) | ((long) buf[1] << 16) | + ((long) buf[2] << 8) | buf[3]; + break; + case 'L': + r = buf[0] | ((long) buf[1] << 8) | ((long) buf[2] << 16) | + ((long) buf[3] << 24); + break; + } + + if (r == EOF) + return 0; + + return r; +} + +/* Find the strings in file FILENAME, read from STREAM. + Assume that STREAM is positioned so that the next byte read + is at address ADDRESS in the file. + Stop reading at address STOP_POINT in the file, if nonzero. + + If STREAM is NULL, do not read from it. + The caller can supply a buffer of characters + to be processed before the data in STREAM. + MAGIC is the address of the buffer and + MAGICCOUNT is how many characters are in it. + Those characters come at address ADDRESS and the data in STREAM follow. */ + +static void +print_strings (filename, stream, address, stop_point, magiccount, magic) + const char *filename; + FILE *stream; + file_off address; + int stop_point; + int magiccount; + char *magic; +{ + char *buf = (char *) xmalloc (sizeof (char) * (string_min + 1)); + + while (1) + { + file_off start; + int i; + long c; + + /* See if the next `string_min' chars are all graphic chars. */ + tryline: + if (stop_point && address >= stop_point) + break; + start = address; + for (i = 0; i < string_min; i++) + { + c = get_char (stream, &address, &magiccount, &magic); + if (c == EOF) + return; + if (! STRING_ISGRAPHIC (c)) + /* Found a non-graphic. Try again starting with next char. */ + goto tryline; + buf[i] = c; + } + + /* We found a run of `string_min' graphic characters. Print up + to the next non-graphic character. */ + + if (print_filenames) + printf ("%s: ", filename); + if (print_addresses) + switch (address_radix) + { + case 8: +#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) + if (sizeof (start) > sizeof (long)) + printf ("%7Lo ", (unsigned long long) start); + else +#else +# if !BFD_HOST_64BIT_LONG + if (start != (unsigned long) start) + printf ("++%7lo ", (unsigned long) start); + else +# endif +#endif + printf ("%7lo ", (unsigned long) start); + break; + + case 10: +#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) + if (sizeof (start) > sizeof (long)) + printf ("%7Ld ", (unsigned long long) start); + else +#else +# if !BFD_HOST_64BIT_LONG + if (start != (unsigned long) start) + printf ("++%7ld ", (unsigned long) start); + else +# endif +#endif + printf ("%7ld ", (long) start); + break; + + case 16: +#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2) + if (sizeof (start) > sizeof (long)) + printf ("%7Lx ", (unsigned long long) start); + else +#else +# if !BFD_HOST_64BIT_LONG + if (start != (unsigned long) start) + printf ("%lx%8.8lx ", start >> 32, start & 0xffffffff); + else +# endif +#endif + printf ("%7lx ", (unsigned long) start); + break; + } + + buf[i] = '\0'; + fputs (buf, stdout); + + while (1) + { + c = get_char (stream, &address, &magiccount, &magic); + if (c == EOF) + break; + if (! STRING_ISGRAPHIC (c)) + break; + putchar (c); + } + + putchar ('\n'); + } +} + +/* Parse string S as an integer, using decimal radix by default, + but allowing octal and hex numbers as in C. */ + +static int +integer_arg (s) + char *s; +{ + int value; + int radix = 10; + char *p = s; + int c; + + if (*p != '0') + radix = 10; + else if (*++p == 'x') + { + radix = 16; + p++; + } + else + radix = 8; + + value = 0; + while (((c = *p++) >= '0' && c <= '9') + || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z')) + { + value *= radix; + if (c >= '0' && c <= '9') + value += c - '0'; + else + value += (c & ~40) - 'A'; + } + + if (c == 'b') + value *= 512; + else if (c == 'B') + value *= 1024; + else + p--; + + if (*p) + fatal (_("invalid integer argument %s"), s); + + return value; +} + +static void +usage (stream, status) + FILE *stream; + int status; +{ + fprintf (stream, _("Usage: %s [option(s)] [file(s)]\n"), program_name); + fprintf (stream, _(" Display printable strings in [file(s)] (stdin by default)\n")); + fprintf (stream, _(" The options are:\n\ + -a - --all Scan the entire file, not just the data section\n\ + -f --print-file-name Print the name of the file before each string\n\ + -n --bytes=[number] Locate & print any NUL-terminated sequence of at\n\ + - least [number] characters (default 4).\n\ + -t --radix={o,x,d} Print the location of the string in base 8, 10 or 16\n\ + -o An alias for --radix=o\n\ + -T --target= Specify the binary file format\n\ + -e --encoding={s,S,b,l,B,L} Select character size and endianness:\n\ + s = 7-bit, S = 8-bit, {b,l} = 16-bit, {B,L} = 32-bit\n\ + -h --help Display this information\n\ + -v --version Print the program's version number\n")); + list_supported_targets (program_name, stream); + if (status == 0) + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); + exit (status); +} diff --git a/contrib/binutils-2.14/binutils/unwind-ia64.c b/contrib/binutils-2.14/binutils/unwind-ia64.c new file mode 100644 index 0000000000..803a5fa541 --- /dev/null +++ b/contrib/binutils-2.14/binutils/unwind-ia64.c @@ -0,0 +1,1129 @@ +/* unwind-ia64.c -- utility routines to dump IA-64 unwind info for readelf. + Copyright 2000, 2001 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang + +This file is part of GNU Binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "unwind-ia64.h" +#include +#include + +#if __GNUC__ >= 2 +/* Define BFD64 here, even if our default architecture is 32 bit ELF + as this will allow us to read in and parse 64bit and 32bit ELF files. + Only do this if we belive that the compiler can support a 64 bit + data type. For now we only rely on GCC being able to do this. */ +#define BFD64 +#endif +#include "bfd.h" + +static bfd_vma unw_rlen = 0; + +static void unw_print_brmask PARAMS ((char *, unsigned int)); +static void unw_print_grmask PARAMS ((char *, unsigned int)); +static void unw_print_frmask PARAMS ((char *, unsigned int)); +static void unw_print_abreg PARAMS ((char *, unsigned int)); +static void unw_print_xyreg PARAMS ((char *, unsigned int, unsigned int)); + +static void +unw_print_brmask (cp, mask) + char * cp; + unsigned int mask; +{ + int sep = 0; + int i; + + for (i = 0; mask && (i < 5); ++i) + { + if (mask & 1) + { + if (sep) + *cp++ = ','; + *cp++ = 'b'; + *cp++ = i + 1 + '0'; + sep = 1; + } + mask >>= 1; + } + *cp = '\0'; +} + +static void +unw_print_grmask (cp, mask) + char * cp; + unsigned int mask; +{ + int sep = 0; + int i; + + for (i = 0; i < 4; ++i) + { + if (mask & 1) + { + if (sep) + *cp++ = ','; + *cp++ = 'r'; + *cp++ = i + 4 + '0'; + sep = 1; + } + mask >>= 1; + } + *cp = '\0'; +} + +static void +unw_print_frmask (cp, mask) + char * cp; + unsigned int mask; +{ + int sep = 0; + int i; + + for (i = 0; i < 20; ++i) + { + if (mask & 1) + { + if (sep) + *cp++ = ','; + *cp++ = 'f'; + if (i < 4) + *cp++ = i + 2 + '0'; + else + { + *cp++ = (i + 2) / 10 + 1 + '0'; + *cp++ = (i + 2) % 10 + '0'; + } + sep = 1; + } + mask >>= 1; + } + *cp = '\0'; +} + +static void +unw_print_abreg (cp, abreg) + char * cp; + unsigned int abreg; +{ + static const char *special_reg[16] = + { + "pr", "psp", "@priunat", "rp", "ar.bsp", "ar.bspstore", "ar.rnat", + "ar.unat", "ar.fpsr", "ar.pfs", "ar.lc", + "Unknown11", "Unknown12", "Unknown13", "Unknown14", "Unknown15" + }; + + switch ((abreg >> 5) & 0x3) + { + case 0: /* gr */ + sprintf (cp, "r%u", (abreg & 0x1f)); + break; + + case 1: /* fr */ + sprintf (cp, "f%u", (abreg & 0x1f)); + break; + + case 2: /* br */ + sprintf (cp, "b%u", (abreg & 0x1f)); + break; + + case 3: /* special */ + strcpy (cp, special_reg[abreg & 0xf]); + break; + } +} + +static void +unw_print_xyreg (cp, x, ytreg) + char * cp; + unsigned int x; + unsigned int ytreg; +{ + switch ((x << 1) | ((ytreg >> 7) & 1)) + { + case 0: /* gr */ + sprintf (cp, "r%u", (ytreg & 0x1f)); + break; + + case 1: /* fr */ + sprintf (cp, "f%u", (ytreg & 0x1f)); + break; + + case 2: /* br */ + sprintf (cp, "b%u", (ytreg & 0x1f)); + break; + } +} + +#define UNW_REG_BSP "bsp" +#define UNW_REG_BSPSTORE "bspstore" +#define UNW_REG_FPSR "fpsr" +#define UNW_REG_LC "lc" +#define UNW_REG_PFS "pfs" +#define UNW_REG_PR "pr" +#define UNW_REG_PSP "psp" +#define UNW_REG_RNAT "rnat" +#define UNW_REG_RP "rp" +#define UNW_REG_UNAT "unat" + +typedef bfd_vma unw_word; + +#define UNW_DEC_BAD_CODE(code) \ + printf ("Unknown code 0x%02x\n", code) + +#define UNW_DEC_PROLOGUE(fmt, body, rlen, arg) \ + do \ + { \ + unw_rlen = rlen; \ + *(int *)arg = body; \ + printf (" %s:%s(rlen=%lu)\n", \ + fmt, body ? "body" : "prologue", (unsigned long) rlen); \ + } \ + while (0) + +#define UNW_DEC_PROLOGUE_GR(fmt, rlen, mask, grsave, arg) \ + do \ + { \ + char regname[16], maskstr[64], *sep; \ + \ + unw_rlen = rlen; \ + *(int *)arg = 0; \ + \ + maskstr[0] = '\0'; \ + sep = ""; \ + if (mask & 0x8) \ + { \ + strcat (maskstr, "rp"); \ + sep = ","; \ + } \ + if (mask & 0x4) \ + { \ + strcat (maskstr, sep); \ + strcat (maskstr, "ar.pfs"); \ + sep = ","; \ + } \ + if (mask & 0x2) \ + { \ + strcat (maskstr, sep); \ + strcat (maskstr, "psp"); \ + sep = ","; \ + } \ + if (mask & 0x1) \ + { \ + strcat (maskstr, sep); \ + strcat (maskstr, "pr"); \ + } \ + sprintf (regname, "r%u", grsave); \ + printf (" %s:prologue_gr(mask=[%s],grsave=%s,rlen=%lu)\n", \ + fmt, maskstr, regname, (unsigned long) rlen); \ + } \ + while (0) + +#define UNW_DEC_FR_MEM(fmt, frmask, arg) \ + do \ + { \ + char frstr[200]; \ + \ + unw_print_frmask (frstr, frmask); \ + printf ("\t%s:fr_mem(frmask=[%s])\n", fmt, frstr); \ + } \ + while (0) + +#define UNW_DEC_GR_MEM(fmt, grmask, arg) \ + do \ + { \ + char grstr[200]; \ + \ + unw_print_grmask (grstr, grmask); \ + printf ("\t%s:gr_mem(grmask=[%s])\n", fmt, grstr); \ + } \ + while (0) + +#define UNW_DEC_FRGR_MEM(fmt, grmask, frmask, arg) \ + do \ + { \ + char frstr[200], grstr[20]; \ + \ + unw_print_grmask (grstr, grmask); \ + unw_print_frmask (frstr, frmask); \ + printf ("\t%s:frgr_mem(grmask=[%s],frmask=[%s])\n", fmt, grstr, frstr); \ + } \ + while (0) + +#define UNW_DEC_BR_MEM(fmt, brmask, arg) \ + do \ + { \ + char brstr[20]; \ + \ + unw_print_brmask (brstr, brmask); \ + printf ("\t%s:br_mem(brmask=[%s])\n", fmt, brstr); \ + } \ + while (0) + +#define UNW_DEC_BR_GR(fmt, brmask, gr, arg) \ + do \ + { \ + char brstr[20]; \ + \ + unw_print_brmask (brstr, brmask); \ + printf ("\t%s:br_gr(brmask=[%s],gr=r%u)\n", fmt, brstr, gr); \ + } \ + while (0) + +#define UNW_DEC_REG_GR(fmt, src, dst, arg) \ + printf ("\t%s:%s_gr(reg=r%u)\n", fmt, src, dst) + +#define UNW_DEC_RP_BR(fmt, dst, arg) \ + printf ("\t%s:rp_br(reg=b%u)\n", fmt, dst) + +#define UNW_DEC_REG_WHEN(fmt, reg, t, arg) \ + printf ("\t%s:%s_when(t=%lu)\n", fmt, reg, (unsigned long) t) + +#define UNW_DEC_REG_SPREL(fmt, reg, spoff, arg) \ + printf ("\t%s:%s_sprel(spoff=0x%lx)\n", \ + fmt, reg, 4*(unsigned long)spoff) + +#define UNW_DEC_REG_PSPREL(fmt, reg, pspoff, arg) \ + printf ("\t%s:%s_psprel(pspoff=0x10-0x%lx)\n", \ + fmt, reg, 4*(unsigned long)pspoff) + +#define UNW_DEC_GR_GR(fmt, grmask, gr, arg) \ + do \ + { \ + char grstr[20]; \ + \ + unw_print_grmask (grstr, grmask); \ + printf ("\t%s:gr_gr(grmask=[%s],r%u)\n", fmt, grstr, gr); \ + } \ + while (0) + +#define UNW_DEC_ABI(fmt, abi, context, arg) \ + do \ + { \ + static const char *abiname[] = \ + { \ + "@svr4", "@hpux", "@nt" \ + }; \ + char buf[20]; \ + const char *abistr = buf; \ + \ + if (abi < 3) \ + abistr = abiname[abi]; \ + else \ + sprintf (buf, "0x%x", abi); \ + printf ("\t%s:unwabi(abi=%s,context=0x%02x)\n", \ + fmt, abistr, context); \ + } \ + while (0) + +#define UNW_DEC_PRIUNAT_GR(fmt, r, arg) \ + printf ("\t%s:priunat_gr(reg=r%u)\n", fmt, r) + +#define UNW_DEC_PRIUNAT_WHEN_GR(fmt, t, arg) \ + printf ("\t%s:priunat_when_gr(t=%lu)\n", fmt, (unsigned long) t) + +#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt, t, arg) \ + printf ("\t%s:priunat_when_mem(t=%lu)\n", fmt, (unsigned long) t) + +#define UNW_DEC_PRIUNAT_PSPREL(fmt, pspoff, arg) \ + printf ("\t%s:priunat_psprel(pspoff=0x10-0x%lx)\n", \ + fmt, 4*(unsigned long)pspoff) + +#define UNW_DEC_PRIUNAT_SPREL(fmt, spoff, arg) \ + printf ("\t%s:priunat_sprel(spoff=0x%lx)\n", \ + fmt, 4*(unsigned long)spoff) + +#define UNW_DEC_MEM_STACK_F(fmt, t, size, arg) \ + printf ("\t%s:mem_stack_f(t=%lu,size=%lu)\n", \ + fmt, (unsigned long) t, 16*(unsigned long)size) + +#define UNW_DEC_MEM_STACK_V(fmt, t, arg) \ + printf ("\t%s:mem_stack_v(t=%lu)\n", fmt, (unsigned long) t) + +#define UNW_DEC_SPILL_BASE(fmt, pspoff, arg) \ + printf ("\t%s:spill_base(pspoff=0x10-0x%lx)\n", \ + fmt, 4*(unsigned long)pspoff) + +#define UNW_DEC_SPILL_MASK(fmt, dp, arg) \ + do \ + { \ + static const char * spill_type = "-frb"; \ + unsigned const char * imaskp = dp; \ + unsigned char mask = 0; \ + bfd_vma insn = 0; \ + \ + printf ("\t%s:spill_mask(imask=[", fmt); \ + for (insn = 0; insn < unw_rlen; ++insn) \ + { \ + if ((insn % 4) == 0) \ + mask = *imaskp++; \ + if (insn > 0 && (insn % 3) == 0) \ + putchar (','); \ + putchar (spill_type[(mask >> (2 * (3 - (insn & 0x3)))) & 0x3]); \ + } \ + printf ("])\n"); \ + dp = imaskp; \ + } \ + while (0) + +#define UNW_DEC_SPILL_SPREL(fmt, t, abreg, spoff, arg) \ + do \ + { \ + char regname[10]; \ + \ + unw_print_abreg (regname, abreg); \ + printf ("\t%s:spill_sprel(reg=%s,t=%lu,spoff=0x%lx)\n", \ + fmt, regname, (unsigned long) t, 4*(unsigned long)off); \ + } \ + while (0) + +#define UNW_DEC_SPILL_PSPREL(fmt, t, abreg, pspoff, arg) \ + do \ + { \ + char regname[10]; \ + \ + unw_print_abreg (regname, abreg); \ + printf ("\t%s:spill_psprel(reg=%s,t=%lu,pspoff=0x10-0x%lx)\n", \ + fmt, regname, (unsigned long) t, 4*(unsigned long)pspoff); \ + } \ + while (0) + +#define UNW_DEC_RESTORE(fmt, t, abreg, arg) \ + do \ + { \ + char regname[10]; \ + \ + unw_print_abreg (regname, abreg); \ + printf ("\t%s:restore(t=%lu,reg=%s)\n", \ + fmt, (unsigned long) t, regname); \ + } \ + while (0) + +#define UNW_DEC_SPILL_REG(fmt, t, abreg, x, ytreg, arg) \ + do \ + { \ + char abregname[10], tregname[10]; \ + \ + unw_print_abreg (abregname, abreg); \ + unw_print_xyreg (tregname, x, ytreg); \ + printf ("\t%s:spill_reg(t=%lu,reg=%s,treg=%s)\n", \ + fmt, (unsigned long) t, abregname, tregname); \ + } \ + while (0) + +#define UNW_DEC_SPILL_SPREL_P(fmt, qp, t, abreg, spoff, arg) \ + do \ + { \ + char regname[20]; \ + \ + unw_print_abreg (regname, abreg); \ + printf ("\t%s:spill_sprel_p(qp=p%u,t=%lu,reg=%s,spoff=0x%lx)\n", \ + fmt, qp, (unsigned long) t, regname, 4 * (unsigned long)spoff); \ + } \ + while (0) + +#define UNW_DEC_SPILL_PSPREL_P(fmt, qp, t, abreg, pspoff, arg) \ + do \ + { \ + char regname[20]; \ + \ + unw_print_abreg (regname, abreg); \ + printf ("\t%s:spill_psprel_p(qp=p%u,t=%lu,reg=%s,pspoff=0x10-0x%lx)\n",\ + fmt, qp, (unsigned long) t, regname, 4*(unsigned long)pspoff);\ + } \ + while (0) + +#define UNW_DEC_RESTORE_P(fmt, qp, t, abreg, arg) \ + do \ + { \ + char regname[20]; \ + \ + unw_print_abreg (regname, abreg); \ + printf ("\t%s:restore_p(qp=p%u,t=%lu,reg=%s)\n", \ + fmt, qp, (unsigned long) t, regname); \ + } \ + while (0) + +#define UNW_DEC_SPILL_REG_P(fmt, qp, t, abreg, x, ytreg, arg) \ + do \ + { \ + char regname[20], tregname[20]; \ + \ + unw_print_abreg (regname, abreg); \ + unw_print_xyreg (tregname, x, ytreg); \ + printf ("\t%s:spill_reg_p(qp=p%u,t=%lu,reg=%s,treg=%s)\n", \ + fmt, qp, (unsigned long) t, regname, tregname); \ + } \ + while (0) + +#define UNW_DEC_LABEL_STATE(fmt, label, arg) \ + printf ("\t%s:label_state(label=%lu)\n", fmt, (unsigned long) label) + +#define UNW_DEC_COPY_STATE(fmt, label, arg) \ + printf ("\t%s:copy_state(label=%lu)\n", fmt, (unsigned long) label) + +#define UNW_DEC_EPILOGUE(fmt, t, ecount, arg) \ + printf ("\t%s:epilogue(t=%lu,ecount=%lu)\n", \ + fmt, (unsigned long) t, (unsigned long) ecount) + +/* + * Generic IA-64 unwind info decoder. + * + * This file is used both by the Linux kernel and objdump. Please + * keep the two copies of this file in sync (modulo differences in the + * prototypes...). + * + * You need to customize the decoder by defining the following + * macros/constants before including this file: + * + * Types: + * unw_word Unsigned integer type with at least 64 bits + * + * Register names: + * UNW_REG_BSP + * UNW_REG_BSPSTORE + * UNW_REG_FPSR + * UNW_REG_LC + * UNW_REG_PFS + * UNW_REG_PR + * UNW_REG_RNAT + * UNW_REG_PSP + * UNW_REG_RP + * UNW_REG_UNAT + * + * Decoder action macros: + * UNW_DEC_BAD_CODE(code) + * UNW_DEC_ABI(fmt,abi,context,arg) + * UNW_DEC_BR_GR(fmt,brmask,gr,arg) + * UNW_DEC_BR_MEM(fmt,brmask,arg) + * UNW_DEC_COPY_STATE(fmt,label,arg) + * UNW_DEC_EPILOGUE(fmt,t,ecount,arg) + * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg) + * UNW_DEC_FR_MEM(fmt,frmask,arg) + * UNW_DEC_GR_GR(fmt,grmask,gr,arg) + * UNW_DEC_GR_MEM(fmt,grmask,arg) + * UNW_DEC_LABEL_STATE(fmt,label,arg) + * UNW_DEC_MEM_STACK_F(fmt,t,size,arg) + * UNW_DEC_MEM_STACK_V(fmt,t,arg) + * UNW_DEC_PRIUNAT_GR(fmt,r,arg) + * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg) + * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg) + * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg) + * UNW_DEC_PROLOGUE(fmt,body,rlen,arg) + * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg) + * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg) + * UNW_DEC_REG_REG(fmt,src,dst,arg) + * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg) + * UNW_DEC_REG_WHEN(fmt,reg,t,arg) + * UNW_DEC_RESTORE(fmt,t,abreg,arg) + * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg) + * UNW_DEC_SPILL_BASE(fmt,pspoff,arg) + * UNW_DEC_SPILL_MASK(fmt,imaskp,arg) + * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg) + * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg) + * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg) + * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg) + */ + +static unw_word unw_decode_uleb128 PARAMS ((const unsigned char **)); +static const unsigned char *unw_decode_x1 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_x2 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_x3 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_x4 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_r1 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_r2 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_r3 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_p1 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_p2_p5 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_p6 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_p7_p10 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_b1 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_b2 PARAMS ((const unsigned char *, + unsigned int, void *)); +static const unsigned char *unw_decode_b3_x4 PARAMS ((const unsigned char *, + unsigned int, void *)); + +static unw_word +unw_decode_uleb128 (dpp) + const unsigned char **dpp; +{ + unsigned shift = 0; + unw_word byte, result = 0; + const unsigned char *bp = *dpp; + + while (1) + { + byte = *bp++; + result |= (byte & 0x7f) << shift; + + if ((byte & 0x80) == 0) + break; + + shift += 7; + } + + *dpp = bp; + + return result; +} + +static const unsigned char * +unw_decode_x1 (dp, code, arg) + const unsigned char * dp; + unsigned int code ATTRIBUTE_UNUSED; + void * arg ATTRIBUTE_UNUSED; +{ + unsigned char byte1, abreg; + unw_word t, off; + + byte1 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL ("X1", t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL ("X1", t, abreg, off, arg); + return dp; +} + +static const unsigned char * +unw_decode_x2 (dp, code, arg) + const unsigned char * dp; + unsigned int code ATTRIBUTE_UNUSED; + void * arg ATTRIBUTE_UNUSED; +{ + unsigned char byte1, byte2, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; + byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + abreg = (byte1 & 0x7f); + ytreg = byte2; + x = (byte1 >> 7) & 1; + if ((byte1 & 0x80) == 0 && ytreg == 0) + UNW_DEC_RESTORE ("X2", t, abreg, arg); + else + UNW_DEC_SPILL_REG ("X2", t, abreg, x, ytreg, arg); + return dp; +} + +static const unsigned char * +unw_decode_x3 (dp, code, arg) + const unsigned char * dp; + unsigned int code ATTRIBUTE_UNUSED; + void * arg ATTRIBUTE_UNUSED; +{ + unsigned char byte1, byte2, abreg, qp; + unw_word t, off; + + byte1 = *dp++; + byte2 = *dp++; + t = unw_decode_uleb128 (&dp); + off = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + + if (byte1 & 0x80) + UNW_DEC_SPILL_SPREL_P ("X3", qp, t, abreg, off, arg); + else + UNW_DEC_SPILL_PSPREL_P ("X3", qp, t, abreg, off, arg); + return dp; +} + +static const unsigned char * +unw_decode_x4 (dp, code, arg) + const unsigned char * dp; + unsigned int code ATTRIBUTE_UNUSED; + void * arg ATTRIBUTE_UNUSED; +{ + unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg; + unw_word t; + + byte1 = *dp++; + byte2 = *dp++; + byte3 = *dp++; + t = unw_decode_uleb128 (&dp); + + qp = (byte1 & 0x3f); + abreg = (byte2 & 0x7f); + x = (byte2 >> 7) & 1; + ytreg = byte3; + + if ((byte2 & 0x80) == 0 && byte3 == 0) + UNW_DEC_RESTORE_P ("X4", qp, t, abreg, arg); + else + UNW_DEC_SPILL_REG_P ("X4", qp, t, abreg, x, ytreg, arg); + return dp; +} + +static const unsigned char * +unw_decode_r1 (dp, code, arg) + const unsigned char *dp; + unsigned int code; + void *arg; +{ + int body = (code & 0x20) != 0; + unw_word rlen; + + rlen = (code & 0x1f); + UNW_DEC_PROLOGUE ("R1", body, rlen, arg); + return dp; +} + +static const unsigned char * +unw_decode_r2 (dp, code, arg) + const unsigned char *dp; + unsigned int code; + void *arg; +{ + unsigned char byte1, mask, grsave; + unw_word rlen; + + byte1 = *dp++; + + mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + grsave = (byte1 & 0x7f); + rlen = unw_decode_uleb128 (& dp); + UNW_DEC_PROLOGUE_GR ("R2", rlen, mask, grsave, arg); + return dp; +} + +static const unsigned char * +unw_decode_r3 (dp, code, arg) + const unsigned char *dp; + unsigned int code; + void *arg; +{ + unw_word rlen; + + rlen = unw_decode_uleb128 (& dp); + UNW_DEC_PROLOGUE ("R3", ((code & 0x3) == 1), rlen, arg); + return dp; +} + +static const unsigned char * +unw_decode_p1 (dp, code, arg) + const unsigned char * dp; + unsigned int code; + void * arg ATTRIBUTE_UNUSED; +{ + unsigned char brmask = (code & 0x1f); + + UNW_DEC_BR_MEM ("P1", brmask, arg); + return dp; +} + +static const unsigned char * +unw_decode_p2_p5 (dp, code, arg) + const unsigned char * dp; + unsigned int code; + void * arg ATTRIBUTE_UNUSED; +{ + if ((code & 0x10) == 0) + { + unsigned char byte1 = *dp++; + + UNW_DEC_BR_GR ("P2", ((code & 0xf) << 1) | ((byte1 >> 7) & 1), + (byte1 & 0x7f), arg); + } + else if ((code & 0x08) == 0) + { + unsigned char byte1 = *dp++, r, dst; + + r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1); + dst = (byte1 & 0x7f); + switch (r) + { + case 0: + UNW_DEC_REG_GR ("P3", UNW_REG_PSP, dst, arg); + break; + case 1: + UNW_DEC_REG_GR ("P3", UNW_REG_RP, dst, arg); + break; + case 2: + UNW_DEC_REG_GR ("P3", UNW_REG_PFS, dst, arg); + break; + case 3: + UNW_DEC_REG_GR ("P3", UNW_REG_PR, dst, arg); + break; + case 4: + UNW_DEC_REG_GR ("P3", UNW_REG_UNAT, dst, arg); + break; + case 5: + UNW_DEC_REG_GR ("P3", UNW_REG_LC, dst, arg); + break; + case 6: + UNW_DEC_RP_BR ("P3", dst, arg); + break; + case 7: + UNW_DEC_REG_GR ("P3", UNW_REG_RNAT, dst, arg); + break; + case 8: + UNW_DEC_REG_GR ("P3", UNW_REG_BSP, dst, arg); + break; + case 9: + UNW_DEC_REG_GR ("P3", UNW_REG_BSPSTORE, dst, arg); + break; + case 10: + UNW_DEC_REG_GR ("P3", UNW_REG_FPSR, dst, arg); + break; + case 11: + UNW_DEC_PRIUNAT_GR ("P3", dst, arg); + break; + default: + UNW_DEC_BAD_CODE (r); + break; + } + } + else if ((code & 0x7) == 0) + UNW_DEC_SPILL_MASK ("P4", dp, arg); + else if ((code & 0x7) == 1) + { + unw_word grmask, frmask, byte1, byte2, byte3; + + byte1 = *dp++; + byte2 = *dp++; + byte3 = *dp++; + grmask = ((byte1 >> 4) & 0xf); + frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3; + UNW_DEC_FRGR_MEM ("P5", grmask, frmask, arg); + } + else + UNW_DEC_BAD_CODE (code); + + return dp; +} + +static const unsigned char * +unw_decode_p6 (dp, code, arg) + const unsigned char * dp; + unsigned int code; + void * arg ATTRIBUTE_UNUSED; +{ + int gregs = (code & 0x10) != 0; + unsigned char mask = (code & 0x0f); + + if (gregs) + UNW_DEC_GR_MEM ("P6", mask, arg); + else + UNW_DEC_FR_MEM ("P6", mask, arg); + return dp; +} + +static const unsigned char * +unw_decode_p7_p10 (dp, code, arg) + const unsigned char *dp; + unsigned int code; + void *arg; +{ + unsigned char r, byte1, byte2; + unw_word t, size; + + if ((code & 0x10) == 0) + { + r = (code & 0xf); + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 0: + size = unw_decode_uleb128 (&dp); + UNW_DEC_MEM_STACK_F ("P7", t, size, arg); + break; + + case 1: + UNW_DEC_MEM_STACK_V ("P7", t, arg); + break; + case 2: + UNW_DEC_SPILL_BASE ("P7", t, arg); + break; + case 3: + UNW_DEC_REG_SPREL ("P7", UNW_REG_PSP, t, arg); + break; + case 4: + UNW_DEC_REG_WHEN ("P7", UNW_REG_RP, t, arg); + break; + case 5: + UNW_DEC_REG_PSPREL ("P7", UNW_REG_RP, t, arg); + break; + case 6: + UNW_DEC_REG_WHEN ("P7", UNW_REG_PFS, t, arg); + break; + case 7: + UNW_DEC_REG_PSPREL ("P7", UNW_REG_PFS, t, arg); + break; + case 8: + UNW_DEC_REG_WHEN ("P7", UNW_REG_PR, t, arg); + break; + case 9: + UNW_DEC_REG_PSPREL ("P7", UNW_REG_PR, t, arg); + break; + case 10: + UNW_DEC_REG_WHEN ("P7", UNW_REG_LC, t, arg); + break; + case 11: + UNW_DEC_REG_PSPREL ("P7", UNW_REG_LC, t, arg); + break; + case 12: + UNW_DEC_REG_WHEN ("P7", UNW_REG_UNAT, t, arg); + break; + case 13: + UNW_DEC_REG_PSPREL ("P7", UNW_REG_UNAT, t, arg); + break; + case 14: + UNW_DEC_REG_WHEN ("P7", UNW_REG_FPSR, t, arg); + break; + case 15: + UNW_DEC_REG_PSPREL ("P7", UNW_REG_FPSR, t, arg); + break; + default: + UNW_DEC_BAD_CODE (r); + break; + } + } + else + { + switch (code & 0xf) + { + case 0x0: /* p8 */ + { + r = *dp++; + t = unw_decode_uleb128 (&dp); + switch (r) + { + case 1: + UNW_DEC_REG_SPREL ("P8", UNW_REG_RP, t, arg); + break; + case 2: + UNW_DEC_REG_SPREL ("P8", UNW_REG_PFS, t, arg); + break; + case 3: + UNW_DEC_REG_SPREL ("P8", UNW_REG_PR, t, arg); + break; + case 4: + UNW_DEC_REG_SPREL ("P8", UNW_REG_LC, t, arg); + break; + case 5: + UNW_DEC_REG_SPREL ("P8", UNW_REG_UNAT, t, arg); + break; + case 6: + UNW_DEC_REG_SPREL ("P8", UNW_REG_FPSR, t, arg); + break; + case 7: + UNW_DEC_REG_WHEN ("P8", UNW_REG_BSP, t, arg); + break; + case 8: + UNW_DEC_REG_PSPREL ("P8", UNW_REG_BSP, t, arg); + break; + case 9: + UNW_DEC_REG_SPREL ("P8", UNW_REG_BSP, t, arg); + break; + case 10: + UNW_DEC_REG_WHEN ("P8", UNW_REG_BSPSTORE, t, arg); + break; + case 11: + UNW_DEC_REG_PSPREL ("P8", UNW_REG_BSPSTORE, t, arg); + break; + case 12: + UNW_DEC_REG_SPREL ("P8", UNW_REG_BSPSTORE, t, arg); + break; + case 13: + UNW_DEC_REG_WHEN ("P8", UNW_REG_RNAT, t, arg); + break; + case 14: + UNW_DEC_REG_PSPREL ("P8", UNW_REG_RNAT, t, arg); + break; + case 15: + UNW_DEC_REG_SPREL ("P8", UNW_REG_RNAT, t, arg); + break; + case 16: + UNW_DEC_PRIUNAT_WHEN_GR ("P8", t, arg); + break; + case 17: + UNW_DEC_PRIUNAT_PSPREL ("P8", t, arg); + break; + case 18: + UNW_DEC_PRIUNAT_SPREL ("P8", t, arg); + break; + case 19: + UNW_DEC_PRIUNAT_WHEN_MEM ("P8", t, arg); + break; + default: + UNW_DEC_BAD_CODE (r); + break; + } + } + break; + + case 0x1: + byte1 = *dp++; + byte2 = *dp++; + UNW_DEC_GR_GR ("P9", (byte1 & 0xf), (byte2 & 0x7f), arg); + break; + + case 0xf: /* p10 */ + byte1 = *dp++; + byte2 = *dp++; + UNW_DEC_ABI ("P10", byte1, byte2, arg); + break; + + case 0x9: + return unw_decode_x1 (dp, code, arg); + + case 0xa: + return unw_decode_x2 (dp, code, arg); + + case 0xb: + return unw_decode_x3 (dp, code, arg); + + case 0xc: + return unw_decode_x4 (dp, code, arg); + + default: + UNW_DEC_BAD_CODE (code); + break; + } + } + return dp; +} + +static const unsigned char * +unw_decode_b1 (dp, code, arg) + const unsigned char * dp; + unsigned int code; + void * arg ATTRIBUTE_UNUSED; +{ + unw_word label = (code & 0x1f); + + if ((code & 0x20) != 0) + UNW_DEC_COPY_STATE ("B1", label, arg); + else + UNW_DEC_LABEL_STATE ("B1", label, arg); + return dp; +} + +static const unsigned char * +unw_decode_b2 (dp, code, arg) + const unsigned char * dp; + unsigned int code; + void * arg ATTRIBUTE_UNUSED; +{ + unw_word t; + + t = unw_decode_uleb128 (& dp); + UNW_DEC_EPILOGUE ("B2", t, (code & 0x1f), arg); + return dp; +} + +static const unsigned char * +unw_decode_b3_x4 (dp, code, arg) + const unsigned char *dp; + unsigned int code; + void *arg; +{ + unw_word t, ecount, label; + + if ((code & 0x10) == 0) + { + t = unw_decode_uleb128 (&dp); + ecount = unw_decode_uleb128 (&dp); + UNW_DEC_EPILOGUE ("B3", t, ecount, arg); + } + else if ((code & 0x07) == 0) + { + label = unw_decode_uleb128 (&dp); + if ((code & 0x08) != 0) + UNW_DEC_COPY_STATE ("B4", label, arg); + else + UNW_DEC_LABEL_STATE ("B4", label, arg); + } + else + switch (code & 0x7) + { + case 1: + return unw_decode_x1 (dp, code, arg); + case 2: + return unw_decode_x2 (dp, code, arg); + case 3: + return unw_decode_x3 (dp, code, arg); + case 4: + return unw_decode_x4 (dp, code, arg); + default: + UNW_DEC_BAD_CODE (code); + break; + } + return dp; +} + +typedef const unsigned char *(*unw_decoder) + PARAMS ((const unsigned char *, unsigned int, void *)); + +static unw_decoder unw_decode_table[2][8] = + { + /* prologue table: */ + { + unw_decode_r1, /* 0 */ + unw_decode_r1, + unw_decode_r2, + unw_decode_r3, + unw_decode_p1, /* 4 */ + unw_decode_p2_p5, + unw_decode_p6, + unw_decode_p7_p10 + }, + { + unw_decode_r1, /* 0 */ + unw_decode_r1, + unw_decode_r2, + unw_decode_r3, + unw_decode_b1, /* 4 */ + unw_decode_b1, + unw_decode_b2, + unw_decode_b3_x4 + } + }; + +/* Decode one descriptor and return address of next descriptor. */ +const unsigned char * +unw_decode (dp, inside_body, ptr_inside_body) + const unsigned char * dp; + int inside_body; + void * ptr_inside_body; +{ + unw_decoder decoder; + unsigned char code; + + code = *dp++; + decoder = unw_decode_table[inside_body][code >> 5]; + return (*decoder) (dp, code, ptr_inside_body); +} diff --git a/contrib/binutils-2.14/binutils/unwind-ia64.h b/contrib/binutils-2.14/binutils/unwind-ia64.h new file mode 100644 index 0000000000..30f15b84a9 --- /dev/null +++ b/contrib/binutils-2.14/binutils/unwind-ia64.h @@ -0,0 +1,31 @@ +/* unwind-ia64.h -- dump IA-64 unwind info. + Copyright 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang + +This file is part of GNU Binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "elf/ia64.h" +#include "ansidecl.h" + +#define UNW_VER(x) ((x) >> 48) +#define UNW_FLAG_MASK 0x0000ffff00000000LL +#define UNW_FLAG_OSMASK 0x0000f00000000000LL +#define UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000LL) +#define UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000LL) +#define UNW_LENGTH(x) ((x) & 0x00000000ffffffffLL) + +extern const unsigned char * unw_decode PARAMS ((const unsigned char *, int, void *)); diff --git a/contrib/binutils-2.14/binutils/version.c b/contrib/binutils-2.14/binutils/version.c new file mode 100644 index 0000000000..0a7baa307d --- /dev/null +++ b/contrib/binutils-2.14/binutils/version.c @@ -0,0 +1,41 @@ +/* version.c -- binutils version information + Copyright 1991, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + +This file is part of GNU Binutils. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include +#include "bfd.h" +#include "bfdver.h" +#include "bucomm.h" + +/* Print the version number and copyright information, and exit. This + implements the --version option for the various programs. */ + +void +print_version (name) + const char *name; +{ + /* This output is intended to follow the GNU standards document. */ + /* xgettext:c-format */ + printf ("GNU %s %s\n", name, BFD_VERSION_STRING); + printf (_("Copyright 2002 Free Software Foundation, Inc.\n")); + printf (_("\ +This program is free software; you may redistribute it under the terms of\n\ +the GNU General Public License. This program has absolutely no warranty.\n")); + exit (0); +} diff --git a/contrib/binutils-2.14/binutils/wrstabs.c b/contrib/binutils-2.14/binutils/wrstabs.c new file mode 100644 index 0000000000..77c7d72a30 --- /dev/null +++ b/contrib/binutils-2.14/binutils/wrstabs.c @@ -0,0 +1,2442 @@ +/* wrstabs.c -- Output stabs debugging information + Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file contains code which writes out stabs debugging + information. */ + +#include +#include + +#include "bfd.h" +#include "bucomm.h" +#include "libiberty.h" +#include "safe-ctype.h" +#include "debug.h" +#include "budbg.h" +#include "aout/aout64.h" +#include "aout/stab_gnu.h" + +/* The size of a stabs symbol. This presumes 32 bit values. */ + +#define STAB_SYMBOL_SIZE (12) + +/* An entry in a string hash table. */ + +struct string_hash_entry +{ + struct bfd_hash_entry root; + /* Next string in this table. */ + struct string_hash_entry *next; + /* Index in string table. */ + long index; + /* Size of type if this is a typedef. */ + unsigned int size; +}; + +/* A string hash table. */ + +struct string_hash_table +{ + struct bfd_hash_table table; +}; + +/* The type stack. Each element on the stack is a string. */ + +struct stab_type_stack +{ + /* The next element on the stack. */ + struct stab_type_stack *next; + /* This element as a string. */ + char *string; + /* The type index of this element. */ + long index; + /* The size of the type. */ + unsigned int size; + /* Whether type string defines a new type. */ + bfd_boolean definition; + /* String defining struct fields. */ + char *fields; + /* NULL terminated array of strings defining base classes for a + class. */ + char **baseclasses; + /* String defining class methods. */ + char *methods; + /* String defining vtable pointer for a class. */ + char *vtable; +}; + +/* This structure is used to keep track of type indices for tagged + types. */ + +struct stab_tag +{ + /* The type index. */ + long index; + /* The tag name. */ + const char *tag; + /* The kind of type. This is set to DEBUG_KIND_ILLEGAL when the + type is defined. */ + enum debug_type_kind kind; + /* The size of the struct. */ + unsigned int size; +}; + +/* We remember various sorts of type indices. They are not related, + but, for convenience, we keep all the information in this + structure. */ + +struct stab_type_cache +{ + /* The void type index. */ + long void_type; + /* Signed integer type indices, indexed by size - 1. */ + long signed_integer_types[8]; + /* Unsigned integer type indices, indexed by size - 1. */ + long unsigned_integer_types[8]; + /* Floating point types, indexed by size - 1. */ + long float_types[16]; + /* Pointers to types, indexed by the type index. */ + long *pointer_types; + size_t pointer_types_alloc; + /* Functions returning types, indexed by the type index. */ + long *function_types; + size_t function_types_alloc; + /* References to types, indexed by the type index. */ + long *reference_types; + size_t reference_types_alloc; + /* Struct/union/class type indices, indexed by the struct id. */ + struct stab_tag *struct_types; + size_t struct_types_alloc; +}; + +/* This is the handle passed through debug_write. */ + +struct stab_write_handle +{ + /* The BFD. */ + bfd *abfd; + /* This buffer holds the symbols. */ + bfd_byte *symbols; + size_t symbols_size; + size_t symbols_alloc; + /* This is a list of hash table entries for the strings. */ + struct string_hash_entry *strings; + /* The last string hash table entry. */ + struct string_hash_entry *last_string; + /* The size of the strings. */ + size_t strings_size; + /* This hash table eliminates duplicate strings. */ + struct string_hash_table strhash; + /* The type stack. */ + struct stab_type_stack *type_stack; + /* The next type index. */ + long type_index; + /* The type cache. */ + struct stab_type_cache type_cache; + /* A mapping from typedef names to type indices. */ + struct string_hash_table typedef_hash; + /* If this is not -1, it is the offset to the most recent N_SO + symbol, and the value of that symbol needs to be set. */ + long so_offset; + /* If this is not -1, it is the offset to the most recent N_FUN + symbol, and the value of that symbol needs to be set. */ + long fun_offset; + /* The last text section address seen. */ + bfd_vma last_text_address; + /* The block nesting depth. */ + unsigned int nesting; + /* The function address. */ + bfd_vma fnaddr; + /* A pending LBRAC symbol. */ + bfd_vma pending_lbrac; + /* The current line number file name. */ + const char *lineno_filename; +}; + +static struct bfd_hash_entry *string_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static bfd_boolean stab_write_symbol + PARAMS ((struct stab_write_handle *, int, int, bfd_vma, const char *)); +static bfd_boolean stab_push_string + PARAMS ((struct stab_write_handle *, const char *, long, bfd_boolean, + unsigned int)); +static bfd_boolean stab_push_defined_type + PARAMS ((struct stab_write_handle *, long, unsigned int)); +static char *stab_pop_type + PARAMS ((struct stab_write_handle *)); +static bfd_boolean stab_modify_type + PARAMS ((struct stab_write_handle *, int, unsigned int, long **, size_t *)); +static long stab_get_struct_index + PARAMS ((struct stab_write_handle *, const char *, unsigned int, + enum debug_type_kind, unsigned int *)); +static bfd_boolean stab_class_method_var + PARAMS ((struct stab_write_handle *, const char *, enum debug_visibility, + bfd_boolean, bfd_boolean, bfd_boolean, bfd_vma, bfd_boolean)); +static bfd_boolean stab_start_compilation_unit + PARAMS ((PTR, const char *)); +static bfd_boolean stab_start_source + PARAMS ((PTR, const char *)); +static bfd_boolean stab_empty_type + PARAMS ((PTR)); +static bfd_boolean stab_void_type + PARAMS ((PTR)); +static bfd_boolean stab_int_type + PARAMS ((PTR, unsigned int, bfd_boolean)); +static bfd_boolean stab_float_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean stab_complex_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean stab_bool_type + PARAMS ((PTR, unsigned int)); +static bfd_boolean stab_enum_type + PARAMS ((PTR, const char *, const char **, bfd_signed_vma *)); +static bfd_boolean stab_pointer_type + PARAMS ((PTR)); +static bfd_boolean stab_function_type + PARAMS ((PTR, int, bfd_boolean)); +static bfd_boolean stab_reference_type + PARAMS ((PTR)); +static bfd_boolean stab_range_type + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma)); +static bfd_boolean stab_array_type + PARAMS ((PTR, bfd_signed_vma, bfd_signed_vma, bfd_boolean)); +static bfd_boolean stab_set_type + PARAMS ((PTR, bfd_boolean)); +static bfd_boolean stab_offset_type + PARAMS ((PTR)); +static bfd_boolean stab_method_type + PARAMS ((PTR, bfd_boolean, int, bfd_boolean)); +static bfd_boolean stab_const_type + PARAMS ((PTR)); +static bfd_boolean stab_volatile_type + PARAMS ((PTR)); +static bfd_boolean stab_start_struct_type + PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int)); +static bfd_boolean stab_struct_field + PARAMS ((PTR, const char *, bfd_vma, bfd_vma, enum debug_visibility)); +static bfd_boolean stab_end_struct_type + PARAMS ((PTR)); +static bfd_boolean stab_start_class_type + PARAMS ((PTR, const char *, unsigned int, bfd_boolean, unsigned int, + bfd_boolean, bfd_boolean)); +static bfd_boolean stab_class_static_member + PARAMS ((PTR, const char *, const char *, enum debug_visibility)); +static bfd_boolean stab_class_baseclass + PARAMS ((PTR, bfd_vma, bfd_boolean, enum debug_visibility)); +static bfd_boolean stab_class_start_method + PARAMS ((PTR, const char *)); +static bfd_boolean stab_class_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, bfd_boolean, + bfd_vma, bfd_boolean)); +static bfd_boolean stab_class_static_method_variant + PARAMS ((PTR, const char *, enum debug_visibility, bfd_boolean, + bfd_boolean)); +static bfd_boolean stab_class_end_method + PARAMS ((PTR)); +static bfd_boolean stab_end_class_type + PARAMS ((PTR)); +static bfd_boolean stab_typedef_type + PARAMS ((PTR, const char *)); +static bfd_boolean stab_tag_type + PARAMS ((PTR, const char *, unsigned int, enum debug_type_kind)); +static bfd_boolean stab_typdef + PARAMS ((PTR, const char *)); +static bfd_boolean stab_tag + PARAMS ((PTR, const char *)); +static bfd_boolean stab_int_constant + PARAMS ((PTR, const char *, bfd_vma)); +static bfd_boolean stab_float_constant + PARAMS ((PTR, const char *, double)); +static bfd_boolean stab_typed_constant + PARAMS ((PTR, const char *, bfd_vma)); +static bfd_boolean stab_variable + PARAMS ((PTR, const char *, enum debug_var_kind, bfd_vma)); +static bfd_boolean stab_start_function + PARAMS ((PTR, const char *, bfd_boolean)); +static bfd_boolean stab_function_parameter + PARAMS ((PTR, const char *, enum debug_parm_kind, bfd_vma)); +static bfd_boolean stab_start_block + PARAMS ((PTR, bfd_vma)); +static bfd_boolean stab_end_block + PARAMS ((PTR, bfd_vma)); +static bfd_boolean stab_end_function + PARAMS ((PTR)); +static bfd_boolean stab_lineno + PARAMS ((PTR, const char *, unsigned long, bfd_vma)); + +static const struct debug_write_fns stab_fns = +{ + stab_start_compilation_unit, + stab_start_source, + stab_empty_type, + stab_void_type, + stab_int_type, + stab_float_type, + stab_complex_type, + stab_bool_type, + stab_enum_type, + stab_pointer_type, + stab_function_type, + stab_reference_type, + stab_range_type, + stab_array_type, + stab_set_type, + stab_offset_type, + stab_method_type, + stab_const_type, + stab_volatile_type, + stab_start_struct_type, + stab_struct_field, + stab_end_struct_type, + stab_start_class_type, + stab_class_static_member, + stab_class_baseclass, + stab_class_start_method, + stab_class_method_variant, + stab_class_static_method_variant, + stab_class_end_method, + stab_end_class_type, + stab_typedef_type, + stab_tag_type, + stab_typdef, + stab_tag, + stab_int_constant, + stab_float_constant, + stab_typed_constant, + stab_variable, + stab_start_function, + stab_function_parameter, + stab_start_block, + stab_end_block, + stab_end_function, + stab_lineno +}; + +/* Routine to create an entry in a string hash table. */ + +static struct bfd_hash_entry * +string_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct string_hash_entry *ret = (struct string_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct string_hash_entry *) NULL) + ret = ((struct string_hash_entry *) + bfd_hash_allocate (table, sizeof (struct string_hash_entry))); + if (ret == (struct string_hash_entry *) NULL) + return NULL; + + /* Call the allocation method of the superclass. */ + ret = ((struct string_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) + { + /* Initialize the local fields. */ + ret->next = NULL; + ret->index = -1; + ret->size = 0; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Look up an entry in a string hash table. */ + +#define string_hash_lookup(t, string, create, copy) \ + ((struct string_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* Add a symbol to the stabs debugging information we are building. */ + +static bfd_boolean +stab_write_symbol (info, type, desc, value, string) + struct stab_write_handle *info; + int type; + int desc; + bfd_vma value; + const char *string; +{ + bfd_size_type strx; + bfd_byte sym[STAB_SYMBOL_SIZE]; + + if (string == NULL) + strx = 0; + else + { + struct string_hash_entry *h; + + h = string_hash_lookup (&info->strhash, string, TRUE, TRUE); + if (h == NULL) + { + non_fatal (_("string_hash_lookup failed: %s"), + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + if (h->index != -1) + strx = h->index; + else + { + strx = info->strings_size; + h->index = strx; + if (info->last_string == NULL) + info->strings = h; + else + info->last_string->next = h; + info->last_string = h; + info->strings_size += strlen (string) + 1; + } + } + + /* This presumes 32 bit values. */ + bfd_put_32 (info->abfd, strx, sym); + bfd_put_8 (info->abfd, type, sym + 4); + bfd_put_8 (info->abfd, 0, sym + 5); + bfd_put_16 (info->abfd, desc, sym + 6); + bfd_put_32 (info->abfd, value, sym + 8); + + if (info->symbols_size + STAB_SYMBOL_SIZE > info->symbols_alloc) + { + info->symbols_alloc *= 2; + info->symbols = (bfd_byte *) xrealloc (info->symbols, + info->symbols_alloc); + } + + memcpy (info->symbols + info->symbols_size, sym, STAB_SYMBOL_SIZE); + + info->symbols_size += STAB_SYMBOL_SIZE; + + return TRUE; +} + +/* Push a string on to the type stack. */ + +static bfd_boolean +stab_push_string (info, string, index, definition, size) + struct stab_write_handle *info; + const char *string; + long index; + bfd_boolean definition; + unsigned int size; +{ + struct stab_type_stack *s; + + s = (struct stab_type_stack *) xmalloc (sizeof *s); + s->string = xstrdup (string); + s->index = index; + s->definition = definition; + s->size = size; + + s->fields = NULL; + s->baseclasses = NULL; + s->methods = NULL; + s->vtable = NULL; + + s->next = info->type_stack; + info->type_stack = s; + + return TRUE; +} + +/* Push a type index which has already been defined. */ + +static bfd_boolean +stab_push_defined_type (info, index, size) + struct stab_write_handle *info; + long index; + unsigned int size; +{ + char buf[20]; + + sprintf (buf, "%ld", index); + return stab_push_string (info, buf, index, FALSE, size); +} + +/* Pop a type off the type stack. The caller is responsible for + freeing the string. */ + +static char * +stab_pop_type (info) + struct stab_write_handle *info; +{ + struct stab_type_stack *s; + char *ret; + + s = info->type_stack; + assert (s != NULL); + + info->type_stack = s->next; + + ret = s->string; + + free (s); + + return ret; +} + +/* The general routine to write out stabs in sections debugging + information. This accumulates the stabs symbols and the strings in + two obstacks. We can't easily write out the information as we go + along, because we need to know the section sizes before we can + write out the section contents. ABFD is the BFD and DHANDLE is the + handle for the debugging information. This sets *PSYMS to point to + the symbols, *PSYMSIZE the size of the symbols, *PSTRINGS to the + strings, and *PSTRINGSIZE to the size of the strings. */ + +bfd_boolean +write_stabs_in_sections_debugging_info (abfd, dhandle, psyms, psymsize, + pstrings, pstringsize) + bfd *abfd; + PTR dhandle; + bfd_byte **psyms; + bfd_size_type *psymsize; + bfd_byte **pstrings; + bfd_size_type *pstringsize; +{ + struct stab_write_handle info; + struct string_hash_entry *h; + bfd_byte *p; + + info.abfd = abfd; + + info.symbols_size = 0; + info.symbols_alloc = 500; + info.symbols = (bfd_byte *) xmalloc (info.symbols_alloc); + + info.strings = NULL; + info.last_string = NULL; + /* Reserve 1 byte for a null byte. */ + info.strings_size = 1; + + if (! bfd_hash_table_init (&info.strhash.table, string_hash_newfunc) + || ! bfd_hash_table_init (&info.typedef_hash.table, string_hash_newfunc)) + { + non_fatal ("bfd_hash_table_init_failed: %s", + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + + info.type_stack = NULL; + info.type_index = 1; + memset (&info.type_cache, 0, sizeof info.type_cache); + info.so_offset = -1; + info.fun_offset = -1; + info.last_text_address = 0; + info.nesting = 0; + info.fnaddr = 0; + info.pending_lbrac = (bfd_vma) -1; + + /* The initial symbol holds the string size. */ + if (! stab_write_symbol (&info, 0, 0, 0, (const char *) NULL)) + return FALSE; + + /* Output an initial N_SO symbol. */ + info.so_offset = info.symbols_size; + if (! stab_write_symbol (&info, N_SO, 0, 0, bfd_get_filename (abfd))) + return FALSE; + + if (! debug_write (dhandle, &stab_fns, (PTR) &info)) + return FALSE; + + assert (info.pending_lbrac == (bfd_vma) -1); + + /* Output a trailing N_SO. */ + if (! stab_write_symbol (&info, N_SO, 0, info.last_text_address, + (const char *) NULL)) + return FALSE; + + /* Put the string size in the initial symbol. */ + bfd_put_32 (abfd, info.strings_size, info.symbols + 8); + + *psyms = info.symbols; + *psymsize = info.symbols_size; + + *pstringsize = info.strings_size; + *pstrings = (bfd_byte *) xmalloc (info.strings_size); + + p = *pstrings; + *p++ = '\0'; + for (h = info.strings; h != NULL; h = h->next) + { + strcpy ((char *) p, h->root.string); + p += strlen ((char *) p) + 1; + } + + return TRUE; +} + +/* Start writing out information for a compilation unit. */ + +static bfd_boolean +stab_start_compilation_unit (p, filename) + PTR p; + const char *filename; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + /* We would normally output an N_SO symbol here. However, that + would force us to reset all of our type information. I think we + will be better off just outputting an N_SOL symbol, and not + worrying about splitting information between files. */ + + info->lineno_filename = filename; + + return stab_write_symbol (info, N_SOL, 0, 0, filename); +} + +/* Start writing out information for a particular source file. */ + +static bfd_boolean +stab_start_source (p, filename) + PTR p; + const char *filename; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + /* FIXME: The symbol's value is supposed to be the text section + address. However, we would have to fill it in later, and gdb + doesn't care, so we don't bother with it. */ + + info->lineno_filename = filename; + + return stab_write_symbol (info, N_SOL, 0, 0, filename); +} + +/* Push an empty type. This shouldn't normally happen. We just use a + void type. */ + +static bfd_boolean +stab_empty_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + /* We don't call stab_void_type if the type is not yet defined, + because that might screw up the typedef. */ + + if (info->type_cache.void_type != 0) + return stab_push_defined_type (info, info->type_cache.void_type, 0); + else + { + long index; + char buf[40]; + + index = info->type_index; + ++info->type_index; + + sprintf (buf, "%ld=%ld", index, index); + + return stab_push_string (info, buf, index, FALSE, 0); + } +} + +/* Push a void type. */ + +static bfd_boolean +stab_void_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + if (info->type_cache.void_type != 0) + return stab_push_defined_type (info, info->type_cache.void_type, 0); + else + { + long index; + char buf[40]; + + index = info->type_index; + ++info->type_index; + + info->type_cache.void_type = index; + + sprintf (buf, "%ld=%ld", index, index); + + return stab_push_string (info, buf, index, TRUE, 0); + } +} + +/* Push an integer type. */ + +static bfd_boolean +stab_int_type (p, size, unsignedp) + PTR p; + unsigned int size; + bfd_boolean unsignedp; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + long *cache; + + if (size <= 0 || (size > sizeof (long) && size != 8)) + { + non_fatal (_("stab_int_type: bad size %u"), size); + return FALSE; + } + + if (unsignedp) + cache = info->type_cache.signed_integer_types; + else + cache = info->type_cache.unsigned_integer_types; + + if (cache[size - 1] != 0) + return stab_push_defined_type (info, cache[size - 1], size); + else + { + long index; + char buf[100]; + + index = info->type_index; + ++info->type_index; + + cache[size - 1] = index; + + sprintf (buf, "%ld=r%ld;", index, index); + if (unsignedp) + { + strcat (buf, "0;"); + if (size < sizeof (long)) + sprintf (buf + strlen (buf), "%ld;", ((long) 1 << (size * 8)) - 1); + else if (size == sizeof (long)) + strcat (buf, "-1;"); + else if (size == 8) + strcat (buf, "01777777777777777777777;"); + else + abort (); + } + else + { + if (size <= sizeof (long)) + sprintf (buf + strlen (buf), "%ld;%ld;", + (long) - ((unsigned long) 1 << (size * 8 - 1)), + (long) (((unsigned long) 1 << (size * 8 - 1)) - 1)); + else if (size == 8) + strcat (buf, "01000000000000000000000;0777777777777777777777;"); + else + abort (); + } + + return stab_push_string (info, buf, index, TRUE, size); + } +} + +/* Push a floating point type. */ + +static bfd_boolean +stab_float_type (p, size) + PTR p; + unsigned int size; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + if (size > 0 + && size - 1 < (sizeof info->type_cache.float_types + / sizeof info->type_cache.float_types[0]) + && info->type_cache.float_types[size - 1] != 0) + return stab_push_defined_type (info, + info->type_cache.float_types[size - 1], + size); + else + { + long index; + char *int_type; + char buf[50]; + + /* Floats are defined as a subrange of int. */ + if (! stab_int_type (info, 4, FALSE)) + return FALSE; + int_type = stab_pop_type (info); + + index = info->type_index; + ++info->type_index; + + if (size > 0 + && size - 1 < (sizeof info->type_cache.float_types + / sizeof info->type_cache.float_types[0])) + info->type_cache.float_types[size - 1] = index; + + sprintf (buf, "%ld=r%s;%u;0;", index, int_type, size); + + free (int_type); + + return stab_push_string (info, buf, index, TRUE, size); + } +} + +/* Push a complex type. */ + +static bfd_boolean +stab_complex_type (p, size) + PTR p; + unsigned int size; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char buf[50]; + long index; + + index = info->type_index; + ++info->type_index; + + sprintf (buf, "%ld=r%ld;%u;0;", index, index, size); + + return stab_push_string (info, buf, index, TRUE, size * 2); +} + +/* Push a bfd_boolean type. We use an XCOFF predefined type, since gdb + always recognizes them. */ + +static bfd_boolean +stab_bool_type (p, size) + PTR p; + unsigned int size; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + long index; + + switch (size) + { + case 1: + index = -21; + break; + + case 2: + index = -22; + break; + + default: + case 4: + index = -16; + break; + + case 8: + index = -33; + break; + } + + return stab_push_defined_type (info, index, size); +} + +/* Push an enum type. */ + +static bfd_boolean +stab_enum_type (p, tag, names, vals) + PTR p; + const char *tag; + const char **names; + bfd_signed_vma *vals; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + size_t len; + const char **pn; + char *buf; + long index = 0; + bfd_signed_vma *pv; + + if (names == NULL) + { + assert (tag != NULL); + + buf = (char *) xmalloc (10 + strlen (tag)); + sprintf (buf, "xe%s:", tag); + /* FIXME: The size is just a guess. */ + if (! stab_push_string (info, buf, 0, FALSE, 4)) + return FALSE; + free (buf); + return TRUE; + } + + len = 10; + if (tag != NULL) + len += strlen (tag); + for (pn = names; *pn != NULL; pn++) + len += strlen (*pn) + 20; + + buf = (char *) xmalloc (len); + + if (tag == NULL) + strcpy (buf, "e"); + else + { + index = info->type_index; + ++info->type_index; + sprintf (buf, "%s:T%ld=e", tag, index); + } + + for (pn = names, pv = vals; *pn != NULL; pn++, pv++) + sprintf (buf + strlen (buf), "%s:%ld,", *pn, (long) *pv); + strcat (buf, ";"); + + if (tag == NULL) + { + /* FIXME: The size is just a guess. */ + if (! stab_push_string (info, buf, 0, FALSE, 4)) + return FALSE; + } + else + { + /* FIXME: The size is just a guess. */ + if (! stab_write_symbol (info, N_LSYM, 0, 0, buf) + || ! stab_push_defined_type (info, index, 4)) + return FALSE; + } + + free (buf); + + return TRUE; +} + +/* Push a modification of the top type on the stack. Cache the + results in CACHE and CACHE_ALLOC. */ + +static bfd_boolean +stab_modify_type (info, mod, size, cache, cache_alloc) + struct stab_write_handle *info; + int mod; + unsigned int size; + long **cache; + size_t *cache_alloc; +{ + long targindex; + long index; + char *s, *buf; + + assert (info->type_stack != NULL); + targindex = info->type_stack->index; + + if (targindex <= 0 + || cache == NULL) + { + bfd_boolean definition; + + /* Either the target type has no index, or we aren't caching + this modifier. Either way we have no way of recording the + new type, so we don't bother to define one. */ + definition = info->type_stack->definition; + s = stab_pop_type (info); + buf = (char *) xmalloc (strlen (s) + 2); + sprintf (buf, "%c%s", mod, s); + free (s); + if (! stab_push_string (info, buf, 0, definition, size)) + return FALSE; + free (buf); + } + else + { + if ((size_t) targindex >= *cache_alloc) + { + size_t alloc; + + alloc = *cache_alloc; + if (alloc == 0) + alloc = 10; + while ((size_t) targindex >= alloc) + alloc *= 2; + *cache = (long *) xrealloc (*cache, alloc * sizeof (long)); + memset (*cache + *cache_alloc, 0, + (alloc - *cache_alloc) * sizeof (long)); + *cache_alloc = alloc; + } + + index = (*cache)[targindex]; + if (index != 0 && ! info->type_stack->definition) + { + /* We have already defined a modification of this type, and + the entry on the type stack is not a definition, so we + can safely discard it (we may have a definition on the + stack, even if we already defined a modification, if it + is a struct which we did not define at the time it was + referenced). */ + free (stab_pop_type (info)); + if (! stab_push_defined_type (info, index, size)) + return FALSE; + } + else + { + index = info->type_index; + ++info->type_index; + + s = stab_pop_type (info); + buf = (char *) xmalloc (strlen (s) + 20); + sprintf (buf, "%ld=%c%s", index, mod, s); + free (s); + + (*cache)[targindex] = index; + + if (! stab_push_string (info, buf, index, TRUE, size)) + return FALSE; + + free (buf); + } + } + + return TRUE; +} + +/* Push a pointer type. */ + +static bfd_boolean +stab_pointer_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + /* FIXME: The size should depend upon the architecture. */ + return stab_modify_type (info, '*', 4, &info->type_cache.pointer_types, + &info->type_cache.pointer_types_alloc); +} + +/* Push a function type. */ + +static bfd_boolean +stab_function_type (p, argcount, varargs) + PTR p; + int argcount; + bfd_boolean varargs ATTRIBUTE_UNUSED; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + int i; + + /* We have no way to represent the argument types, so we just + discard them. However, if they define new types, we must output + them. We do this by producing empty typedefs. */ + for (i = 0; i < argcount; i++) + { + if (! info->type_stack->definition) + free (stab_pop_type (info)); + else + { + char *s, *buf; + + s = stab_pop_type (info); + + buf = (char *) xmalloc (strlen (s) + 3); + sprintf (buf, ":t%s", s); + free (s); + + if (! stab_write_symbol (info, N_LSYM, 0, 0, buf)) + return FALSE; + + free (buf); + } + } + + return stab_modify_type (info, 'f', 0, &info->type_cache.function_types, + &info->type_cache.function_types_alloc); +} + +/* Push a reference type. */ + +static bfd_boolean +stab_reference_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + /* FIXME: The size should depend upon the architecture. */ + return stab_modify_type (info, '&', 4, &info->type_cache.reference_types, + &info->type_cache.reference_types_alloc); +} + +/* Push a range type. */ + +static bfd_boolean +stab_range_type (p, low, high) + PTR p; + bfd_signed_vma low; + bfd_signed_vma high; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + unsigned int size; + char *s, *buf; + + definition = info->type_stack->definition; + size = info->type_stack->size; + + s = stab_pop_type (info); + buf = (char *) xmalloc (strlen (s) + 100); + sprintf (buf, "r%s;%ld;%ld;", s, (long) low, (long) high); + free (s); + + if (! stab_push_string (info, buf, 0, definition, size)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Push an array type. */ + +static bfd_boolean +stab_array_type (p, low, high, stringp) + PTR p; + bfd_signed_vma low; + bfd_signed_vma high; + bfd_boolean stringp; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + unsigned int element_size; + char *range, *element, *buf; + long index; + unsigned int size; + + definition = info->type_stack->definition; + range = stab_pop_type (info); + + definition = definition || info->type_stack->definition; + element_size = info->type_stack->size; + element = stab_pop_type (info); + + buf = (char *) xmalloc (strlen (range) + strlen (element) + 100); + + if (! stringp) + { + index = 0; + *buf = '\0'; + } + else + { + /* We need to define a type in order to include the string + attribute. */ + index = info->type_index; + ++info->type_index; + definition = TRUE; + sprintf (buf, "%ld=@S;", index); + } + + sprintf (buf + strlen (buf), "ar%s;%ld;%ld;%s", + range, (long) low, (long) high, element); + free (range); + free (element); + + if (high < low) + size = 0; + else + size = element_size * ((high - low) + 1); + if (! stab_push_string (info, buf, index, definition, size)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Push a set type. */ + +static bfd_boolean +stab_set_type (p, bitstringp) + PTR p; + bfd_boolean bitstringp; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + char *s, *buf; + long index; + + definition = info->type_stack->definition; + + s = stab_pop_type (info); + buf = (char *) xmalloc (strlen (s) + 30); + + if (! bitstringp) + { + *buf = '\0'; + index = 0; + } + else + { + /* We need to define a type in order to include the string + attribute. */ + index = info->type_index; + ++info->type_index; + definition = TRUE; + sprintf (buf, "%ld=@S;", index); + } + + sprintf (buf + strlen (buf), "S%s", s); + free (s); + + if (! stab_push_string (info, buf, index, definition, 0)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Push an offset type. */ + +static bfd_boolean +stab_offset_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + char *target, *base, *buf; + + definition = info->type_stack->definition; + target = stab_pop_type (info); + + definition = definition || info->type_stack->definition; + base = stab_pop_type (info); + + buf = (char *) xmalloc (strlen (target) + strlen (base) + 3); + sprintf (buf, "@%s,%s", base, target); + free (base); + free (target); + + if (! stab_push_string (info, buf, 0, definition, 0)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Push a method type. */ + +static bfd_boolean +stab_method_type (p, domainp, argcount, varargs) + PTR p; + bfd_boolean domainp; + int argcount; + bfd_boolean varargs; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + char *domain, *return_type, *buf; + char **args; + int i; + size_t len; + + /* We don't bother with stub method types, because that would + require a mangler for C++ argument types. This will waste space + in the debugging output. */ + + /* We need a domain. I'm not sure DOMAINP can ever be false, + anyhow. */ + if (! domainp) + { + if (! stab_empty_type (p)) + return FALSE; + } + + definition = info->type_stack->definition; + domain = stab_pop_type (info); + + /* A non-varargs function is indicated by making the last parameter + type be void. */ + + if (argcount < 0) + { + args = NULL; + argcount = 0; + } + else if (argcount == 0) + { + if (varargs) + args = NULL; + else + { + args = (char **) xmalloc (1 * sizeof (*args)); + if (! stab_empty_type (p)) + return FALSE; + definition = definition || info->type_stack->definition; + args[0] = stab_pop_type (info); + argcount = 1; + } + } + else + { + args = (char **) xmalloc ((argcount + 1) * sizeof (*args)); + for (i = argcount - 1; i >= 0; i--) + { + definition = definition || info->type_stack->definition; + args[i] = stab_pop_type (info); + } + if (! varargs) + { + if (! stab_empty_type (p)) + return FALSE; + definition = definition || info->type_stack->definition; + args[argcount] = stab_pop_type (info); + ++argcount; + } + } + + definition = definition || info->type_stack->definition; + return_type = stab_pop_type (info); + + len = strlen (domain) + strlen (return_type) + 10; + for (i = 0; i < argcount; i++) + len += strlen (args[i]); + + buf = (char *) xmalloc (len); + + sprintf (buf, "#%s,%s", domain, return_type); + free (domain); + free (return_type); + for (i = 0; i < argcount; i++) + { + strcat (buf, ","); + strcat (buf, args[i]); + free (args[i]); + } + strcat (buf, ";"); + + if (args != NULL) + free (args); + + if (! stab_push_string (info, buf, 0, definition, 0)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Push a const version of a type. */ + +static bfd_boolean +stab_const_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + return stab_modify_type (info, 'k', info->type_stack->size, + (long **) NULL, (size_t *) NULL); +} + +/* Push a volatile version of a type. */ + +static bfd_boolean +stab_volatile_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + return stab_modify_type (info, 'B', info->type_stack->size, + (long **) NULL, (size_t *) NULL); +} + +/* Get the type index to use for a struct/union/class ID. This should + return -1 if it fails. */ + +static long +stab_get_struct_index (info, tag, id, kind, psize) + struct stab_write_handle *info; + const char *tag; + unsigned int id; + enum debug_type_kind kind; + unsigned int *psize; +{ + if (id >= info->type_cache.struct_types_alloc) + { + size_t alloc; + + alloc = info->type_cache.struct_types_alloc; + if (alloc == 0) + alloc = 10; + while (id >= alloc) + alloc *= 2; + info->type_cache.struct_types = + (struct stab_tag *) xrealloc (info->type_cache.struct_types, + alloc * sizeof (struct stab_tag)); + memset ((info->type_cache.struct_types + + info->type_cache.struct_types_alloc), + 0, + ((alloc - info->type_cache.struct_types_alloc) + * sizeof (struct stab_tag))); + info->type_cache.struct_types_alloc = alloc; + } + + if (info->type_cache.struct_types[id].index == 0) + { + info->type_cache.struct_types[id].index = info->type_index; + ++info->type_index; + info->type_cache.struct_types[id].tag = tag; + info->type_cache.struct_types[id].kind = kind; + } + + if (kind == DEBUG_KIND_ILLEGAL) + { + /* This is a definition of the struct. */ + info->type_cache.struct_types[id].kind = kind; + info->type_cache.struct_types[id].size = *psize; + } + else + *psize = info->type_cache.struct_types[id].size; + + return info->type_cache.struct_types[id].index; +} + +/* Start outputting a struct. We ignore the tag, and handle it in + stab_tag. */ + +static bfd_boolean +stab_start_struct_type (p, tag, id, structp, size) + PTR p; + const char *tag; + unsigned int id; + bfd_boolean structp; + unsigned int size; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + long index; + bfd_boolean definition; + char *buf; + + buf = (char *) xmalloc (40); + + if (id == 0) + { + index = 0; + *buf = '\0'; + definition = FALSE; + } + else + { + index = stab_get_struct_index (info, tag, id, DEBUG_KIND_ILLEGAL, + &size); + if (index < 0) + return FALSE; + sprintf (buf, "%ld=", index); + definition = TRUE; + } + + sprintf (buf + strlen (buf), "%c%u", + structp ? 's' : 'u', + size); + + if (! stab_push_string (info, buf, index, definition, size)) + return FALSE; + + info->type_stack->fields = (char *) xmalloc (1); + info->type_stack->fields[0] = '\0'; + + return TRUE; +} + +/* Add a field to a struct. */ + +static bfd_boolean +stab_struct_field (p, name, bitpos, bitsize, visibility) + PTR p; + const char *name; + bfd_vma bitpos; + bfd_vma bitsize; + enum debug_visibility visibility; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + unsigned int size; + char *s, *n; + const char *vis; + + definition = info->type_stack->definition; + size = info->type_stack->size; + s = stab_pop_type (info); + + /* Add this field to the end of the current struct fields, which is + currently on the top of the stack. */ + + assert (info->type_stack->fields != NULL); + n = (char *) xmalloc (strlen (info->type_stack->fields) + + strlen (name) + + strlen (s) + + 50); + + switch (visibility) + { + default: + abort (); + + case DEBUG_VISIBILITY_PUBLIC: + vis = ""; + break; + + case DEBUG_VISIBILITY_PRIVATE: + vis = "/0"; + break; + + case DEBUG_VISIBILITY_PROTECTED: + vis = "/1"; + break; + } + + if (bitsize == 0) + { + bitsize = size * 8; + if (bitsize == 0) + non_fatal (_("%s: warning: unknown size for field `%s' in struct"), + bfd_get_filename (info->abfd), name); + } + + sprintf (n, "%s%s:%s%s,%ld,%ld;", info->type_stack->fields, name, vis, s, + (long) bitpos, (long) bitsize); + + free (info->type_stack->fields); + info->type_stack->fields = n; + + if (definition) + info->type_stack->definition = TRUE; + + return TRUE; +} + +/* Finish up a struct. */ + +static bfd_boolean +stab_end_struct_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + long index; + unsigned int size; + char *fields, *first, *buf; + + assert (info->type_stack != NULL && info->type_stack->fields != NULL); + + definition = info->type_stack->definition; + index = info->type_stack->index; + size = info->type_stack->size; + fields = info->type_stack->fields; + first = stab_pop_type (info); + + buf = (char *) xmalloc (strlen (first) + strlen (fields) + 2); + sprintf (buf, "%s%s;", first, fields); + free (first); + free (fields); + + if (! stab_push_string (info, buf, index, definition, size)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Start outputting a class. */ + +static bfd_boolean +stab_start_class_type (p, tag, id, structp, size, vptr, ownvptr) + PTR p; + const char *tag; + unsigned int id; + bfd_boolean structp; + unsigned int size; + bfd_boolean vptr; + bfd_boolean ownvptr; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + char *vstring; + + if (! vptr || ownvptr) + { + definition = FALSE; + vstring = NULL; + } + else + { + definition = info->type_stack->definition; + vstring = stab_pop_type (info); + } + + if (! stab_start_struct_type (p, tag, id, structp, size)) + return FALSE; + + if (vptr) + { + char *vtable; + + if (ownvptr) + { + assert (info->type_stack->index > 0); + vtable = (char *) xmalloc (20); + sprintf (vtable, "~%%%ld", info->type_stack->index); + } + else + { + vtable = (char *) xmalloc (strlen (vstring) + 3); + sprintf (vtable, "~%%%s", vstring); + free (vstring); + } + + info->type_stack->vtable = vtable; + } + + if (definition) + info->type_stack->definition = TRUE; + + return TRUE; +} + +/* Add a static member to the class on the type stack. */ + +static bfd_boolean +stab_class_static_member (p, name, physname, visibility) + PTR p; + const char *name; + const char *physname; + enum debug_visibility visibility; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + char *s, *n; + const char *vis; + + definition = info->type_stack->definition; + s = stab_pop_type (info); + + /* Add this field to the end of the current struct fields, which is + currently on the top of the stack. */ + + assert (info->type_stack->fields != NULL); + n = (char *) xmalloc (strlen (info->type_stack->fields) + + strlen (name) + + strlen (s) + + strlen (physname) + + 10); + + switch (visibility) + { + default: + abort (); + + case DEBUG_VISIBILITY_PUBLIC: + vis = ""; + break; + + case DEBUG_VISIBILITY_PRIVATE: + vis = "/0"; + break; + + case DEBUG_VISIBILITY_PROTECTED: + vis = "/1"; + break; + } + + sprintf (n, "%s%s:%s%s:%s;", info->type_stack->fields, name, vis, s, + physname); + + free (info->type_stack->fields); + info->type_stack->fields = n; + + if (definition) + info->type_stack->definition = TRUE; + + return TRUE; +} + +/* Add a base class to the class on the type stack. */ + +static bfd_boolean +stab_class_baseclass (p, bitpos, virtual, visibility) + PTR p; + bfd_vma bitpos; + bfd_boolean virtual; + enum debug_visibility visibility; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + bfd_boolean definition; + char *s; + char *buf; + unsigned int c; + char **baseclasses; + + definition = info->type_stack->definition; + s = stab_pop_type (info); + + /* Build the base class specifier. */ + + buf = (char *) xmalloc (strlen (s) + 25); + buf[0] = virtual ? '1' : '0'; + switch (visibility) + { + default: + abort (); + + case DEBUG_VISIBILITY_PRIVATE: + buf[1] = '0'; + break; + + case DEBUG_VISIBILITY_PROTECTED: + buf[1] = '1'; + break; + + case DEBUG_VISIBILITY_PUBLIC: + buf[1] = '2'; + break; + } + + sprintf (buf + 2, "%ld,%s;", (long) bitpos, s); + free (s); + + /* Add the new baseclass to the existing ones. */ + + assert (info->type_stack != NULL && info->type_stack->fields != NULL); + + if (info->type_stack->baseclasses == NULL) + c = 0; + else + { + c = 0; + while (info->type_stack->baseclasses[c] != NULL) + ++c; + } + + baseclasses = (char **) xrealloc (info->type_stack->baseclasses, + (c + 2) * sizeof (*baseclasses)); + baseclasses[c] = buf; + baseclasses[c + 1] = NULL; + + info->type_stack->baseclasses = baseclasses; + + if (definition) + info->type_stack->definition = TRUE; + + return TRUE; +} + +/* Start adding a method to the class on the type stack. */ + +static bfd_boolean +stab_class_start_method (p, name) + PTR p; + const char *name; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char *m; + + assert (info->type_stack != NULL && info->type_stack->fields != NULL); + + if (info->type_stack->methods == NULL) + { + m = (char *) xmalloc (strlen (name) + 3); + *m = '\0'; + } + else + { + m = (char *) xrealloc (info->type_stack->methods, + (strlen (info->type_stack->methods) + + strlen (name) + + 4)); + } + + sprintf (m + strlen (m), "%s::", name); + + info->type_stack->methods = m; + + return TRUE; +} + +/* Add a variant, either static or not, to the current method. */ + +static bfd_boolean +stab_class_method_var (info, physname, visibility, staticp, constp, volatilep, + voffset, contextp) + struct stab_write_handle *info; + const char *physname; + enum debug_visibility visibility; + bfd_boolean staticp; + bfd_boolean constp; + bfd_boolean volatilep; + bfd_vma voffset; + bfd_boolean contextp; +{ + bfd_boolean definition; + char *type; + char *context = NULL; + char visc, qualc, typec; + + definition = info->type_stack->definition; + type = stab_pop_type (info); + + if (contextp) + { + definition = definition || info->type_stack->definition; + context = stab_pop_type (info); + } + + assert (info->type_stack != NULL && info->type_stack->methods != NULL); + + switch (visibility) + { + default: + abort (); + + case DEBUG_VISIBILITY_PRIVATE: + visc = '0'; + break; + + case DEBUG_VISIBILITY_PROTECTED: + visc = '1'; + break; + + case DEBUG_VISIBILITY_PUBLIC: + visc = '2'; + break; + } + + if (constp) + { + if (volatilep) + qualc = 'D'; + else + qualc = 'B'; + } + else + { + if (volatilep) + qualc = 'C'; + else + qualc = 'A'; + } + + if (staticp) + typec = '?'; + else if (! contextp) + typec = '.'; + else + typec = '*'; + + info->type_stack->methods = + (char *) xrealloc (info->type_stack->methods, + (strlen (info->type_stack->methods) + + strlen (type) + + strlen (physname) + + (contextp ? strlen (context) : 0) + + 40)); + + sprintf (info->type_stack->methods + strlen (info->type_stack->methods), + "%s:%s;%c%c%c", type, physname, visc, qualc, typec); + free (type); + + if (contextp) + { + sprintf (info->type_stack->methods + strlen (info->type_stack->methods), + "%ld;%s;", (long) voffset, context); + free (context); + } + + if (definition) + info->type_stack->definition = TRUE; + + return TRUE; +} + +/* Add a variant to the current method. */ + +static bfd_boolean +stab_class_method_variant (p, physname, visibility, constp, volatilep, + voffset, contextp) + PTR p; + const char *physname; + enum debug_visibility visibility; + bfd_boolean constp; + bfd_boolean volatilep; + bfd_vma voffset; + bfd_boolean contextp; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + return stab_class_method_var (info, physname, visibility, FALSE, constp, + volatilep, voffset, contextp); +} + +/* Add a static variant to the current method. */ + +static bfd_boolean +stab_class_static_method_variant (p, physname, visibility, constp, volatilep) + PTR p; + const char *physname; + enum debug_visibility visibility; + bfd_boolean constp; + bfd_boolean volatilep; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + return stab_class_method_var (info, physname, visibility, TRUE, constp, + volatilep, 0, FALSE); +} + +/* Finish up a method. */ + +static bfd_boolean +stab_class_end_method (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + assert (info->type_stack != NULL && info->type_stack->methods != NULL); + + /* We allocated enough room on info->type_stack->methods to add the + trailing semicolon. */ + strcat (info->type_stack->methods, ";"); + + return TRUE; +} + +/* Finish up a class. */ + +static bfd_boolean +stab_end_class_type (p) + PTR p; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + size_t len; + unsigned int i = 0; + char *buf; + + assert (info->type_stack != NULL && info->type_stack->fields != NULL); + + /* Work out the size we need to allocate for the class definition. */ + + len = (strlen (info->type_stack->string) + + strlen (info->type_stack->fields) + + 10); + if (info->type_stack->baseclasses != NULL) + { + len += 20; + for (i = 0; info->type_stack->baseclasses[i] != NULL; i++) + len += strlen (info->type_stack->baseclasses[i]); + } + if (info->type_stack->methods != NULL) + len += strlen (info->type_stack->methods); + if (info->type_stack->vtable != NULL) + len += strlen (info->type_stack->vtable); + + /* Build the class definition. */ + + buf = (char *) xmalloc (len); + + strcpy (buf, info->type_stack->string); + + if (info->type_stack->baseclasses != NULL) + { + sprintf (buf + strlen (buf), "!%u,", i); + for (i = 0; info->type_stack->baseclasses[i] != NULL; i++) + { + strcat (buf, info->type_stack->baseclasses[i]); + free (info->type_stack->baseclasses[i]); + } + free (info->type_stack->baseclasses); + info->type_stack->baseclasses = NULL; + } + + strcat (buf, info->type_stack->fields); + free (info->type_stack->fields); + info->type_stack->fields = NULL; + + if (info->type_stack->methods != NULL) + { + strcat (buf, info->type_stack->methods); + free (info->type_stack->methods); + info->type_stack->methods = NULL; + } + + strcat (buf, ";"); + + if (info->type_stack->vtable != NULL) + { + strcat (buf, info->type_stack->vtable); + free (info->type_stack->vtable); + info->type_stack->vtable = NULL; + } + + /* Replace the string on the top of the stack with the complete + class definition. */ + free (info->type_stack->string); + info->type_stack->string = buf; + + return TRUE; +} + +/* Push a typedef which was previously defined. */ + +static bfd_boolean +stab_typedef_type (p, name) + PTR p; + const char *name; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + struct string_hash_entry *h; + + h = string_hash_lookup (&info->typedef_hash, name, FALSE, FALSE); + assert (h != NULL && h->index > 0); + + return stab_push_defined_type (info, h->index, h->size); +} + +/* Push a struct, union or class tag. */ + +static bfd_boolean +stab_tag_type (p, name, id, kind) + PTR p; + const char *name; + unsigned int id; + enum debug_type_kind kind; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + long index; + unsigned int size; + + index = stab_get_struct_index (info, name, id, kind, &size); + if (index < 0) + return FALSE; + + return stab_push_defined_type (info, index, size); +} + +/* Define a typedef. */ + +static bfd_boolean +stab_typdef (p, name) + PTR p; + const char *name; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + long index; + unsigned int size; + char *s, *buf; + struct string_hash_entry *h; + + index = info->type_stack->index; + size = info->type_stack->size; + s = stab_pop_type (info); + + buf = (char *) xmalloc (strlen (name) + strlen (s) + 20); + + if (index > 0) + sprintf (buf, "%s:t%s", name, s); + else + { + index = info->type_index; + ++info->type_index; + sprintf (buf, "%s:t%ld=%s", name, index, s); + } + + free (s); + + if (! stab_write_symbol (info, N_LSYM, 0, 0, buf)) + return FALSE; + + free (buf); + + h = string_hash_lookup (&info->typedef_hash, name, TRUE, FALSE); + if (h == NULL) + { + non_fatal (_("string_hash_lookup failed: %s"), + bfd_errmsg (bfd_get_error ())); + return FALSE; + } + + /* I don't think we care about redefinitions. */ + + h->index = index; + h->size = size; + + return TRUE; +} + +/* Define a tag. */ + +static bfd_boolean +stab_tag (p, tag) + PTR p; + const char *tag; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char *s, *buf; + + s = stab_pop_type (info); + + buf = (char *) xmalloc (strlen (tag) + strlen (s) + 3); + + sprintf (buf, "%s:T%s", tag, s); + free (s); + + if (! stab_write_symbol (info, N_LSYM, 0, 0, buf)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Define an integer constant. */ + +static bfd_boolean +stab_int_constant (p, name, val) + PTR p; + const char *name; + bfd_vma val; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char *buf; + + buf = (char *) xmalloc (strlen (name) + 20); + sprintf (buf, "%s:c=i%ld", name, (long) val); + + if (! stab_write_symbol (info, N_LSYM, 0, 0, buf)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Define a floating point constant. */ + +static bfd_boolean +stab_float_constant (p, name, val) + PTR p; + const char *name; + double val; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char *buf; + + buf = (char *) xmalloc (strlen (name) + 20); + sprintf (buf, "%s:c=f%g", name, val); + + if (! stab_write_symbol (info, N_LSYM, 0, 0, buf)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Define a typed constant. */ + +static bfd_boolean +stab_typed_constant (p, name, val) + PTR p; + const char *name; + bfd_vma val; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char *s, *buf; + + s = stab_pop_type (info); + + buf = (char *) xmalloc (strlen (name) + strlen (s) + 20); + sprintf (buf, "%s:c=e%s,%ld", name, s, (long) val); + free (s); + + if (! stab_write_symbol (info, N_LSYM, 0, 0, buf)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Record a variable. */ + +static bfd_boolean +stab_variable (p, name, kind, val) + PTR p; + const char *name; + enum debug_var_kind kind; + bfd_vma val; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char *s, *buf; + int stab_type; + const char *kindstr; + + s = stab_pop_type (info); + + switch (kind) + { + default: + abort (); + + case DEBUG_GLOBAL: + stab_type = N_GSYM; + kindstr = "G"; + break; + + case DEBUG_STATIC: + stab_type = N_STSYM; + kindstr = "S"; + break; + + case DEBUG_LOCAL_STATIC: + stab_type = N_STSYM; + kindstr = "V"; + break; + + case DEBUG_LOCAL: + stab_type = N_LSYM; + kindstr = ""; + + /* Make sure that this is a type reference or definition. */ + if (! ISDIGIT (*s)) + { + char *n; + long index; + + index = info->type_index; + ++info->type_index; + n = (char *) xmalloc (strlen (s) + 20); + sprintf (n, "%ld=%s", index, s); + free (s); + s = n; + } + break; + + case DEBUG_REGISTER: + stab_type = N_RSYM; + kindstr = "r"; + break; + } + + buf = (char *) xmalloc (strlen (name) + strlen (s) + 3); + sprintf (buf, "%s:%s%s", name, kindstr, s); + free (s); + + if (! stab_write_symbol (info, stab_type, 0, val, buf)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Start outputting a function. */ + +static bfd_boolean +stab_start_function (p, name, globalp) + PTR p; + const char *name; + bfd_boolean globalp; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char *rettype, *buf; + + assert (info->nesting == 0 && info->fun_offset == -1); + + rettype = stab_pop_type (info); + + buf = (char *) xmalloc (strlen (name) + strlen (rettype) + 3); + sprintf (buf, "%s:%c%s", name, + globalp ? 'F' : 'f', + rettype); + + /* We don't know the value now, so we set it in start_block. */ + info->fun_offset = info->symbols_size; + + if (! stab_write_symbol (info, N_FUN, 0, 0, buf)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Output a function parameter. */ + +static bfd_boolean +stab_function_parameter (p, name, kind, val) + PTR p; + const char *name; + enum debug_parm_kind kind; + bfd_vma val; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + char *s, *buf; + int stab_type; + char kindc; + + s = stab_pop_type (info); + + switch (kind) + { + default: + abort (); + + case DEBUG_PARM_STACK: + stab_type = N_PSYM; + kindc = 'p'; + break; + + case DEBUG_PARM_REG: + stab_type = N_RSYM; + kindc = 'P'; + break; + + case DEBUG_PARM_REFERENCE: + stab_type = N_PSYM; + kindc = 'v'; + break; + + case DEBUG_PARM_REF_REG: + stab_type = N_RSYM; + kindc = 'a'; + break; + } + + buf = (char *) xmalloc (strlen (name) + strlen (s) + 3); + sprintf (buf, "%s:%c%s", name, kindc, s); + free (s); + + if (! stab_write_symbol (info, stab_type, 0, val, buf)) + return FALSE; + + free (buf); + + return TRUE; +} + +/* Start a block. */ + +static bfd_boolean +stab_start_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + /* Fill in any slots which have been waiting for the first known + text address. */ + + if (info->so_offset != -1) + { + bfd_put_32 (info->abfd, addr, info->symbols + info->so_offset + 8); + info->so_offset = -1; + } + + if (info->fun_offset != -1) + { + bfd_put_32 (info->abfd, addr, info->symbols + info->fun_offset + 8); + info->fun_offset = -1; + } + + ++info->nesting; + + /* We will be called with a top level block surrounding the + function, but stabs information does not output that block, so we + ignore it. */ + + if (info->nesting == 1) + { + info->fnaddr = addr; + return TRUE; + } + + /* We have to output the LBRAC symbol after any variables which are + declared inside the block. We postpone the LBRAC until the next + start_block or end_block. */ + + /* If we have postponed an LBRAC, output it now. */ + if (info->pending_lbrac != (bfd_vma) -1) + { + if (! stab_write_symbol (info, N_LBRAC, 0, info->pending_lbrac, + (const char *) NULL)) + return FALSE; + } + + /* Remember the address and output it later. */ + + info->pending_lbrac = addr - info->fnaddr; + + return TRUE; +} + +/* End a block. */ + +static bfd_boolean +stab_end_block (p, addr) + PTR p; + bfd_vma addr; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + if (addr > info->last_text_address) + info->last_text_address = addr; + + /* If we have postponed an LBRAC, output it now. */ + if (info->pending_lbrac != (bfd_vma) -1) + { + if (! stab_write_symbol (info, N_LBRAC, 0, info->pending_lbrac, + (const char *) NULL)) + return FALSE; + info->pending_lbrac = (bfd_vma) -1; + } + + assert (info->nesting > 0); + + --info->nesting; + + /* We ignore the outermost block. */ + if (info->nesting == 0) + return TRUE; + + return stab_write_symbol (info, N_RBRAC, 0, addr - info->fnaddr, + (const char *) NULL); +} + +/* End a function. */ + +static bfd_boolean +stab_end_function (p) + PTR p ATTRIBUTE_UNUSED; +{ + return TRUE; +} + +/* Output a line number. */ + +static bfd_boolean +stab_lineno (p, file, lineno, addr) + PTR p; + const char *file; + unsigned long lineno; + bfd_vma addr; +{ + struct stab_write_handle *info = (struct stab_write_handle *) p; + + assert (info->lineno_filename != NULL); + + if (addr > info->last_text_address) + info->last_text_address = addr; + + if (strcmp (file, info->lineno_filename) != 0) + { + if (! stab_write_symbol (info, N_SOL, 0, addr, file)) + return FALSE; + info->lineno_filename = file; + } + + return stab_write_symbol (info, N_SLINE, lineno, addr - info->fnaddr, + (const char *) NULL); +} diff --git a/contrib/binutils-2.14/gas/CONTRIBUTORS b/contrib/binutils-2.14/gas/CONTRIBUTORS new file mode 100644 index 0000000000..d564ba8f01 --- /dev/null +++ b/contrib/binutils-2.14/gas/CONTRIBUTORS @@ -0,0 +1,110 @@ +(This file is under construction.) -*- text -*- + +If you've contributed to gas and your name isn't listed here, it is +not meant as a slight. I just don't know about it. Email me, +nickc@redhat.com and I'll correct the situation. + +This file will eventually be deleted: The general info will go into +the documentation, and info on specific files will go into an AUTHORS +file, as requested by the FSF. + +++++++++++++++++ + +Dean Elsner wrote the original gas for vax. [more details?] + +Jay Fenlason maintained gas for a while, adding support for +gdb-specific debug information and the 68k series machines, most of +the preprocessing pass, and extensive changes in messages.c, +input-file.c, write.c. + +K. Richard Pixley maintained gas for a while, adding various +enhancements and many bug fixes, including merging support for several +processors, breaking gas up to handle multiple object file format +backends (including heavy rewrite, testing, an integration of the coff +and b.out backends), adding configuration including heavy testing and +verification of cross assemblers and file splits and renaming, +converted gas to strictly ansi C including full prototypes, added +support for m680[34]0 & cpu32, considerable work on i960 including a +coff port (including considerable amounts of reverse engineering), a +sparc opcode file rewrite, decstation, rs6000, and hp300hpux host +ports, updated "know" assertions and made them work, much other +reorganization, cleanup, and lint. + +Ken Raeburn wrote the high-level BFD interface code to replace most of +the code in format-specific I/O modules. + +The original Vax-VMS support was contributed by David L. Kashtan. +Eric Youngdale and Pat Rankin have done much work with it since. + +The Intel 80386 machine description was written by Eliot Dresselhaus. + +Minh Tran-Le at IntelliCorp contributed some AIX 386 support. + +The Motorola 88k machine description was contributed by Devon Bowen of +Buffalo University and Torbjorn Granlund of the Swedish Institute of +Computer Science. + +Keith Knowles at the Open Software Foundation wrote the original MIPS +back end (tc-mips.c, tc-mips.h), and contributed Rose format support +that hasn't been merged in yet. Ralph Campbell worked with the MIPS +code to support a.out format. + +Support for the Zilog Z8k and Hitachi H8/300, H8/500 and SH processors +(tc-z8k, tc-h8300, tc-h8500, tc-sh), and IEEE 695 object file format +(obj-ieee), was written by Steve Chamberlain of Cygnus Solutions. +Steve also modified the COFF back end (obj-coffbfd) to use BFD for +some low-level operations, for use with the Hitachi, 29k and Zilog +targets. + +John Gilmore built the AMD 29000 support, added .include support, and +simplified the configuration of which versions accept which +pseudo-ops. He updated the 68k machine description so that Motorola's +opcodes always produced fixed-size instructions (e.g. jsr), while +synthetic instructions remained shrinkable (jbsr). John fixed many +bugs, including true tested cross-compilation support, and one bug in +relaxation that took a week and required the proverbial one-bit fix. + +Ian Lance Taylor of Cygnus Solutions merged the Motorola and MIT +syntaxes for the 68k, completed support for some COFF targets (68k, +i386 SVR3, and SCO Unix), wrote the ECOFF support based on Michael +Meissner's mips-tfile program, wrote the PowerPC and RS/6000 support, +and made a few other minor patches. He handled the binutils releases +for versions 2.7 through 2.9. + +David Edelsohn contributed fixes for the PowerPC and AIX support. + +Steve Chamberlain made gas able to generate listings. + +Support for the HP9000/300 was contributed by Glenn Engel of HP. + +Support for ELF format files has been worked on by Mark Eichin of +Cygnus Solutions (original, incomplete implementation), Pete +Hoogenboom at the University of Utah (HPPA mainly), Michael Meissner +of the Open Software Foundation (i386 mainly), and Ken Raeburn of +Cygnus Solutions (sparc, initial 64-bit support). + +Several engineers at Cygnus Solutions have also provided many small +bug fixes and configuration enhancements. + +The initial Alpha support was contributed by Carnegie-Mellon +University. Additional work was done by Ken Raeburn of Cygnus +Solutions. Richard Henderson then rewrote much of the Alpha support. + +Ian Dall updated the support code for the National Semiconductor 32000 +series, and added support for Mach 3 and NetBSD running on the PC532. + +Klaus Kaempf ported the assembler and the binutils to openVMS/Alpha. + +Steve Haworth contributed the support for the Texas Instruction c30 +(tms320c30). + +H.J. Lu has contributed many patches and much testing. + +Alan Modra reworked much of the i386 backend, improving the error +checking, updating the code, and improving the 16 bit support, using +patches from the work of Martynas Kunigelis and H.J. Lu. + +Many others have contributed large or small bugfixes and enhancements. If +you've contributed significant work and are not mentioned on this list, and +want to be, let us know. Some of the history has been lost; we aren't +intentionally leaving anyone out. diff --git a/contrib/binutils-2.14/gas/COPYING b/contrib/binutils-2.14/gas/COPYING new file mode 100644 index 0000000000..c27986e64c --- /dev/null +++ b/contrib/binutils-2.14/gas/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright 1989, 1991, 1997 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/binutils-2.14/gas/MAINTAINERS b/contrib/binutils-2.14/gas/MAINTAINERS new file mode 100644 index 0000000000..d59a3bd7f8 --- /dev/null +++ b/contrib/binutils-2.14/gas/MAINTAINERS @@ -0,0 +1 @@ +See ../binutils/MAINTAINERS diff --git a/contrib/binutils-2.14/gas/NEWS b/contrib/binutils-2.14/gas/NEWS new file mode 100644 index 0000000000..46dfc1321f --- /dev/null +++ b/contrib/binutils-2.14/gas/NEWS @@ -0,0 +1,386 @@ +-*- text -*- + +* Added support for MIPS32 Release 2. + +* Added support for Xtensa architecture. + +* Support for Intel's iWMMXt processor (an ARM variant) added. + +* An assembler test generator has been contributed and an example file that + uses it (gas/testsuite/gas/all/test-gen.c and test-exmaple.c). + +* Support for SH2E added. + +* GASP has now been removed. + +* Support for Texas Instruments TMS320C4x and TMS320C3x series of + DSP's contributed by Michael Hayes and Svein E. Seldal. + +* Support for the Ubicom IP2xxx microcontroller added. + +Changes in 2.13: + +* Support for the Fujitsu FRV architecture added by Red Hat. Models for FR400 + and FR500 included. + +* Support for DLX processor added. + +* GASP has now been deprecated and will be removed in a future release. Use + the macro facilities in GAS instead. + +* GASP now correctly parses floating point numbers. Unless the base is + explicitly specified, they are interpreted as decimal numbers regardless of + the currently specified base. + +Changes in 2.12: + +* Support for Don Knuth's MMIX, by Hans-Peter Nilsson. + +* Support for the OpenRISC 32-bit embedded processor by OpenCores. + +* The ARM assembler now accepts -march=..., -mcpu=... and -mfpu=... for + specifying the target instruction set. The old method of specifying the + target processor has been deprecated, but is still accepted for + compatibility. + +* Support for the VFP floating-point instruction set has been added to + the ARM assembler. + +* New psuedo op: .incbin to include a set of binary data at a given point + in the assembly. Contributed by Anders Norlander. + +* The MIPS assembler now accepts -march/-mtune. -mcpu has been deprecated + but still works for compatability. + +* The MIPS assembler no longer issues a warning by default when it + generates a nop instruction from a macro. The new command line option + -n will turn on the warning. + +Changes in 2.11: + +* Support for PDP-11 and 2.11BSD a.out format, by Lars Brinkhoff. + +* x86 gas now supports the full Pentium4 instruction set. + +* Support for AMD x86-64 architecture, by Jan Hubicka, SuSE Labs. + +* Support for Motorola 68HC11 and 68HC12. + +* Support for Texas Instruments TMS320C54x (tic54x). + +* Support for IA-64. + +* Support for i860, by Jason Eckhardt. + +* Support for CRIS (Axis Communications ETRAX series). + +* x86 gas has a new .arch pseudo op to specify the target CPU architecture. + +* x86 gas -q command line option quietens warnings about register size changes + due to suffix, indirect jmp/call without `*', stand-alone prefixes, and + translating various deprecated floating point instructions. + +Changes in 2.10: + +* Support for the ARM msr instruction was changed to only allow an immediate + operand when altering the flags field. + +* Support for ATMEL AVR. + +* Support for IBM 370 ELF. Somewhat experimental. + +* Support for numbers with suffixes. + +* Added support for breaking to the end of repeat loops. + +* Added support for parallel instruction syntax (DOUBLEBAR_PARALLEL). + +* New .elseif pseudo-op added. + +* New --fatal-warnings option. + +* picoJava architecture support added. + +* Motorola MCore 210 processor support added. + +* A new pseudo-op .intel_syntax has been implemented to allow gas to parse i386 + assembly programs with intel syntax. + +* New pseudo-ops .func,.endfunc to aid in debugging user-written assembler code. + +* Added -gdwarf2 option to generate DWARF 2 debugging information. + +* Full 16-bit mode support for i386. + +* Greatly improved instruction operand checking for i386. This change will + produce errors or warnings on incorrect assembly code that previous versions + of gas accepted. If you get unexpected messages from code that worked with + older versions of gas, please double check the code before reporting a bug. + +* Weak symbol support added for COFF targets. + +* Mitsubishi D30V support added. + +* Texas Instruments c80 (tms320c80) support added. + +* i960 ELF support added. + +* ARM ELF support added. + +Changes in 2.9: + +* Texas Instruments c30 (tms320c30) support added. + +* The assembler now optimizes the exception frame information generated by egcs + and gcc 2.8. The new --traditional-format option disables this optimization. + +* Added --gstabs option to generate stabs debugging information. + +* The -a option takes a new suboption, m (e.g., -alm) to expand macros in a + listing. + +* Added -MD option to print dependencies. + +Changes in 2.8: + +* BeOS support added. + +* MIPS16 support added. + +* Motorola ColdFire 5200 support added (configure for m68k and use -m5200). + +* Alpha/VMS support added. + +* m68k options --base-size-default-16, --base-size-default-32, + --disp-size-default-16, and --disp-size-default-32 added. + +* The alignment directives now take an optional third argument, which is the + maximum number of bytes to skip. If doing the alignment would require + skipping more than the given number of bytes, the alignment is not done at + all. + +* The ELF assembler has a new pseudo-op, .symver, used for symbol versioning. + +* The -a option takes a new suboption, c (e.g., -alc), to skip false + conditionals in listings. + +* Added new pseudo-op, .equiv; it's like .equ, except that it is an error if + the symbol is already defined. + +Changes in 2.7: + +* The PowerPC assembler now allows the use of symbolic register names (r0, + etc.) if -mregnames is used. Symbolic names preceded by a '%' (%r0, etc.) + can be used any time. PowerPC 860 move to/from SPR instructions have been + added. + +* Alpha Linux (ELF) support added. + +* PowerPC ELF support added. + +* m68k Linux (ELF) support added. + +* i960 Hx/Jx support added. + +* i386/PowerPC gnu-win32 support added. + +* SCO ELF support added. For OpenServer 5 targets (i386-unknown-sco3.2v5) the + default is to build COFF-only support. To get a set of tools that generate + ELF (they'll understand both COFF and ELF), you must configure with + target=i386-unknown-sco3.2v5elf. + +* m88k-motorola-sysv3* support added. + +Changes in 2.6: + +* Gas now directly supports macros, without requiring GASP. + +* Gas now has an MRI assembler compatibility mode. Use -M or --mri to select + MRI mode. The pseudo-op ``.mri 1'' will switch into the MRI mode until the + ``.mri 0'' is seen; this can be convenient for inline assembler code. + +* Added --defsym SYM=VALUE option. + +* Added -mips4 support to MIPS assembler. + +* Added PIC support to Solaris and SPARC SunOS 4 assembler. + +Changes in 2.4: + +* Converted this directory to use an autoconf-generated configure script. + +* ARM support, from Richard Earnshaw. + +* Updated VMS support, from Pat Rankin, including considerably improved + debugging support. + +* Support for the control registers in the 68060. + +* Handles (ignores) a new directive ".this_GCC_requires_the_GNU_assembler", to + provide for possible future gcc changes, for targets where gas provides some + features not available in the native assembler. If the native assembler is + used, it should become obvious pretty quickly what the problem is. + +* Usage message is available with "--help". + +* The GNU Assembler Preprocessor (gasp) is included. (Actually, it was in 2.3 + also, but didn't get into the NEWS file.) + +* Weak symbol support for a.out. + +* A bug in the listing code which could cause an infinite loop has been fixed. + Bugs in listings when generating a COFF object file have also been fixed. + +* Initial i386-svr4 PIC implementation from Eric Youngdale, based on code by + Paul Kranenburg. + +* Improved Alpha support. Immediate constants can have a much larger range + now. Support for the 21164 has been contributed by Digital. + +* Updated ns32k (pc532-mach, netbsd532) support from Ian Dall. + +Changes in 2.3: + +* Mach i386 support, by David Mackenzie and Ken Raeburn. + +* RS/6000 and PowerPC support by Ian Taylor. + +* VMS command scripts (make-gas.com, config-gas.com) have been worked on a bit, + based on mail received from various people. The `-h#' option should work + again too. + +* HP-PA work, by Jeff Law. Note, for the PA, gas-2.3 has been designed to work + with gdb-4.12 and gcc-2.6. As gcc-2.6 has not been released yet, a special + version of gcc-2.5.8 has been patched to work with gas-2.3. You can retrieve + this special version of gcc-2.5.8 via anonymous ftp from jaguar.cs.utah.edu + in the "dist" directory. + +* Vax support in gas fixed for BSD, so it builds and seems to run a couple + simple tests okay. I haven't put it through extensive testing. (GNU make is + currently required for BSD 4.3 builds.) + +* Support for the DEC Alpha, running OSF/1 (ECOFF format). The gas support is + based on code donated by CMU, which used an a.out-based format. I'm afraid + the alpha-a.out support is pretty badly mangled, and much of it removed; + making it work will require rewriting it as BFD support for the format anyways. + +* Irix 5 support. + +* The test suites have been fixed up a bit, so that they should work with a + couple different versions of expect and dejagnu. + +* Symbols' values are now handled internally as expressions, permitting more + flexibility in evaluating them in some cases. Some details of relocation + handling have also changed, and simple constant pool management has been + added, to make the Alpha port easier. + +* New option "--statistics" for printing out program run times. This is + intended to be used with the gcc "-Q" option, which prints out times spent in + various phases of compilation. (You should be able to get all of them + printed out with "gcc -Q -Wa,--statistics", I think.) + +Changes in 2.2: + +* RS/6000 AIX and MIPS SGI Irix 5 support has been added. + +* Configurations that are still in development (and therefore are convenient to + have listed in configure.in) still get rejected without a minor change to + gas/Makefile.in, so people not doing development work shouldn't get the + impression that support for such configurations is actually believed to be + reliable. + +* The program name (usually "as") is printed when a fatal error message is + displayed. This should prevent some confusion about the source of occasional + messages about "internal errors". + +* ELF support is falling into place. Support for the 386 should be working. + Support for SPARC Solaris is in. HPPA support from Utah is being integrated. + +* Symbol values are maintained as expressions instead of being immediately + boiled down to add-symbol, sub-symbol, and constant. This permits slightly + more complex calculations involving symbols whose values are not alreadey + known. + +* DBX-style debugging info ("stabs") is now supported for COFF formats. + If any stabs directives are seen in the source, GAS will create two new + sections: a ".stab" and a ".stabstr" section. The format of the .stab + section is nearly identical to the a.out symbol format, and .stabstr is + its string table. For this to be useful, you must have configured GCC + to generate stabs (by defining DBX_DEBUGGING_INFO), and must have a GDB + that can use the stab sections (4.11 or later). + +* LynxOS, on i386 and m68k platforms, is now supported. SPARC LynxOS + support is in progress. + +Changes in 2.1: + +* Several small fixes for i386-aix (PS/2) support from Minh Tran-Le have been + incorporated, but not well tested yet. + +* Altered the opcode table split for m68k; it should require less VM to compile + with gcc now. + +* Some minor adjustments to add (Convergent Technologies') Miniframe support, + suggested by Ronald Cole. + +* HPPA support (running OSF only, not HPUX) has been contributed by Utah. This + includes improved ELF support, which I've started adapting for SPARC Solaris + 2.x. Integration isn't completely, so it probably won't work. + +* HP9000/300 support, donated by HP, has been merged in. + +* Ian Taylor has finished the MIPS ECOFF (Ultrix, Irix) support. + +* Better error messages for unsupported configurations (e.g., hppa-hpux). + +* Test suite framework is starting to become reasonable. + +Changes in 2.0: + +* Mostly bug fixes. + +* Some more merging of BFD and ELF code, but ELF still doesn't work. + +Changes in 1.94: + +* BFD merge is partly done. Adventurous souls may try giving configure the + "--with-bfd-assembler" option. Currently, ELF format requires it, a.out + format accepts it; SPARC CPU accepts it. It's the default only for OS "elf" + or "solaris". (ELF isn't really supported yet. It needs work. I've got + some code from Utah for HP-PA ELF, and from DG for m88k ELF, but they're not + fully merged yet.) + +* The 68K opcode table has been split in half. It should now compile under gcc + without consuming ridiculous amounts of memory. + +* A couple data structures have been reduced in size. This should result in + saving a little bit of space at runtime. + +* Support for MIPS, from OSF and Ralph Campbell, has been merged in. The OSF + code provided ROSE format support, which I haven't merged in yet. (I can + make it available, if anyone wants to try it out.) Ralph's code, for BSD + 4.4, supports a.out format. We don't have ECOFF support in just yet; it's + coming. + +* Support for the Hitachi H8/500 has been added. + +* VMS host and target support should be working now, thanks chiefly to Eric + Youngdale. + +Changes in 1.93.01: + +* For m68k, support for more processors has been added: 68040, CPU32, 68851. + +* For i386, .align is now power-of-two; was number-of-bytes. + +* For m68k, "%" is now accepted before register names. For COFF format, which + doesn't use underscore prefixes for C labels, it is required, so variable "a0" + can be distinguished from the register. + +* Last public release was 1.38. Lots of configuration changes since then, lots + of new CPUs and formats, lots of bugs fixed. + + +Local variables: +fill-column: 79 +End: diff --git a/contrib/binutils-2.14/gas/README b/contrib/binutils-2.14/gas/README new file mode 100644 index 0000000000..319fda956f --- /dev/null +++ b/contrib/binutils-2.14/gas/README @@ -0,0 +1,278 @@ + README for GAS + +A number of things have changed since version 1 and the wonderful +world of gas looks very different. There's still a lot of irrelevant +garbage lying around that will be cleaned up in time. Documentation +is scarce, as are logs of the changes made since the last gas release. +My apologies, and I'll try to get something useful. + +Unpacking and Installation - Summary +==================================== + +See ../binutils/README. + +To build just the assembler, make the target all-gas. + +Documentation +============= + +The GAS release includes texinfo source for its manual, which can be processed +into `info' or `dvi' forms. + +The DVI form is suitable for printing or displaying; the commands for doing +this vary from system to system. On many systems, `lpr -d' will print a DVI +file. On others, you may need to run a program such as `dvips' to convert the +DVI file into a form your system can print. + +If you wish to build the DVI file, you will need to have TeX installed on your +system. You can rebuild it by typing: + + cd gas/doc + make as.dvi + +The Info form is viewable with the GNU Emacs `info' subsystem, or the +stand-alone `info' program, available as part of the GNU Texinfo distribution. +To build the info files, you will need the `makeinfo' program. Type: + + cd gas/doc + make info + +Specifying names for hosts and targets +====================================== + + The specifications used for hosts and targets in the `configure' +script are based on a three-part naming scheme, but some short +predefined aliases are also supported. The full naming scheme encodes +three pieces of information in the following pattern: + + ARCHITECTURE-VENDOR-OS + + For example, you can use the alias `sun4' as a HOST argument or in a +`--target=TARGET' option. The equivalent full name is +`sparc-sun-sunos4'. + + The `configure' script accompanying GAS does not provide any query +facility to list all supported host and target names or aliases. +`configure' calls the Bourne shell script `config.sub' to map +abbreviations to full names; you can read the script, if you wish, or +you can use it to test your guesses on abbreviations--for example: + + % sh config.sub sun4 + sparc-sun-sunos411 + % sh config.sub sun3 + m68k-sun-sunos411 + % sh config.sub decstation + mips-dec-ultrix42 + % sh config.sub hp300bsd + m68k-hp-bsd + % sh config.sub i386v + i386-unknown-sysv + % sh config.sub i786v + Invalid configuration `i786v': machine `i786v' not recognized + + +`configure' options +=================== + + Here is a summary of the `configure' options and arguments that are +most often useful for building GAS. `configure' also has several other +options not listed here. + + configure [--help] + [--prefix=DIR] + [--srcdir=PATH] + [--host=HOST] + [--target=TARGET] + [--with-OPTION] + [--enable-OPTION] + +You may introduce options with a single `-' rather than `--' if you +prefer; but you may abbreviate option names if you use `--'. + +`--help' + Print a summary of the options to `configure', and exit. + +`-prefix=DIR' + Configure the source to install programs and files under directory + `DIR'. + +`--srcdir=PATH' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--host=HOST' + Configure GAS to run on the specified HOST. Normally the + configure script can figure this out automatically. + + There is no convenient way to generate a list of all available + hosts. + +`--target=TARGET' + Configure GAS for cross-assembling programs for the specified + TARGET. Without this option, GAS is configured to assemble .o files + that run on the same machine (HOST) as GAS itself. + + There is no convenient way to generate a list of all available + targets. + +`--enable-OPTION' + These flags tell the program or library being configured to + configure itself differently from the default for the specified + host/target combination. See below for a list of `--enable' + options recognized in the gas distribution. + +`configure' accepts other options, for compatibility with configuring +other GNU tools recursively; but these are the only options that affect +GAS or its supporting libraries. + +The `--enable' options recognized by software in the gas distribution are: + +`--enable-targets=...' + This causes one or more specified configurations to be added to those for + which BFD support is compiled. Currently gas cannot use any format other + than its compiled-in default, so this option is not very useful. + +`--enable-bfd-assembler' + This causes the assembler to use the new code being merged into it to use + BFD data structures internally, and use BFD for writing object files. + For most targets, this isn't supported yet. For most targets where it has + been done, it's already the default. So generally you won't need to use + this option. + +Supported platforms +=================== + +At this point I believe gas to be ANSI only code for most target cpu's. That +is, there should be relatively few, if any host system dependencies. So +porting (as a cross-assembler) to hosts not yet supported should be fairly +easy. Porting to a new target shouldn't be too tough if it's a variant of one +already supported. + +Native assembling should work on: + + sun3 + sun4 + 386bsd + bsd/386 + delta (m68k-sysv from Motorola) + delta88 (m88k-sysv from Motorola) + GNU/linux + m68k hpux 8.0 (hpux 7.0 may be a problem) + vax bsd, ultrix, vms + hp9000s300 + decstation + irix 4 + irix 5 + miniframe (m68k-sysv from Convergent Technologies) + i386-aix (ps/2) + hppa (hpux 4.3bsd, osf1) + AIX + unixware + sco 3.2v4.2 + sco openserver 5.0 (a.k.a. 3.2v5.0 ) + sparc solaris + ns32k (netbsd, lites) + +I believe that gas as a cross-assembler can currently be targeted for +most of the above hosts, plus + + arm + decstation-bsd (a.out format, to be used in BSD 4.4) + ebmon29k + go32 (DOS on i386, with DJGPP -- old a.out version) + H8/300, H8/500 (Hitachi) + i386-aix (ps/2) + i960-coff + mips ecoff (decstation-ultrix, iris, mips magnum, mips-idt-ecoff) + Mitsubishi d10v and d30v + nindy960 + powerpc EABI + SH (Hitachi) + sco386 + TI tic30 and tic80 + vax bsd or ultrix? + vms + vxworks68k + vxworks960 + z8000 (Zilog) + +MIPS ECOFF support has been added, but GAS will not run a C-style +preprocessor. If you want that, rename your file to have a ".S" suffix, and +run gcc on it. Or run "gcc -xassembler-with-cpp foo.s". + +Support for ELF should work now for sparc, hppa, i386, alpha, m68k, +MIPS, powerpc. + +Support for sequent (ns32k), tahoe, i860 may be suffering from bitrot. + +If you try out gas on some host or target not listed above, please let me know +the results, so I can update the list. + +Compiler Support Hacks +====================== + +On a few targets, the assembler has been modified to support a feature +that is potentially useful when assembling compiler output, but which +may confuse assembly language programmers. If assembler encounters a +.word pseudo-op of the form symbol1-symbol2 (the difference of two +symbols), and the difference of those two symbols will not fit in 16 +bits, the assembler will create a branch around a long jump to +symbol1, and insert this into the output directly before the next +label: The .word will (instead of containing garbage, or giving an +error message) contain (the address of the long jump)-symbol2. This +allows the assembler to assemble jump tables that jump to locations +very far away into code that works properly. If the next label is +more than 32K away from the .word, you lose (silently); RMS claims +this will never happen. If the -K option is given, you will get a +warning message when this happens. + + +REPORTING BUGS IN GAS +===================== + +Bugs in gas should be reported to: + + bug-gnu-utils@gnu.org. + +They may be cross-posted to gcc-bugs@gnu.org if they affect the use of +gas with gcc. They should not be reported just to gcc-bugs, since not +all of the maintainers read that list. + +If you report a bug in GAS, please remember to include: + +A description of exactly what went wrong, and exactly what should have +happened instead. + +The type of machine (VAX, 68020, etc) and operating system (BSD, SunOS, DYNIX, +VMS, etc) GAS was running on. + +The configuration name(s) given to the "configure" script. The +"config.status" file should have this information. + +The options given to GAS at run time. + +The actual input file that caused the problem. + +It is silly to report a bug in GAS without including an input file for GAS. +Don't ask us to generate the file just because you made it from files you +think we have access to. + +1. You might be mistaken. +2. It might take us a lot of time to install things to regenerate that file. +3. We might get a different file from the one you got, and might not see any + bug. + +To save us these delays and uncertainties, always send the input file for the +program that failed. A smaller test case that demonstrates the problem is of +course preferable, but be sure it is a complete input file, and that it really +does demonstrate the problem; but if paring it down would cause large delays +in filing the bug report, don't bother. + +If the input file is very large, and you are on the internet, you may want to +make it available for anonymous FTP instead of mailing it. If you do, include +instructions for FTP'ing it in your bug report. + +If you expect to be contributing a large number of test cases, it would be +helpful if you would look at the test suite included in the release (based on +the Deja Gnu testing framework, available from the usual ftp sites) and write +test cases to fit into that framework. This is certainly not required. diff --git a/contrib/binutils-2.14/gas/app.c b/contrib/binutils-2.14/gas/app.c new file mode 100644 index 0000000000..f752962bcd --- /dev/null +++ b/contrib/binutils-2.14/gas/app.c @@ -0,0 +1,1348 @@ +/* This is the Assembler Pre-Processor + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Modified by Allen Wirfs-Brock, Instantiations Inc 2/90. */ +/* App, the assembler pre-processor. This pre-processor strips out excess + spaces, turns single-quoted characters into a decimal constant, and turns + # into a .line \n.file + pair. This needs better error-handling. */ + +#include +#include "as.h" /* For BAD_CASE() only. */ + +#if (__STDC__ != 1) +#ifndef const +#define const /* empty */ +#endif +#endif + +#ifdef TC_M68K +/* Whether we are scrubbing in m68k MRI mode. This is different from + flag_m68k_mri, because the two flags will be affected by the .mri + pseudo-op at different times. */ +static int scrub_m68k_mri; + +/* The pseudo-op which switches in and out of MRI mode. See the + comment in do_scrub_chars. */ +static const char mri_pseudo[] = ".mri 0"; +#else +#define scrub_m68k_mri 0 +#endif + +#if defined TC_ARM && defined OBJ_ELF +/* The pseudo-op for which we need to special-case `@' characters. + See the comment in do_scrub_chars. */ +static const char symver_pseudo[] = ".symver"; +static const char * symver_state; +#endif + +static char lex[256]; +static const char symbol_chars[] = +"$._ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + +#define LEX_IS_SYMBOL_COMPONENT 1 +#define LEX_IS_WHITESPACE 2 +#define LEX_IS_LINE_SEPARATOR 3 +#define LEX_IS_COMMENT_START 4 +#define LEX_IS_LINE_COMMENT_START 5 +#define LEX_IS_TWOCHAR_COMMENT_1ST 6 +#define LEX_IS_STRINGQUOTE 8 +#define LEX_IS_COLON 9 +#define LEX_IS_NEWLINE 10 +#define LEX_IS_ONECHAR_QUOTE 11 +#ifdef TC_V850 +#define LEX_IS_DOUBLEDASH_1ST 12 +#endif +#ifdef TC_M32R +#define DOUBLEBAR_PARALLEL +#endif +#ifdef DOUBLEBAR_PARALLEL +#define LEX_IS_DOUBLEBAR_1ST 13 +#endif +#define LEX_IS_PARALLEL_SEPARATOR 14 +#define IS_SYMBOL_COMPONENT(c) (lex[c] == LEX_IS_SYMBOL_COMPONENT) +#define IS_WHITESPACE(c) (lex[c] == LEX_IS_WHITESPACE) +#define IS_LINE_SEPARATOR(c) (lex[c] == LEX_IS_LINE_SEPARATOR) +#define IS_PARALLEL_SEPARATOR(c) (lex[c] == LEX_IS_PARALLEL_SEPARATOR) +#define IS_COMMENT(c) (lex[c] == LEX_IS_COMMENT_START) +#define IS_LINE_COMMENT(c) (lex[c] == LEX_IS_LINE_COMMENT_START) +#define IS_NEWLINE(c) (lex[c] == LEX_IS_NEWLINE) + +static int process_escape PARAMS ((int)); + +/* FIXME-soon: The entire lexer/parser thingy should be + built statically at compile time rather than dynamically + each and every time the assembler is run. xoxorich. */ + +void +do_scrub_begin (m68k_mri) + int m68k_mri ATTRIBUTE_UNUSED; +{ + const char *p; + int c; + + lex[' '] = LEX_IS_WHITESPACE; + lex['\t'] = LEX_IS_WHITESPACE; + lex['\r'] = LEX_IS_WHITESPACE; + lex['\n'] = LEX_IS_NEWLINE; + lex[':'] = LEX_IS_COLON; + +#ifdef TC_M68K + scrub_m68k_mri = m68k_mri; + + if (! m68k_mri) +#endif + { + lex['"'] = LEX_IS_STRINGQUOTE; + +#if ! defined (TC_HPPA) && ! defined (TC_I370) + /* I370 uses single-quotes to delimit integer, float constants. */ + lex['\''] = LEX_IS_ONECHAR_QUOTE; +#endif + +#ifdef SINGLE_QUOTE_STRINGS + lex['\''] = LEX_IS_STRINGQUOTE; +#endif + } + + /* Note: if any other character can be LEX_IS_STRINGQUOTE, the loop + in state 5 of do_scrub_chars must be changed. */ + + /* Note that these override the previous defaults, e.g. if ';' is a + comment char, then it isn't a line separator. */ + for (p = symbol_chars; *p; ++p) + lex[(unsigned char) *p] = LEX_IS_SYMBOL_COMPONENT; + + for (c = 128; c < 256; ++c) + lex[c] = LEX_IS_SYMBOL_COMPONENT; + +#ifdef tc_symbol_chars + /* This macro permits the processor to specify all characters which + may appears in an operand. This will prevent the scrubber from + discarding meaningful whitespace in certain cases. The i386 + backend uses this to support prefixes, which can confuse the + scrubber as to whether it is parsing operands or opcodes. */ + for (p = tc_symbol_chars; *p; ++p) + lex[(unsigned char) *p] = LEX_IS_SYMBOL_COMPONENT; +#endif + + /* The m68k backend wants to be able to change comment_chars. */ +#ifndef tc_comment_chars +#define tc_comment_chars comment_chars +#endif + for (p = tc_comment_chars; *p; p++) + lex[(unsigned char) *p] = LEX_IS_COMMENT_START; + + for (p = line_comment_chars; *p; p++) + lex[(unsigned char) *p] = LEX_IS_LINE_COMMENT_START; + + for (p = line_separator_chars; *p; p++) + lex[(unsigned char) *p] = LEX_IS_LINE_SEPARATOR; + +#ifdef tc_parallel_separator_chars + /* This macro permits the processor to specify all characters which + separate parallel insns on the same line. */ + for (p = tc_parallel_separator_chars; *p; p++) + lex[(unsigned char) *p] = LEX_IS_PARALLEL_SEPARATOR; +#endif + + /* Only allow slash-star comments if slash is not in use. + FIXME: This isn't right. We should always permit them. */ + if (lex['/'] == 0) + lex['/'] = LEX_IS_TWOCHAR_COMMENT_1ST; + +#ifdef TC_M68K + if (m68k_mri) + { + lex['\''] = LEX_IS_STRINGQUOTE; + lex[';'] = LEX_IS_COMMENT_START; + lex['*'] = LEX_IS_LINE_COMMENT_START; + /* The MRI documentation says '!' is LEX_IS_COMMENT_START, but + then it can't be used in an expression. */ + lex['!'] = LEX_IS_LINE_COMMENT_START; + } +#endif + +#ifdef TC_V850 + lex['-'] = LEX_IS_DOUBLEDASH_1ST; +#endif +#ifdef DOUBLEBAR_PARALLEL + lex['|'] = LEX_IS_DOUBLEBAR_1ST; +#endif +#ifdef TC_D30V + /* Must do this is we want VLIW instruction with "->" or "<-". */ + lex['-'] = LEX_IS_SYMBOL_COMPONENT; +#endif +} + +/* Saved state of the scrubber. */ +static int state; +static int old_state; +static char *out_string; +static char out_buf[20]; +static int add_newlines; +static char *saved_input; +static int saved_input_len; +static char input_buffer[32 * 1024]; +static const char *mri_state; +static char mri_last_ch; + +/* Data structure for saving the state of app across #include's. Note that + app is called asynchronously to the parsing of the .include's, so our + state at the time .include is interpreted is completely unrelated. + That's why we have to save it all. */ + +struct app_save +{ + int state; + int old_state; + char * out_string; + char out_buf[sizeof (out_buf)]; + int add_newlines; + char * saved_input; + int saved_input_len; +#ifdef TC_M68K + int scrub_m68k_mri; +#endif + const char * mri_state; + char mri_last_ch; +#if defined TC_ARM && defined OBJ_ELF + const char * symver_state; +#endif +}; + +char * +app_push () +{ + register struct app_save *saved; + + saved = (struct app_save *) xmalloc (sizeof (*saved)); + saved->state = state; + saved->old_state = old_state; + saved->out_string = out_string; + memcpy (saved->out_buf, out_buf, sizeof (out_buf)); + saved->add_newlines = add_newlines; + if (saved_input == NULL) + saved->saved_input = NULL; + else + { + saved->saved_input = xmalloc (saved_input_len); + memcpy (saved->saved_input, saved_input, saved_input_len); + saved->saved_input_len = saved_input_len; + } +#ifdef TC_M68K + saved->scrub_m68k_mri = scrub_m68k_mri; +#endif + saved->mri_state = mri_state; + saved->mri_last_ch = mri_last_ch; +#if defined TC_ARM && defined OBJ_ELF + saved->symver_state = symver_state; +#endif + + /* do_scrub_begin() is not useful, just wastes time. */ + + state = 0; + saved_input = NULL; + + return (char *) saved; +} + +void +app_pop (arg) + char *arg; +{ + register struct app_save *saved = (struct app_save *) arg; + + /* There is no do_scrub_end (). */ + state = saved->state; + old_state = saved->old_state; + out_string = saved->out_string; + memcpy (out_buf, saved->out_buf, sizeof (out_buf)); + add_newlines = saved->add_newlines; + if (saved->saved_input == NULL) + saved_input = NULL; + else + { + assert (saved->saved_input_len <= (int) (sizeof input_buffer)); + memcpy (input_buffer, saved->saved_input, saved->saved_input_len); + saved_input = input_buffer; + saved_input_len = saved->saved_input_len; + free (saved->saved_input); + } +#ifdef TC_M68K + scrub_m68k_mri = saved->scrub_m68k_mri; +#endif + mri_state = saved->mri_state; + mri_last_ch = saved->mri_last_ch; +#if defined TC_ARM && defined OBJ_ELF + symver_state = saved->symver_state; +#endif + + free (arg); +} + +/* @@ This assumes that \n &c are the same on host and target. This is not + necessarily true. */ + +static int +process_escape (ch) + int ch; +{ + switch (ch) + { + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case '\'': + return '\''; + case '"': + return '\"'; + default: + return ch; + } +} + +/* This function is called to process input characters. The GET + parameter is used to retrieve more input characters. GET should + set its parameter to point to a buffer, and return the length of + the buffer; it should return 0 at end of file. The scrubbed output + characters are put into the buffer starting at TOSTART; the TOSTART + buffer is TOLEN bytes in length. The function returns the number + of scrubbed characters put into TOSTART. This will be TOLEN unless + end of file was seen. This function is arranged as a state + machine, and saves its state so that it may return at any point. + This is the way the old code used to work. */ + +int +do_scrub_chars (get, tostart, tolen) + int (*get) PARAMS ((char *, int)); + char *tostart; + int tolen; +{ + char *to = tostart; + char *toend = tostart + tolen; + char *from; + char *fromend; + int fromlen; + register int ch, ch2 = 0; + + /*State 0: beginning of normal line + 1: After first whitespace on line (flush more white) + 2: After first non-white (opcode) on line (keep 1white) + 3: after second white on line (into operands) (flush white) + 4: after putting out a .line, put out digits + 5: parsing a string, then go to old-state + 6: putting out \ escape in a "d string. + 7: After putting out a .appfile, put out string. + 8: After putting out a .appfile string, flush until newline. + 9: After seeing symbol char in state 3 (keep 1white after symchar) + 10: After seeing whitespace in state 9 (keep white before symchar) + 11: After seeing a symbol character in state 0 (eg a label definition) + -1: output string in out_string and go to the state in old_state + -2: flush text until a '*' '/' is seen, then go to state old_state +#ifdef TC_V850 + 12: After seeing a dash, looking for a second dash as a start + of comment. +#endif +#ifdef DOUBLEBAR_PARALLEL + 13: After seeing a vertical bar, looking for a second + vertical bar as a parallel expression separator. +#endif + */ + + /* I added states 9 and 10 because the MIPS ECOFF assembler uses + constructs like ``.loc 1 20''. This was turning into ``.loc + 120''. States 9 and 10 ensure that a space is never dropped in + between characters which could appear in an identifier. Ian + Taylor, ian@cygnus.com. + + I added state 11 so that something like "Lfoo add %r25,%r26,%r27" works + correctly on the PA (and any other target where colons are optional). + Jeff Law, law@cs.utah.edu. + + I added state 13 so that something like "cmp r1, r2 || trap #1" does not + get squashed into "cmp r1,r2||trap#1", with the all important space + between the 'trap' and the '#1' being eliminated. nickc@cygnus.com */ + + /* This macro gets the next input character. */ + +#define GET() \ + (from < fromend \ + ? * (unsigned char *) (from++) \ + : (saved_input = NULL, \ + fromlen = (*get) (input_buffer, sizeof input_buffer), \ + from = input_buffer, \ + fromend = from + fromlen, \ + (fromlen == 0 \ + ? EOF \ + : * (unsigned char *) (from++)))) + + /* This macro pushes a character back on the input stream. */ + +#define UNGET(uch) (*--from = (uch)) + + /* This macro puts a character into the output buffer. If this + character fills the output buffer, this macro jumps to the label + TOFULL. We use this rather ugly approach because we need to + handle two different termination conditions: EOF on the input + stream, and a full output buffer. It would be simpler if we + always read in the entire input stream before processing it, but + I don't want to make such a significant change to the assembler's + memory usage. */ + +#define PUT(pch) \ + do \ + { \ + *to++ = (pch); \ + if (to >= toend) \ + goto tofull; \ + } \ + while (0) + + if (saved_input != NULL) + { + from = saved_input; + fromend = from + saved_input_len; + } + else + { + fromlen = (*get) (input_buffer, sizeof input_buffer); + if (fromlen == 0) + return 0; + from = input_buffer; + fromend = from + fromlen; + } + + while (1) + { + /* The cases in this switch end with continue, in order to + branch back to the top of this while loop and generate the + next output character in the appropriate state. */ + switch (state) + { + case -1: + ch = *out_string++; + if (*out_string == '\0') + { + state = old_state; + old_state = 3; + } + PUT (ch); + continue; + + case -2: + for (;;) + { + do + { + ch = GET (); + + if (ch == EOF) + { + as_warn (_("end of file in comment")); + goto fromeof; + } + + if (ch == '\n') + PUT ('\n'); + } + while (ch != '*'); + + while ((ch = GET ()) == '*') + ; + + if (ch == EOF) + { + as_warn (_("end of file in comment")); + goto fromeof; + } + + if (ch == '/') + break; + + UNGET (ch); + } + + state = old_state; + UNGET (' '); + continue; + + case 4: + ch = GET (); + if (ch == EOF) + goto fromeof; + else if (ch >= '0' && ch <= '9') + PUT (ch); + else + { + while (ch != EOF && IS_WHITESPACE (ch)) + ch = GET (); + if (ch == '"') + { + UNGET (ch); + if (scrub_m68k_mri) + out_string = "\n\tappfile "; + else + out_string = "\n\t.appfile "; + old_state = 7; + state = -1; + PUT (*out_string++); + } + else + { + while (ch != EOF && ch != '\n') + ch = GET (); + state = 0; + PUT (ch); + } + } + continue; + + case 5: + /* We are going to copy everything up to a quote character, + with special handling for a backslash. We try to + optimize the copying in the simple case without using the + GET and PUT macros. */ + { + char *s; + int len; + + for (s = from; s < fromend; s++) + { + ch = *s; + /* This condition must be changed if the type of any + other character can be LEX_IS_STRINGQUOTE. */ + if (ch == '\\' + || ch == '"' + || ch == '\'' + || ch == '\n') + break; + } + len = s - from; + if (len > toend - to) + len = toend - to; + if (len > 0) + { + memcpy (to, from, len); + to += len; + from += len; + } + } + + ch = GET (); + if (ch == EOF) + { + as_warn (_("end of file in string; inserted '\"'")); + state = old_state; + UNGET ('\n'); + PUT ('"'); + } + else if (lex[ch] == LEX_IS_STRINGQUOTE) + { + state = old_state; + PUT (ch); + } +#ifndef NO_STRING_ESCAPES + else if (ch == '\\') + { + state = 6; + PUT (ch); + } +#endif + else if (scrub_m68k_mri && ch == '\n') + { + /* Just quietly terminate the string. This permits lines like + bne label loop if we haven't reach end yet. */ + state = old_state; + UNGET (ch); + PUT ('\''); + } + else + { + PUT (ch); + } + continue; + + case 6: + state = 5; + ch = GET (); + switch (ch) + { + /* Handle strings broken across lines, by turning '\n' into + '\\' and 'n'. */ + case '\n': + UNGET ('n'); + add_newlines++; + PUT ('\\'); + continue; + + case EOF: + as_warn (_("end of file in string; '\"' inserted")); + PUT ('"'); + continue; + + case '"': + case '\\': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': + case 'x': + case 'X': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + break; + + default: +#ifdef ONLY_STANDARD_ESCAPES + as_warn (_("unknown escape '\\%c' in string; ignored"), ch); +#endif + break; + } + PUT (ch); + continue; + + case 7: + ch = GET (); + state = 5; + old_state = 8; + if (ch == EOF) + goto fromeof; + PUT (ch); + continue; + + case 8: + do + ch = GET (); + while (ch != '\n' && ch != EOF); + if (ch == EOF) + goto fromeof; + state = 0; + PUT (ch); + continue; + +#ifdef DOUBLEBAR_PARALLEL + case 13: + ch = GET (); + if (ch != '|') + abort (); + + /* Reset back to state 1 and pretend that we are parsing a + line from just after the first white space. */ + state = 1; + PUT ('|'); + continue; +#endif + } + + /* OK, we are somewhere in states 0 through 4 or 9 through 11. */ + + /* flushchar: */ + ch = GET (); + + recycle: + +#if defined TC_ARM && defined OBJ_ELF + /* We need to watch out for .symver directives. See the comment later + in this function. */ + if (symver_state == NULL) + { + if ((state == 0 || state == 1) && ch == symver_pseudo[0]) + symver_state = symver_pseudo + 1; + } + else + { + /* We advance to the next state if we find the right + character. */ + if (ch != '\0' && (*symver_state == ch)) + ++symver_state; + else if (*symver_state != '\0') + /* We did not get the expected character, or we didn't + get a valid terminating character after seeing the + entire pseudo-op, so we must go back to the beginning. */ + symver_state = NULL; + else + { + /* We've read the entire pseudo-op. If this is the end + of the line, go back to the beginning. */ + if (IS_NEWLINE (ch)) + symver_state = NULL; + } + } +#endif /* TC_ARM && OBJ_ELF */ + +#ifdef TC_M68K + /* We want to have pseudo-ops which control whether we are in + MRI mode or not. Unfortunately, since m68k MRI mode affects + the scrubber, that means that we need a special purpose + recognizer here. */ + if (mri_state == NULL) + { + if ((state == 0 || state == 1) + && ch == mri_pseudo[0]) + mri_state = mri_pseudo + 1; + } + else + { + /* We advance to the next state if we find the right + character, or if we need a space character and we get any + whitespace character, or if we need a '0' and we get a + '1' (this is so that we only need one state to handle + ``.mri 0'' and ``.mri 1''). */ + if (ch != '\0' + && (*mri_state == ch + || (*mri_state == ' ' + && lex[ch] == LEX_IS_WHITESPACE) + || (*mri_state == '0' + && ch == '1'))) + { + mri_last_ch = ch; + ++mri_state; + } + else if (*mri_state != '\0' + || (lex[ch] != LEX_IS_WHITESPACE + && lex[ch] != LEX_IS_NEWLINE)) + { + /* We did not get the expected character, or we didn't + get a valid terminating character after seeing the + entire pseudo-op, so we must go back to the + beginning. */ + mri_state = NULL; + } + else + { + /* We've read the entire pseudo-op. mips_last_ch is + either '0' or '1' indicating whether to enter or + leave MRI mode. */ + do_scrub_begin (mri_last_ch == '1'); + mri_state = NULL; + + /* We continue handling the character as usual. The + main gas reader must also handle the .mri pseudo-op + to control expression parsing and the like. */ + } + } +#endif + + if (ch == EOF) + { + if (state != 0) + { + as_warn (_("end of file not at end of a line; newline inserted")); + state = 0; + PUT ('\n'); + } + goto fromeof; + } + + switch (lex[ch]) + { + case LEX_IS_WHITESPACE: + do + { + ch = GET (); + } + while (ch != EOF && IS_WHITESPACE (ch)); + if (ch == EOF) + goto fromeof; + + if (state == 0) + { + /* Preserve a single whitespace character at the + beginning of a line. */ + state = 1; + UNGET (ch); + PUT (' '); + break; + } + +#ifdef KEEP_WHITE_AROUND_COLON + if (lex[ch] == LEX_IS_COLON) + { + /* Only keep this white if there's no white *after* the + colon. */ + ch2 = GET (); + UNGET (ch2); + if (!IS_WHITESPACE (ch2)) + { + state = 9; + UNGET (ch); + PUT (' '); + break; + } + } +#endif + if (IS_COMMENT (ch) + || ch == '/' + || IS_LINE_SEPARATOR (ch) + || IS_PARALLEL_SEPARATOR (ch)) + { + if (scrub_m68k_mri) + { + /* In MRI mode, we keep these spaces. */ + UNGET (ch); + PUT (' '); + break; + } + goto recycle; + } + + /* If we're in state 2 or 11, we've seen a non-white + character followed by whitespace. If the next character + is ':', this is whitespace after a label name which we + normally must ignore. In MRI mode, though, spaces are + not permitted between the label and the colon. */ + if ((state == 2 || state == 11) + && lex[ch] == LEX_IS_COLON + && ! scrub_m68k_mri) + { + state = 1; + PUT (ch); + break; + } + + switch (state) + { + case 0: + state++; + goto recycle; /* Punted leading sp */ + case 1: + /* We can arrive here if we leave a leading whitespace + character at the beginning of a line. */ + goto recycle; + case 2: + state = 3; + if (to + 1 < toend) + { + /* Optimize common case by skipping UNGET/GET. */ + PUT (' '); /* Sp after opco */ + goto recycle; + } + UNGET (ch); + PUT (' '); + break; + case 3: + if (scrub_m68k_mri) + { + /* In MRI mode, we keep these spaces. */ + UNGET (ch); + PUT (' '); + break; + } + goto recycle; /* Sp in operands */ + case 9: + case 10: + if (scrub_m68k_mri) + { + /* In MRI mode, we keep these spaces. */ + state = 3; + UNGET (ch); + PUT (' '); + break; + } + state = 10; /* Sp after symbol char */ + goto recycle; + case 11: + if (LABELS_WITHOUT_COLONS || flag_m68k_mri) + state = 1; + else + { + /* We know that ch is not ':', since we tested that + case above. Therefore this is not a label, so it + must be the opcode, and we've just seen the + whitespace after it. */ + state = 3; + } + UNGET (ch); + PUT (' '); /* Sp after label definition. */ + break; + default: + BAD_CASE (state); + } + break; + + case LEX_IS_TWOCHAR_COMMENT_1ST: + ch2 = GET (); + if (ch2 == '*') + { + for (;;) + { + do + { + ch2 = GET (); + if (ch2 != EOF && IS_NEWLINE (ch2)) + add_newlines++; + } + while (ch2 != EOF && ch2 != '*'); + + while (ch2 == '*') + ch2 = GET (); + + if (ch2 == EOF || ch2 == '/') + break; + + /* This UNGET will ensure that we count newlines + correctly. */ + UNGET (ch2); + } + + if (ch2 == EOF) + as_warn (_("end of file in multiline comment")); + + ch = ' '; + goto recycle; + } +#ifdef DOUBLESLASH_LINE_COMMENTS + else if (ch2 == '/') + { + do + { + ch = GET (); + } + while (ch != EOF && !IS_NEWLINE (ch)); + if (ch == EOF) + as_warn ("end of file in comment; newline inserted"); + state = 0; + PUT ('\n'); + break; + } +#endif + else + { + if (ch2 != EOF) + UNGET (ch2); + if (state == 9 || state == 10) + state = 3; + PUT (ch); + } + break; + + case LEX_IS_STRINGQUOTE: + if (state == 10) + { + /* Preserve the whitespace in foo "bar". */ + UNGET (ch); + state = 3; + PUT (' '); + + /* PUT didn't jump out. We could just break, but we + know what will happen, so optimize a bit. */ + ch = GET (); + old_state = 3; + } + else if (state == 9) + old_state = 3; + else + old_state = state; + state = 5; + PUT (ch); + break; + +#ifndef IEEE_STYLE + case LEX_IS_ONECHAR_QUOTE: + if (state == 10) + { + /* Preserve the whitespace in foo 'b'. */ + UNGET (ch); + state = 3; + PUT (' '); + break; + } + ch = GET (); + if (ch == EOF) + { + as_warn (_("end of file after a one-character quote; \\0 inserted")); + ch = 0; + } + if (ch == '\\') + { + ch = GET (); + if (ch == EOF) + { + as_warn (_("end of file in escape character")); + ch = '\\'; + } + else + ch = process_escape (ch); + } + sprintf (out_buf, "%d", (int) (unsigned char) ch); + + /* None of these 'x constants for us. We want 'x'. */ + if ((ch = GET ()) != '\'') + { +#ifdef REQUIRE_CHAR_CLOSE_QUOTE + as_warn (_("missing close quote; (assumed)")); +#else + if (ch != EOF) + UNGET (ch); +#endif + } + if (strlen (out_buf) == 1) + { + PUT (out_buf[0]); + break; + } + if (state == 9) + old_state = 3; + else + old_state = state; + state = -1; + out_string = out_buf; + PUT (*out_string++); + break; +#endif + + case LEX_IS_COLON: +#ifdef KEEP_WHITE_AROUND_COLON + state = 9; +#else + if (state == 9 || state == 10) + state = 3; + else if (state != 3) + state = 1; +#endif + PUT (ch); + break; + + case LEX_IS_NEWLINE: + /* Roll out a bunch of newlines from inside comments, etc. */ + if (add_newlines) + { + --add_newlines; + UNGET (ch); + } + /* Fall through. */ + + case LEX_IS_LINE_SEPARATOR: + state = 0; + PUT (ch); + break; + + case LEX_IS_PARALLEL_SEPARATOR: + state = 1; + PUT (ch); + break; + +#ifdef TC_V850 + case LEX_IS_DOUBLEDASH_1ST: + ch2 = GET (); + if (ch2 != '-') + { + UNGET (ch2); + goto de_fault; + } + /* Read and skip to end of line. */ + do + { + ch = GET (); + } + while (ch != EOF && ch != '\n'); + + if (ch == EOF) + as_warn (_("end of file in comment; newline inserted")); + + state = 0; + PUT ('\n'); + break; +#endif +#ifdef DOUBLEBAR_PARALLEL + case LEX_IS_DOUBLEBAR_1ST: + ch2 = GET (); + UNGET (ch2); + if (ch2 != '|') + goto de_fault; + + /* Handle '||' in two states as invoking PUT twice might + result in the first one jumping out of this loop. We'd + then lose track of the state and one '|' char. */ + state = 13; + PUT ('|'); + break; +#endif + case LEX_IS_LINE_COMMENT_START: + /* FIXME-someday: The two character comment stuff was badly + thought out. On i386, we want '/' as line comment start + AND we want C style comments. hence this hack. The + whole lexical process should be reworked. xoxorich. */ + if (ch == '/') + { + ch2 = GET (); + if (ch2 == '*') + { + old_state = 3; + state = -2; + break; + } + else + { + UNGET (ch2); + } + } + + if (state == 0 || state == 1) /* Only comment at start of line. */ + { + int startch; + + startch = ch; + + do + { + ch = GET (); + } + while (ch != EOF && IS_WHITESPACE (ch)); + + if (ch == EOF) + { + as_warn (_("end of file in comment; newline inserted")); + PUT ('\n'); + break; + } + + if (ch < '0' || ch > '9' || state != 0 || startch != '#') + { + /* Not a cpp line. */ + while (ch != EOF && !IS_NEWLINE (ch)) + ch = GET (); + if (ch == EOF) + as_warn (_("end of file in comment; newline inserted")); + state = 0; + PUT ('\n'); + break; + } + /* Looks like `# 123 "filename"' from cpp. */ + UNGET (ch); + old_state = 4; + state = -1; + if (scrub_m68k_mri) + out_string = "\tappline "; + else + out_string = "\t.appline "; + PUT (*out_string++); + break; + } + +#ifdef TC_D10V + /* All insns end in a char for which LEX_IS_SYMBOL_COMPONENT is true. + Trap is the only short insn that has a first operand that is + neither register nor label. + We must prevent exef0f ||trap #1 to degenerate to exef0f ||trap#1 . + We can't make '#' LEX_IS_SYMBOL_COMPONENT because it is + already LEX_IS_LINE_COMMENT_START. However, it is the + only character in line_comment_chars for d10v, hence we + can recognize it as such. */ + /* An alternative approach would be to reset the state to 1 when + we see '||', '<'- or '->', but that seems to be overkill. */ + if (state == 10) + PUT (' '); +#endif + /* We have a line comment character which is not at the + start of a line. If this is also a normal comment + character, fall through. Otherwise treat it as a default + character. */ + if (strchr (tc_comment_chars, ch) == NULL + && (! scrub_m68k_mri + || (ch != '!' && ch != '*'))) + goto de_fault; + if (scrub_m68k_mri + && (ch == '!' || ch == '*' || ch == '#') + && state != 1 + && state != 10) + goto de_fault; + /* Fall through. */ + case LEX_IS_COMMENT_START: +#if defined TC_ARM && defined OBJ_ELF + /* On the ARM, `@' is the comment character. + Unfortunately this is also a special character in ELF .symver + directives (and .type, though we deal with those another way). + So we check if this line is such a directive, and treat + the character as default if so. This is a hack. */ + if ((symver_state != NULL) && (*symver_state == 0)) + goto de_fault; +#endif +#ifdef WARN_COMMENTS + if (!found_comment) + as_where (&found_comment_file, &found_comment); +#endif + do + { + ch = GET (); + } + while (ch != EOF && !IS_NEWLINE (ch)); + if (ch == EOF) + as_warn (_("end of file in comment; newline inserted")); + state = 0; + PUT ('\n'); + break; + + case LEX_IS_SYMBOL_COMPONENT: + if (state == 10) + { + /* This is a symbol character following another symbol + character, with whitespace in between. We skipped + the whitespace earlier, so output it now. */ + UNGET (ch); + state = 3; + PUT (' '); + break; + } + + if (state == 3) + state = 9; + + /* This is a common case. Quickly copy CH and all the + following symbol component or normal characters. */ + if (to + 1 < toend + && mri_state == NULL +#if defined TC_ARM && defined OBJ_ELF + && symver_state == NULL +#endif + ) + { + char *s; + int len; + + for (s = from; s < fromend; s++) + { + int type; + + ch2 = *(unsigned char *) s; + type = lex[ch2]; + if (type != 0 + && type != LEX_IS_SYMBOL_COMPONENT) + break; + } + + if (s > from) + /* Handle the last character normally, for + simplicity. */ + --s; + + len = s - from; + + if (len > (toend - to) - 1) + len = (toend - to) - 1; + + if (len > 0) + { + PUT (ch); + if (len > 8) + { + memcpy (to, from, len); + to += len; + from += len; + } + else + { + switch (len) + { + case 8: *to++ = *from++; + case 7: *to++ = *from++; + case 6: *to++ = *from++; + case 5: *to++ = *from++; + case 4: *to++ = *from++; + case 3: *to++ = *from++; + case 2: *to++ = *from++; + case 1: *to++ = *from++; + } + } + ch = GET (); + } + } + + /* Fall through. */ + default: + de_fault: + /* Some relatively `normal' character. */ + if (state == 0) + { + state = 11; /* Now seeing label definition. */ + } + else if (state == 1) + { + state = 2; /* Ditto. */ + } + else if (state == 9) + { + if (lex[ch] != LEX_IS_SYMBOL_COMPONENT) + state = 3; + } + else if (state == 10) + { + if (ch == '\\') + { + /* Special handling for backslash: a backslash may + be the beginning of a formal parameter (of a + macro) following another symbol character, with + whitespace in between. If that is the case, we + output a space before the parameter. Strictly + speaking, correct handling depends upon what the + macro parameter expands into; if the parameter + expands into something which does not start with + an operand character, then we don't want to keep + the space. We don't have enough information to + make the right choice, so here we are making the + choice which is more likely to be correct. */ + PUT (' '); + } + + state = 3; + } + PUT (ch); + break; + } + } + + /*NOTREACHED*/ + + fromeof: + /* We have reached the end of the input. */ + return to - tostart; + + tofull: + /* The output buffer is full. Save any input we have not yet + processed. */ + if (fromend > from) + { + saved_input = from; + saved_input_len = fromend - from; + } + else + saved_input = NULL; + + return to - tostart; +} + diff --git a/contrib/binutils-2.14/gas/as.c b/contrib/binutils-2.14/gas/as.c new file mode 100644 index 0000000000..23ed9f7825 --- /dev/null +++ b/contrib/binutils-2.14/gas/as.c @@ -0,0 +1,1123 @@ +/* as.c - GAS main program. + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Main program for AS; a 32-bit assembler of GNU. + * Understands command arguments. + * Has a few routines that don't fit in other modules because they + * are shared. + * + * bugs + * + * : initialisers + * Since no-one else says they will support them in future: I + * don't support them now. + */ + +#include "ansidecl.h" + +#define COMMON + +#include "as.h" +#include "subsegs.h" +#include "output-file.h" +#include "sb.h" +#include "macro.h" +#include "dwarf2dbg.h" + +#ifdef BFD_ASSEMBLER +#include "bfdver.h" +#endif + +#ifdef HAVE_ITBL_CPU +#include "itbl-ops.h" +#else +#define itbl_parse(itbl_file) 1 +#define itbl_init() +#endif + +#ifdef HAVE_SBRK +#ifdef NEED_DECLARATION_SBRK +extern PTR sbrk (); +#endif +#endif + +static void show_usage PARAMS ((FILE *)); +static void parse_args PARAMS ((int *, char ***)); +static void dump_statistics PARAMS ((void)); +static void perform_an_assembly_pass PARAMS ((int argc, char **argv)); +static int macro_expr PARAMS ((const char *, int, sb *, int *)); +#ifdef USING_CGEN +/* Perform any cgen specific initialisation for gas. */ +extern void gas_cgen_begin PARAMS ((void)); +#endif + +/* True if a listing is wanted. */ +int listing; + +/* Name of listing file. */ +static char *listing_filename = NULL; + +/* Type of debugging to generate. */ + +enum debug_info_type debug_type = DEBUG_UNSPECIFIED; + +/* Maximum level of macro nesting. */ +int max_macro_nest = 100; + +/* argv[0] */ +char *myname; +#ifdef BFD_ASSEMBLER +segT reg_section, expr_section; +segT text_section, data_section, bss_section; +#endif + +/* The default obstack chunk size. If we set this to zero, the + obstack code will use whatever will fit in a 4096 byte block. */ +int chunksize = 0; + +/* To monitor memory allocation more effectively, make this non-zero. + Then the chunk sizes for gas and bfd will be reduced. */ +int debug_memory = 0; + +/* We build a list of defsyms as we read the options, and then define + them after we have initialized everything. */ + +struct defsym_list { + struct defsym_list *next; + char *name; + valueT value; +}; + +static struct defsym_list *defsyms; + +/* Keep a record of the itbl files we read in. */ + +struct itbl_file_list { + struct itbl_file_list *next; + char *name; +}; + +static struct itbl_file_list *itbl_files; + +#ifdef USE_EMULATIONS +#define EMULATION_ENVIRON "AS_EMULATION" + +extern struct emulation mipsbelf, mipslelf, mipself; +extern struct emulation mipsbecoff, mipslecoff, mipsecoff; +extern struct emulation i386coff, i386elf, i386aout; +extern struct emulation crisaout, criself; + +static struct emulation *const emulations[] = { EMULATIONS }; +static const int n_emulations = sizeof (emulations) / sizeof (emulations[0]); + +static void select_emulation_mode PARAMS ((int, char **)); + +static void +select_emulation_mode (argc, argv) + int argc; + char **argv; +{ + int i; + char *p, *em = 0; + + for (i = 1; i < argc; i++) + if (!strncmp ("--em", argv[i], 4)) + break; + + if (i == argc) + goto do_default; + + p = strchr (argv[i], '='); + if (p) + p++; + else + p = argv[i + 1]; + + if (!p || !*p) + as_fatal (_("missing emulation mode name")); + em = p; + + do_default: + if (em == 0) + em = getenv (EMULATION_ENVIRON); + if (em == 0) + em = DEFAULT_EMULATION; + + if (em) + { + for (i = 0; i < n_emulations; i++) + if (!strcmp (emulations[i]->name, em)) + break; + if (i == n_emulations) + as_fatal (_("unrecognized emulation name `%s'"), em); + this_emulation = emulations[i]; + } + else + this_emulation = emulations[0]; + + this_emulation->init (); +} + +const char * +default_emul_bfd_name () +{ + abort (); + return NULL; +} + +void +common_emul_init () +{ + this_format = this_emulation->format; + + if (this_emulation->leading_underscore == 2) + this_emulation->leading_underscore = this_format->dfl_leading_underscore; + + if (this_emulation->default_endian != 2) + target_big_endian = this_emulation->default_endian; + + if (this_emulation->fake_label_name == 0) + { + if (this_emulation->leading_underscore) + this_emulation->fake_label_name = "L0\001"; + else + /* What other parameters should we test? */ + this_emulation->fake_label_name = ".L0\001"; + } +} +#endif + +void +print_version_id () +{ + static int printed; + if (printed) + return; + printed = 1; + +#ifdef BFD_ASSEMBLER + fprintf (stderr, _("GNU assembler version %s (%s) using BFD version %s"), + VERSION, TARGET_ALIAS, BFD_VERSION_STRING); +#else + fprintf (stderr, _("GNU assembler version %s (%s)"), VERSION, TARGET_ALIAS); +#endif + fprintf (stderr, "\n"); +} + +static void +show_usage (stream) + FILE *stream; +{ + fprintf (stream, _("Usage: %s [option...] [asmfile...]\n"), myname); + + fprintf (stream, _("\ +Options:\n\ + -a[sub-option...] turn on listings\n\ + Sub-options [default hls]:\n\ + c omit false conditionals\n\ + d omit debugging directives\n\ + h include high-level source\n\ + l include assembly\n\ + m include macro expansions\n\ + n omit forms processing\n\ + s include symbols\n\ + =FILE list to FILE (must be last sub-option)\n")); + + fprintf (stream, _("\ + -D produce assembler debugging messages\n")); + fprintf (stream, _("\ + --defsym SYM=VAL define symbol SYM to given value\n")); +#ifdef USE_EMULATIONS + { + int i; + char *def_em; + + fprintf (stream, "\ + --em=["); + for (i = 0; i < n_emulations - 1; i++) + fprintf (stream, "%s | ", emulations[i]->name); + fprintf (stream, "%s]\n", emulations[i]->name); + + def_em = getenv (EMULATION_ENVIRON); + if (!def_em) + def_em = DEFAULT_EMULATION; + fprintf (stream, _("\ + emulate output (default %s)\n"), def_em); + } +#endif + fprintf (stream, _("\ + -f skip whitespace and comment preprocessing\n")); + fprintf (stream, _("\ + --gstabs generate stabs debugging information\n")); + fprintf (stream, _("\ + --gdwarf2 generate DWARF2 debugging information\n")); + fprintf (stream, _("\ + --help show this message and exit\n")); + fprintf (stream, _("\ + --target-help show target specific options\n")); + fprintf (stream, _("\ + -I DIR add DIR to search list for .include directives\n")); + fprintf (stream, _("\ + -J don't warn about signed overflow\n")); + fprintf (stream, _("\ + -K warn when differences altered for long displacements\n")); + fprintf (stream, _("\ + -L,--keep-locals keep local symbols (e.g. starting with `L')\n")); + fprintf (stream, _("\ + -M,--mri assemble in MRI compatibility mode\n")); + fprintf (stream, _("\ + --MD FILE write dependency information in FILE (default none)\n")); + fprintf (stream, _("\ + -nocpp ignored\n")); + fprintf (stream, _("\ + -o OBJFILE name the object-file output OBJFILE (default a.out)\n")); + fprintf (stream, _("\ + -R fold data section into text section\n")); + fprintf (stream, _("\ + --statistics print various measured statistics from execution\n")); + fprintf (stream, _("\ + --strip-local-absolute strip local absolute symbols\n")); + fprintf (stream, _("\ + --traditional-format Use same format as native assembler when possible\n")); + fprintf (stream, _("\ + --version print assembler version number and exit\n")); + fprintf (stream, _("\ + -W --no-warn suppress warnings\n")); + fprintf (stream, _("\ + --warn don't suppress warnings\n")); + fprintf (stream, _("\ + --fatal-warnings treat warnings as errors\n")); + fprintf (stream, _("\ + --itbl INSTTBL extend instruction set to include instructions\n\ + matching the specifications defined in file INSTTBL\n")); + fprintf (stream, _("\ + -w ignored\n")); + fprintf (stream, _("\ + -X ignored\n")); + fprintf (stream, _("\ + -Z generate object file even after errors\n")); + fprintf (stream, _("\ + --listing-lhs-width set the width in words of the output data column of\n\ + the listing\n")); + fprintf (stream, _("\ + --listing-lhs-width2 set the width in words of the continuation lines\n\ + of the output data column; ignored if smaller than\n\ + the width of the first line\n")); + fprintf (stream, _("\ + --listing-rhs-width set the max width in characters of the lines from\n\ + the source file\n")); + fprintf (stream, _("\ + --listing-cont-lines set the maximum number of continuation lines used\n\ + for the output data column of the listing\n")); + + md_show_usage (stream); + + fputc ('\n', stream); + fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO); +} + +/* Since it is easy to do here we interpret the special arg "-" + to mean "use stdin" and we set that argv[] pointing to "". + After we have munged argv[], the only things left are source file + name(s) and ""(s) denoting stdin. These file names are used + (perhaps more than once) later. + + check for new machine-dep cmdline options in + md_parse_option definitions in config/tc-*.c. */ + +static void +parse_args (pargc, pargv) + int *pargc; + char ***pargv; +{ + int old_argc, new_argc; + char **old_argv, **new_argv; + + /* Starting the short option string with '-' is for programs that + expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. */ + + char *shortopts; + extern const char *md_shortopts; + static const char std_shortopts[] = { + '-', 'J', +#ifndef WORKING_DOT_WORD + /* -K is not meaningful if .word is not being hacked. */ + 'K', +#endif + 'L', 'M', 'R', 'W', 'Z', 'f', 'a', ':', ':', 'D', 'I', ':', 'o', ':', +#ifndef VMS + /* -v takes an argument on VMS, so we don't make it a generic + option. */ + 'v', +#endif + 'w', 'X', + /* New option for extending instruction set (see also --itbl below) */ + 't', ':', + '\0' + }; + struct option *longopts; + extern struct option md_longopts[]; + extern size_t md_longopts_size; + static const struct option std_longopts[] = { +#define OPTION_HELP (OPTION_STD_BASE) + {"help", no_argument, NULL, OPTION_HELP}, + /* getopt allows abbreviations, so we do this to stop it from + treating -k as an abbreviation for --keep-locals. Some + ports use -k to enable PIC assembly. */ + {"keep-locals", no_argument, NULL, 'L'}, + {"keep-locals", no_argument, NULL, 'L'}, + {"mri", no_argument, NULL, 'M'}, +#define OPTION_NOCPP (OPTION_STD_BASE + 1) + {"nocpp", no_argument, NULL, OPTION_NOCPP}, +#define OPTION_STATISTICS (OPTION_STD_BASE + 2) + {"statistics", no_argument, NULL, OPTION_STATISTICS}, +#define OPTION_VERSION (OPTION_STD_BASE + 3) + {"version", no_argument, NULL, OPTION_VERSION}, +#define OPTION_DUMPCONFIG (OPTION_STD_BASE + 4) + {"dump-config", no_argument, NULL, OPTION_DUMPCONFIG}, +#define OPTION_VERBOSE (OPTION_STD_BASE + 5) + {"verbose", no_argument, NULL, OPTION_VERBOSE}, +#define OPTION_EMULATION (OPTION_STD_BASE + 6) + {"emulation", required_argument, NULL, OPTION_EMULATION}, +#define OPTION_DEFSYM (OPTION_STD_BASE + 7) + {"defsym", required_argument, NULL, OPTION_DEFSYM}, +#define OPTION_INSTTBL (OPTION_STD_BASE + 8) + /* New option for extending instruction set (see also -t above). + The "-t file" or "--itbl file" option extends the basic set of + valid instructions by reading "file", a text file containing a + list of instruction formats. The additional opcodes and their + formats are added to the built-in set of instructions, and + mnemonics for new registers may also be defined. */ + {"itbl", required_argument, NULL, OPTION_INSTTBL}, +#define OPTION_LISTING_LHS_WIDTH (OPTION_STD_BASE + 9) + {"listing-lhs-width", required_argument, NULL, OPTION_LISTING_LHS_WIDTH}, +#define OPTION_LISTING_LHS_WIDTH2 (OPTION_STD_BASE + 10) + {"listing-lhs-width2", required_argument, NULL, OPTION_LISTING_LHS_WIDTH2}, +#define OPTION_LISTING_RHS_WIDTH (OPTION_STD_BASE + 11) + {"listing-rhs-width", required_argument, NULL, OPTION_LISTING_RHS_WIDTH}, +#define OPTION_LISTING_CONT_LINES (OPTION_STD_BASE + 12) + {"listing-cont-lines", required_argument, NULL, OPTION_LISTING_CONT_LINES}, +#define OPTION_DEPFILE (OPTION_STD_BASE + 13) + {"MD", required_argument, NULL, OPTION_DEPFILE}, +#define OPTION_GSTABS (OPTION_STD_BASE + 14) + {"gstabs", no_argument, NULL, OPTION_GSTABS}, +#define OPTION_STRIP_LOCAL_ABSOLUTE (OPTION_STD_BASE + 15) + {"strip-local-absolute", no_argument, NULL, OPTION_STRIP_LOCAL_ABSOLUTE}, +#define OPTION_TRADITIONAL_FORMAT (OPTION_STD_BASE + 16) + {"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT}, +#define OPTION_GDWARF2 (OPTION_STD_BASE + 17) + {"gdwarf2", no_argument, NULL, OPTION_GDWARF2}, + {"no-warn", no_argument, NULL, 'W'}, +#define OPTION_WARN (OPTION_STD_BASE + 18) + {"warn", no_argument, NULL, OPTION_WARN}, +#define OPTION_TARGET_HELP (OPTION_STD_BASE + 19) + {"target-help", no_argument, NULL, OPTION_TARGET_HELP}, +#define OPTION_WARN_FATAL (OPTION_STD_BASE + 20) + {"fatal-warnings", no_argument, NULL, OPTION_WARN_FATAL} + /* When you add options here, check that they do not collide with + OPTION_MD_BASE. See as.h. */ + }; + + /* Construct the option lists from the standard list and the target + dependent list. Include space for an extra NULL option and + always NULL terminate. */ + shortopts = concat (std_shortopts, md_shortopts, (char *) NULL); + longopts = (struct option *) xmalloc (sizeof (std_longopts) + + md_longopts_size + + sizeof (struct option)); + memcpy (longopts, std_longopts, sizeof (std_longopts)); + memcpy ((char *) longopts + sizeof (std_longopts), + md_longopts, md_longopts_size); + memset ((char *) longopts + sizeof (std_longopts) + md_longopts_size, + 0, sizeof (struct option)); + + /* Make a local copy of the old argv. */ + old_argc = *pargc; + old_argv = *pargv; + + /* Initialize a new argv that contains no options. */ + new_argv = (char **) xmalloc (sizeof (char *) * (old_argc + 1)); + new_argv[0] = old_argv[0]; + new_argc = 1; + new_argv[new_argc] = NULL; + + while (1) + { + /* getopt_long_only is like getopt_long, but '-' as well as '--' can + indicate a long option. */ + int longind; + int optc = getopt_long_only (old_argc, old_argv, shortopts, longopts, + &longind); + + if (optc == -1) + break; + + switch (optc) + { + default: + /* md_parse_option should return 1 if it recognizes optc, + 0 if not. */ + if (md_parse_option (optc, optarg) != 0) + break; + /* `-v' isn't included in the general short_opts list, so check for + it explicity here before deciding we've gotten a bad argument. */ + if (optc == 'v') + { +#ifdef VMS + /* Telling getopt to treat -v's value as optional can result + in it picking up a following filename argument here. The + VMS code in md_parse_option can return 0 in that case, + but it has no way of pushing the filename argument back. */ + if (optarg && *optarg) + new_argv[new_argc++] = optarg, new_argv[new_argc] = NULL; + else +#else + case 'v': +#endif + case OPTION_VERBOSE: + print_version_id (); + break; + } + /* Fall through. */ + + case '?': + exit (EXIT_FAILURE); + + case 1: /* File name. */ + if (!strcmp (optarg, "-")) + optarg = ""; + new_argv[new_argc++] = optarg; + new_argv[new_argc] = NULL; + break; + + case OPTION_TARGET_HELP: + md_show_usage (stdout); + exit (EXIT_SUCCESS); + + case OPTION_HELP: + show_usage (stdout); + exit (EXIT_SUCCESS); + + case OPTION_NOCPP: + break; + + case OPTION_STATISTICS: + flag_print_statistics = 1; + break; + + case OPTION_STRIP_LOCAL_ABSOLUTE: + flag_strip_local_absolute = 1; + break; + + case OPTION_TRADITIONAL_FORMAT: + flag_traditional_format = 1; + break; + + case OPTION_VERSION: + /* This output is intended to follow the GNU standards document. */ +#ifdef BFD_ASSEMBLER + printf (_("GNU assembler %s\n"), BFD_VERSION_STRING); +#else + printf (_("GNU assembler %s\n"), VERSION); +#endif + printf (_("Copyright 2002 Free Software Foundation, Inc.\n")); + printf (_("\ +This program is free software; you may redistribute it under the terms of\n\ +the GNU General Public License. This program has absolutely no warranty.\n")); + printf (_("This assembler was configured for a target of `%s'.\n"), + TARGET_ALIAS); + exit (EXIT_SUCCESS); + + case OPTION_EMULATION: +#ifdef USE_EMULATIONS + if (strcmp (optarg, this_emulation->name)) + as_fatal (_("multiple emulation names specified")); +#else + as_fatal (_("emulations not handled in this configuration")); +#endif + break; + + case OPTION_DUMPCONFIG: + fprintf (stderr, _("alias = %s\n"), TARGET_ALIAS); + fprintf (stderr, _("canonical = %s\n"), TARGET_CANONICAL); + fprintf (stderr, _("cpu-type = %s\n"), TARGET_CPU); +#ifdef TARGET_OBJ_FORMAT + fprintf (stderr, _("format = %s\n"), TARGET_OBJ_FORMAT); +#endif +#ifdef TARGET_FORMAT + fprintf (stderr, _("bfd-target = %s\n"), TARGET_FORMAT); +#endif + exit (EXIT_SUCCESS); + + case OPTION_DEFSYM: + { + char *s; + valueT i; + struct defsym_list *n; + + for (s = optarg; *s != '\0' && *s != '='; s++) + ; + if (*s == '\0') + as_fatal (_("bad defsym; format is --defsym name=value")); + *s++ = '\0'; +#ifdef BFD_ASSEMBLER + i = bfd_scan_vma (s, (const char **) NULL, 0); +#else + i = strtol (s, (char **) NULL, 0); +#endif + n = (struct defsym_list *) xmalloc (sizeof *n); + n->next = defsyms; + n->name = optarg; + n->value = i; + defsyms = n; + } + break; + + case OPTION_INSTTBL: + case 't': + { + /* optarg is the name of the file containing the instruction + formats, opcodes, register names, etc. */ + struct itbl_file_list *n; + + if (optarg == NULL) + { + as_warn (_("no file name following -t option")); + break; + } + + n = (struct itbl_file_list *) xmalloc (sizeof *n); + n->next = itbl_files; + n->name = optarg; + itbl_files = n; + + /* Parse the file and add the new instructions to our internal + table. If multiple instruction tables are specified, the + information from this table gets appended onto the existing + internal table. */ + itbl_files->name = xstrdup (optarg); + if (itbl_parse (itbl_files->name) != 0) + as_fatal (_("failed to read instruction table %s\n"), + itbl_files->name); + } + break; + + case OPTION_DEPFILE: + start_dependencies (optarg); + break; + + case OPTION_GSTABS: + debug_type = DEBUG_STABS; + break; + + case OPTION_GDWARF2: + debug_type = DEBUG_DWARF2; + break; + + case 'J': + flag_signed_overflow_ok = 1; + break; + +#ifndef WORKING_DOT_WORD + case 'K': + flag_warn_displacement = 1; + break; +#endif + + case 'L': + flag_keep_locals = 1; + break; + + case OPTION_LISTING_LHS_WIDTH: + listing_lhs_width = atoi (optarg); + if (listing_lhs_width_second < listing_lhs_width) + listing_lhs_width_second = listing_lhs_width; + break; + case OPTION_LISTING_LHS_WIDTH2: + { + int tmp = atoi (optarg); + if (tmp > listing_lhs_width) + listing_lhs_width_second = tmp; + } + break; + case OPTION_LISTING_RHS_WIDTH: + listing_rhs_width = atoi (optarg); + break; + case OPTION_LISTING_CONT_LINES: + listing_lhs_cont_lines = atoi (optarg); + break; + + case 'M': + flag_mri = 1; +#ifdef TC_M68K + flag_m68k_mri = 1; +#endif + break; + + case 'R': + flag_readonly_data_in_text = 1; + break; + + case 'W': + flag_no_warnings = 1; + break; + + case OPTION_WARN: + flag_no_warnings = 0; + flag_fatal_warnings = 0; + break; + + case OPTION_WARN_FATAL: + flag_no_warnings = 0; + flag_fatal_warnings = 1; + break; + + case 'Z': + flag_always_generate_output = 1; + break; + + case 'a': + if (optarg) + { + if (md_parse_option (optc, optarg) != 0) + break; + + while (*optarg) + { + switch (*optarg) + { + case 'c': + listing |= LISTING_NOCOND; + break; + case 'd': + listing |= LISTING_NODEBUG; + break; + case 'h': + listing |= LISTING_HLL; + break; + case 'l': + listing |= LISTING_LISTING; + break; + case 'm': + listing |= LISTING_MACEXP; + break; + case 'n': + listing |= LISTING_NOFORM; + break; + case 's': + listing |= LISTING_SYMBOLS; + break; + case '=': + listing_filename = xstrdup (optarg + 1); + optarg += strlen (listing_filename); + break; + default: + as_fatal (_("invalid listing option `%c'"), *optarg); + break; + } + optarg++; + } + } + if (!listing) + listing = LISTING_DEFAULT; + break; + + case 'D': + /* DEBUG is implemented: it debugs different + things from other people's assemblers. */ + flag_debug = 1; + break; + + case 'f': + flag_no_comments = 1; + break; + + case 'I': + { /* Include file directory. */ + char *temp = xstrdup (optarg); + add_include_dir (temp); + break; + } + + case 'o': + out_file_name = xstrdup (optarg); + break; + + case 'w': + break; + + case 'X': + /* -X means treat warnings as errors. */ + break; + } + } + + free (shortopts); + free (longopts); + + *pargc = new_argc; + *pargv = new_argv; + +#ifdef md_after_parse_args + md_after_parse_args (); +#endif +} + +static long start_time; + +int main PARAMS ((int, char **)); + +int +main (argc, argv) + int argc; + char **argv; +{ + int macro_alternate; + int macro_strip_at; + int keep_it; + + start_time = get_run_time (); + +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale (LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale (LC_CTYPE, ""); +#endif + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + if (debug_memory) + chunksize = 64; + +#ifdef HOST_SPECIAL_INIT + HOST_SPECIAL_INIT (argc, argv); +#endif + + myname = argv[0]; + xmalloc_set_program_name (myname); + + START_PROGRESS (myname, 0); + +#ifndef OBJ_DEFAULT_OUTPUT_FILE_NAME +#define OBJ_DEFAULT_OUTPUT_FILE_NAME "a.out" +#endif + + out_file_name = OBJ_DEFAULT_OUTPUT_FILE_NAME; + + hex_init (); +#ifdef BFD_ASSEMBLER + bfd_init (); + bfd_set_error_program_name (myname); +#endif + +#ifdef USE_EMULATIONS + select_emulation_mode (argc, argv); +#endif + + PROGRESS (1); + symbol_begin (); + frag_init (); + subsegs_begin (); + parse_args (&argc, &argv); + read_begin (); + input_scrub_begin (); + expr_begin (); + + if (flag_print_statistics) + xatexit (dump_statistics); + + macro_alternate = 0; + macro_strip_at = 0; +#ifdef TC_I960 + macro_strip_at = flag_mri; +#endif +#ifdef TC_A29K + /* For compatibility with the AMD 29K family macro assembler + specification. */ + macro_alternate = 1; + macro_strip_at = 1; +#endif + + macro_init (macro_alternate, flag_mri, macro_strip_at, macro_expr); + + PROGRESS (1); + +#ifdef BFD_ASSEMBLER + output_file_create (out_file_name); + assert (stdoutput != 0); +#endif + +#ifdef tc_init_after_args + tc_init_after_args (); +#endif + + itbl_init (); + + /* Now that we have fully initialized, and have created the output + file, define any symbols requested by --defsym command line + arguments. */ + while (defsyms != NULL) + { + symbolS *sym; + struct defsym_list *next; + + sym = symbol_new (defsyms->name, absolute_section, defsyms->value, + &zero_address_frag); + symbol_table_insert (sym); + next = defsyms->next; + free (defsyms); + defsyms = next; + } + + PROGRESS (1); + + /* Assemble it. */ + perform_an_assembly_pass (argc, argv); + + cond_finish_check (-1); + +#ifdef md_end + md_end (); +#endif + + /* If we've been collecting dwarf2 .debug_line info, either for + assembly debugging or on behalf of the compiler, emit it now. */ + dwarf2_finish (); + + if (seen_at_least_1_file () + && (flag_always_generate_output || had_errors () == 0)) + keep_it = 1; + else + keep_it = 0; + +#if defined (BFD_ASSEMBLER) || !defined (BFD) + /* This used to be done at the start of write_object_file in + write.c, but that caused problems when doing listings when + keep_it was zero. This could probably be moved above md_end, but + I didn't want to risk the change. */ + subsegs_finish (); +#endif + + if (keep_it) + write_object_file (); + +#ifndef NO_LISTING + listing_print (listing_filename); +#endif + +#ifndef OBJ_VMS /* does its own file handling */ +#ifndef BFD_ASSEMBLER + if (keep_it) +#endif + output_file_close (out_file_name); +#endif + + if (flag_fatal_warnings && had_warnings () > 0 && had_errors () == 0) + as_bad (_("%d warnings, treating warnings as errors"), had_warnings ()); + + if (had_errors () > 0 && ! flag_always_generate_output) + keep_it = 0; + + if (!keep_it) + unlink (out_file_name); + + input_scrub_end (); + + END_PROGRESS (myname); + + /* Use xexit instead of return, because under VMS environments they + may not place the same interpretation on the value given. */ + if (had_errors () > 0) + xexit (EXIT_FAILURE); + + /* Only generate dependency file if assembler was successful. */ + print_dependencies (); + + xexit (EXIT_SUCCESS); +} + +static void +dump_statistics () +{ +#ifdef HAVE_SBRK + char *lim = (char *) sbrk (0); +#endif + long run_time = get_run_time () - start_time; + + fprintf (stderr, _("%s: total time in assembly: %ld.%06ld\n"), + myname, run_time / 1000000, run_time % 1000000); +#ifdef HAVE_SBRK + fprintf (stderr, _("%s: data size %ld\n"), + myname, (long) (lim - (char *) &environ)); +#endif + + subsegs_print_statistics (stderr); + write_print_statistics (stderr); + symbol_print_statistics (stderr); + read_print_statistics (stderr); + +#ifdef tc_print_statistics + tc_print_statistics (stderr); +#endif +#ifdef obj_print_statistics + obj_print_statistics (stderr); +#endif +} + +/* Here to attempt 1 pass over each input file. + We scan argv[*] looking for filenames or exactly "" which is + shorthand for stdin. Any argv that is NULL is not a file-name. + We set need_pass_2 TRUE if, after this, we still have unresolved + expressions of the form (unknown value)+-(unknown value). + + Note the un*x semantics: there is only 1 logical input file, but it + may be a catenation of many 'physical' input files. */ + +static void +perform_an_assembly_pass (argc, argv) + int argc; + char **argv; +{ + int saw_a_file = 0; +#ifdef BFD_ASSEMBLER + flagword applicable; +#endif + + need_pass_2 = 0; + +#ifndef BFD_ASSEMBLER +#ifdef MANY_SEGMENTS + { + unsigned int i; + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + segment_info[i].fix_root = 0; + } + /* Create the three fixed ones. */ + { + segT seg; + +#ifdef TE_APOLLO + seg = subseg_new (".wtext", 0); +#else + seg = subseg_new (".text", 0); +#endif + assert (seg == SEG_E0); + seg = subseg_new (".data", 0); + assert (seg == SEG_E1); + seg = subseg_new (".bss", 0); + assert (seg == SEG_E2); +#ifdef TE_APOLLO + create_target_segments (); +#endif + } + +#else /* not MANY_SEGMENTS */ + text_fix_root = NULL; + data_fix_root = NULL; + bss_fix_root = NULL; +#endif /* not MANY_SEGMENTS */ +#else /* BFD_ASSEMBLER */ + /* Create the standard sections, and those the assembler uses + internally. */ + text_section = subseg_new (TEXT_SECTION_NAME, 0); + data_section = subseg_new (DATA_SECTION_NAME, 0); + bss_section = subseg_new (BSS_SECTION_NAME, 0); + /* @@ FIXME -- we're setting the RELOC flag so that sections are assumed + to have relocs, otherwise we don't find out in time. */ + applicable = bfd_applicable_section_flags (stdoutput); + bfd_set_section_flags (stdoutput, text_section, + applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_CODE | SEC_READONLY)); + bfd_set_section_flags (stdoutput, data_section, + applicable & (SEC_ALLOC | SEC_LOAD | SEC_RELOC + | SEC_DATA)); + bfd_set_section_flags (stdoutput, bss_section, applicable & SEC_ALLOC); + seg_info (bss_section)->bss = 1; + subseg_new (BFD_ABS_SECTION_NAME, 0); + subseg_new (BFD_UND_SECTION_NAME, 0); + reg_section = subseg_new ("*GAS `reg' section*", 0); + expr_section = subseg_new ("*GAS `expr' section*", 0); + +#endif /* BFD_ASSEMBLER */ + + subseg_set (text_section, 0); + + /* This may add symbol table entries, which requires having an open BFD, + and sections already created, in BFD_ASSEMBLER mode. */ + md_begin (); + +#ifdef USING_CGEN + gas_cgen_begin (); +#endif +#ifdef obj_begin + obj_begin (); +#endif + + /* Skip argv[0]. */ + argv++; + argc--; + + while (argc--) + { + if (*argv) + { /* Is it a file-name argument? */ + PROGRESS (1); + saw_a_file++; + /* argv->"" if stdin desired, else->filename */ + read_a_source_file (*argv); + } + argv++; /* completed that argv */ + } + if (!saw_a_file) + read_a_source_file (""); +} + +/* The interface between the macro code and gas expression handling. */ + +static int +macro_expr (emsg, idx, in, val) + const char *emsg; + int idx; + sb *in; + int *val; +{ + char *hold; + expressionS ex; + + sb_terminate (in); + + hold = input_line_pointer; + input_line_pointer = in->ptr + idx; + expression (&ex); + idx = input_line_pointer - in->ptr; + input_line_pointer = hold; + + if (ex.X_op != O_constant) + as_bad ("%s", emsg); + + *val = (int) ex.X_add_number; + + return idx; +} diff --git a/contrib/binutils-2.14/gas/as.h b/contrib/binutils-2.14/gas/as.h new file mode 100644 index 0000000000..cdb267adbf --- /dev/null +++ b/contrib/binutils-2.14/gas/as.h @@ -0,0 +1,691 @@ +/* as.h - global header file + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef GAS +#define GAS 1 +/* I think this stuff is largely out of date. xoxorich. + * + * CAPITALISED names are #defined. + * "lowercaseH" is #defined if "lowercase.h" has been #include-d. + * "lowercaseT" is a typedef of "lowercase" objects. + * "lowercaseP" is type "pointer to object of type 'lowercase'". + * "lowercaseS" is typedef struct ... lowercaseS. + * + * #define DEBUG to enable all the "know" assertion tests. + * #define SUSPECT when debugging hash code. + * #define COMMON as "extern" for all modules except one, where you #define + * COMMON as "". + * If TEST is #defined, then we are testing a module: #define COMMON as "". + */ + +#include "config.h" +#include "bin-bugs.h" + +/* This is the code recommended in the autoconf documentation, almost + verbatim. If it doesn't work for you, let me know, and notify + djm@gnu.ai.mit.edu as well. */ +/* Added void* version for STDC case. This is to be compatible with + the declaration in bison.simple, used for m68k operand parsing. + --KR 1995.08.08 */ +/* Force void* decl for hpux. This is what Bison uses. --KR 1995.08.16 */ + +#ifndef __GNUC__ +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX +/* Indented so that pre-ansi C compilers will ignore it, rather than + choke on it. Some versions of AIX require this to be the first + thing in the file. */ + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +# if !defined (__STDC__) && !defined (__hpux) +extern char *alloca (); +# else +extern void *alloca (); +# endif /* __STDC__, __hpux */ +# endif /* alloca */ +# endif /* _AIX */ +# endif /* HAVE_ALLOCA_H */ +#endif /* __GNUC__ */ + +/* Now, tend to the rest of the configuration. */ + +/* System include files first... */ +#include +#ifdef HAVE_STRING_H +#include +#else +#ifdef HAVE_STRINGS_H +#include +#endif +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +/* for size_t, pid_t */ +#include +#endif + +#include "getopt.h" +/* The first getopt value for machine-independent long options. + 150 isn't special; it's just an arbitrary non-ASCII char value. */ +#define OPTION_STD_BASE 150 +/* The first getopt value for machine-dependent long options. + 190 gives the standard options room to grow. */ +#define OPTION_MD_BASE 190 + +#ifdef DEBUG +#undef NDEBUG +#endif +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) +#define __PRETTY_FUNCTION__ ((char*)0) +#endif +#if 0 + +/* Handle lossage with assert.h. */ +#ifndef BROKEN_ASSERT +#include +#else /* BROKEN_ASSERT */ +#ifndef NDEBUG +#define assert(p) ((p) ? 0 : (as_assert (__FILE__, __LINE__, __PRETTY_FUNCTION__), 0)) +#else +#define assert(p) ((p), 0) +#endif +#endif /* BROKEN_ASSERT */ + +#else + +#define assert(P) ((P) ? 0 : (as_assert (__FILE__, __LINE__, __PRETTY_FUNCTION__), 0)) +#undef abort +#define abort() as_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#endif + +/* Now GNU header files... */ +#include "ansidecl.h" +#ifdef BFD_ASSEMBLER +#include "bfd.h" +#endif +#include "libiberty.h" + +/* Define the standard progress macros. */ +#include "progress.h" + +/* This doesn't get taken care of anywhere. */ +#ifndef __MWERKS__ /* Metrowerks C chokes on the "defined (inline)" */ +#if !defined (__GNUC__) && !defined (inline) +#define inline +#endif +#endif /* !__MWERKS__ */ + +/* Other stuff from config.h. */ +#ifdef NEED_DECLARATION_STRSTR +extern char *strstr (); +#endif +#ifdef NEED_DECLARATION_MALLOC +extern PTR malloc (); +extern PTR realloc (); +#endif +#ifdef NEED_DECLARATION_FREE +extern void free (); +#endif +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#ifdef NEED_DECLARATION_ENVIRON +extern char **environ; +#endif + +/* This is needed for VMS. */ +#if ! defined (HAVE_UNLINK) && defined (HAVE_REMOVE) +#define unlink remove +#endif + +/* Hack to make "gcc -Wall" not complain about obstack macros. */ +#if !defined (memcpy) && !defined (bcopy) +#define bcopy(src,dest,size) memcpy (dest, src, size) +#endif + +/* Make Saber happier on obstack.h. */ +#ifdef SABER +#undef __PTR_TO_INT +#define __PTR_TO_INT(P) ((int) (P)) +#undef __INT_TO_PTR +#define __INT_TO_PTR(P) ((char *) (P)) +#endif + +#ifndef __LINE__ +#define __LINE__ "unknown" +#endif /* __LINE__ */ + +#ifndef __FILE__ +#define __FILE__ "unknown" +#endif /* __FILE__ */ + +#ifndef FOPEN_WB +#if defined GO32 || defined __MINGW32__ +#include "fopen-bin.h" +#else +#include "fopen-same.h" +#endif +#endif + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free xfree + +#define xfree free + +#include "asintl.h" + +#define BAD_CASE(val) \ + { \ + as_fatal (_("Case value %ld unexpected at line %d of file \"%s\"\n"), \ + (long) val, __LINE__, __FILE__); \ + } + +#include "flonum.h" + +/* These are assembler-wide concepts */ + +#ifdef BFD_ASSEMBLER +extern bfd *stdoutput; +typedef bfd_vma addressT; +typedef bfd_signed_vma offsetT; +#else +typedef unsigned long addressT; +typedef long offsetT; +#endif + +/* Type of symbol value, etc. For use in prototypes. */ +typedef addressT valueT; + +#ifndef COMMON +#ifdef TEST +#define COMMON /* declare our COMMONs storage here. */ +#else +#define COMMON extern /* our commons live elswhere */ +#endif +#endif +/* COMMON now defined */ + +#ifdef DEBUG +#ifndef know +#define know(p) assert(p) /* Verify our assumptions! */ +#endif /* not yet defined */ +#else +#define know(p) /* know() checks are no-op.ed */ +#endif + +/* input_scrub.c */ + +/* Supplies sanitised buffers to read.c. + Also understands printing line-number part of error messages. */ + +/* subsegs.c Sub-segments. Also, segment(=expression type)s.*/ + +#ifndef BFD_ASSEMBLER + +#ifdef MANY_SEGMENTS +#include "bfd.h" +#define N_SEGMENTS 40 +#define SEG_NORMAL(x) ((x) >= SEG_E0 && (x) <= SEG_E39) +#define SEG_LIST SEG_E0,SEG_E1,SEG_E2,SEG_E3,SEG_E4,SEG_E5,SEG_E6,SEG_E7,SEG_E8,SEG_E9,\ + SEG_E10,SEG_E11,SEG_E12,SEG_E13,SEG_E14,SEG_E15,SEG_E16,SEG_E17,SEG_E18,SEG_E19,\ + SEG_E20,SEG_E21,SEG_E22,SEG_E23,SEG_E24,SEG_E25,SEG_E26,SEG_E27,SEG_E28,SEG_E29,\ + SEG_E30,SEG_E31,SEG_E32,SEG_E33,SEG_E34,SEG_E35,SEG_E36,SEG_E37,SEG_E38,SEG_E39 +#define SEG_TEXT SEG_E0 +#define SEG_DATA SEG_E1 +#define SEG_BSS SEG_E2 +#define SEG_LAST SEG_E39 +#else +#define N_SEGMENTS 3 +#define SEG_NORMAL(x) ((x) == SEG_TEXT || (x) == SEG_DATA || (x) == SEG_BSS) +#define SEG_LIST SEG_TEXT,SEG_DATA,SEG_BSS +#endif + +typedef enum _segT { + SEG_ABSOLUTE = 0, + SEG_LIST, + SEG_UNKNOWN, + SEG_GOOF, /* Only happens if AS has a logic error. */ + /* Invented so we don't crash printing */ + /* error message involving weird segment. */ + SEG_EXPR, /* Intermediate expression values. */ + SEG_DEBUG, /* Debug segment */ + SEG_NTV, /* Transfert vector preload segment */ + SEG_PTV, /* Transfert vector postload segment */ + SEG_REGISTER /* Mythical: a register-valued expression */ +} segT; + +#define SEG_MAXIMUM_ORDINAL (SEG_REGISTER) +#else +typedef asection *segT; +#define SEG_NORMAL(SEG) ((SEG) != absolute_section \ + && (SEG) != undefined_section \ + && (SEG) != reg_section \ + && (SEG) != expr_section) +#endif +typedef int subsegT; + +/* What subseg we are accreting now? */ +COMMON subsegT now_subseg; + +/* Segment our instructions emit to. */ +COMMON segT now_seg; + +#ifdef BFD_ASSEMBLER +#define segment_name(SEG) bfd_get_section_name (stdoutput, SEG) +#else +extern char const *const seg_name[]; +#define segment_name(SEG) seg_name[(int) (SEG)] +#endif + +#ifndef BFD_ASSEMBLER +extern int section_alignment[]; +#endif + +#ifdef BFD_ASSEMBLER +extern segT reg_section, expr_section; +/* Shouldn't these be eliminated someday? */ +extern segT text_section, data_section, bss_section; +#define absolute_section bfd_abs_section_ptr +#define undefined_section bfd_und_section_ptr +#else +#define reg_section SEG_REGISTER +#define expr_section SEG_EXPR +#define text_section SEG_TEXT +#define data_section SEG_DATA +#define bss_section SEG_BSS +#define absolute_section SEG_ABSOLUTE +#define undefined_section SEG_UNKNOWN +#endif + +/* relax() */ + +enum _relax_state { + /* Variable chars to be repeated fr_offset times. + Fr_symbol unused. Used with fr_offset == 0 for a + constant length frag. */ + rs_fill = 1, + + /* Align. The fr_offset field holds the power of 2 to which to + align. The fr_var field holds the number of characters in the + fill pattern. The fr_subtype field holds the maximum number of + bytes to skip when aligning, or 0 if there is no maximum. */ + rs_align, + + /* Align code. The fr_offset field holds the power of 2 to which + to align. This type is only generated by machine specific + code, which is normally responsible for handling the fill + pattern. The fr_subtype field holds the maximum number of + bytes to skip when aligning, or 0 if there is no maximum. */ + rs_align_code, + + /* Test for alignment. Like rs_align, but used by several targets + to warn if data is not properly aligned. */ + rs_align_test, + + /* Org: Fr_offset, fr_symbol: address. 1 variable char: fill + character. */ + rs_org, + +#ifndef WORKING_DOT_WORD + /* JF: gunpoint */ + rs_broken_word, +#endif + + /* machine-specific relaxable (or similarly alterable) instruction */ + rs_machine_dependent, + + /* .space directive with expression operand that needs to be computed + later. Similar to rs_org, but different. + fr_symbol: operand + 1 variable char: fill character */ + rs_space, + + /* A DWARF leb128 value; only ELF uses this. The subtype is 0 for + unsigned, 1 for signed. */ + rs_leb128, + + /* Exception frame information which we may be able to optimize. */ + rs_cfa, + + /* Cross-fragment dwarf2 line number optimization. */ + rs_dwarf2dbg +}; + +typedef enum _relax_state relax_stateT; + +/* This type is used in prototypes, so it can't be a type that will be + widened for argument passing. */ +typedef unsigned int relax_substateT; + +/* Enough bits for address, but still an integer type. + Could be a problem, cross-assembling for 64-bit machines. */ +typedef addressT relax_addressT; + +/* main program "as.c" (command arguments etc) */ + +COMMON unsigned char flag_no_comments; /* -f */ +COMMON unsigned char flag_debug; /* -D */ +COMMON unsigned char flag_signed_overflow_ok; /* -J */ +#ifndef WORKING_DOT_WORD +COMMON unsigned char flag_warn_displacement; /* -K */ +#endif + +/* True if local symbols should be retained. */ +COMMON int flag_keep_locals; /* -L */ + +/* True if we are assembling in MRI mode. */ +COMMON int flag_mri; + +/* Should the data section be made read-only and appended to the text + section? */ +COMMON unsigned char flag_readonly_data_in_text; /* -R */ + +/* True if warnings should be inhibited. */ +COMMON int flag_no_warnings; /* -W */ + +/* True if warnings count as errors. */ +COMMON int flag_fatal_warnings; /* --fatal-warnings */ + +/* True if we should attempt to generate output even if non-fatal errors + are detected. */ +COMMON unsigned char flag_always_generate_output; /* -Z */ + +/* This is true if the assembler should output time and space usage. */ +COMMON unsigned char flag_print_statistics; + +/* True if local absolute symbols are to be stripped. */ +COMMON int flag_strip_local_absolute; + +/* True if we should generate a traditional format object file. */ +COMMON int flag_traditional_format; + +/* name of emitted object file */ +COMMON char *out_file_name; + +/* name of file defining extensions to the basic instruction set */ +COMMON char *insttbl_file_name; + +/* TRUE if we need a second pass. */ +COMMON int need_pass_2; + +/* TRUE if we should do no relaxing, and + leave lots of padding. */ +COMMON int linkrelax; + +/* TRUE if we should produce a listing. */ +extern int listing; + +/* Type of debugging information we should generate. We currently support + stabs, ECOFF, and DWARF2. + + NOTE! This means debug information about the assembly source code itself + and _not_ about possible debug information from a high-level language. + This is especially relevant to DWARF2, since the compiler may emit line + number directives that the assembler resolves. */ + +enum debug_info_type { + DEBUG_UNSPECIFIED, + DEBUG_NONE, + DEBUG_STABS, + DEBUG_ECOFF, + DEBUG_DWARF, + DEBUG_DWARF2 +}; + +extern enum debug_info_type debug_type; + +/* Maximum level of macro nesting. */ +extern int max_macro_nest; + +/* Obstack chunk size. Keep large for efficient space use, make small to + increase malloc calls for monitoring memory allocation. */ +extern int chunksize; + +struct _pseudo_type { + /* assembler mnemonic, lower case, no '.' */ + const char *poc_name; + /* Do the work */ + void (*poc_handler) PARAMS ((int)); + /* Value to pass to handler */ + int poc_val; +}; + +typedef struct _pseudo_type pseudo_typeS; + +/* Prefer varargs for non-ANSI compiler, since some will barf if the + ellipsis definition is used with a no-arguments declaration. */ +#if defined (HAVE_VARARGS_H) && !defined (__STDC__) +#undef HAVE_STDARG_H +#endif + +#if defined (HAVE_STDARG_H) +#define USE_STDARG +#endif +#if !defined (USE_STDARG) && defined (HAVE_VARARGS_H) +#define USE_VARARGS +#endif + +#ifdef USE_STDARG +#if (__GNUC__ >= 2) && !defined(VMS) +/* for use with -Wformat */ + +#if __GNUC__ == 2 && __GNUC_MINOR__ < 6 +/* Support for double underscores in attribute names was added in gcc + 2.6, so avoid them if we are using an earlier version. */ +#define __printf__ printf +#define __format__ format +#endif + +#define PRINTF_LIKE(FCN) \ + void FCN (const char *format, ...) \ + __attribute__ ((__format__ (__printf__, 1, 2))) +#define PRINTF_WHERE_LIKE(FCN) \ + void FCN (char *file, unsigned int line, const char *format, ...) \ + __attribute__ ((__format__ (__printf__, 3, 4))) + +#else /* __GNUC__ < 2 || defined(VMS) */ + +#define PRINTF_LIKE(FCN) void FCN PARAMS ((const char *format, ...)) +#define PRINTF_WHERE_LIKE(FCN) void FCN PARAMS ((char *file, \ + unsigned int line, \ + const char *format, ...)) + +#endif /* __GNUC__ < 2 || defined(VMS) */ + +#else /* ! USE_STDARG */ + +#define PRINTF_LIKE(FCN) void FCN () +#define PRINTF_WHERE_LIKE(FCN) void FCN () + +#endif /* ! USE_STDARG */ + +PRINTF_LIKE (as_bad); +PRINTF_LIKE (as_fatal) ATTRIBUTE_NORETURN; +PRINTF_LIKE (as_tsktsk); +PRINTF_LIKE (as_warn); +PRINTF_WHERE_LIKE (as_bad_where); +PRINTF_WHERE_LIKE (as_warn_where); + +void as_assert PARAMS ((const char *, int, const char *)); +void as_abort PARAMS ((const char *, int, const char *)) ATTRIBUTE_NORETURN; + +void fprint_value PARAMS ((FILE *file, addressT value)); +void sprint_value PARAMS ((char *buf, addressT value)); + +int had_errors PARAMS ((void)); +int had_warnings PARAMS ((void)); + +void print_version_id PARAMS ((void)); +char *app_push PARAMS ((void)); +char *atof_ieee PARAMS ((char *str, int what_kind, LITTLENUM_TYPE * words)); +char *input_scrub_include_file PARAMS ((char *filename, char *position)); +extern void input_scrub_insert_line PARAMS((const char *line)); +extern void input_scrub_insert_file PARAMS((char *path)); +char *input_scrub_new_file PARAMS ((char *filename)); +char *input_scrub_next_buffer PARAMS ((char **bufp)); +int do_scrub_chars PARAMS ((int (*get) (char *, int), char *to, int tolen)); +int gen_to_words PARAMS ((LITTLENUM_TYPE * words, int precision, + long exponent_bits)); +int had_err PARAMS ((void)); +int ignore_input PARAMS ((void)); +void cond_finish_check PARAMS ((int)); +void cond_exit_macro PARAMS ((int)); +int seen_at_least_1_file PARAMS ((void)); +void app_pop PARAMS ((char *arg)); +void as_howmuch PARAMS ((FILE * stream)); +void as_perror PARAMS ((const char *gripe, const char *filename)); +void as_where PARAMS ((char **namep, unsigned int *linep)); +void bump_line_counters PARAMS ((void)); +void do_scrub_begin PARAMS ((int)); +void input_scrub_begin PARAMS ((void)); +void input_scrub_close PARAMS ((void)); +void input_scrub_end PARAMS ((void)); +int new_logical_line PARAMS ((char *fname, int line_number)); +void subsegs_begin PARAMS ((void)); +void subseg_change PARAMS ((segT seg, int subseg)); +segT subseg_new PARAMS ((const char *name, subsegT subseg)); +segT subseg_force_new PARAMS ((const char *name, subsegT subseg)); +void subseg_set PARAMS ((segT seg, subsegT subseg)); +#ifdef BFD_ASSEMBLER +segT subseg_get PARAMS ((const char *, int)); +#endif +int subseg_text_p PARAMS ((segT)); + +void start_dependencies PARAMS ((char *)); +void register_dependency PARAMS ((char *)); +void print_dependencies PARAMS ((void)); + +struct expressionS; +struct fix; +typedef struct symbol symbolS; +struct relax_type; +typedef struct frag fragS; + +#ifdef BFD_ASSEMBLER +/* literal.c */ +valueT add_to_literal_pool PARAMS ((symbolS *, valueT, segT, int)); +#endif + +int check_eh_frame PARAMS ((struct expressionS *, unsigned int *)); +int eh_frame_estimate_size_before_relax PARAMS ((fragS *)); +int eh_frame_relax_frag PARAMS ((fragS *)); +void eh_frame_convert_frag PARAMS ((fragS *)); + +int generic_force_reloc PARAMS ((struct fix *)); + +#include "expr.h" /* Before targ-*.h */ + +/* this one starts the chain of target dependant headers */ +#include "targ-env.h" + +#ifdef OBJ_MAYBE_ELF +#define IS_ELF (OUTPUT_FLAVOR == bfd_target_elf_flavour) +#else +#ifdef OBJ_ELF +#define IS_ELF 1 +#else +#define IS_ELF 0 +#endif +#endif + +#include "write.h" +#include "frags.h" +#include "hash.h" +#include "read.h" +#include "symbols.h" + +#include "tc.h" +#include "obj.h" + +#ifdef USE_EMULATIONS +#include "emul.h" +#endif +#include "listing.h" + +#ifdef TC_M68K +/* True if we are assembling in m68k MRI mode. */ +COMMON int flag_m68k_mri; +#else +#define flag_m68k_mri 0 +#endif + +#ifdef WARN_COMMENTS +COMMON int warn_comment; +COMMON unsigned int found_comment; +COMMON char *found_comment_file; +#endif + +#ifndef NUMBERS_WITH_SUFFIX +#define NUMBERS_WITH_SUFFIX 0 +#endif + +#ifndef LOCAL_LABELS_DOLLAR +#define LOCAL_LABELS_DOLLAR 0 +#endif + +#ifndef LOCAL_LABELS_FB +#define LOCAL_LABELS_FB 0 +#endif + +#ifndef LABELS_WITHOUT_COLONS +#define LABELS_WITHOUT_COLONS 0 +#endif + +#ifndef NO_PSEUDO_DOT +#define NO_PSEUDO_DOT 0 +#endif + +#ifndef TEXT_SECTION_NAME +#define TEXT_SECTION_NAME ".text" +#define DATA_SECTION_NAME ".data" +#define BSS_SECTION_NAME ".bss" +#endif + +#ifndef OCTETS_PER_BYTE_POWER +#define OCTETS_PER_BYTE_POWER 0 +#endif +#ifndef OCTETS_PER_BYTE +#define OCTETS_PER_BYTE (1< + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef ENABLE_NLS +# include +# define _(String) gettext (String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define textdomain(Domainname) while (0) /* nothing */ +# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */ +# define _(String) (String) +# define N_(String) (String) +#endif diff --git a/contrib/binutils-2.14/gas/atof-generic.c b/contrib/binutils-2.14/gas/atof-generic.c new file mode 100644 index 0000000000..c5d10d4205 --- /dev/null +++ b/contrib/binutils-2.14/gas/atof-generic.c @@ -0,0 +1,634 @@ +/* atof_generic.c - turn a string of digits into a Flonum + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include + +#include "as.h" +#include "safe-ctype.h" + +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (1) +#endif + +#ifdef TRACE +static void flonum_print PARAMS ((const FLONUM_TYPE *)); +#endif + +#define ASSUME_DECIMAL_MARK_IS_DOT + +/***********************************************************************\ + * * + * Given a string of decimal digits , with optional decimal * + * mark and optional decimal exponent (place value) of the * + * lowest_order decimal digit: produce a floating point * + * number. The number is 'generic' floating point: our * + * caller will encode it for a specific machine architecture. * + * * + * Assumptions * + * uses base (radix) 2 * + * this machine uses 2's complement binary integers * + * target flonums use " " " " * + * target flonums exponents fit in a long * + * * + \***********************************************************************/ + +/* + + Syntax: + + ::= + ::= '+' | '-' | {empty} + ::= + | + | + | + + ::= {empty} + | + + ::= | + ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' + ::= {one character from "string_of_decimal_exponent_marks"} + ::= {one character from "string_of_decimal_marks"} + + */ + +int +atof_generic (address_of_string_pointer, + string_of_decimal_marks, + string_of_decimal_exponent_marks, + address_of_generic_floating_point_number) + /* return pointer to just AFTER number we read. */ + char **address_of_string_pointer; + /* At most one per number. */ + const char *string_of_decimal_marks; + const char *string_of_decimal_exponent_marks; + FLONUM_TYPE *address_of_generic_floating_point_number; +{ + int return_value; /* 0 means OK. */ + char *first_digit; + unsigned int number_of_digits_before_decimal; + unsigned int number_of_digits_after_decimal; + long decimal_exponent; + unsigned int number_of_digits_available; + char digits_sign_char; + + /* + * Scan the input string, abstracting (1)digits (2)decimal mark (3) exponent. + * It would be simpler to modify the string, but we don't; just to be nice + * to caller. + * We need to know how many digits we have, so we can allocate space for + * the digits' value. + */ + + char *p; + char c; + int seen_significant_digit; + +#ifdef ASSUME_DECIMAL_MARK_IS_DOT + assert (string_of_decimal_marks[0] == '.' + && string_of_decimal_marks[1] == 0); +#define IS_DECIMAL_MARK(c) ((c) == '.') +#else +#define IS_DECIMAL_MARK(c) (0 != strchr (string_of_decimal_marks, (c))) +#endif + + first_digit = *address_of_string_pointer; + c = *first_digit; + + if (c == '-' || c == '+') + { + digits_sign_char = c; + first_digit++; + } + else + digits_sign_char = '+'; + + switch (first_digit[0]) + { + case 'n': + case 'N': + if (!strncasecmp ("nan", first_digit, 3)) + { + address_of_generic_floating_point_number->sign = 0; + address_of_generic_floating_point_number->exponent = 0; + address_of_generic_floating_point_number->leader = + address_of_generic_floating_point_number->low; + *address_of_string_pointer = first_digit + 3; + return 0; + } + break; + + case 'i': + case 'I': + if (!strncasecmp ("inf", first_digit, 3)) + { + address_of_generic_floating_point_number->sign = + digits_sign_char == '+' ? 'P' : 'N'; + address_of_generic_floating_point_number->exponent = 0; + address_of_generic_floating_point_number->leader = + address_of_generic_floating_point_number->low; + + first_digit += 3; + if (!strncasecmp ("inity", first_digit, 5)) + first_digit += 5; + + *address_of_string_pointer = first_digit; + + return 0; + } + break; + } + + number_of_digits_before_decimal = 0; + number_of_digits_after_decimal = 0; + decimal_exponent = 0; + seen_significant_digit = 0; + for (p = first_digit; + (((c = *p) != '\0') + && (!c || !IS_DECIMAL_MARK (c)) + && (!c || !strchr (string_of_decimal_exponent_marks, c))); + p++) + { + if (ISDIGIT (c)) + { + if (seen_significant_digit || c > '0') + { + ++number_of_digits_before_decimal; + seen_significant_digit = 1; + } + else + { + first_digit++; + } + } + else + { + break; /* p -> char after pre-decimal digits. */ + } + } /* For each digit before decimal mark. */ + +#ifndef OLD_FLOAT_READS + /* Ignore trailing 0's after the decimal point. The original code here + * (ifdef'd out) does not do this, and numbers like + * 4.29496729600000000000e+09 (2**31) + * come out inexact for some reason related to length of the digit + * string. + */ + if (c && IS_DECIMAL_MARK (c)) + { + unsigned int zeros = 0; /* Length of current string of zeros */ + + for (p++; (c = *p) && ISDIGIT (c); p++) + { + if (c == '0') + { + zeros++; + } + else + { + number_of_digits_after_decimal += 1 + zeros; + zeros = 0; + } + } + } +#else + if (c && IS_DECIMAL_MARK (c)) + { + for (p++; + (((c = *p) != '\0') + && (!c || !strchr (string_of_decimal_exponent_marks, c))); + p++) + { + if (ISDIGIT (c)) + { + /* This may be retracted below. */ + number_of_digits_after_decimal++; + + if ( /* seen_significant_digit || */ c > '0') + { + seen_significant_digit = TRUE; + } + } + else + { + if (!seen_significant_digit) + { + number_of_digits_after_decimal = 0; + } + break; + } + } /* For each digit after decimal mark. */ + } + + while (number_of_digits_after_decimal + && first_digit[number_of_digits_before_decimal + + number_of_digits_after_decimal] == '0') + --number_of_digits_after_decimal; +#endif + + if (flag_m68k_mri) + { + while (c == '_') + c = *++p; + } + if (c && strchr (string_of_decimal_exponent_marks, c)) + { + char digits_exponent_sign_char; + + c = *++p; + if (flag_m68k_mri) + { + while (c == '_') + c = *++p; + } + if (c && strchr ("+-", c)) + { + digits_exponent_sign_char = c; + c = *++p; + } + else + { + digits_exponent_sign_char = '+'; + } + + for (; (c); c = *++p) + { + if (ISDIGIT (c)) + { + decimal_exponent = decimal_exponent * 10 + c - '0'; + /* + * BUG! If we overflow here, we lose! + */ + } + else + { + break; + } + } + + if (digits_exponent_sign_char == '-') + { + decimal_exponent = -decimal_exponent; + } + } + + *address_of_string_pointer = p; + + number_of_digits_available = + number_of_digits_before_decimal + number_of_digits_after_decimal; + return_value = 0; + if (number_of_digits_available == 0) + { + address_of_generic_floating_point_number->exponent = 0; /* Not strictly necessary */ + address_of_generic_floating_point_number->leader + = -1 + address_of_generic_floating_point_number->low; + address_of_generic_floating_point_number->sign = digits_sign_char; + /* We have just concocted (+/-)0.0E0 */ + + } + else + { + int count; /* Number of useful digits left to scan. */ + + LITTLENUM_TYPE *digits_binary_low; + unsigned int precision; + unsigned int maximum_useful_digits; + unsigned int number_of_digits_to_use; + unsigned int more_than_enough_bits_for_digits; + unsigned int more_than_enough_littlenums_for_digits; + unsigned int size_of_digits_in_littlenums; + unsigned int size_of_digits_in_chars; + FLONUM_TYPE power_of_10_flonum; + FLONUM_TYPE digits_flonum; + + precision = (address_of_generic_floating_point_number->high + - address_of_generic_floating_point_number->low + + 1); /* Number of destination littlenums. */ + + /* Includes guard bits (two littlenums worth) */ +#if 0 /* The integer version below is very close, and it doesn't + require floating point support (which is currently buggy on + the Alpha). */ + maximum_useful_digits = (((double) (precision - 2)) + * ((double) (LITTLENUM_NUMBER_OF_BITS)) + / (LOG_TO_BASE_2_OF_10)) + + 2; /* 2 :: guard digits. */ +#else + maximum_useful_digits = (((precision - 2)) + * ( (LITTLENUM_NUMBER_OF_BITS)) + * 1000000 / 3321928) + + 2; /* 2 :: guard digits. */ +#endif + + if (number_of_digits_available > maximum_useful_digits) + { + number_of_digits_to_use = maximum_useful_digits; + } + else + { + number_of_digits_to_use = number_of_digits_available; + } + + /* Cast these to SIGNED LONG first, otherwise, on systems with + LONG wider than INT (such as Alpha OSF/1), unsignedness may + cause unexpected results. */ + decimal_exponent += ((long) number_of_digits_before_decimal + - (long) number_of_digits_to_use); + +#if 0 + more_than_enough_bits_for_digits + = ((((double) number_of_digits_to_use) * LOG_TO_BASE_2_OF_10) + 1); +#else + more_than_enough_bits_for_digits + = (number_of_digits_to_use * 3321928 / 1000000 + 1); +#endif + + more_than_enough_littlenums_for_digits + = (more_than_enough_bits_for_digits + / LITTLENUM_NUMBER_OF_BITS) + + 2; + + /* Compute (digits) part. In "12.34E56" this is the "1234" part. + Arithmetic is exact here. If no digits are supplied then this + part is a 0 valued binary integer. Allocate room to build up + the binary number as littlenums. We want this memory to + disappear when we leave this function. Assume no alignment + problems => (room for n objects) == n * (room for 1 + object). */ + + size_of_digits_in_littlenums = more_than_enough_littlenums_for_digits; + size_of_digits_in_chars = size_of_digits_in_littlenums + * sizeof (LITTLENUM_TYPE); + + digits_binary_low = (LITTLENUM_TYPE *) + alloca (size_of_digits_in_chars); + + memset ((char *) digits_binary_low, '\0', size_of_digits_in_chars); + + /* Digits_binary_low[] is allocated and zeroed. */ + + /* + * Parse the decimal digits as if * digits_low was in the units position. + * Emit a binary number into digits_binary_low[]. + * + * Use a large-precision version of: + * (((1st-digit) * 10 + 2nd-digit) * 10 + 3rd-digit ...) * 10 + last-digit + */ + + for (p = first_digit, count = number_of_digits_to_use; count; p++, --count) + { + c = *p; + if (ISDIGIT (c)) + { + /* + * Multiply by 10. Assume can never overflow. + * Add this digit to digits_binary_low[]. + */ + + long carry; + LITTLENUM_TYPE *littlenum_pointer; + LITTLENUM_TYPE *littlenum_limit; + + littlenum_limit = digits_binary_low + + more_than_enough_littlenums_for_digits + - 1; + + carry = c - '0'; /* char -> binary */ + + for (littlenum_pointer = digits_binary_low; + littlenum_pointer <= littlenum_limit; + littlenum_pointer++) + { + long work; + + work = carry + 10 * (long) (*littlenum_pointer); + *littlenum_pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; + } + + if (carry != 0) + { + /* + * We have a GROSS internal error. + * This should never happen. + */ + as_fatal (_("failed sanity check")); + } + } + else + { + ++count; /* '.' doesn't alter digits used count. */ + } + } + + /* + * Digits_binary_low[] properly encodes the value of the digits. + * Forget about any high-order littlenums that are 0. + */ + while (digits_binary_low[size_of_digits_in_littlenums - 1] == 0 + && size_of_digits_in_littlenums >= 2) + size_of_digits_in_littlenums--; + + digits_flonum.low = digits_binary_low; + digits_flonum.high = digits_binary_low + size_of_digits_in_littlenums - 1; + digits_flonum.leader = digits_flonum.high; + digits_flonum.exponent = 0; + /* + * The value of digits_flonum . sign should not be important. + * We have already decided the output's sign. + * We trust that the sign won't influence the other parts of the number! + * So we give it a value for these reasons: + * (1) courtesy to humans reading/debugging + * these numbers so they don't get excited about strange values + * (2) in future there may be more meaning attached to sign, + * and what was + * harmless noise may become disruptive, ill-conditioned (or worse) + * input. + */ + digits_flonum.sign = '+'; + + { + /* + * Compute the mantssa (& exponent) of the power of 10. + * If sucessful, then multiply the power of 10 by the digits + * giving return_binary_mantissa and return_binary_exponent. + */ + + LITTLENUM_TYPE *power_binary_low; + int decimal_exponent_is_negative; + /* This refers to the "-56" in "12.34E-56". */ + /* FALSE: decimal_exponent is positive (or 0) */ + /* TRUE: decimal_exponent is negative */ + FLONUM_TYPE temporary_flonum; + LITTLENUM_TYPE *temporary_binary_low; + unsigned int size_of_power_in_littlenums; + unsigned int size_of_power_in_chars; + + size_of_power_in_littlenums = precision; + /* Precision has a built-in fudge factor so we get a few guard bits. */ + + decimal_exponent_is_negative = decimal_exponent < 0; + if (decimal_exponent_is_negative) + { + decimal_exponent = -decimal_exponent; + } + + /* From now on: the decimal exponent is > 0. Its sign is separate. */ + + size_of_power_in_chars = size_of_power_in_littlenums + * sizeof (LITTLENUM_TYPE) + 2; + + power_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars); + temporary_binary_low = (LITTLENUM_TYPE *) alloca (size_of_power_in_chars); + memset ((char *) power_binary_low, '\0', size_of_power_in_chars); + *power_binary_low = 1; + power_of_10_flonum.exponent = 0; + power_of_10_flonum.low = power_binary_low; + power_of_10_flonum.leader = power_binary_low; + power_of_10_flonum.high = power_binary_low + size_of_power_in_littlenums - 1; + power_of_10_flonum.sign = '+'; + temporary_flonum.low = temporary_binary_low; + temporary_flonum.high = temporary_binary_low + size_of_power_in_littlenums - 1; + /* + * (power) == 1. + * Space for temporary_flonum allocated. + */ + + /* + * ... + * + * WHILE more bits + * DO find next bit (with place value) + * multiply into power mantissa + * OD + */ + { + int place_number_limit; + /* Any 10^(2^n) whose "n" exceeds this */ + /* value will fall off the end of */ + /* flonum_XXXX_powers_of_ten[]. */ + int place_number; + const FLONUM_TYPE *multiplicand; /* -> 10^(2^n) */ + + place_number_limit = table_size_of_flonum_powers_of_ten; + + multiplicand = (decimal_exponent_is_negative + ? flonum_negative_powers_of_ten + : flonum_positive_powers_of_ten); + + for (place_number = 1;/* Place value of this bit of exponent. */ + decimal_exponent;/* Quit when no more 1 bits in exponent. */ + decimal_exponent >>= 1, place_number++) + { + if (decimal_exponent & 1) + { + if (place_number > place_number_limit) + { + /* The decimal exponent has a magnitude so great + that our tables can't help us fragment it. + Although this routine is in error because it + can't imagine a number that big, signal an + error as if it is the user's fault for + presenting such a big number. */ + return_value = ERROR_EXPONENT_OVERFLOW; + /* quit out of loop gracefully */ + decimal_exponent = 0; + } + else + { +#ifdef TRACE + printf ("before multiply, place_number = %d., power_of_10_flonum:\n", + place_number); + + flonum_print (&power_of_10_flonum); + (void) putchar ('\n'); +#endif +#ifdef TRACE + printf ("multiplier:\n"); + flonum_print (multiplicand + place_number); + (void) putchar ('\n'); +#endif + flonum_multip (multiplicand + place_number, + &power_of_10_flonum, &temporary_flonum); +#ifdef TRACE + printf ("after multiply:\n"); + flonum_print (&temporary_flonum); + (void) putchar ('\n'); +#endif + flonum_copy (&temporary_flonum, &power_of_10_flonum); +#ifdef TRACE + printf ("after copy:\n"); + flonum_print (&power_of_10_flonum); + (void) putchar ('\n'); +#endif + } /* If this bit of decimal_exponent was computable.*/ + } /* If this bit of decimal_exponent was set. */ + } /* For each bit of binary representation of exponent */ +#ifdef TRACE + printf ("after computing power_of_10_flonum:\n"); + flonum_print (&power_of_10_flonum); + (void) putchar ('\n'); +#endif + } + + } + + /* + * power_of_10_flonum is power of ten in binary (mantissa) , (exponent). + * It may be the number 1, in which case we don't NEED to multiply. + * + * Multiply (decimal digits) by power_of_10_flonum. + */ + + flonum_multip (&power_of_10_flonum, &digits_flonum, address_of_generic_floating_point_number); + /* Assert sign of the number we made is '+'. */ + address_of_generic_floating_point_number->sign = digits_sign_char; + + } + return return_value; +} + +#ifdef TRACE +static void +flonum_print (f) + const FLONUM_TYPE *f; +{ + LITTLENUM_TYPE *lp; + char littlenum_format[10]; + sprintf (littlenum_format, " %%0%dx", sizeof (LITTLENUM_TYPE) * 2); +#define print_littlenum(LP) (printf (littlenum_format, LP)) + printf ("flonum @%p %c e%ld", f, f->sign, f->exponent); + if (f->low < f->high) + for (lp = f->high; lp >= f->low; lp--) + print_littlenum (*lp); + else + for (lp = f->low; lp <= f->high; lp++) + print_littlenum (*lp); + printf ("\n"); + fflush (stdout); +} +#endif + +/* end of atof_generic.c */ diff --git a/contrib/binutils-2.14/gas/bignum-copy.c b/contrib/binutils-2.14/gas/bignum-copy.c new file mode 100644 index 0000000000..b4ed7d1df4 --- /dev/null +++ b/contrib/binutils-2.14/gas/bignum-copy.c @@ -0,0 +1,81 @@ +/* bignum_copy.c - copy a bignum + Copyright 1987, 1990, 1991, 1992, 1993, 2000 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "as.h" + +/* + * bignum_copy () + * + * Copy a bignum from in to out. + * If the output is shorter than the input, copy lower-order littlenums. + * Return 0 or the number of significant littlenums dropped. + * Assumes littlenum arrays are densely packed: no unused chars between + * the littlenums. Uses memcpy() to move littlenums, and wants to + * know length (in chars) of the input bignum. + */ + +/* void */ +int +bignum_copy (in, in_length, out, out_length) + register LITTLENUM_TYPE *in; + register int in_length; /* in sizeof(littlenum)s */ + register LITTLENUM_TYPE *out; + register int out_length; /* in sizeof(littlenum)s */ +{ + int significant_littlenums_dropped; + + if (out_length < in_length) + { + LITTLENUM_TYPE *p; /* -> most significant (non-zero) input + littlenum. */ + + memcpy ((void *) out, (void *) in, + (unsigned int) out_length << LITTLENUM_SHIFT); + for (p = in + in_length - 1; p >= in; --p) + { + if (*p) + break; + } + significant_littlenums_dropped = p - in - in_length + 1; + + if (significant_littlenums_dropped < 0) + { + significant_littlenums_dropped = 0; + } + } + else + { + memcpy ((char *) out, (char *) in, + (unsigned int) in_length << LITTLENUM_SHIFT); + + if (out_length > in_length) + { + memset ((char *) (out + in_length), + '\0', + (unsigned int) (out_length - in_length) << LITTLENUM_SHIFT); + } + + significant_littlenums_dropped = 0; + } + + return (significant_littlenums_dropped); +} /* bignum_copy() */ + +/* end of bignum-copy.c */ diff --git a/contrib/binutils-2.14/gas/bignum.h b/contrib/binutils-2.14/gas/bignum.h new file mode 100644 index 0000000000..42954cff5c --- /dev/null +++ b/contrib/binutils-2.14/gas/bignum.h @@ -0,0 +1,52 @@ +/* bignum.h-arbitrary precision integers + Copyright 1987, 1992 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/***********************************************************************\ + * * + * Arbitrary-precision integer arithmetic. * + * For speed, we work in groups of bits, even though this * + * complicates algorithms. * + * Each group of bits is called a 'littlenum'. * + * A bunch of littlenums representing a (possibly large) * + * integer is called a 'bignum'. * + * Bignums are >= 0. * + * * + \***********************************************************************/ + +#define LITTLENUM_NUMBER_OF_BITS (16) +#define LITTLENUM_RADIX (1 << LITTLENUM_NUMBER_OF_BITS) +#define LITTLENUM_MASK (0xFFFF) +#define LITTLENUM_SHIFT (1) +#define CHARS_PER_LITTLENUM (1 << LITTLENUM_SHIFT) +#ifndef BITS_PER_CHAR +#define BITS_PER_CHAR (8) +#endif + +typedef unsigned short LITTLENUM_TYPE; + +/* JF truncated this to get around a problem with GCC */ +#define LOG_TO_BASE_2_OF_10 (3.3219280948873623478703194294893901758651) +/* WARNING: I haven't checked that the trailing digits are correct! */ + +/* lengths are in sizeof(littlenum)s */ + +int bignum_copy PARAMS ((LITTLENUM_TYPE * in, int in_length, + LITTLENUM_TYPE * out, int out_length)); + +/* end of bignum.h */ diff --git a/contrib/binutils-2.14/gas/bit_fix.h b/contrib/binutils-2.14/gas/bit_fix.h new file mode 100644 index 0000000000..80c002278a --- /dev/null +++ b/contrib/binutils-2.14/gas/bit_fix.h @@ -0,0 +1,48 @@ +/* bit_fix.h + Copyright 1987, 1992, 2000, 2001 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* The bit_fix was implemented to support machines that need variables + to be inserted in bitfields other than 1, 2 and 4 bytes. + Furthermore it gives us a possibillity to mask in bits in the symbol + when it's fixed in the objectcode and check the symbols limits. + + The or-mask is used to set the huffman bits in displacements for the + ns32k port. + The acbi, addqi, movqi, cmpqi instruction requires an assembler that + can handle bitfields. Ie. handle an expression, evaluate it and insert + the result in some bitfield. (eg: 5 bits in a short field of an opcode) + */ + +#ifndef __bit_fix_h__ +#define __bit_fix_h__ + +struct bit_fix { + int fx_bit_size; /* Length of bitfield */ + int fx_bit_offset; /* Bit offset to bitfield */ + long fx_bit_base; /* Where do we apply the bitfix. + If this is zero, default is assumed. */ + long fx_bit_base_adj; /* Adjustment of base */ + long fx_bit_max; /* Signextended max for bitfield */ + long fx_bit_min; /* Signextended min for bitfield */ + long fx_bit_add; /* Or mask, used for huffman prefix */ +}; +typedef struct bit_fix bit_fixS; + +#endif /* __bit_fix_h__ */ diff --git a/contrib/binutils-2.14/gas/cond.c b/contrib/binutils-2.14/gas/cond.c new file mode 100644 index 0000000000..b7a4082c52 --- /dev/null +++ b/contrib/binutils-2.14/gas/cond.c @@ -0,0 +1,554 @@ +/* cond.c - conditional assembly pseudo-ops, and .include + Copyright 1990, 1991, 1992, 1993, 1995, 1997, 1998, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" +#include "macro.h" + +#include "obstack.h" + +/* This is allocated to grow and shrink as .ifdef/.endif pairs are + scanned. */ +struct obstack cond_obstack; + +struct file_line { + char *file; + unsigned int line; +}; + +/* We push one of these structures for each .if, and pop it at the + .endif. */ + +struct conditional_frame { + /* The source file & line number of the "if". */ + struct file_line if_file_line; + /* The source file & line of the "else". */ + struct file_line else_file_line; + /* The previous conditional. */ + struct conditional_frame *previous_cframe; + /* Have we seen an else yet? */ + int else_seen; + /* Whether we are currently ignoring input. */ + int ignoring; + /* Whether a conditional at a higher level is ignoring input. + Set also when a branch of an "if .. elseif .." tree has matched + to prevent further matches. */ + int dead_tree; + /* Macro nesting level at which this conditional was created. */ + int macro_nest; +}; + +static void initialize_cframe PARAMS ((struct conditional_frame *cframe)); +static char *get_mri_string PARAMS ((int, int *)); + +static struct conditional_frame *current_cframe = NULL; + +/* Performs the .ifdef (test_defined == 1) and + the .ifndef (test_defined == 0) pseudo op. */ + +void +s_ifdef (test_defined) + int test_defined; +{ + /* Points to name of symbol. */ + char *name; + /* Points to symbol. */ + symbolS *symbolP; + struct conditional_frame cframe; + char c; + + /* Leading whitespace is part of operand. */ + SKIP_WHITESPACE (); + name = input_line_pointer; + + if (!is_name_beginner (*name)) + { + as_bad (_("invalid identifier for \".ifdef\"")); + obstack_1grow (&cond_obstack, 0); + ignore_rest_of_line (); + return; + } + + c = get_symbol_end (); + symbolP = symbol_find (name); + *input_line_pointer = c; + + initialize_cframe (&cframe); + + if (cframe.dead_tree) + cframe.ignoring = 1; + else + { + int is_defined; + + /* Use the same definition of 'defined' as .equiv so that a symbol + which has been referenced but not yet given a value/address is + considered to be undefined. */ + is_defined = + symbolP != NULL + && S_IS_DEFINED (symbolP) + && S_GET_SEGMENT (symbolP) != reg_section; + + cframe.ignoring = ! (test_defined ^ is_defined); + } + + current_cframe = ((struct conditional_frame *) + obstack_copy (&cond_obstack, &cframe, + sizeof (cframe))); + + if (LISTING_SKIP_COND () + && cframe.ignoring + && (cframe.previous_cframe == NULL + || ! cframe.previous_cframe->ignoring)) + listing_list (2); + + demand_empty_rest_of_line (); +} + +void +s_if (arg) + int arg; +{ + expressionS operand; + struct conditional_frame cframe; + int t; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + /* Leading whitespace is part of operand. */ + SKIP_WHITESPACE (); + + if (current_cframe != NULL && current_cframe->ignoring) + { + operand.X_add_number = 0; + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + else + { + expression (&operand); + if (operand.X_op != O_constant) + as_bad (_("non-constant expression in \".if\" statement")); + } + + switch ((operatorT) arg) + { + case O_eq: t = operand.X_add_number == 0; break; + case O_ne: t = operand.X_add_number != 0; break; + case O_lt: t = operand.X_add_number < 0; break; + case O_le: t = operand.X_add_number <= 0; break; + case O_ge: t = operand.X_add_number >= 0; break; + case O_gt: t = operand.X_add_number > 0; break; + default: + abort (); + return; + } + + /* If the above error is signaled, this will dispatch + using an undefined result. No big deal. */ + initialize_cframe (&cframe); + cframe.ignoring = cframe.dead_tree || ! t; + current_cframe = ((struct conditional_frame *) + obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); + + if (LISTING_SKIP_COND () + && cframe.ignoring + && (cframe.previous_cframe == NULL + || ! cframe.previous_cframe->ignoring)) + listing_list (2); + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + +/* Get a string for the MRI IFC or IFNC pseudo-ops. */ + +static char * +get_mri_string (terminator, len) + int terminator; + int *len; +{ + char *ret; + char *s; + + SKIP_WHITESPACE (); + s = ret = input_line_pointer; + if (*input_line_pointer == '\'') + { + ++s; + ++input_line_pointer; + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + { + *s++ = *input_line_pointer++; + if (s[-1] == '\'') + { + if (*input_line_pointer != '\'') + break; + ++input_line_pointer; + } + } + SKIP_WHITESPACE (); + } + else + { + while (*input_line_pointer != terminator + && ! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + s = input_line_pointer; + while (s > ret && (s[-1] == ' ' || s[-1] == '\t')) + --s; + } + + *len = s - ret; + return ret; +} + +/* The MRI IFC and IFNC pseudo-ops. */ + +void +s_ifc (arg) + int arg; +{ + char *stop = NULL; + char stopc; + char *s1, *s2; + int len1, len2; + int res; + struct conditional_frame cframe; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + s1 = get_mri_string (',', &len1); + + if (*input_line_pointer != ',') + as_bad (_("bad format for ifc or ifnc")); + else + ++input_line_pointer; + + s2 = get_mri_string (';', &len2); + + res = len1 == len2 && strncmp (s1, s2, len1) == 0; + + initialize_cframe (&cframe); + cframe.ignoring = cframe.dead_tree || ! (res ^ arg); + current_cframe = ((struct conditional_frame *) + obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); + + if (LISTING_SKIP_COND () + && cframe.ignoring + && (cframe.previous_cframe == NULL + || ! cframe.previous_cframe->ignoring)) + listing_list (2); + + if (flag_mri) + mri_comment_end (stop, stopc); + + demand_empty_rest_of_line (); +} + +void +s_elseif (arg) + int arg; +{ + if (current_cframe == NULL) + { + as_bad (_("\".elseif\" without matching \".if\"")); + } + else if (current_cframe->else_seen) + { + as_bad (_("\".elseif\" after \".else\"")); + as_bad_where (current_cframe->else_file_line.file, + current_cframe->else_file_line.line, + _("here is the previous \"else\"")); + as_bad_where (current_cframe->if_file_line.file, + current_cframe->if_file_line.line, + _("here is the previous \"if\"")); + } + else + { + as_where (¤t_cframe->else_file_line.file, + ¤t_cframe->else_file_line.line); + + current_cframe->dead_tree |= !current_cframe->ignoring; + current_cframe->ignoring = current_cframe->dead_tree; + } + + if (current_cframe == NULL || current_cframe->ignoring) + { + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + + if (current_cframe == NULL) + return; + } + else + { + expressionS operand; + int t; + + /* Leading whitespace is part of operand. */ + SKIP_WHITESPACE (); + + expression (&operand); + if (operand.X_op != O_constant) + as_bad (_("non-constant expression in \".elseif\" statement")); + + switch ((operatorT) arg) + { + case O_eq: t = operand.X_add_number == 0; break; + case O_ne: t = operand.X_add_number != 0; break; + case O_lt: t = operand.X_add_number < 0; break; + case O_le: t = operand.X_add_number <= 0; break; + case O_ge: t = operand.X_add_number >= 0; break; + case O_gt: t = operand.X_add_number > 0; break; + default: + abort (); + return; + } + + current_cframe->ignoring = current_cframe->dead_tree || ! t; + } + + if (LISTING_SKIP_COND () + && (current_cframe->previous_cframe == NULL + || ! current_cframe->previous_cframe->ignoring)) + { + if (! current_cframe->ignoring) + listing_list (1); + else + listing_list (2); + } + + demand_empty_rest_of_line (); +} + +void +s_endif (arg) + int arg ATTRIBUTE_UNUSED; +{ + struct conditional_frame *hold; + + if (current_cframe == NULL) + { + as_bad (_("\".endif\" without \".if\"")); + } + else + { + if (LISTING_SKIP_COND () + && current_cframe->ignoring + && (current_cframe->previous_cframe == NULL + || ! current_cframe->previous_cframe->ignoring)) + listing_list (1); + + hold = current_cframe; + current_cframe = current_cframe->previous_cframe; + obstack_free (&cond_obstack, hold); + } /* if one pop too many */ + + if (flag_mri) + { + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + + demand_empty_rest_of_line (); +} + +void +s_else (arg) + int arg ATTRIBUTE_UNUSED; +{ + if (current_cframe == NULL) + { + as_bad (_("\".else\" without matching \".if\"")); + } + else if (current_cframe->else_seen) + { + as_bad (_("duplicate \"else\"")); + as_bad_where (current_cframe->else_file_line.file, + current_cframe->else_file_line.line, + _("here is the previous \"else\"")); + as_bad_where (current_cframe->if_file_line.file, + current_cframe->if_file_line.line, + _("here is the previous \"if\"")); + } + else + { + as_where (¤t_cframe->else_file_line.file, + ¤t_cframe->else_file_line.line); + + current_cframe->ignoring = + current_cframe->dead_tree | !current_cframe->ignoring; + + if (LISTING_SKIP_COND () + && (current_cframe->previous_cframe == NULL + || ! current_cframe->previous_cframe->ignoring)) + { + if (! current_cframe->ignoring) + listing_list (1); + else + listing_list (2); + } + + current_cframe->else_seen = 1; + } + + if (flag_mri) + { + while (! is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + + demand_empty_rest_of_line (); +} + +void +s_ifeqs (arg) + int arg; +{ + char *s1, *s2; + int len1, len2; + int res; + struct conditional_frame cframe; + + s1 = demand_copy_C_string (&len1); + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (_(".ifeqs syntax error")); + ignore_rest_of_line (); + return; + } + + ++input_line_pointer; + + s2 = demand_copy_C_string (&len2); + + res = len1 == len2 && strncmp (s1, s2, len1) == 0; + + initialize_cframe (&cframe); + cframe.ignoring = cframe.dead_tree || ! (res ^ arg); + current_cframe = ((struct conditional_frame *) + obstack_copy (&cond_obstack, &cframe, sizeof (cframe))); + + if (LISTING_SKIP_COND () + && cframe.ignoring + && (cframe.previous_cframe == NULL + || ! cframe.previous_cframe->ignoring)) + listing_list (2); + + demand_empty_rest_of_line (); +} + +int +ignore_input () +{ + char *s; + + s = input_line_pointer; + + if (NO_PSEUDO_DOT || flag_m68k_mri) + { + if (s[-1] != '.') + --s; + } + else + { + if (s[-1] != '.') + return (current_cframe != NULL) && (current_cframe->ignoring); + } + + /* We cannot ignore certain pseudo ops. */ + if (((s[0] == 'i' + || s[0] == 'I') + && (!strncasecmp (s, "if", 2) + || !strncasecmp (s, "ifdef", 5) + || !strncasecmp (s, "ifndef", 6))) + || ((s[0] == 'e' + || s[0] == 'E') + && (!strncasecmp (s, "else", 4) + || !strncasecmp (s, "endif", 5) + || !strncasecmp (s, "endc", 4)))) + return 0; + + return (current_cframe != NULL) && (current_cframe->ignoring); +} + +static void +initialize_cframe (cframe) + struct conditional_frame *cframe; +{ + memset (cframe, 0, sizeof (*cframe)); + as_where (&cframe->if_file_line.file, + &cframe->if_file_line.line); + cframe->previous_cframe = current_cframe; + cframe->dead_tree = current_cframe != NULL && current_cframe->ignoring; + cframe->macro_nest = macro_nest; +} + +/* Give an error if a conditional is unterminated inside a macro or + the assembly as a whole. If NEST is non negative, we are being + called because of the end of a macro expansion. If NEST is + negative, we are being called at the of the input files. */ + +void +cond_finish_check (nest) + int nest; +{ + if (current_cframe != NULL && current_cframe->macro_nest >= nest) + { + if (nest >= 0) + as_bad (_("end of macro inside conditional")); + else + as_bad (_("end of file inside conditional")); + as_bad_where (current_cframe->if_file_line.file, + current_cframe->if_file_line.line, + _("here is the start of the unterminated conditional")); + if (current_cframe->else_seen) + as_bad_where (current_cframe->else_file_line.file, + current_cframe->else_file_line.line, + _("here is the \"else\" of the unterminated conditional")); + } +} + +/* This function is called when we exit out of a macro. We assume + that any conditionals which began within the macro are correctly + nested, and just pop them off the stack. */ + +void +cond_exit_macro (nest) + int nest; +{ + while (current_cframe != NULL && current_cframe->macro_nest >= nest) + { + struct conditional_frame *hold; + + hold = current_cframe; + current_cframe = current_cframe->previous_cframe; + obstack_free (&cond_obstack, hold); + } +} diff --git a/contrib/binutils-2.14/gas/config/atof-ieee.c b/contrib/binutils-2.14/gas/config/atof-ieee.c new file mode 100644 index 0000000000..0ad39c9b30 --- /dev/null +++ b/contrib/binutils-2.14/gas/config/atof-ieee.c @@ -0,0 +1,734 @@ +/* atof_ieee.c - turn a Flonum into an IEEE floating point number + Copyright 1987, 1992, 1994, 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" + +/* Flonums returned here. */ +extern FLONUM_TYPE generic_floating_point_number; + +static int next_bits PARAMS ((int)); +static void unget_bits PARAMS ((int)); +static void make_invalid_floating_point_number PARAMS ((LITTLENUM_TYPE *)); + +extern const char EXP_CHARS[]; +/* Precision in LittleNums. */ +/* Don't count the gap in the m68k extended precision format. */ +#define MAX_PRECISION (5) +#define F_PRECISION (2) +#define D_PRECISION (4) +#define X_PRECISION (5) +#define P_PRECISION (5) + +/* Length in LittleNums of guard bits. */ +#define GUARD (2) + +#ifndef TC_LARGEST_EXPONENT_IS_NORMAL +#define TC_LARGEST_EXPONENT_IS_NORMAL(PRECISION) 0 +#endif + +static const unsigned long mask[] = +{ + 0x00000000, + 0x00000001, + 0x00000003, + 0x00000007, + 0x0000000f, + 0x0000001f, + 0x0000003f, + 0x0000007f, + 0x000000ff, + 0x000001ff, + 0x000003ff, + 0x000007ff, + 0x00000fff, + 0x00001fff, + 0x00003fff, + 0x00007fff, + 0x0000ffff, + 0x0001ffff, + 0x0003ffff, + 0x0007ffff, + 0x000fffff, + 0x001fffff, + 0x003fffff, + 0x007fffff, + 0x00ffffff, + 0x01ffffff, + 0x03ffffff, + 0x07ffffff, + 0x0fffffff, + 0x1fffffff, + 0x3fffffff, + 0x7fffffff, + 0xffffffff, +}; + +static int bits_left_in_littlenum; +static int littlenums_left; +static LITTLENUM_TYPE *littlenum_pointer; + +static int +next_bits (number_of_bits) + int number_of_bits; +{ + int return_value; + + if (!littlenums_left) + return (0); + if (number_of_bits >= bits_left_in_littlenum) + { + return_value = mask[bits_left_in_littlenum] & *littlenum_pointer; + number_of_bits -= bits_left_in_littlenum; + return_value <<= number_of_bits; + + if (--littlenums_left) + { + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS - number_of_bits; + --littlenum_pointer; + return_value |= + (*littlenum_pointer >> bits_left_in_littlenum) + & mask[number_of_bits]; + } + } + else + { + bits_left_in_littlenum -= number_of_bits; + return_value = + mask[number_of_bits] & (*littlenum_pointer >> bits_left_in_littlenum); + } + return return_value; +} + +/* Num had better be less than LITTLENUM_NUMBER_OF_BITS. */ + +static void +unget_bits (num) + int num; +{ + if (!littlenums_left) + { + ++littlenum_pointer; + ++littlenums_left; + bits_left_in_littlenum = num; + } + else if (bits_left_in_littlenum + num > LITTLENUM_NUMBER_OF_BITS) + { + bits_left_in_littlenum = + num - (LITTLENUM_NUMBER_OF_BITS - bits_left_in_littlenum); + ++littlenum_pointer; + ++littlenums_left; + } + else + bits_left_in_littlenum += num; +} + +static void +make_invalid_floating_point_number (words) + LITTLENUM_TYPE *words; +{ + as_bad (_("cannot create floating-point number")); + /* Zero the leftmost bit. */ + words[0] = (LITTLENUM_TYPE) ((unsigned) -1) >> 1; + words[1] = (LITTLENUM_TYPE) -1; + words[2] = (LITTLENUM_TYPE) -1; + words[3] = (LITTLENUM_TYPE) -1; + words[4] = (LITTLENUM_TYPE) -1; + words[5] = (LITTLENUM_TYPE) -1; +} + +/* Warning: This returns 16-bit LITTLENUMs. It is up to the caller to + figure out any alignment problems and to conspire for the + bytes/word to be emitted in the right order. Bigendians beware! */ + +/* Note that atof-ieee always has X and P precisions enabled. it is up + to md_atof to filter them out if the target machine does not support + them. */ + +/* Returns pointer past text consumed. */ + +char * +atof_ieee (str, what_kind, words) + char *str; /* Text to convert to binary. */ + int what_kind; /* 'd', 'f', 'g', 'h'. */ + LITTLENUM_TYPE *words; /* Build the binary here. */ +{ + /* Extra bits for zeroed low-order bits. + The 1st MAX_PRECISION are zeroed, the last contain flonum bits. */ + static LITTLENUM_TYPE bits[MAX_PRECISION + MAX_PRECISION + GUARD]; + char *return_value; + /* Number of 16-bit words in the format. */ + int precision; + long exponent_bits; + FLONUM_TYPE save_gen_flonum; + + /* We have to save the generic_floating_point_number because it + contains storage allocation about the array of LITTLENUMs where + the value is actually stored. We will allocate our own array of + littlenums below, but have to restore the global one on exit. */ + save_gen_flonum = generic_floating_point_number; + + return_value = str; + generic_floating_point_number.low = bits + MAX_PRECISION; + generic_floating_point_number.high = NULL; + generic_floating_point_number.leader = NULL; + generic_floating_point_number.exponent = 0; + generic_floating_point_number.sign = '\0'; + + /* Use more LittleNums than seems necessary: the highest flonum may + have 15 leading 0 bits, so could be useless. */ + + memset (bits, '\0', sizeof (LITTLENUM_TYPE) * MAX_PRECISION); + + switch (what_kind) + { + case 'f': + case 'F': + case 's': + case 'S': + precision = F_PRECISION; + exponent_bits = 8; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + precision = D_PRECISION; + exponent_bits = 11; + break; + + case 'x': + case 'X': + case 'e': + case 'E': + precision = X_PRECISION; + exponent_bits = 15; + break; + + case 'p': + case 'P': + + precision = P_PRECISION; + exponent_bits = -1; + break; + + default: + make_invalid_floating_point_number (words); + return (NULL); + } + + generic_floating_point_number.high + = generic_floating_point_number.low + precision - 1 + GUARD; + + if (atof_generic (&return_value, ".", EXP_CHARS, + &generic_floating_point_number)) + { + make_invalid_floating_point_number (words); + return (NULL); + } + gen_to_words (words, precision, exponent_bits); + + /* Restore the generic_floating_point_number's storage alloc (and + everything else). */ + generic_floating_point_number = save_gen_flonum; + + return return_value; +} + +/* Turn generic_floating_point_number into a real float/double/extended. */ + +int +gen_to_words (words, precision, exponent_bits) + LITTLENUM_TYPE *words; + int precision; + long exponent_bits; +{ + int return_value = 0; + + long exponent_1; + long exponent_2; + long exponent_3; + long exponent_4; + int exponent_skippage; + LITTLENUM_TYPE word1; + LITTLENUM_TYPE *lp; + LITTLENUM_TYPE *words_end; + + words_end = words + precision; +#ifdef TC_M68K + if (precision == X_PRECISION) + /* On the m68k the extended precision format has a gap of 16 bits + between the exponent and the mantissa. */ + words_end++; +#endif + + if (generic_floating_point_number.low > generic_floating_point_number.leader) + { + /* 0.0e0 seen. */ + if (generic_floating_point_number.sign == '+') + words[0] = 0x0000; + else + words[0] = 0x8000; + memset (&words[1], '\0', + (words_end - words - 1) * sizeof (LITTLENUM_TYPE)); + return return_value; + } + + /* NaN: Do the right thing. */ + if (generic_floating_point_number.sign == 0) + { + if (TC_LARGEST_EXPONENT_IS_NORMAL (precision)) + as_warn ("NaNs are not supported by this target\n"); + if (precision == F_PRECISION) + { + words[0] = 0x7fff; + words[1] = 0xffff; + } + else if (precision == X_PRECISION) + { +#ifdef TC_M68K + words[0] = 0x7fff; + words[1] = 0; + words[2] = 0xffff; + words[3] = 0xffff; + words[4] = 0xffff; + words[5] = 0xffff; +#else /* ! TC_M68K */ +#ifdef TC_I386 + words[0] = 0xffff; + words[1] = 0xc000; + words[2] = 0; + words[3] = 0; + words[4] = 0; +#else /* ! TC_I386 */ + abort (); +#endif /* ! TC_I386 */ +#endif /* ! TC_M68K */ + } + else + { + words[0] = 0x7fff; + words[1] = 0xffff; + words[2] = 0xffff; + words[3] = 0xffff; + } + return return_value; + } + else if (generic_floating_point_number.sign == 'P') + { + if (TC_LARGEST_EXPONENT_IS_NORMAL (precision)) + as_warn ("Infinities are not supported by this target\n"); + + /* +INF: Do the right thing. */ + if (precision == F_PRECISION) + { + words[0] = 0x7f80; + words[1] = 0; + } + else if (precision == X_PRECISION) + { +#ifdef TC_M68K + words[0] = 0x7fff; + words[1] = 0; + words[2] = 0; + words[3] = 0; + words[4] = 0; + words[5] = 0; +#else /* ! TC_M68K */ +#ifdef TC_I386 + words[0] = 0x7fff; + words[1] = 0x8000; + words[2] = 0; + words[3] = 0; + words[4] = 0; +#else /* ! TC_I386 */ + abort (); +#endif /* ! TC_I386 */ +#endif /* ! TC_M68K */ + } + else + { + words[0] = 0x7ff0; + words[1] = 0; + words[2] = 0; + words[3] = 0; + } + return return_value; + } + else if (generic_floating_point_number.sign == 'N') + { + if (TC_LARGEST_EXPONENT_IS_NORMAL (precision)) + as_warn ("Infinities are not supported by this target\n"); + + /* Negative INF. */ + if (precision == F_PRECISION) + { + words[0] = 0xff80; + words[1] = 0x0; + } + else if (precision == X_PRECISION) + { +#ifdef TC_M68K + words[0] = 0xffff; + words[1] = 0; + words[2] = 0; + words[3] = 0; + words[4] = 0; + words[5] = 0; +#else /* ! TC_M68K */ +#ifdef TC_I386 + words[0] = 0xffff; + words[1] = 0x8000; + words[2] = 0; + words[3] = 0; + words[4] = 0; +#else /* ! TC_I386 */ + abort (); +#endif /* ! TC_I386 */ +#endif /* ! TC_M68K */ + } + else + { + words[0] = 0xfff0; + words[1] = 0x0; + words[2] = 0x0; + words[3] = 0x0; + } + return return_value; + } + + /* The floating point formats we support have: + Bit 15 is sign bit. + Bits 14:n are excess-whatever exponent. + Bits n-1:0 (if any) are most significant bits of fraction. + Bits 15:0 of the next word(s) are the next most significant bits. + + So we need: number of bits of exponent, number of bits of + mantissa. */ + bits_left_in_littlenum = LITTLENUM_NUMBER_OF_BITS; + littlenum_pointer = generic_floating_point_number.leader; + littlenums_left = (1 + + generic_floating_point_number.leader + - generic_floating_point_number.low); + + /* Seek (and forget) 1st significant bit. */ + for (exponent_skippage = 0; !next_bits (1); ++exponent_skippage);; + exponent_1 = (generic_floating_point_number.exponent + + generic_floating_point_number.leader + + 1 + - generic_floating_point_number.low); + + /* Radix LITTLENUM_RADIX, point just higher than + generic_floating_point_number.leader. */ + exponent_2 = exponent_1 * LITTLENUM_NUMBER_OF_BITS; + + /* Radix 2. */ + exponent_3 = exponent_2 - exponent_skippage; + + /* Forget leading zeros, forget 1st bit. */ + exponent_4 = exponent_3 + ((1 << (exponent_bits - 1)) - 2); + + /* Offset exponent. */ + lp = words; + + /* Word 1. Sign, exponent and perhaps high bits. */ + word1 = ((generic_floating_point_number.sign == '+') + ? 0 + : (1 << (LITTLENUM_NUMBER_OF_BITS - 1))); + + /* Assume 2's complement integers. */ + if (exponent_4 <= 0) + { + int prec_bits; + int num_bits; + + unget_bits (1); + num_bits = -exponent_4; + prec_bits = + LITTLENUM_NUMBER_OF_BITS * precision - (exponent_bits + 1 + num_bits); +#ifdef TC_I386 + if (precision == X_PRECISION && exponent_bits == 15) + { + /* On the i386 a denormalized extended precision float is + shifted down by one, effectively decreasing the exponent + bias by one. */ + prec_bits -= 1; + num_bits += 1; + } +#endif + + if (num_bits >= LITTLENUM_NUMBER_OF_BITS - exponent_bits) + { + /* Bigger than one littlenum. */ + num_bits -= (LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits; + *lp++ = word1; + if (num_bits + exponent_bits + 1 + > precision * LITTLENUM_NUMBER_OF_BITS) + { + /* Exponent overflow. */ + make_invalid_floating_point_number (words); + return return_value; + } +#ifdef TC_M68K + if (precision == X_PRECISION && exponent_bits == 15) + *lp++ = 0; +#endif + while (num_bits >= LITTLENUM_NUMBER_OF_BITS) + { + num_bits -= LITTLENUM_NUMBER_OF_BITS; + *lp++ = 0; + } + if (num_bits) + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - (num_bits)); + } + else + { + if (precision == X_PRECISION && exponent_bits == 15) + { + *lp++ = word1; +#ifdef TC_M68K + *lp++ = 0; +#endif + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS - num_bits); + } + else + { + word1 |= next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) + - (exponent_bits + num_bits)); + *lp++ = word1; + } + } + while (lp < words_end) + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS); + + /* Round the mantissa up, but don't change the number. */ + if (next_bits (1)) + { + --lp; + if (prec_bits >= LITTLENUM_NUMBER_OF_BITS) + { + int n = 0; + int tmp_bits; + + n = 0; + tmp_bits = prec_bits; + while (tmp_bits > LITTLENUM_NUMBER_OF_BITS) + { + if (lp[n] != (LITTLENUM_TYPE) - 1) + break; + --n; + tmp_bits -= LITTLENUM_NUMBER_OF_BITS; + } + if (tmp_bits > LITTLENUM_NUMBER_OF_BITS + || (lp[n] & mask[tmp_bits]) != mask[tmp_bits] + || (prec_bits != (precision * LITTLENUM_NUMBER_OF_BITS + - exponent_bits - 1) +#ifdef TC_I386 + /* An extended precision float with only the integer + bit set would be invalid. That must be converted + to the smallest normalized number. */ + && !(precision == X_PRECISION + && prec_bits == (precision * LITTLENUM_NUMBER_OF_BITS + - exponent_bits - 2)) +#endif + )) + { + unsigned long carry; + + for (carry = 1; carry && (lp >= words); lp--) + { + carry = *lp + carry; + *lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + } + } + else + { + /* This is an overflow of the denormal numbers. We + need to forget what we have produced, and instead + generate the smallest normalized number. */ + lp = words; + word1 = ((generic_floating_point_number.sign == '+') + ? 0 + : (1 << (LITTLENUM_NUMBER_OF_BITS - 1))); + word1 |= (1 + << ((LITTLENUM_NUMBER_OF_BITS - 1) + - exponent_bits)); + *lp++ = word1; +#ifdef TC_I386 + /* Set the integer bit in the extended precision format. + This cannot happen on the m68k where the mantissa + just overflows into the integer bit above. */ + if (precision == X_PRECISION) + *lp++ = 1 << (LITTLENUM_NUMBER_OF_BITS - 1); +#endif + while (lp < words_end) + *lp++ = 0; + } + } + else + *lp += 1; + } + + return return_value; + } + else if ((unsigned long) exponent_4 > mask[exponent_bits] + || (! TC_LARGEST_EXPONENT_IS_NORMAL (precision) + && (unsigned long) exponent_4 == mask[exponent_bits])) + { + /* Exponent overflow. Lose immediately. */ + + /* We leave return_value alone: admit we read the + number, but return a floating exception + because we can't encode the number. */ + make_invalid_floating_point_number (words); + return return_value; + } + else + { + word1 |= (exponent_4 << ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits)) + | next_bits ((LITTLENUM_NUMBER_OF_BITS - 1) - exponent_bits); + } + + *lp++ = word1; + + /* X_PRECISION is special: on the 68k, it has 16 bits of zero in the + middle. Either way, it is then followed by a 1 bit. */ + if (exponent_bits == 15 && precision == X_PRECISION) + { +#ifdef TC_M68K + *lp++ = 0; +#endif + *lp++ = (1 << (LITTLENUM_NUMBER_OF_BITS - 1) + | next_bits (LITTLENUM_NUMBER_OF_BITS - 1)); + } + + /* The rest of the words are just mantissa bits. */ + while (lp < words_end) + *lp++ = next_bits (LITTLENUM_NUMBER_OF_BITS); + + if (next_bits (1)) + { + unsigned long carry; + /* Since the NEXT bit is a 1, round UP the mantissa. + The cunning design of these hidden-1 floats permits + us to let the mantissa overflow into the exponent, and + it 'does the right thing'. However, we lose if the + highest-order bit of the lowest-order word flips. + Is that clear? */ + + /* #if (sizeof(carry)) < ((sizeof(bits[0]) * BITS_PER_CHAR) + 2) + Please allow at least 1 more bit in carry than is in a LITTLENUM. + We need that extra bit to hold a carry during a LITTLENUM carry + propagation. Another extra bit (kept 0) will assure us that we + don't get a sticky sign bit after shifting right, and that + permits us to propagate the carry without any masking of bits. + #endif */ + for (carry = 1, lp--; carry; lp--) + { + carry = *lp + carry; + *lp = carry; + carry >>= LITTLENUM_NUMBER_OF_BITS; + if (lp == words) + break; + } + if (precision == X_PRECISION && exponent_bits == 15) + { + /* Extended precision numbers have an explicit integer bit + that we may have to restore. */ + if (lp == words) + { +#ifdef TC_M68K + /* On the m68k there is a gap of 16 bits. We must + explicitly propagate the carry into the exponent. */ + words[0] += words[1]; + words[1] = 0; + lp++; +#endif + /* Put back the integer bit. */ + lp[1] |= 1 << (LITTLENUM_NUMBER_OF_BITS - 1); + } + } + if ((word1 ^ *words) & (1 << (LITTLENUM_NUMBER_OF_BITS - 1))) + { + /* We leave return_value alone: admit we read the number, + but return a floating exception because we can't encode + the number. */ + *words &= ~(1 << (LITTLENUM_NUMBER_OF_BITS - 1)); +#if 0 + make_invalid_floating_point_number (words); + return return_value; +#endif + } + } + return return_value; +} + +#if 0 +/* Unused. */ +/* This routine is a real kludge. Someone really should do it better, + but I'm too lazy, and I don't understand this stuff all too well + anyway. (JF) */ + +static void +int_to_gen (x) + long x; +{ + char buf[20]; + char *bufp; + + sprintf (buf, "%ld", x); + bufp = &buf[0]; + if (atof_generic (&bufp, ".", EXP_CHARS, &generic_floating_point_number)) + as_bad (_("Error converting number to floating point (Exponent overflow?)")); +} +#endif + +#ifdef TEST +char * +print_gen (gen) + FLONUM_TYPE *gen; +{ + FLONUM_TYPE f; + LITTLENUM_TYPE arr[10]; + double dv; + float fv; + static char sbuf[40]; + + if (gen) + { + f = generic_floating_point_number; + generic_floating_point_number = *gen; + } + gen_to_words (&arr[0], 4, 11); + memcpy (&dv, &arr[0], sizeof (double)); + sprintf (sbuf, "%x %x %x %x %.14G ", arr[0], arr[1], arr[2], arr[3], dv); + gen_to_words (&arr[0], 2, 8); + memcpy (&fv, &arr[0], sizeof (float)); + sprintf (sbuf + strlen (sbuf), "%x %x %.12g\n", arr[0], arr[1], fv); + + if (gen) + generic_floating_point_number = f; + + return (sbuf); +} + +#endif diff --git a/contrib/binutils-2.14/gas/config/obj-elf.c b/contrib/binutils-2.14/gas/config/obj-elf.c new file mode 100644 index 0000000000..7c2423c11b --- /dev/null +++ b/contrib/binutils-2.14/gas/config/obj-elf.c @@ -0,0 +1,2366 @@ +/* ELF object file format + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, + or (at your option) any later version. + + GAS is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#define OBJ_HEADER "obj-elf.h" +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "obstack.h" +#include "struc-symbol.h" + +#ifndef ECOFF_DEBUGGING +#define ECOFF_DEBUGGING 0 +#else +#define NEED_ECOFF_DEBUG +#endif + +#ifdef NEED_ECOFF_DEBUG +#include "ecoff.h" +#endif + +#ifdef TC_ALPHA +#include "elf/alpha.h" +#endif + +#ifdef TC_MIPS +#include "elf/mips.h" +#endif + +#ifdef TC_PPC +#include "elf/ppc.h" +#endif + +#ifdef TC_I370 +#include "elf/i370.h" +#endif + +static bfd_vma elf_s_get_size PARAMS ((symbolS *)); +static void elf_s_set_size PARAMS ((symbolS *, bfd_vma)); +static bfd_vma elf_s_get_align PARAMS ((symbolS *)); +static void elf_s_set_align PARAMS ((symbolS *, bfd_vma)); +static void elf_s_set_other PARAMS ((symbolS *, int)); +static int elf_sec_sym_ok_for_reloc PARAMS ((asection *)); +static void adjust_stab_sections PARAMS ((bfd *, asection *, PTR)); +static void build_group_lists PARAMS ((bfd *, asection *, PTR)); +static int elf_separate_stab_sections PARAMS ((void)); +static void elf_init_stab_section PARAMS ((segT)); +static symbolS *elf_common PARAMS ((int)); + +#ifdef NEED_ECOFF_DEBUG +static bfd_boolean elf_get_extr PARAMS ((asymbol *, EXTR *)); +static void elf_set_index PARAMS ((asymbol *, bfd_size_type)); +#endif + +static void obj_elf_line PARAMS ((int)); +void obj_elf_version PARAMS ((int)); +static void obj_elf_size PARAMS ((int)); +static void obj_elf_type PARAMS ((int)); +static void obj_elf_ident PARAMS ((int)); +static void obj_elf_weak PARAMS ((int)); +static void obj_elf_local PARAMS ((int)); +static void obj_elf_visibility PARAMS ((int)); +static int obj_elf_parse_section_letters PARAMS ((char *, size_t)); +static int obj_elf_section_word PARAMS ((char *, size_t)); +static char *obj_elf_section_name PARAMS ((void)); +static int obj_elf_section_type PARAMS ((char *, size_t)); +static void obj_elf_symver PARAMS ((int)); +static void obj_elf_subsection PARAMS ((int)); +static void obj_elf_popsection PARAMS ((int)); +static void obj_elf_tls_common PARAMS ((int)); + +static const pseudo_typeS elf_pseudo_table[] = +{ + {"comm", obj_elf_common, 0}, + {"common", obj_elf_common, 1}, + {"ident", obj_elf_ident, 0}, + {"local", obj_elf_local, 0}, + {"previous", obj_elf_previous, 0}, + {"section", obj_elf_section, 0}, + {"section.s", obj_elf_section, 0}, + {"sect", obj_elf_section, 0}, + {"sect.s", obj_elf_section, 0}, + {"pushsection", obj_elf_section, 1}, + {"popsection", obj_elf_popsection, 0}, + {"size", obj_elf_size, 0}, + {"type", obj_elf_type, 0}, + {"version", obj_elf_version, 0}, + {"weak", obj_elf_weak, 0}, + + /* These define symbol visibility. */ + {"internal", obj_elf_visibility, STV_INTERNAL}, + {"hidden", obj_elf_visibility, STV_HIDDEN}, + {"protected", obj_elf_visibility, STV_PROTECTED}, + + /* These are used for stabs-in-elf configurations. */ + {"line", obj_elf_line, 0}, + + /* This is a GNU extension to handle symbol versions. */ + {"symver", obj_elf_symver, 0}, + + /* A GNU extension to change subsection only. */ + {"subsection", obj_elf_subsection, 0}, + + /* These are GNU extensions to aid in garbage collecting C++ vtables. */ + {"vtable_inherit", (void (*) PARAMS ((int))) &obj_elf_vtable_inherit, 0}, + {"vtable_entry", (void (*) PARAMS ((int))) &obj_elf_vtable_entry, 0}, + + /* These are used for dwarf. */ + {"2byte", cons, 2}, + {"4byte", cons, 4}, + {"8byte", cons, 8}, + + /* We need to trap the section changing calls to handle .previous. */ + {"data", obj_elf_data, 0}, + {"text", obj_elf_text, 0}, + + {"tls_common", obj_elf_tls_common, 0}, + + /* End sentinel. */ + {NULL, NULL, 0}, +}; + +static const pseudo_typeS ecoff_debug_pseudo_table[] = +{ +#ifdef NEED_ECOFF_DEBUG + /* COFF style debugging information for ECOFF. .ln is not used; .loc + is used instead. */ + { "def", ecoff_directive_def, 0 }, + { "dim", ecoff_directive_dim, 0 }, + { "endef", ecoff_directive_endef, 0 }, + { "file", ecoff_directive_file, 0 }, + { "scl", ecoff_directive_scl, 0 }, + { "tag", ecoff_directive_tag, 0 }, + { "val", ecoff_directive_val, 0 }, + + /* COFF debugging requires pseudo-ops .size and .type, but ELF + already has meanings for those. We use .esize and .etype + instead. These are only generated by gcc anyhow. */ + { "esize", ecoff_directive_size, 0 }, + { "etype", ecoff_directive_type, 0 }, + + /* ECOFF specific debugging information. */ + { "begin", ecoff_directive_begin, 0 }, + { "bend", ecoff_directive_bend, 0 }, + { "end", ecoff_directive_end, 0 }, + { "ent", ecoff_directive_ent, 0 }, + { "fmask", ecoff_directive_fmask, 0 }, + { "frame", ecoff_directive_frame, 0 }, + { "loc", ecoff_directive_loc, 0 }, + { "mask", ecoff_directive_mask, 0 }, + + /* Other ECOFF directives. */ + { "extern", ecoff_directive_extern, 0 }, + + /* These are used on Irix. I don't know how to implement them. */ + { "alias", s_ignore, 0 }, + { "bgnb", s_ignore, 0 }, + { "endb", s_ignore, 0 }, + { "lab", s_ignore, 0 }, + { "noalias", s_ignore, 0 }, + { "verstamp", s_ignore, 0 }, + { "vreg", s_ignore, 0 }, +#endif + + {NULL, NULL, 0} /* end sentinel */ +}; + +#undef NO_RELOC +#include "aout/aout64.h" + +/* This is called when the assembler starts. */ + +void +elf_begin () +{ + /* Add symbols for the known sections to the symbol table. */ + symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, + TEXT_SECTION_NAME))); + symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, + DATA_SECTION_NAME))); + symbol_table_insert (section_symbol (bfd_get_section_by_name (stdoutput, + BSS_SECTION_NAME))); +} + +void +elf_pop_insert () +{ + pop_insert (elf_pseudo_table); + if (ECOFF_DEBUGGING) + pop_insert (ecoff_debug_pseudo_table); +} + +static bfd_vma +elf_s_get_size (sym) + symbolS *sym; +{ + return S_GET_SIZE (sym); +} + +static void +elf_s_set_size (sym, sz) + symbolS *sym; + bfd_vma sz; +{ + S_SET_SIZE (sym, sz); +} + +static bfd_vma +elf_s_get_align (sym) + symbolS *sym; +{ + return S_GET_ALIGN (sym); +} + +static void +elf_s_set_align (sym, align) + symbolS *sym; + bfd_vma align; +{ + S_SET_ALIGN (sym, align); +} + +int +elf_s_get_other (sym) + symbolS *sym; +{ + return elf_symbol (symbol_get_bfdsym (sym))->internal_elf_sym.st_other; +} + +static void +elf_s_set_other (sym, other) + symbolS *sym; + int other; +{ + S_SET_OTHER (sym, other); +} + +static int +elf_sec_sym_ok_for_reloc (sec) + asection *sec; +{ + return obj_sec_sym_ok_for_reloc (sec); +} + +void +elf_file_symbol (s) + const char *s; +{ + symbolS *sym; + + sym = symbol_new (s, absolute_section, (valueT) 0, (struct frag *) 0); + symbol_set_frag (sym, &zero_address_frag); + symbol_get_bfdsym (sym)->flags |= BSF_FILE; + + if (symbol_rootP != sym) + { + symbol_remove (sym, &symbol_rootP, &symbol_lastP); + symbol_insert (sym, symbol_rootP, &symbol_rootP, &symbol_lastP); +#ifdef DEBUG + verify_symbol_chain (symbol_rootP, symbol_lastP); +#endif + } + +#ifdef NEED_ECOFF_DEBUG + ecoff_new_file (s); +#endif +} + +static symbolS * +elf_common (is_common) + int is_common; +{ + char *name; + char c; + char *p; + offsetT temp, size, sign; + symbolS *symbolP; + int have_align; + expressionS exp; + + if (flag_mri && is_common) + { + s_mri_common (0); + return NULL; + } + + name = input_line_pointer; + c = get_symbol_end (); + /* just after name is now '\0' */ + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (_("expected comma after symbol-name")); + ignore_rest_of_line (); + return NULL; + } + input_line_pointer++; /* skip ',' */ + temp = get_absolute_expr (&exp); + sign = (offsetT) 1 << (stdoutput->arch_info->bits_per_address - 1); + size = temp & ((sign << 1) - 1); + if (temp != size || !exp.X_unsigned) + { + as_bad (_(".COMMon length (%ld) out of range, ignored."), (long) temp); + ignore_rest_of_line (); + return NULL; + } + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + if (S_IS_DEFINED (symbolP) && ! S_IS_COMMON (symbolP)) + { + as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP)); + ignore_rest_of_line (); + return NULL; + } + if (S_GET_VALUE (symbolP) != 0) + { + if (S_GET_VALUE (symbolP) != (valueT) size) + { + as_warn (_("length of .comm \"%s\" is already %ld; not changed to %ld"), + S_GET_NAME (symbolP), (long) S_GET_VALUE (symbolP), + (long) size); + } + } + know (symbolP->sy_frag == &zero_address_frag); + if (*input_line_pointer != ',') + have_align = 0; + else + { + have_align = 1; + input_line_pointer++; + SKIP_WHITESPACE (); + } + if (! have_align || *input_line_pointer != '"') + { + if (! have_align) + temp = 0; + else + { + temp = get_absolute_expr (&exp); + if (!exp.X_unsigned) + { + temp = 0; + as_warn (_("common alignment negative; 0 assumed")); + } + } + if (symbol_get_obj (symbolP)->local) + { + segT old_sec; + int old_subsec; + char *pfrag; + int align; + + /* allocate_bss: */ + old_sec = now_seg; + old_subsec = now_subseg; + if (temp) + { + /* convert to a power of 2 alignment */ + for (align = 0; (temp & 1) == 0; temp >>= 1, ++align); + if (temp != 1) + { + as_bad (_("common alignment not a power of 2")); + ignore_rest_of_line (); + return NULL; + } + } + else + align = 0; + record_alignment (bss_section, align); + subseg_set (bss_section, 0); + if (align) + frag_align (align, 0, 0); + if (S_GET_SEGMENT (symbolP) == bss_section) + symbol_get_frag (symbolP)->fr_symbol = 0; + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) size, (char *) 0); + *pfrag = 0; + S_SET_SIZE (symbolP, size); + S_SET_SEGMENT (symbolP, bss_section); + S_CLEAR_EXTERNAL (symbolP); + subseg_set (old_sec, old_subsec); + } + else + { + allocate_common: + S_SET_VALUE (symbolP, (valueT) size); + S_SET_ALIGN (symbolP, temp); + S_SET_EXTERNAL (symbolP); + S_SET_SEGMENT (symbolP, bfd_com_section_ptr); + } + } + else + { + input_line_pointer++; + /* @@ Some use the dot, some don't. Can we get some consistency?? */ + if (*input_line_pointer == '.') + input_line_pointer++; + /* @@ Some say data, some say bss. */ + if (strncmp (input_line_pointer, "bss\"", 4) + && strncmp (input_line_pointer, "data\"", 5)) + { + while (*--input_line_pointer != '"') + ; + input_line_pointer--; + goto bad_common_segment; + } + while (*input_line_pointer++ != '"') + ; + goto allocate_common; + } + + symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT; + + demand_empty_rest_of_line (); + return symbolP; + + { + bad_common_segment: + p = input_line_pointer; + while (*p && *p != '\n') + p++; + c = *p; + *p = '\0'; + as_bad (_("bad .common segment %s"), input_line_pointer + 1); + *p = c; + input_line_pointer = p; + ignore_rest_of_line (); + return NULL; + } +} + +void +obj_elf_common (is_common) + int is_common; +{ + elf_common (is_common); +} + +static void +obj_elf_tls_common (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + symbolS *symbolP = elf_common (0); + + if (symbolP) + symbol_get_bfdsym (symbolP)->flags |= BSF_THREAD_LOCAL; +} + +static void +obj_elf_local (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + int c; + symbolS *symbolP; + + do + { + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + S_CLEAR_EXTERNAL (symbolP); + symbol_get_obj (symbolP)->local = 1; + if (c == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + c = '\n'; + } + } + while (c == ','); + demand_empty_rest_of_line (); +} + +static void +obj_elf_weak (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + int c; + symbolS *symbolP; + + do + { + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + S_SET_WEAK (symbolP); + symbol_get_obj (symbolP)->local = 1; + if (c == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\n') + c = '\n'; + } + } + while (c == ','); + demand_empty_rest_of_line (); +} + +static void +obj_elf_visibility (visibility) + int visibility; +{ + char *name; + int c; + symbolS *symbolP; + asymbol *bfdsym; + elf_symbol_type *elfsym; + + do + { + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + + SKIP_WHITESPACE (); + + bfdsym = symbol_get_bfdsym (symbolP); + elfsym = elf_symbol_from (bfd_asymbol_bfd (bfdsym), bfdsym); + + assert (elfsym); + + elfsym->internal_elf_sym.st_other &= ~3; + elfsym->internal_elf_sym.st_other |= visibility; + + if (c == ',') + { + input_line_pointer ++; + + SKIP_WHITESPACE (); + + if (*input_line_pointer == '\n') + c = '\n'; + } + } + while (c == ','); + + demand_empty_rest_of_line (); +} + +static segT previous_section; +static int previous_subsection; + +struct section_stack +{ + struct section_stack *next; + segT seg, prev_seg; + int subseg, prev_subseg; +}; + +static struct section_stack *section_stack; + +/* Handle the .section pseudo-op. This code supports two different + syntaxes. + + The first is found on Solaris, and looks like + .section ".sec1",#alloc,#execinstr,#write + Here the names after '#' are the SHF_* flags to turn on for the + section. I'm not sure how it determines the SHT_* type (BFD + doesn't really give us control over the type, anyhow). + + The second format is found on UnixWare, and probably most SVR4 + machines, and looks like + .section .sec1,"a",@progbits + The quoted string may contain any combination of a, w, x, and + represents the SHF_* flags to turn on for the section. The string + beginning with '@' can be progbits or nobits. There should be + other possibilities, but I don't know what they are. In any case, + BFD doesn't really let us set the section type. */ + +/* Certain named sections have particular defined types, listed on p. + 4-19 of the ABI. */ +struct special_section +{ + const char *name; + int type; + int attributes; +}; + +static struct special_section const special_sections[] = +{ + { ".bss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { ".comment", SHT_PROGBITS, 0 }, + { ".data", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".data1", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".debug", SHT_PROGBITS, 0 }, +#if defined (TC_HPPA) && !defined (TE_LINUX) && TARGET_ARCH_SIZE == 64 + { ".fini", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".init", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, +#else + { ".fini", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { ".init", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, +#endif + { ".line", SHT_PROGBITS, 0 }, + { ".note", SHT_NOTE, 0 }, + { ".rodata", SHT_PROGBITS, SHF_ALLOC }, + { ".rodata1", SHT_PROGBITS, SHF_ALLOC }, + { ".tbss", SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, + { ".tdata", SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, + { ".text", SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { ".init_array",SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, + { ".fini_array",SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, + { ".preinit_array",SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, + +#ifdef ELF_TC_SPECIAL_SECTIONS + ELF_TC_SPECIAL_SECTIONS +#endif + +#if 0 + /* The following section names are special, but they can not + reasonably appear in assembler code. Some of the attributes are + processor dependent. */ + { ".dynamic", SHT_DYNAMIC, SHF_ALLOC /* + SHF_WRITE */ }, + { ".dynstr", SHT_STRTAB, SHF_ALLOC }, + { ".dynsym", SHT_DYNSYM, SHF_ALLOC }, + { ".got", SHT_PROGBITS, 0 }, + { ".hash", SHT_HASH, SHF_ALLOC }, + { ".interp", SHT_PROGBITS, /* SHF_ALLOC */ }, + { ".plt", SHT_PROGBITS, 0 }, + { ".shstrtab",SHT_STRTAB, 0 }, + { ".strtab", SHT_STRTAB, /* SHF_ALLOC */ }, + { ".symtab", SHT_SYMTAB, /* SHF_ALLOC */ }, +#endif + + { NULL, 0, 0 } +}; + +void +obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push) + const char *name; + int type; + int attr; + int entsize; + const char *group_name; + int linkonce; + int push; +{ + asection *old_sec; + segT sec; + flagword flags; + int i; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + /* Switch to the section, creating it if necessary. */ + if (push) + { + struct section_stack *elt; + elt = xmalloc (sizeof (struct section_stack)); + elt->next = section_stack; + elt->seg = now_seg; + elt->prev_seg = previous_section; + elt->subseg = now_subseg; + elt->prev_subseg = previous_subsection; + section_stack = elt; + } + previous_section = now_seg; + previous_subsection = now_subseg; + + old_sec = bfd_get_section_by_name (stdoutput, name); + sec = subseg_new (name, 0); + + /* See if this is one of the special sections. */ + for (i = 0; special_sections[i].name != NULL; i++) + if (strcmp (name, special_sections[i].name) == 0) + { + if (type == SHT_NULL) + type = special_sections[i].type; + else if (type != special_sections[i].type) + { + if (old_sec == NULL + /* FIXME: gcc, as of 2002-10-22, will emit + + .section .init_array,"aw",@progbits + + for __attribute__ ((section (".init_array"))). + "@progbits" is incorrect. */ + && special_sections[i].type != SHT_INIT_ARRAY + && special_sections[i].type != SHT_FINI_ARRAY + && special_sections[i].type != SHT_PREINIT_ARRAY) + { + as_warn (_("setting incorrect section type for %s"), name); + } + else + { + as_warn (_("ignoring incorrect section type for %s"), name); + type = special_sections[i].type; + } + } + if ((attr &~ special_sections[i].attributes) != 0 + && old_sec == NULL) + { + /* As a GNU extension, we permit a .note section to be + allocatable. If the linker sees an allocateable .note + section, it will create a PT_NOTE segment in the output + file. */ + if (strcmp (name, ".note") != 0 + || attr != SHF_ALLOC) + as_warn (_("setting incorrect section attributes for %s"), + name); + } + attr |= special_sections[i].attributes; + break; + } + + /* Convert ELF type and flags to BFD flags. */ + flags = (SEC_RELOC + | ((attr & SHF_WRITE) ? 0 : SEC_READONLY) + | ((attr & SHF_ALLOC) ? SEC_ALLOC : 0) + | (((attr & SHF_ALLOC) && type != SHT_NOBITS) ? SEC_LOAD : 0) + | ((attr & SHF_EXECINSTR) ? SEC_CODE : 0) + | ((attr & SHF_MERGE) ? SEC_MERGE : 0) + | ((attr & SHF_STRINGS) ? SEC_STRINGS : 0) + | ((attr & SHF_TLS) ? SEC_THREAD_LOCAL : 0)); +#ifdef md_elf_section_flags + flags = md_elf_section_flags (flags, attr, type); +#endif + + if (old_sec == NULL) + { + symbolS *secsym; + + /* Prevent SEC_HAS_CONTENTS from being inadvertently set. */ + if (type == SHT_NOBITS) + seg_info (sec)->bss = 1; + + if (linkonce) + flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + bfd_set_section_flags (stdoutput, sec, flags); + if (flags & SEC_MERGE) + sec->entsize = entsize; + elf_group_name (sec) = group_name; + + /* Add a symbol for this section to the symbol table. */ + secsym = symbol_find (name); + if (secsym != NULL) + symbol_set_bfdsym (secsym, sec->symbol); + else + symbol_table_insert (section_symbol (sec)); + } + else if (attr != 0) + { + /* If section attributes are specified the second time we see a + particular section, then check that they are the same as we + saw the first time. */ + if (((old_sec->flags ^ flags) + & (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE + | SEC_EXCLUDE | SEC_SORT_ENTRIES | SEC_MERGE | SEC_STRINGS + | SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD + | SEC_THREAD_LOCAL))) + as_warn (_("ignoring changed section attributes for %s"), name); + if ((flags & SEC_MERGE) && old_sec->entsize != (unsigned) entsize) + as_warn (_("ignoring changed section entity size for %s"), name); + if ((attr & SHF_GROUP) != 0 + && strcmp (elf_group_name (old_sec), group_name) != 0) + as_warn (_("ignoring new section group for %s"), name); + } + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +static int +obj_elf_parse_section_letters (str, len) + char *str; + size_t len; +{ + int attr = 0; + + while (len > 0) + { + switch (*str) + { + case 'a': + attr |= SHF_ALLOC; + break; + case 'w': + attr |= SHF_WRITE; + break; + case 'x': + attr |= SHF_EXECINSTR; + break; + case 'M': + attr |= SHF_MERGE; + break; + case 'S': + attr |= SHF_STRINGS; + break; + case 'G': + attr |= SHF_GROUP; + break; + case 'T': + attr |= SHF_TLS; + break; + /* Compatibility. */ + case 'm': + if (*(str - 1) == 'a') + { + attr |= SHF_MERGE; + if (len > 1 && str[1] == 's') + { + attr |= SHF_STRINGS; + str++, len--; + } + break; + } + default: + { + char *bad_msg = _("unrecognized .section attribute: want a,w,x,M,S,G,T"); +#ifdef md_elf_section_letter + int md_attr = md_elf_section_letter (*str, &bad_msg); + if (md_attr >= 0) + attr |= md_attr; + else +#endif + { + as_warn ("%s", bad_msg); + attr = -1; + } + } + break; + } + str++, len--; + } + + return attr; +} + +static int +obj_elf_section_word (str, len) + char *str; + size_t len; +{ + if (len == 5 && strncmp (str, "write", 5) == 0) + return SHF_WRITE; + if (len == 5 && strncmp (str, "alloc", 5) == 0) + return SHF_ALLOC; + if (len == 9 && strncmp (str, "execinstr", 9) == 0) + return SHF_EXECINSTR; + if (len == 3 && strncmp (str, "tls", 3) == 0) + return SHF_TLS; + +#ifdef md_elf_section_word + { + int md_attr = md_elf_section_word (str, len); + if (md_attr >= 0) + return md_attr; + } +#endif + + as_warn (_("unrecognized section attribute")); + return 0; +} + +static int +obj_elf_section_type (str, len) + char *str; + size_t len; +{ + if (len == 8 && strncmp (str, "progbits", 8) == 0) + return SHT_PROGBITS; + if (len == 6 && strncmp (str, "nobits", 6) == 0) + return SHT_NOBITS; + +#ifdef md_elf_section_type + { + int md_type = md_elf_section_type (str, len); + if (md_type >= 0) + return md_type; + } +#endif + + as_warn (_("unrecognized section type")); + return 0; +} + +/* Get name of section. */ +static char * +obj_elf_section_name () +{ + char *name; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '"') + { + int dummy; + + name = demand_copy_C_string (&dummy); + if (name == NULL) + { + ignore_rest_of_line (); + return NULL; + } + } + else + { + char *end = input_line_pointer; + + while (0 == strchr ("\n\t,; ", *end)) + end++; + if (end == input_line_pointer) + { + as_warn (_("missing name")); + ignore_rest_of_line (); + return NULL; + } + + name = xmalloc (end - input_line_pointer + 1); + memcpy (name, input_line_pointer, end - input_line_pointer); + name[end - input_line_pointer] = '\0'; + input_line_pointer = end; + } + SKIP_WHITESPACE (); + return name; +} + +void +obj_elf_section (push) + int push; +{ + char *name, *group_name, *beg; + int type, attr, dummy; + int entsize; + int linkonce; + +#ifndef TC_I370 + if (flag_mri) + { + char mri_type; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + previous_section = now_seg; + previous_subsection = now_subseg; + + s_mri_sect (&mri_type); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif + + return; + } +#endif /* ! defined (TC_I370) */ + + name = obj_elf_section_name (); + if (name == NULL) + return; + type = SHT_NULL; + attr = 0; + group_name = NULL; + entsize = 0; + linkonce = 0; + + if (*input_line_pointer == ',') + { + /* Skip the comma. */ + ++input_line_pointer; + SKIP_WHITESPACE (); + + if (*input_line_pointer == '"') + { + beg = demand_copy_C_string (&dummy); + if (beg == NULL) + { + ignore_rest_of_line (); + return; + } + attr |= obj_elf_parse_section_letters (beg, strlen (beg)); + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + char c; + char *save = input_line_pointer; + + ++input_line_pointer; + SKIP_WHITESPACE (); + c = *input_line_pointer; + if (c == '"') + { + beg = demand_copy_C_string (&dummy); + if (beg == NULL) + { + ignore_rest_of_line (); + return; + } + type = obj_elf_section_type (beg, strlen (beg)); + } + else if (c == '@' || c == '%') + { + beg = ++input_line_pointer; + c = get_symbol_end (); + *input_line_pointer = c; + type = obj_elf_section_type (beg, input_line_pointer - beg); + } + else + input_line_pointer = save; + } + + SKIP_WHITESPACE (); + if ((attr & SHF_MERGE) != 0 && *input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + entsize = get_absolute_expression (); + SKIP_WHITESPACE (); + if (entsize < 0) + { + as_warn (_("invalid merge entity size")); + attr &= ~SHF_MERGE; + entsize = 0; + } + } + else if ((attr & SHF_MERGE) != 0) + { + as_warn (_("entity size for SHF_MERGE not specified")); + attr &= ~SHF_MERGE; + } + + if ((attr & SHF_GROUP) != 0 && *input_line_pointer == ',') + { + ++input_line_pointer; + group_name = obj_elf_section_name (); + if (group_name == NULL) + attr &= ~SHF_GROUP; + else if (strncmp (input_line_pointer, ",comdat", 7) == 0) + { + input_line_pointer += 7; + linkonce = 1; + } + else if (strncmp (name, ".gnu.linkonce", 13) == 0) + linkonce = 1; + } + else if ((attr & SHF_GROUP) != 0) + { + as_warn (_("group name for SHF_GROUP not specified")); + attr &= ~SHF_GROUP; + } + } + else + { + do + { + char c; + + SKIP_WHITESPACE (); + if (*input_line_pointer != '#') + { + as_warn (_("character following name is not '#'")); + ignore_rest_of_line (); + return; + } + beg = ++input_line_pointer; + c = get_symbol_end (); + *input_line_pointer = c; + + attr |= obj_elf_section_word (beg, input_line_pointer - beg); + + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + --input_line_pointer; + } + } + + demand_empty_rest_of_line (); + + obj_elf_change_section (name, type, attr, entsize, group_name, linkonce, push); +} + +/* Change to the .data section. */ + +void +obj_elf_data (i) + int i; +{ +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + previous_section = now_seg; + previous_subsection = now_subseg; + s_data (i); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +/* Change to the .text section. */ + +void +obj_elf_text (i) + int i; +{ +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + previous_section = now_seg; + previous_subsection = now_subseg; + s_text (i); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +static void +obj_elf_subsection (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + register int temp; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + previous_section = now_seg; + previous_subsection = now_subseg; + + temp = get_absolute_expression (); + subseg_set (now_seg, (subsegT) temp); + demand_empty_rest_of_line (); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +/* This can be called from the processor backends if they change + sections. */ + +void +obj_elf_section_change_hook () +{ + previous_section = now_seg; + previous_subsection = now_subseg; +} + +void +obj_elf_previous (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + segT new_section; + int new_subsection; + + if (previous_section == 0) + { + as_warn (_(".previous without corresponding .section; ignored")); + return; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + new_section = previous_section; + new_subsection = previous_subsection; + previous_section = now_seg; + previous_subsection = now_subseg; + subseg_set (new_section, new_subsection); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +static void +obj_elf_popsection (xxx) + int xxx ATTRIBUTE_UNUSED; +{ + struct section_stack *top = section_stack; + + if (top == NULL) + { + as_warn (_(".popsection without corresponding .pushsection; ignored")); + return; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + section_stack = top->next; + previous_section = top->prev_seg; + previous_subsection = top->prev_subseg; + subseg_set (top->seg, top->subseg); + free (top); + +#ifdef md_elf_section_change_hook + md_elf_section_change_hook (); +#endif +} + +static void +obj_elf_line (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + /* Assume delimiter is part of expression. BSD4.2 as fails with + delightful bug, so we are not being incompatible here. */ + new_logical_line ((char *) NULL, (int) (get_absolute_expression ())); + demand_empty_rest_of_line (); +} + +/* This handles the .symver pseudo-op, which is used to specify a + symbol version. The syntax is ``.symver NAME,SYMVERNAME''. + SYMVERNAME may contain ELF_VER_CHR ('@') characters. This + pseudo-op causes the assembler to emit a symbol named SYMVERNAME + with the same value as the symbol NAME. */ + +static void +obj_elf_symver (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char c; + char old_lexat; + symbolS *sym; + + name = input_line_pointer; + c = get_symbol_end (); + + sym = symbol_find_or_make (name); + + *input_line_pointer = c; + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (_("expected comma after name in .symver")); + ignore_rest_of_line (); + return; + } + + ++input_line_pointer; + SKIP_WHITESPACE (); + name = input_line_pointer; + + /* Temporarily include '@' in symbol names. */ + old_lexat = lex_type[(unsigned char) '@']; + lex_type[(unsigned char) '@'] |= LEX_NAME; + c = get_symbol_end (); + lex_type[(unsigned char) '@'] = old_lexat; + + if (symbol_get_obj (sym)->versioned_name == NULL) + { + symbol_get_obj (sym)->versioned_name = xstrdup (name); + + *input_line_pointer = c; + + if (strchr (symbol_get_obj (sym)->versioned_name, + ELF_VER_CHR) == NULL) + { + as_bad (_("missing version name in `%s' for symbol `%s'"), + symbol_get_obj (sym)->versioned_name, + S_GET_NAME (sym)); + ignore_rest_of_line (); + return; + } + } + else + { + if (strcmp (symbol_get_obj (sym)->versioned_name, name)) + { + as_bad (_("multiple versions [`%s'|`%s'] for symbol `%s'"), + name, symbol_get_obj (sym)->versioned_name, + S_GET_NAME (sym)); + ignore_rest_of_line (); + return; + } + + *input_line_pointer = c; + } + + demand_empty_rest_of_line (); +} + +/* This handles the .vtable_inherit pseudo-op, which is used to indicate + to the linker the hierarchy in which a particular table resides. The + syntax is ".vtable_inherit CHILDNAME, PARENTNAME". */ + +struct fix * +obj_elf_vtable_inherit (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *cname, *pname; + symbolS *csym, *psym; + char c, bad = 0; + + if (*input_line_pointer == '#') + ++input_line_pointer; + + cname = input_line_pointer; + c = get_symbol_end (); + csym = symbol_find (cname); + + /* GCFIXME: should check that we don't have two .vtable_inherits for + the same child symbol. Also, we can currently only do this if the + child symbol is already exists and is placed in a fragment. */ + + if (csym == NULL || symbol_get_frag (csym) == NULL) + { + as_bad ("expected `%s' to have already been set for .vtable_inherit", + cname); + bad = 1; + } + + *input_line_pointer = c; + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad ("expected comma after name in .vtable_inherit"); + ignore_rest_of_line (); + return NULL; + } + + ++input_line_pointer; + SKIP_WHITESPACE (); + + if (*input_line_pointer == '#') + ++input_line_pointer; + + if (input_line_pointer[0] == '0' + && (input_line_pointer[1] == '\0' + || ISSPACE (input_line_pointer[1]))) + { + psym = section_symbol (absolute_section); + ++input_line_pointer; + } + else + { + pname = input_line_pointer; + c = get_symbol_end (); + psym = symbol_find_or_make (pname); + *input_line_pointer = c; + } + + demand_empty_rest_of_line (); + + if (bad) + return NULL; + + assert (symbol_get_value_expression (csym)->X_op == O_constant); + return fix_new (symbol_get_frag (csym), + symbol_get_value_expression (csym)->X_add_number, + 0, psym, 0, 0, BFD_RELOC_VTABLE_INHERIT); +} + +/* This handles the .vtable_entry pseudo-op, which is used to indicate + to the linker that a vtable slot was used. The syntax is + ".vtable_entry tablename, offset". */ + +struct fix * +obj_elf_vtable_entry (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + symbolS *sym; + offsetT offset; + char c; + + if (*input_line_pointer == '#') + ++input_line_pointer; + + name = input_line_pointer; + c = get_symbol_end (); + sym = symbol_find_or_make (name); + *input_line_pointer = c; + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad ("expected comma after name in .vtable_entry"); + ignore_rest_of_line (); + return NULL; + } + + ++input_line_pointer; + if (*input_line_pointer == '#') + ++input_line_pointer; + + offset = get_absolute_expression (); + + demand_empty_rest_of_line (); + + return fix_new (frag_now, frag_now_fix (), 0, sym, offset, 0, + BFD_RELOC_VTABLE_ENTRY); +} + +void +elf_obj_read_begin_hook () +{ +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_read_begin_hook (); +#endif +} + +void +elf_obj_symbol_new_hook (symbolP) + symbolS *symbolP; +{ + struct elf_obj_sy *sy_obj; + + sy_obj = symbol_get_obj (symbolP); + sy_obj->size = NULL; + sy_obj->versioned_name = NULL; + +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_symbol_new_hook (symbolP); +#endif +} + +/* When setting one symbol equal to another, by default we probably + want them to have the same "size", whatever it means in the current + context. */ + +void +elf_copy_symbol_attributes (dest, src) + symbolS *dest, *src; +{ + struct elf_obj_sy *srcelf = symbol_get_obj (src); + struct elf_obj_sy *destelf = symbol_get_obj (dest); + if (srcelf->size) + { + if (destelf->size == NULL) + destelf->size = + (expressionS *) xmalloc (sizeof (expressionS)); + *destelf->size = *srcelf->size; + } + else + { + if (destelf->size != NULL) + free (destelf->size); + destelf->size = NULL; + } + S_SET_SIZE (dest, S_GET_SIZE (src)); + /* Don't copy visibility. */ + S_SET_OTHER (dest, (ELF_ST_VISIBILITY (S_GET_OTHER (dest)) + | (S_GET_OTHER (src) & ~ELF_ST_VISIBILITY (-1)))); +} + +void +obj_elf_version (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + unsigned int c; + char *p; + asection *seg = now_seg; + subsegT subseg = now_subseg; + Elf_Internal_Note i_note; + Elf_External_Note e_note; + asection *note_secp = (asection *) NULL; + int len; + + SKIP_WHITESPACE (); + if (*input_line_pointer == '\"') + { + ++input_line_pointer; /* -> 1st char of string. */ + name = input_line_pointer; + + while (is_a_char (c = next_char_of_string ())) + ; + c = *input_line_pointer; + *input_line_pointer = '\0'; + *(input_line_pointer - 1) = '\0'; + *input_line_pointer = c; + + /* create the .note section */ + + note_secp = subseg_new (".note", 0); + bfd_set_section_flags (stdoutput, + note_secp, + SEC_HAS_CONTENTS | SEC_READONLY); + + /* process the version string */ + + len = strlen (name); + + i_note.namesz = ((len + 1) + 3) & ~3; /* round this to word boundary */ + i_note.descsz = 0; /* no description */ + i_note.type = NT_VERSION; + p = frag_more (sizeof (e_note.namesz)); + md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz)); + p = frag_more (sizeof (e_note.descsz)); + md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz)); + p = frag_more (sizeof (e_note.type)); + md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type)); + p = frag_more (len + 1); + strcpy (p, name); + + frag_align (2, 0, 0); + + subseg_set (seg, subseg); + } + else + { + as_bad (_("expected quoted string")); + } + demand_empty_rest_of_line (); +} + +static void +obj_elf_size (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name = input_line_pointer; + char c = get_symbol_end (); + char *p; + expressionS exp; + symbolS *sym; + + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + *p = 0; + as_bad (_("expected comma after name `%s' in .size directive"), name); + *p = c; + ignore_rest_of_line (); + return; + } + input_line_pointer++; + expression (&exp); + if (exp.X_op == O_absent) + { + as_bad (_("missing expression in .size directive")); + exp.X_op = O_constant; + exp.X_add_number = 0; + } + *p = 0; + sym = symbol_find_or_make (name); + *p = c; + if (exp.X_op == O_constant) + { + S_SET_SIZE (sym, exp.X_add_number); + if (symbol_get_obj (sym)->size) + { + xfree (symbol_get_obj (sym)->size); + symbol_get_obj (sym)->size = NULL; + } + } + else + { + symbol_get_obj (sym)->size = + (expressionS *) xmalloc (sizeof (expressionS)); + *symbol_get_obj (sym)->size = exp; + } + demand_empty_rest_of_line (); +} + +/* Handle the ELF .type pseudo-op. This sets the type of a symbol. + There are five syntaxes: + + The first (used on Solaris) is + .type SYM,#function + The second (used on UnixWare) is + .type SYM,@function + The third (reportedly to be used on Irix 6.0) is + .type SYM STT_FUNC + The fourth (used on NetBSD/Arm and Linux/ARM) is + .type SYM,%function + The fifth (used on SVR4/860) is + .type SYM,"function" + */ + +static void +obj_elf_type (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char c; + int type; + const char *typename; + symbolS *sym; + elf_symbol_type *elfsym; + + name = input_line_pointer; + c = get_symbol_end (); + sym = symbol_find_or_make (name); + elfsym = (elf_symbol_type *) symbol_get_bfdsym (sym); + *input_line_pointer = c; + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + ++input_line_pointer; + + SKIP_WHITESPACE (); + if ( *input_line_pointer == '#' + || *input_line_pointer == '@' + || *input_line_pointer == '"' + || *input_line_pointer == '%') + ++input_line_pointer; + + typename = input_line_pointer; + c = get_symbol_end (); + + type = 0; + if (strcmp (typename, "function") == 0 + || strcmp (typename, "STT_FUNC") == 0) + type = BSF_FUNCTION; + else if (strcmp (typename, "object") == 0 + || strcmp (typename, "STT_OBJECT") == 0) + type = BSF_OBJECT; + else if (strcmp (typename, "tls_object") == 0 + || strcmp (typename, "STT_TLS") == 0) + type = BSF_OBJECT | BSF_THREAD_LOCAL; +#ifdef md_elf_symbol_type + else if ((type = md_elf_symbol_type (typename, sym, elfsym)) != -1) + ; +#endif + else + as_bad (_("unrecognized symbol type \"%s\""), typename); + + *input_line_pointer = c; + + if (*input_line_pointer == '"') + ++input_line_pointer; + + elfsym->symbol.flags |= type; + + demand_empty_rest_of_line (); +} + +static void +obj_elf_ident (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + static segT comment_section; + segT old_section = now_seg; + int old_subsection = now_subseg; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (!comment_section) + { + char *p; + comment_section = subseg_new (".comment", 0); + bfd_set_section_flags (stdoutput, comment_section, + SEC_READONLY | SEC_HAS_CONTENTS); + p = frag_more (1); + *p = 0; + } + else + subseg_set (comment_section, 0); + stringer (1); + subseg_set (old_section, old_subsection); +} + +#ifdef INIT_STAB_SECTION + +/* The first entry in a .stabs section is special. */ + +void +obj_elf_init_stab_section (seg) + segT seg; +{ + char *file; + char *p; + char *stabstr_name; + unsigned int stroff; + + /* Force the section to align to a longword boundary. Without this, + UnixWare ar crashes. */ + bfd_set_section_alignment (stdoutput, seg, 2); + + /* Make space for this first symbol. */ + p = frag_more (12); + /* Zero it out. */ + memset (p, 0, 12); + as_where (&file, (unsigned int *) NULL); + stabstr_name = (char *) xmalloc (strlen (segment_name (seg)) + 4); + strcpy (stabstr_name, segment_name (seg)); + strcat (stabstr_name, "str"); + stroff = get_stab_string_offset (file, stabstr_name); + know (stroff == 1); + md_number_to_chars (p, stroff, 4); + seg_info (seg)->stabu.p = p; +} + +#endif + +/* Fill in the counts in the first entry in a .stabs section. */ + +static void +adjust_stab_sections (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx ATTRIBUTE_UNUSED; +{ + char *name; + asection *strsec; + char *p; + int strsz, nsyms; + + if (strncmp (".stab", sec->name, 5)) + return; + if (!strcmp ("str", sec->name + strlen (sec->name) - 3)) + return; + + name = (char *) alloca (strlen (sec->name) + 4); + strcpy (name, sec->name); + strcat (name, "str"); + strsec = bfd_get_section_by_name (abfd, name); + if (strsec) + strsz = bfd_section_size (abfd, strsec); + else + strsz = 0; + nsyms = bfd_section_size (abfd, sec) / 12 - 1; + + p = seg_info (sec)->stabu.p; + assert (p != 0); + + bfd_h_put_16 (abfd, (bfd_vma) nsyms, (bfd_byte *) p + 6); + bfd_h_put_32 (abfd, (bfd_vma) strsz, (bfd_byte *) p + 8); +} + +#ifdef NEED_ECOFF_DEBUG + +/* This function is called by the ECOFF code. It is supposed to + record the external symbol information so that the backend can + write it out correctly. The ELF backend doesn't actually handle + this at the moment, so we do it ourselves. We save the information + in the symbol. */ + +void +elf_ecoff_set_ext (sym, ext) + symbolS *sym; + struct ecoff_extr *ext; +{ + symbol_get_bfdsym (sym)->udata.p = (PTR) ext; +} + +/* This function is called by bfd_ecoff_debug_externals. It is + supposed to *EXT to the external symbol information, and return + whether the symbol should be used at all. */ + +static bfd_boolean +elf_get_extr (sym, ext) + asymbol *sym; + EXTR *ext; +{ + if (sym->udata.p == NULL) + return FALSE; + *ext = *(EXTR *) sym->udata.p; + return TRUE; +} + +/* This function is called by bfd_ecoff_debug_externals. It has + nothing to do for ELF. */ + +/*ARGSUSED*/ +static void +elf_set_index (sym, indx) + asymbol *sym ATTRIBUTE_UNUSED; + bfd_size_type indx ATTRIBUTE_UNUSED; +{ +} + +#endif /* NEED_ECOFF_DEBUG */ + +void +elf_frob_symbol (symp, puntp) + symbolS *symp; + int *puntp; +{ + struct elf_obj_sy *sy_obj; + +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + ecoff_frob_symbol (symp); +#endif + + sy_obj = symbol_get_obj (symp); + + if (sy_obj->size != NULL) + { + switch (sy_obj->size->X_op) + { + case O_subtract: + S_SET_SIZE (symp, + (S_GET_VALUE (sy_obj->size->X_add_symbol) + + sy_obj->size->X_add_number + - S_GET_VALUE (sy_obj->size->X_op_symbol))); + break; + case O_constant: + S_SET_SIZE (symp, + (S_GET_VALUE (sy_obj->size->X_add_symbol) + + sy_obj->size->X_add_number)); + break; + default: + as_bad (_(".size expression too complicated to fix up")); + break; + } + free (sy_obj->size); + sy_obj->size = NULL; + } + + if (sy_obj->versioned_name != NULL) + { + char *p; + + p = strchr (sy_obj->versioned_name, ELF_VER_CHR); + know (p != NULL); + + /* This symbol was given a new name with the .symver directive. + + If this is an external reference, just rename the symbol to + include the version string. This will make the relocs be + against the correct versioned symbol. + + If this is a definition, add an alias. FIXME: Using an alias + will permit the debugging information to refer to the right + symbol. However, it's not clear whether it is the best + approach. */ + + if (! S_IS_DEFINED (symp)) + { + /* Verify that the name isn't using the @@ syntax--this is + reserved for definitions of the default version to link + against. */ + if (p[1] == ELF_VER_CHR) + { + as_bad (_("invalid attempt to declare external version name as default in symbol `%s'"), + sy_obj->versioned_name); + *puntp = TRUE; + } + S_SET_NAME (symp, sy_obj->versioned_name); + } + else + { + if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR) + { + size_t l; + + /* The @@@ syntax is a special case. It renames the + symbol name to versioned_name with one `@' removed. */ + l = strlen (&p[3]) + 1; + memmove (&p [2], &p[3], l); + S_SET_NAME (symp, sy_obj->versioned_name); + } + else + { + symbolS *symp2; + + /* FIXME: Creating a new symbol here is risky. We're + in the final loop over the symbol table. We can + get away with it only because the symbol goes to + the end of the list, where the loop will still see + it. It would probably be better to do this in + obj_frob_file_before_adjust. */ + + symp2 = symbol_find_or_make (sy_obj->versioned_name); + + /* Now we act as though we saw symp2 = sym. */ + + S_SET_SEGMENT (symp2, S_GET_SEGMENT (symp)); + + /* Subtracting out the frag address here is a hack + because we are in the middle of the final loop. */ + S_SET_VALUE (symp2, + (S_GET_VALUE (symp) + - symbol_get_frag (symp)->fr_address)); + + symbol_set_frag (symp2, symbol_get_frag (symp)); + + /* This will copy over the size information. */ + copy_symbol_attributes (symp2, symp); + + S_SET_OTHER (symp2, S_GET_OTHER (symp)); + + if (S_IS_WEAK (symp)) + S_SET_WEAK (symp2); + + if (S_IS_EXTERNAL (symp)) + S_SET_EXTERNAL (symp2); + } + } + } + + /* Double check weak symbols. */ + if (S_IS_WEAK (symp)) + { + if (S_IS_COMMON (symp)) + as_bad (_("symbol `%s' can not be both weak and common"), + S_GET_NAME (symp)); + } + +#ifdef TC_MIPS + /* The Irix 5 and 6 assemblers set the type of any common symbol and + any undefined non-function symbol to STT_OBJECT. We try to be + compatible, since newer Irix 5 and 6 linkers care. However, we + only set undefined symbols to be STT_OBJECT if we are on Irix, + because that is the only time gcc will generate the necessary + .global directives to mark functions. */ + + if (S_IS_COMMON (symp)) + symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; + + if (strstr (TARGET_OS, "irix") != NULL + && ! S_IS_DEFINED (symp) + && (symbol_get_bfdsym (symp)->flags & BSF_FUNCTION) == 0) + symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; +#endif + +#if 0 /* TC_PPC */ + /* If TC_PPC is defined, we used to force the type of a symbol to be + BSF_OBJECT if it was otherwise unset. This was required by some + version of VxWorks. Thomas de Lellis says + that this is no longer needed, so it is now commented out. */ + if ((symbol_get_bfdsym (symp)->flags + & (BSF_FUNCTION | BSF_FILE | BSF_SECTION_SYM)) == 0 + && S_IS_DEFINED (symp)) + symbol_get_bfdsym (symp)->flags |= BSF_OBJECT; +#endif +} + +struct group_list +{ + asection **head; /* Section lists. */ + unsigned int *elt_count; /* Number of sections in each list. */ + unsigned int num_group; /* Number of lists. */ +}; + +/* Called via bfd_map_over_sections. If SEC is a member of a group, + add it to a list of sections belonging to the group. INF is a + pointer to a struct group_list, which is where we store the head of + each list. */ + +static void +build_group_lists (abfd, sec, inf) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR inf; +{ + struct group_list *list = (struct group_list *) inf; + const char *group_name = elf_group_name (sec); + unsigned int i; + + if (group_name == NULL) + return; + + /* If this group already has a list, add the section to the head of + the list. */ + for (i = 0; i < list->num_group; i++) + { + if (strcmp (group_name, elf_group_name (list->head[i])) == 0) + { + elf_next_in_group (sec) = list->head[i]; + list->head[i] = sec; + list->elt_count[i] += 1; + return; + } + } + + /* New group. Make the arrays bigger in chunks to minimize calls to + realloc. */ + i = list->num_group; + if ((i & 127) == 0) + { + unsigned int newsize = i + 128; + list->head = xrealloc (list->head, newsize * sizeof (*list->head)); + list->elt_count = xrealloc (list->elt_count, + newsize * sizeof (*list->elt_count)); + } + list->head[i] = sec; + list->elt_count[i] = 1; + list->num_group += 1; +} + +void +elf_frob_file () +{ + struct group_list list; + unsigned int i; + + bfd_map_over_sections (stdoutput, adjust_stab_sections, (PTR) 0); + + /* Go find section groups. */ + list.num_group = 0; + list.head = NULL; + list.elt_count = NULL; + bfd_map_over_sections (stdoutput, build_group_lists, (PTR) &list); + + /* Make the SHT_GROUP sections that describe each section group. We + can't set up the section contents here yet, because elf section + indices have yet to be calculated. elf.c:set_group_contents does + the rest of the work. */ + for (i = 0; i < list.num_group; i++) + { + const char *group_name = elf_group_name (list.head[i]); + const char *sec_name; + asection *s; + flagword flags; + struct symbol *sy; + int has_sym; + + flags = SEC_READONLY | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_GROUP; + for (s = list.head[i]; s != NULL; s = elf_next_in_group (s)) + if ((s->flags ^ flags) & SEC_LINK_ONCE) + { + flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; + if (s != list.head[i]) + { + as_warn (_("assuming all members of group `%s' are COMDAT"), + group_name); + break; + } + } + + sec_name = group_name; + sy = symbol_find_exact (group_name); + has_sym = 0; + if (sy != NULL + && (sy == symbol_lastP + || (sy->sy_next != NULL + && sy->sy_next->sy_previous == sy))) + { + has_sym = 1; + sec_name = ".group"; + } + s = subseg_force_new (sec_name, 0); + if (s == NULL + || !bfd_set_section_flags (stdoutput, s, flags) + || !bfd_set_section_alignment (stdoutput, s, 2)) + { + as_fatal (_("can't create group: %s"), + bfd_errmsg (bfd_get_error ())); + } + + /* Pass a pointer to the first section in this group. */ + elf_next_in_group (s) = list.head[i]; + if (has_sym) + elf_group_id (s) = sy->bsym; + + s->_raw_size = 4 * (list.elt_count[i] + 1); + s->contents = frag_more (s->_raw_size); + frag_now->fr_fix = frag_now_fix_octets (); + } + +#ifdef elf_tc_final_processing + elf_tc_final_processing (); +#endif +} + +/* It removes any unneeded versioned symbols from the symbol table. */ + +void +elf_frob_file_before_adjust () +{ + if (symbol_rootP) + { + symbolS *symp; + + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + if (!S_IS_DEFINED (symp)) + { + if (symbol_get_obj (symp)->versioned_name) + { + char *p; + + /* The @@@ syntax is a special case. If the symbol is + not defined, 2 `@'s will be removed from the + versioned_name. */ + + p = strchr (symbol_get_obj (symp)->versioned_name, + ELF_VER_CHR); + know (p != NULL); + if (p [1] == ELF_VER_CHR && p [2] == ELF_VER_CHR) + { + size_t l = strlen (&p[3]) + 1; + memmove (&p [1], &p[3], l); + } + if (symbol_used_p (symp) == 0 + && symbol_used_in_reloc_p (symp) == 0) + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + } + + /* If there was .weak foo, but foo was neither defined nor + used anywhere, remove it. */ + + else if (S_IS_WEAK (symp) + && symbol_used_p (symp) == 0 + && symbol_used_in_reloc_p (symp) == 0) + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + } + } +} + +/* It is required that we let write_relocs have the opportunity to + optimize away fixups before output has begun, since it is possible + to eliminate all fixups for a section and thus we never should + have generated the relocation section. */ + +void +elf_frob_file_after_relocs () +{ +#ifdef NEED_ECOFF_DEBUG + if (ECOFF_DEBUGGING) + /* Generate the ECOFF debugging information. */ + { + const struct ecoff_debug_swap *debug_swap; + struct ecoff_debug_info debug; + char *buf; + asection *sec; + + debug_swap + = get_elf_backend_data (stdoutput)->elf_backend_ecoff_debug_swap; + know (debug_swap != (const struct ecoff_debug_swap *) NULL); + ecoff_build_debug (&debug.symbolic_header, &buf, debug_swap); + + /* Set up the pointers in debug. */ +#define SET(ptr, offset, type) \ + debug.ptr = (type) (buf + debug.symbolic_header.offset) + + SET (line, cbLineOffset, unsigned char *); + SET (external_dnr, cbDnOffset, PTR); + SET (external_pdr, cbPdOffset, PTR); + SET (external_sym, cbSymOffset, PTR); + SET (external_opt, cbOptOffset, PTR); + SET (external_aux, cbAuxOffset, union aux_ext *); + SET (ss, cbSsOffset, char *); + SET (external_fdr, cbFdOffset, PTR); + SET (external_rfd, cbRfdOffset, PTR); + /* ssext and external_ext are set up just below. */ + +#undef SET + + /* Set up the external symbols. */ + debug.ssext = debug.ssext_end = NULL; + debug.external_ext = debug.external_ext_end = NULL; + if (! bfd_ecoff_debug_externals (stdoutput, &debug, debug_swap, TRUE, + elf_get_extr, elf_set_index)) + as_fatal (_("failed to set up debugging information: %s"), + bfd_errmsg (bfd_get_error ())); + + sec = bfd_get_section_by_name (stdoutput, ".mdebug"); + assert (sec != NULL); + + know (!stdoutput->output_has_begun); + + /* We set the size of the section, call bfd_set_section_contents + to force the ELF backend to allocate a file position, and then + write out the data. FIXME: Is this really the best way to do + this? */ + sec->_raw_size = bfd_ecoff_debug_size (stdoutput, &debug, debug_swap); + + /* Pass BUF to bfd_set_section_contents because this will + eventually become a call to fwrite, and ISO C prohibits + passing a NULL pointer to a stdio function even if the + pointer will not be used. */ + if (! bfd_set_section_contents (stdoutput, sec, (PTR) buf, + (file_ptr) 0, (bfd_size_type) 0)) + as_fatal (_("can't start writing .mdebug section: %s"), + bfd_errmsg (bfd_get_error ())); + + know (stdoutput->output_has_begun); + know (sec->filepos != 0); + + if (! bfd_ecoff_write_debug (stdoutput, &debug, debug_swap, + sec->filepos)) + as_fatal (_("could not write .mdebug section: %s"), + bfd_errmsg (bfd_get_error ())); + } +#endif /* NEED_ECOFF_DEBUG */ +} + +#ifdef SCO_ELF + +/* Heavily plagarized from obj_elf_version. The idea is to emit the + SCO specific identifier in the .notes section to satisfy the SCO + linker. + + This looks more complicated than it really is. As opposed to the + "obvious" solution, this should handle the cross dev cases + correctly. (i.e, hosting on a 64 bit big endian processor, but + generating SCO Elf code) Efficiency isn't a concern, as there + should be exactly one of these sections per object module. + + SCO OpenServer 5 identifies it's ELF modules with a standard ELF + .note section. + + int_32 namesz = 4 ; Name size + int_32 descsz = 12 ; Descriptive information + int_32 type = 1 ; + char name[4] = "SCO" ; Originator name ALWAYS SCO + NULL + int_32 version = (major ver # << 16) | version of tools ; + int_32 source = (tool_id << 16 ) | 1 ; + int_32 info = 0 ; These are set by the SCO tools, but we + don't know enough about the source + environment to set them. SCO ld currently + ignores them, and recommends we set them + to zero. */ + +#define SCO_MAJOR_VERSION 0x1 +#define SCO_MINOR_VERSION 0x1 + +void +sco_id () +{ + + char *name; + unsigned int c; + char ch; + char *p; + asection *seg = now_seg; + subsegT subseg = now_subseg; + Elf_Internal_Note i_note; + Elf_External_Note e_note; + asection *note_secp = (asection *) NULL; + int i, len; + + /* create the .note section */ + + note_secp = subseg_new (".note", 0); + bfd_set_section_flags (stdoutput, + note_secp, + SEC_HAS_CONTENTS | SEC_READONLY); + + /* process the version string */ + + i_note.namesz = 4; + i_note.descsz = 12; /* 12 descriptive bytes */ + i_note.type = NT_VERSION; /* Contains a version string */ + + p = frag_more (sizeof (i_note.namesz)); + md_number_to_chars (p, (valueT) i_note.namesz, 4); + + p = frag_more (sizeof (i_note.descsz)); + md_number_to_chars (p, (valueT) i_note.descsz, 4); + + p = frag_more (sizeof (i_note.type)); + md_number_to_chars (p, (valueT) i_note.type, 4); + + p = frag_more (4); + strcpy (p, "SCO"); + + /* Note: this is the version number of the ELF we're representing */ + p = frag_more (4); + md_number_to_chars (p, (SCO_MAJOR_VERSION << 16) | (SCO_MINOR_VERSION), 4); + + /* Here, we pick a magic number for ourselves (yes, I "registered" + it with SCO. The bottom bit shows that we are compat with the + SCO ABI. */ + p = frag_more (4); + md_number_to_chars (p, 0x4c520000 | 0x0001, 4); + + /* If we knew (or cared) what the source language options were, we'd + fill them in here. SCO has given us permission to ignore these + and just set them to zero. */ + p = frag_more (4); + md_number_to_chars (p, 0x0000, 4); + + frag_align (2, 0, 0); + + /* We probably can't restore the current segment, for there likely + isn't one yet... */ + if (seg && subseg) + subseg_set (seg, subseg); + +} + +#endif /* SCO_ELF */ + +static int +elf_separate_stab_sections () +{ +#ifdef NEED_ECOFF_DEBUG + return (!ECOFF_DEBUGGING); +#else + return 1; +#endif +} + +static void +elf_init_stab_section (seg) + segT seg; +{ +#ifdef NEED_ECOFF_DEBUG + if (!ECOFF_DEBUGGING) +#endif + obj_elf_init_stab_section (seg); +} + +const struct format_ops elf_format_ops = +{ + bfd_target_elf_flavour, + 0, /* dfl_leading_underscore */ + 1, /* emit_section_symbols */ + elf_begin, + elf_file_symbol, + elf_frob_symbol, + elf_frob_file, + elf_frob_file_before_adjust, + 0, /* obj_frob_file_before_fix */ + elf_frob_file_after_relocs, + elf_s_get_size, elf_s_set_size, + elf_s_get_align, elf_s_set_align, + elf_s_get_other, + elf_s_set_other, + 0, /* s_get_desc */ + 0, /* s_set_desc */ + 0, /* s_get_type */ + 0, /* s_set_type */ + elf_copy_symbol_attributes, +#ifdef NEED_ECOFF_DEBUG + ecoff_generate_asm_lineno, + ecoff_stab, +#else + 0, /* generate_asm_lineno */ + 0, /* process_stab */ +#endif + elf_separate_stab_sections, + elf_init_stab_section, + elf_sec_sym_ok_for_reloc, + elf_pop_insert, +#ifdef NEED_ECOFF_DEBUG + elf_ecoff_set_ext, +#else + 0, /* ecoff_set_ext */ +#endif + elf_obj_read_begin_hook, + elf_obj_symbol_new_hook +}; diff --git a/contrib/binutils-2.14/gas/config/obj-elf.h b/contrib/binutils-2.14/gas/config/obj-elf.h new file mode 100644 index 0000000000..0fa2ba6093 --- /dev/null +++ b/contrib/binutils-2.14/gas/config/obj-elf.h @@ -0,0 +1,243 @@ +/* ELF object file format. + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* HP PA-RISC support was contributed by the Center for Software Science + at the University of Utah. */ + +#ifndef _OBJ_ELF_H +#define _OBJ_ELF_H + +#define OBJ_ELF 1 + +/* Note that all macros in this file should be wrapped in #ifndef, for + sake of obj-multi.h which includes this file. */ + +#ifndef OUTPUT_FLAVOR +#define OUTPUT_FLAVOR bfd_target_elf_flavour +#endif + +#include "bfd.h" + +#define BYTES_IN_WORD 4 /* for now */ +#include "bfd/elf-bfd.h" + +#include "targ-cpu.h" + +#ifdef TC_ALPHA +#define ECOFF_DEBUGGING (alpha_flag_mdebug > 0) +extern int alpha_flag_mdebug; +#endif + +/* For now, always set ECOFF_DEBUGGING for a MIPS target. */ +#ifdef TC_MIPS +#define ECOFF_DEBUGGING mips_flag_mdebug +extern int mips_flag_mdebug; +#endif /* TC_MIPS */ + +#ifdef OBJ_MAYBE_ECOFF +#ifndef ECOFF_DEBUGGING +#define ECOFF_DEBUGGING 1 +#endif +#endif + +/* Additional information we keep for each symbol. */ +struct elf_obj_sy +{ + /* Whether the symbol has been marked as local. */ + int local; + + /* Use this to keep track of .size expressions that involve + differences that we can't compute yet. */ + expressionS *size; + + /* The name specified by the .symver directive. */ + char *versioned_name; + +#ifdef ECOFF_DEBUGGING + /* If we are generating ECOFF debugging information, we need some + additional fields for each symbol. */ + struct efdr *ecoff_file; + struct localsym *ecoff_symbol; + valueT ecoff_extern_size; +#endif +}; + +#define OBJ_SYMFIELD_TYPE struct elf_obj_sy + +/* Symbol fields used by the ELF back end. */ +#define ELF_TARGET_SYMBOL_FIELDS int local:1; + +/* Don't change this; change ELF_TARGET_SYMBOL_FIELDS instead. */ +#ifndef TARGET_SYMBOL_FIELDS +#define TARGET_SYMBOL_FIELDS ELF_TARGET_SYMBOL_FIELDS +#endif + +/* #include "targ-cpu.h" */ + +#ifndef FALSE +#define FALSE 0 +#define TRUE !FALSE +#endif + +#ifndef obj_begin +#define obj_begin() elf_begin () +#endif +extern void elf_begin PARAMS ((void)); + +/* should be conditional on address size! */ +#define elf_symbol(asymbol) ((elf_symbol_type *) (&(asymbol)->the_bfd)) + +#ifndef S_GET_SIZE +#define S_GET_SIZE(S) \ + (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_size) +#endif +#ifndef S_SET_SIZE +#define S_SET_SIZE(S,V) \ + (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_size = (V)) +#endif + +#ifndef S_GET_ALIGN +#define S_GET_ALIGN(S) \ + (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_value) +#endif +#ifndef S_SET_ALIGN +#define S_SET_ALIGN(S,V) \ + (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_value = (V)) +#endif + +int elf_s_get_other PARAMS ((symbolS *)); +#ifndef S_GET_OTHER +#define S_GET_OTHER(S) (elf_s_get_other (S)) +#endif +#ifndef S_SET_OTHER +#define S_SET_OTHER(S,V) \ + (elf_symbol (symbol_get_bfdsym (S))->internal_elf_sym.st_other = (V)) +#endif + +extern asection *gdb_section; + +#ifndef obj_frob_file +#define obj_frob_file elf_frob_file +#endif +extern void elf_frob_file PARAMS ((void)); + +#ifndef obj_frob_file_before_adjust +#define obj_frob_file_before_adjust elf_frob_file_before_adjust +#endif +extern void elf_frob_file_before_adjust PARAMS ((void)); + +#ifndef obj_frob_file_after_relocs +#define obj_frob_file_after_relocs elf_frob_file_after_relocs +#endif +extern void elf_frob_file_after_relocs PARAMS ((void)); + +#ifndef obj_app_file +#define obj_app_file elf_file_symbol +#endif +extern void elf_file_symbol PARAMS ((const char *)); + +extern void obj_elf_section_change_hook PARAMS ((void)); + +extern void obj_elf_section PARAMS ((int)); +extern void obj_elf_previous PARAMS ((int)); +extern void obj_elf_version PARAMS ((int)); +extern void obj_elf_common PARAMS ((int)); +extern void obj_elf_data PARAMS ((int)); +extern void obj_elf_text PARAMS ((int)); +extern void obj_elf_change_section + PARAMS ((const char *, int, int, int, const char *, int, int)); +extern struct fix *obj_elf_vtable_inherit PARAMS ((int)); +extern struct fix *obj_elf_vtable_entry PARAMS ((int)); + +/* BFD wants to write the udata field, which is a no-no for the + predefined section symbols in bfd/section.c. They are read-only. */ +#ifndef obj_sec_sym_ok_for_reloc +#define obj_sec_sym_ok_for_reloc(SEC) ((SEC)->owner != 0) +#endif + +void elf_obj_read_begin_hook PARAMS ((void)); +#ifndef obj_read_begin_hook +#define obj_read_begin_hook elf_obj_read_begin_hook +#endif + +void elf_obj_symbol_new_hook PARAMS ((symbolS *)); +#ifndef obj_symbol_new_hook +#define obj_symbol_new_hook elf_obj_symbol_new_hook +#endif + +void elf_copy_symbol_attributes PARAMS ((symbolS *, symbolS *)); +#ifndef OBJ_COPY_SYMBOL_ATTRIBUTES +#define OBJ_COPY_SYMBOL_ATTRIBUTES(DEST, SRC) \ + (elf_copy_symbol_attributes (DEST, SRC)) +#endif + +#ifndef SEPARATE_STAB_SECTIONS +/* Avoid ifndef each separate macro setting by wrapping the whole of the + stab group on the assumption that whoever sets SEPARATE_STAB_SECTIONS + caters to ECOFF_DEBUGGING and the right setting of INIT_STAB_SECTIONS + and OBJ_PROCESS_STAB too, without needing the tweaks below. */ + +/* Stabs go in a separate section. */ +#define SEPARATE_STAB_SECTIONS 1 + +/* We need 12 bytes at the start of the section to hold some initial + information. */ +extern void obj_elf_init_stab_section PARAMS ((segT)); +#define INIT_STAB_SECTION(seg) obj_elf_init_stab_section (seg) + +#ifdef ECOFF_DEBUGGING +/* We smuggle stabs in ECOFF rather than using a separate section. + The Irix linker can not handle a separate stabs section. */ + +#undef SEPARATE_STAB_SECTIONS +#define SEPARATE_STAB_SECTIONS (!ECOFF_DEBUGGING) + +#undef INIT_STAB_SECTION +#define INIT_STAB_SECTION(seg) \ + ((void) (ECOFF_DEBUGGING ? 0 : (obj_elf_init_stab_section (seg), 0))) + +#undef OBJ_PROCESS_STAB +#define OBJ_PROCESS_STAB(seg, what, string, type, other, desc) \ + if (ECOFF_DEBUGGING) \ + ecoff_stab ((seg), (what), (string), (type), (other), (desc)) +#endif /* ECOFF_DEBUGGING */ + +#endif /* SEPARATE_STAB_SECTIONS not defined. */ + +extern void elf_frob_symbol PARAMS ((symbolS *, int *)); +#ifndef obj_frob_symbol +#define obj_frob_symbol(symp, punt) elf_frob_symbol (symp, &punt) +#endif + +extern void elf_pop_insert PARAMS ((void)); +#ifndef obj_pop_insert +#define obj_pop_insert() elf_pop_insert() +#endif + +#ifndef OBJ_MAYBE_ELF +#define obj_ecoff_set_ext elf_ecoff_set_ext +#ifdef ANSI_PROTOTYPES +struct ecoff_extr; +#endif +extern void elf_ecoff_set_ext PARAMS ((symbolS *, struct ecoff_extr *)); +#endif + +#endif /* _OBJ_ELF_H */ diff --git a/contrib/binutils-2.14/gas/config/tc-i386.c b/contrib/binutils-2.14/gas/config/tc-i386.c new file mode 100644 index 0000000000..92540ad625 --- /dev/null +++ b/contrib/binutils-2.14/gas/config/tc-i386.c @@ -0,0 +1,6301 @@ +/* i386.c -- Assemble code for the Intel 80386 + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Intel 80386 machine specific gas. + Written by Eliot Dresselhaus (eliot@mgm.mit.edu). + x86_64 support by Jan Hubicka (jh@suse.cz) + Bugs & suggestions are completely welcome. This is free software. + Please help us make it better. */ + +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "dwarf2dbg.h" +#include "opcode/i386.h" + +#ifndef REGISTER_WARNINGS +#define REGISTER_WARNINGS 1 +#endif + +#ifndef INFER_ADDR_PREFIX +#define INFER_ADDR_PREFIX 1 +#endif + +#ifndef SCALE1_WHEN_NO_INDEX +/* Specifying a scale factor besides 1 when there is no index is + futile. eg. `mov (%ebx,2),%al' does exactly the same as + `mov (%ebx),%al'. To slavishly follow what the programmer + specified, set SCALE1_WHEN_NO_INDEX to 0. */ +#define SCALE1_WHEN_NO_INDEX 1 +#endif + +#ifdef BFD_ASSEMBLER +#define RELOC_ENUM enum bfd_reloc_code_real +#else +#define RELOC_ENUM int +#endif + +#ifndef DEFAULT_ARCH +#define DEFAULT_ARCH "i386" +#endif + +#ifndef INLINE +#if __GNUC__ >= 2 +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +static INLINE unsigned int mode_from_disp_size PARAMS ((unsigned int)); +static INLINE int fits_in_signed_byte PARAMS ((offsetT)); +static INLINE int fits_in_unsigned_byte PARAMS ((offsetT)); +static INLINE int fits_in_unsigned_word PARAMS ((offsetT)); +static INLINE int fits_in_signed_word PARAMS ((offsetT)); +static INLINE int fits_in_unsigned_long PARAMS ((offsetT)); +static INLINE int fits_in_signed_long PARAMS ((offsetT)); +static int smallest_imm_type PARAMS ((offsetT)); +static offsetT offset_in_range PARAMS ((offsetT, int)); +static int add_prefix PARAMS ((unsigned int)); +static void set_code_flag PARAMS ((int)); +static void set_16bit_gcc_code_flag PARAMS ((int)); +static void set_intel_syntax PARAMS ((int)); +static void set_cpu_arch PARAMS ((int)); +static char *output_invalid PARAMS ((int c)); +static int i386_operand PARAMS ((char *operand_string)); +static int i386_intel_operand PARAMS ((char *operand_string, int got_a_float)); +static const reg_entry *parse_register PARAMS ((char *reg_string, + char **end_op)); +static char *parse_insn PARAMS ((char *, char *)); +static char *parse_operands PARAMS ((char *, const char *)); +static void swap_operands PARAMS ((void)); +static void optimize_imm PARAMS ((void)); +static void optimize_disp PARAMS ((void)); +static int match_template PARAMS ((void)); +static int check_string PARAMS ((void)); +static int process_suffix PARAMS ((void)); +static int check_byte_reg PARAMS ((void)); +static int check_long_reg PARAMS ((void)); +static int check_qword_reg PARAMS ((void)); +static int check_word_reg PARAMS ((void)); +static int finalize_imm PARAMS ((void)); +static int process_operands PARAMS ((void)); +static const seg_entry *build_modrm_byte PARAMS ((void)); +static void output_insn PARAMS ((void)); +static void output_branch PARAMS ((void)); +static void output_jump PARAMS ((void)); +static void output_interseg_jump PARAMS ((void)); +static void output_imm PARAMS ((fragS *insn_start_frag, + offsetT insn_start_off)); +static void output_disp PARAMS ((fragS *insn_start_frag, + offsetT insn_start_off)); +#ifndef I386COFF +static void s_bss PARAMS ((int)); +#endif + +static const char *default_arch = DEFAULT_ARCH; + +/* 'md_assemble ()' gathers together information and puts it into a + i386_insn. */ + +union i386_op + { + expressionS *disps; + expressionS *imms; + const reg_entry *regs; + }; + +struct _i386_insn + { + /* TM holds the template for the insn were currently assembling. */ + template tm; + + /* SUFFIX holds the instruction mnemonic suffix if given. + (e.g. 'l' for 'movl') */ + char suffix; + + /* OPERANDS gives the number of given operands. */ + unsigned int operands; + + /* REG_OPERANDS, DISP_OPERANDS, MEM_OPERANDS, IMM_OPERANDS give the number + of given register, displacement, memory operands and immediate + operands. */ + unsigned int reg_operands, disp_operands, mem_operands, imm_operands; + + /* TYPES [i] is the type (see above #defines) which tells us how to + use OP[i] for the corresponding operand. */ + unsigned int types[MAX_OPERANDS]; + + /* Displacement expression, immediate expression, or register for each + operand. */ + union i386_op op[MAX_OPERANDS]; + + /* Flags for operands. */ + unsigned int flags[MAX_OPERANDS]; +#define Operand_PCrel 1 + + /* Relocation type for operand */ + RELOC_ENUM reloc[MAX_OPERANDS]; + + /* BASE_REG, INDEX_REG, and LOG2_SCALE_FACTOR are used to encode + the base index byte below. */ + const reg_entry *base_reg; + const reg_entry *index_reg; + unsigned int log2_scale_factor; + + /* SEG gives the seg_entries of this insn. They are zero unless + explicit segment overrides are given. */ + const seg_entry *seg[2]; + + /* PREFIX holds all the given prefix opcodes (usually null). + PREFIXES is the number of prefix opcodes. */ + unsigned int prefixes; + unsigned char prefix[MAX_PREFIXES]; + + /* RM and SIB are the modrm byte and the sib byte where the + addressing modes of this insn are encoded. */ + + modrm_byte rm; + rex_byte rex; + sib_byte sib; + }; + +typedef struct _i386_insn i386_insn; + +/* List of chars besides those in app.c:symbol_chars that can start an + operand. Used to prevent the scrubber eating vital white-space. */ +#ifdef LEX_AT +const char extra_symbol_chars[] = "*%-(@["; +#else +const char extra_symbol_chars[] = "*%-(["; +#endif + +#if (defined (TE_I386AIX) \ + || ((defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) \ + && !defined (TE_LINUX) \ + && !defined (TE_FreeBSD) \ + && !defined (TE_NetBSD))) +/* This array holds the chars that always start a comment. If the + pre-processor is disabled, these aren't very useful. */ +const char comment_chars[] = "#/"; +#define PREFIX_SEPARATOR '\\' + +/* This array holds the chars that only start a comment at the beginning of + a line. If the line seems to have the form '# 123 filename' + .line and .file directives will appear in the pre-processed output. + Note that input_file.c hand checks for '#' at the beginning of the + first line of the input file. This is because the compiler outputs + #NO_APP at the beginning of its output. + Also note that comments started like this one will always work if + '/' isn't otherwise defined. */ +const char line_comment_chars[] = "#"; + +#else +/* Putting '/' here makes it impossible to use the divide operator. + However, we need it for compatibility with SVR4 systems. */ +const char comment_chars[] = "#"; +#define PREFIX_SEPARATOR '/' + +const char line_comment_chars[] = "/#"; +#endif + +const char line_separator_chars[] = ";"; + +/* Chars that can be used to separate mant from exp in floating point + nums. */ +const char EXP_CHARS[] = "eE"; + +/* Chars that mean this number is a floating point constant + As in 0f12.456 + or 0d1.2345e12. */ +const char FLT_CHARS[] = "fFdDxX"; + +/* Tables for lexical analysis. */ +static char mnemonic_chars[256]; +static char register_chars[256]; +static char operand_chars[256]; +static char identifier_chars[256]; +static char digit_chars[256]; + +/* Lexical macros. */ +#define is_mnemonic_char(x) (mnemonic_chars[(unsigned char) x]) +#define is_operand_char(x) (operand_chars[(unsigned char) x]) +#define is_register_char(x) (register_chars[(unsigned char) x]) +#define is_space_char(x) ((x) == ' ') +#define is_identifier_char(x) (identifier_chars[(unsigned char) x]) +#define is_digit_char(x) (digit_chars[(unsigned char) x]) + +/* All non-digit non-letter charcters that may occur in an operand. */ +static char operand_special_chars[] = "%$-+(,)*._~/<>|&^!:[@]"; + +/* md_assemble() always leaves the strings it's passed unaltered. To + effect this we maintain a stack of saved characters that we've smashed + with '\0's (indicating end of strings for various sub-fields of the + assembler instruction). */ +static char save_stack[32]; +static char *save_stack_p; +#define END_STRING_AND_SAVE(s) \ + do { *save_stack_p++ = *(s); *(s) = '\0'; } while (0) +#define RESTORE_END_STRING(s) \ + do { *(s) = *--save_stack_p; } while (0) + +/* The instruction we're assembling. */ +static i386_insn i; + +/* Possible templates for current insn. */ +static const templates *current_templates; + +/* Per instruction expressionS buffers: 2 displacements & 2 immediate max. */ +static expressionS disp_expressions[2], im_expressions[2]; + +/* Current operand we are working on. */ +static int this_operand; + +/* We support four different modes. FLAG_CODE variable is used to distinguish + these. */ + +enum flag_code { + CODE_32BIT, + CODE_16BIT, + CODE_64BIT }; +#define NUM_FLAG_CODE ((int) CODE_64BIT + 1) + +static enum flag_code flag_code; +static int use_rela_relocations = 0; + +/* The names used to print error messages. */ +static const char *flag_code_names[] = + { + "32", + "16", + "64" + }; + +/* 1 for intel syntax, + 0 if att syntax. */ +static int intel_syntax = 0; + +/* 1 if register prefix % not required. */ +static int allow_naked_reg = 0; + +/* Used in 16 bit gcc mode to add an l suffix to call, ret, enter, + leave, push, and pop instructions so that gcc has the same stack + frame as in 32 bit mode. */ +static char stackop_size = '\0'; + +/* Non-zero to quieten some warnings. */ +static int quiet_warnings = 0; + +/* CPU name. */ +static const char *cpu_arch_name = NULL; + +/* CPU feature flags. */ +static unsigned int cpu_arch_flags = CpuUnknownFlags | CpuNo64; + +/* If set, conditional jumps are not automatically promoted to handle + larger than a byte offset. */ +static unsigned int no_cond_jump_promotion = 0; + +/* Pre-defined "_GLOBAL_OFFSET_TABLE_". */ +symbolS *GOT_symbol; + +/* Interface to relax_segment. + There are 3 major relax states for 386 jump insns because the + different types of jumps add different sizes to frags when we're + figuring out what sort of jump to choose to reach a given label. */ + +/* Types. */ +#define UNCOND_JUMP 0 +#define COND_JUMP 1 +#define COND_JUMP86 2 + +/* Sizes. */ +#define CODE16 1 +#define SMALL 0 +#define SMALL16 (SMALL | CODE16) +#define BIG 2 +#define BIG16 (BIG | CODE16) + +#ifndef INLINE +#ifdef __GNUC__ +#define INLINE __inline__ +#else +#define INLINE +#endif +#endif + +#define ENCODE_RELAX_STATE(type, size) \ + ((relax_substateT) (((type) << 2) | (size))) +#define TYPE_FROM_RELAX_STATE(s) \ + ((s) >> 2) +#define DISP_SIZE_FROM_RELAX_STATE(s) \ + ((((s) & 3) == BIG ? 4 : (((s) & 3) == BIG16 ? 2 : 1))) + +/* This table is used by relax_frag to promote short jumps to long + ones where necessary. SMALL (short) jumps may be promoted to BIG + (32 bit long) ones, and SMALL16 jumps to BIG16 (16 bit long). We + don't allow a short jump in a 32 bit code segment to be promoted to + a 16 bit offset jump because it's slower (requires data size + prefix), and doesn't work, unless the destination is in the bottom + 64k of the code segment (The top 16 bits of eip are zeroed). */ + +const relax_typeS md_relax_table[] = +{ + /* The fields are: + 1) most positive reach of this state, + 2) most negative reach of this state, + 3) how many bytes this mode will have in the variable part of the frag + 4) which index into the table to try if we can't fit into this one. */ + + /* UNCOND_JUMP states. */ + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG)}, + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16)}, + /* dword jmp adds 4 bytes to frag: + 0 extra opcode bytes, 4 displacement bytes. */ + {0, 0, 4, 0}, + /* word jmp adds 2 byte2 to frag: + 0 extra opcode bytes, 2 displacement bytes. */ + {0, 0, 2, 0}, + + /* COND_JUMP states. */ + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG)}, + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP, BIG16)}, + /* dword conditionals adds 5 bytes to frag: + 1 extra opcode byte, 4 displacement bytes. */ + {0, 0, 5, 0}, + /* word conditionals add 3 bytes to frag: + 1 extra opcode byte, 2 displacement bytes. */ + {0, 0, 3, 0}, + + /* COND_JUMP86 states. */ + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG)}, + {127 + 1, -128 + 1, 1, ENCODE_RELAX_STATE (COND_JUMP86, BIG16)}, + /* dword conditionals adds 5 bytes to frag: + 1 extra opcode byte, 4 displacement bytes. */ + {0, 0, 5, 0}, + /* word conditionals add 4 bytes to frag: + 1 displacement byte and a 3 byte long branch insn. */ + {0, 0, 4, 0} +}; + +static const arch_entry cpu_arch[] = { + {"i8086", Cpu086 }, + {"i186", Cpu086|Cpu186 }, + {"i286", Cpu086|Cpu186|Cpu286 }, + {"i386", Cpu086|Cpu186|Cpu286|Cpu386 }, + {"i486", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486 }, + {"i586", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX }, + {"i686", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuSSE }, + {"pentium", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuMMX }, + {"pentiumpro",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuMMX|CpuSSE }, + {"pentium4", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuMMX|CpuSSE|CpuSSE2 }, + {"k6", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|CpuK6|CpuMMX|Cpu3dnow }, + {"athlon", Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuMMX|Cpu3dnow }, + {"sledgehammer",Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuK6|CpuAthlon|CpuSledgehammer|CpuMMX|Cpu3dnow|CpuSSE|CpuSSE2 }, + {NULL, 0 } +}; + +const pseudo_typeS md_pseudo_table[] = +{ +#if !defined(OBJ_AOUT) && !defined(USE_ALIGN_PTWO) + {"align", s_align_bytes, 0}, +#else + {"align", s_align_ptwo, 0}, +#endif + {"arch", set_cpu_arch, 0}, +#ifndef I386COFF + {"bss", s_bss, 0}, +#endif + {"ffloat", float_cons, 'f'}, + {"dfloat", float_cons, 'd'}, + {"tfloat", float_cons, 'x'}, + {"value", cons, 2}, + {"noopt", s_ignore, 0}, + {"optim", s_ignore, 0}, + {"code16gcc", set_16bit_gcc_code_flag, CODE_16BIT}, + {"code16", set_code_flag, CODE_16BIT}, + {"code32", set_code_flag, CODE_32BIT}, + {"code64", set_code_flag, CODE_64BIT}, + {"intel_syntax", set_intel_syntax, 1}, + {"att_syntax", set_intel_syntax, 0}, + {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0}, + {"loc", dwarf2_directive_loc, 0}, + {0, 0, 0} +}; + +/* For interface with expression (). */ +extern char *input_line_pointer; + +/* Hash table for instruction mnemonic lookup. */ +static struct hash_control *op_hash; + +/* Hash table for register lookup. */ +static struct hash_control *reg_hash; + +void +i386_align_code (fragP, count) + fragS *fragP; + int count; +{ + /* Various efficient no-op patterns for aligning code labels. + Note: Don't try to assemble the instructions in the comments. + 0L and 0w are not legal. */ + static const char f32_1[] = + {0x90}; /* nop */ + static const char f32_2[] = + {0x89,0xf6}; /* movl %esi,%esi */ + static const char f32_3[] = + {0x8d,0x76,0x00}; /* leal 0(%esi),%esi */ + static const char f32_4[] = + {0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ + static const char f32_5[] = + {0x90, /* nop */ + 0x8d,0x74,0x26,0x00}; /* leal 0(%esi,1),%esi */ + static const char f32_6[] = + {0x8d,0xb6,0x00,0x00,0x00,0x00}; /* leal 0L(%esi),%esi */ + static const char f32_7[] = + {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ + static const char f32_8[] = + {0x90, /* nop */ + 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00}; /* leal 0L(%esi,1),%esi */ + static const char f32_9[] = + {0x89,0xf6, /* movl %esi,%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_10[] = + {0x8d,0x76,0x00, /* leal 0(%esi),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_11[] = + {0x8d,0x74,0x26,0x00, /* leal 0(%esi,1),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_12[] = + {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ + 0x8d,0xbf,0x00,0x00,0x00,0x00}; /* leal 0L(%edi),%edi */ + static const char f32_13[] = + {0x8d,0xb6,0x00,0x00,0x00,0x00, /* leal 0L(%esi),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_14[] = + {0x8d,0xb4,0x26,0x00,0x00,0x00,0x00, /* leal 0L(%esi,1),%esi */ + 0x8d,0xbc,0x27,0x00,0x00,0x00,0x00}; /* leal 0L(%edi,1),%edi */ + static const char f32_15[] = + {0xeb,0x0d,0x90,0x90,0x90,0x90,0x90, /* jmp .+15; lotsa nops */ + 0x90,0x90,0x90,0x90,0x90,0x90,0x90,0x90}; + static const char f16_3[] = + {0x8d,0x74,0x00}; /* lea 0(%esi),%esi */ + static const char f16_4[] = + {0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ + static const char f16_5[] = + {0x90, /* nop */ + 0x8d,0xb4,0x00,0x00}; /* lea 0w(%si),%si */ + static const char f16_6[] = + {0x89,0xf6, /* mov %si,%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char f16_7[] = + {0x8d,0x74,0x00, /* lea 0(%si),%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char f16_8[] = + {0x8d,0xb4,0x00,0x00, /* lea 0w(%si),%si */ + 0x8d,0xbd,0x00,0x00}; /* lea 0w(%di),%di */ + static const char *const f32_patt[] = { + f32_1, f32_2, f32_3, f32_4, f32_5, f32_6, f32_7, f32_8, + f32_9, f32_10, f32_11, f32_12, f32_13, f32_14, f32_15 + }; + static const char *const f16_patt[] = { + f32_1, f32_2, f16_3, f16_4, f16_5, f16_6, f16_7, f16_8, + f32_15, f32_15, f32_15, f32_15, f32_15, f32_15, f32_15 + }; + + if (count <= 0 || count > 15) + return; + + /* The recommended way to pad 64bit code is to use NOPs preceded by + maximally four 0x66 prefixes. Balance the size of nops. */ + if (flag_code == CODE_64BIT) + { + int i; + int nnops = (count + 3) / 4; + int len = count / nnops; + int remains = count - nnops * len; + int pos = 0; + + for (i = 0; i < remains; i++) + { + memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len); + fragP->fr_literal[fragP->fr_fix + pos + len] = 0x90; + pos += len + 1; + } + for (; i < nnops; i++) + { + memset (fragP->fr_literal + fragP->fr_fix + pos, 0x66, len - 1); + fragP->fr_literal[fragP->fr_fix + pos + len - 1] = 0x90; + pos += len; + } + } + else + if (flag_code == CODE_16BIT) + { + memcpy (fragP->fr_literal + fragP->fr_fix, + f16_patt[count - 1], count); + if (count > 8) + /* Adjust jump offset. */ + fragP->fr_literal[fragP->fr_fix + 1] = count - 2; + } + else + memcpy (fragP->fr_literal + fragP->fr_fix, + f32_patt[count - 1], count); + fragP->fr_var = count; +} + +static INLINE unsigned int +mode_from_disp_size (t) + unsigned int t; +{ + return (t & Disp8) ? 1 : (t & (Disp16 | Disp32 | Disp32S)) ? 2 : 0; +} + +static INLINE int +fits_in_signed_byte (num) + offsetT num; +{ + return (num >= -128) && (num <= 127); +} + +static INLINE int +fits_in_unsigned_byte (num) + offsetT num; +{ + return (num & 0xff) == num; +} + +static INLINE int +fits_in_unsigned_word (num) + offsetT num; +{ + return (num & 0xffff) == num; +} + +static INLINE int +fits_in_signed_word (num) + offsetT num; +{ + return (-32768 <= num) && (num <= 32767); +} +static INLINE int +fits_in_signed_long (num) + offsetT num ATTRIBUTE_UNUSED; +{ +#ifndef BFD64 + return 1; +#else + return (!(((offsetT) -1 << 31) & num) + || (((offsetT) -1 << 31) & num) == ((offsetT) -1 << 31)); +#endif +} /* fits_in_signed_long() */ +static INLINE int +fits_in_unsigned_long (num) + offsetT num ATTRIBUTE_UNUSED; +{ +#ifndef BFD64 + return 1; +#else + return (num & (((offsetT) 2 << 31) - 1)) == num; +#endif +} /* fits_in_unsigned_long() */ + +static int +smallest_imm_type (num) + offsetT num; +{ + if (cpu_arch_flags != (Cpu086 | Cpu186 | Cpu286 | Cpu386 | Cpu486 | CpuNo64)) + { + /* This code is disabled on the 486 because all the Imm1 forms + in the opcode table are slower on the i486. They're the + versions with the implicitly specified single-position + displacement, which has another syntax if you really want to + use that form. */ + if (num == 1) + return Imm1 | Imm8 | Imm8S | Imm16 | Imm32 | Imm32S | Imm64; + } + return (fits_in_signed_byte (num) + ? (Imm8S | Imm8 | Imm16 | Imm32 | Imm32S | Imm64) + : fits_in_unsigned_byte (num) + ? (Imm8 | Imm16 | Imm32 | Imm32S | Imm64) + : (fits_in_signed_word (num) || fits_in_unsigned_word (num)) + ? (Imm16 | Imm32 | Imm32S | Imm64) + : fits_in_signed_long (num) + ? (Imm32 | Imm32S | Imm64) + : fits_in_unsigned_long (num) + ? (Imm32 | Imm64) + : Imm64); +} + +static offsetT +offset_in_range (val, size) + offsetT val; + int size; +{ + addressT mask; + + switch (size) + { + case 1: mask = ((addressT) 1 << 8) - 1; break; + case 2: mask = ((addressT) 1 << 16) - 1; break; + case 4: mask = ((addressT) 2 << 31) - 1; break; +#ifdef BFD64 + case 8: mask = ((addressT) 2 << 63) - 1; break; +#endif + default: abort (); + } + + /* If BFD64, sign extend val. */ + if (!use_rela_relocations) + if ((val & ~(((addressT) 2 << 31) - 1)) == 0) + val = (val ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31); + + if ((val & ~mask) != 0 && (val & ~mask) != ~mask) + { + char buf1[40], buf2[40]; + + sprint_value (buf1, val); + sprint_value (buf2, val & mask); + as_warn (_("%s shortened to %s"), buf1, buf2); + } + return val & mask; +} + +/* Returns 0 if attempting to add a prefix where one from the same + class already exists, 1 if non rep/repne added, 2 if rep/repne + added. */ +static int +add_prefix (prefix) + unsigned int prefix; +{ + int ret = 1; + int q; + + if (prefix >= REX_OPCODE && prefix < REX_OPCODE + 16 + && flag_code == CODE_64BIT) + q = REX_PREFIX; + else + switch (prefix) + { + default: + abort (); + + case CS_PREFIX_OPCODE: + case DS_PREFIX_OPCODE: + case ES_PREFIX_OPCODE: + case FS_PREFIX_OPCODE: + case GS_PREFIX_OPCODE: + case SS_PREFIX_OPCODE: + q = SEG_PREFIX; + break; + + case REPNE_PREFIX_OPCODE: + case REPE_PREFIX_OPCODE: + ret = 2; + /* fall thru */ + case LOCK_PREFIX_OPCODE: + q = LOCKREP_PREFIX; + break; + + case FWAIT_OPCODE: + q = WAIT_PREFIX; + break; + + case ADDR_PREFIX_OPCODE: + q = ADDR_PREFIX; + break; + + case DATA_PREFIX_OPCODE: + q = DATA_PREFIX; + break; + } + + if (i.prefix[q] != 0) + { + as_bad (_("same type of prefix used twice")); + return 0; + } + + i.prefixes += 1; + i.prefix[q] = prefix; + return ret; +} + +static void +set_code_flag (value) + int value; +{ + flag_code = value; + cpu_arch_flags &= ~(Cpu64 | CpuNo64); + cpu_arch_flags |= (flag_code == CODE_64BIT ? Cpu64 : CpuNo64); + if (value == CODE_64BIT && !(cpu_arch_flags & CpuSledgehammer)) + { + as_bad (_("64bit mode not supported on this CPU.")); + } + if (value == CODE_32BIT && !(cpu_arch_flags & Cpu386)) + { + as_bad (_("32bit mode not supported on this CPU.")); + } + stackop_size = '\0'; +} + +static void +set_16bit_gcc_code_flag (new_code_flag) + int new_code_flag; +{ + flag_code = new_code_flag; + cpu_arch_flags &= ~(Cpu64 | CpuNo64); + cpu_arch_flags |= (flag_code == CODE_64BIT ? Cpu64 : CpuNo64); + stackop_size = 'l'; +} + +static void +set_intel_syntax (syntax_flag) + int syntax_flag; +{ + /* Find out if register prefixing is specified. */ + int ask_naked_reg = 0; + + SKIP_WHITESPACE (); + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *string = input_line_pointer; + int e = get_symbol_end (); + + if (strcmp (string, "prefix") == 0) + ask_naked_reg = 1; + else if (strcmp (string, "noprefix") == 0) + ask_naked_reg = -1; + else + as_bad (_("bad argument to syntax directive.")); + *input_line_pointer = e; + } + demand_empty_rest_of_line (); + + intel_syntax = syntax_flag; + + if (ask_naked_reg == 0) + { +#ifdef BFD_ASSEMBLER + allow_naked_reg = (intel_syntax + && (bfd_get_symbol_leading_char (stdoutput) != '\0')); +#else + /* Conservative default. */ + allow_naked_reg = 0; +#endif + } + else + allow_naked_reg = (ask_naked_reg < 0); +} + +static void +set_cpu_arch (dummy) + int dummy ATTRIBUTE_UNUSED; +{ + SKIP_WHITESPACE (); + + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *string = input_line_pointer; + int e = get_symbol_end (); + int i; + + for (i = 0; cpu_arch[i].name; i++) + { + if (strcmp (string, cpu_arch[i].name) == 0) + { + cpu_arch_name = cpu_arch[i].name; + cpu_arch_flags = (cpu_arch[i].flags + | (flag_code == CODE_64BIT ? Cpu64 : CpuNo64)); + break; + } + } + if (!cpu_arch[i].name) + as_bad (_("no such architecture: `%s'"), string); + + *input_line_pointer = e; + } + else + as_bad (_("missing cpu architecture")); + + no_cond_jump_promotion = 0; + if (*input_line_pointer == ',' + && !is_end_of_line[(unsigned char) input_line_pointer[1]]) + { + char *string = ++input_line_pointer; + int e = get_symbol_end (); + + if (strcmp (string, "nojumps") == 0) + no_cond_jump_promotion = 1; + else if (strcmp (string, "jumps") == 0) + ; + else + as_bad (_("no such architecture modifier: `%s'"), string); + + *input_line_pointer = e; + } + + demand_empty_rest_of_line (); +} + +#ifdef BFD_ASSEMBLER +unsigned long +i386_mach () +{ + if (!strcmp (default_arch, "x86_64")) + return bfd_mach_x86_64; + else if (!strcmp (default_arch, "i386")) + return bfd_mach_i386_i386; + else + as_fatal (_("Unknown architecture")); +} +#endif + +void +md_begin () +{ + const char *hash_err; + + /* Initialize op_hash hash table. */ + op_hash = hash_new (); + + { + const template *optab; + templates *core_optab; + + /* Setup for loop. */ + optab = i386_optab; + core_optab = (templates *) xmalloc (sizeof (templates)); + core_optab->start = optab; + + while (1) + { + ++optab; + if (optab->name == NULL + || strcmp (optab->name, (optab - 1)->name) != 0) + { + /* different name --> ship out current template list; + add to hash table; & begin anew. */ + core_optab->end = optab; + hash_err = hash_insert (op_hash, + (optab - 1)->name, + (PTR) core_optab); + if (hash_err) + { + as_fatal (_("Internal Error: Can't hash %s: %s"), + (optab - 1)->name, + hash_err); + } + if (optab->name == NULL) + break; + core_optab = (templates *) xmalloc (sizeof (templates)); + core_optab->start = optab; + } + } + } + + /* Initialize reg_hash hash table. */ + reg_hash = hash_new (); + { + const reg_entry *regtab; + + for (regtab = i386_regtab; + regtab < i386_regtab + sizeof (i386_regtab) / sizeof (i386_regtab[0]); + regtab++) + { + hash_err = hash_insert (reg_hash, regtab->reg_name, (PTR) regtab); + if (hash_err) + as_fatal (_("Internal Error: Can't hash %s: %s"), + regtab->reg_name, + hash_err); + } + } + + /* Fill in lexical tables: mnemonic_chars, operand_chars. */ + { + int c; + char *p; + + for (c = 0; c < 256; c++) + { + if (ISDIGIT (c)) + { + digit_chars[c] = c; + mnemonic_chars[c] = c; + register_chars[c] = c; + operand_chars[c] = c; + } + else if (ISLOWER (c)) + { + mnemonic_chars[c] = c; + register_chars[c] = c; + operand_chars[c] = c; + } + else if (ISUPPER (c)) + { + mnemonic_chars[c] = TOLOWER (c); + register_chars[c] = mnemonic_chars[c]; + operand_chars[c] = c; + } + + if (ISALPHA (c) || ISDIGIT (c)) + identifier_chars[c] = c; + else if (c >= 128) + { + identifier_chars[c] = c; + operand_chars[c] = c; + } + } + +#ifdef LEX_AT + identifier_chars['@'] = '@'; +#endif + digit_chars['-'] = '-'; + identifier_chars['_'] = '_'; + identifier_chars['.'] = '.'; + + for (p = operand_special_chars; *p != '\0'; p++) + operand_chars[(unsigned char) *p] = *p; + } + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (OUTPUT_FLAVOR == bfd_target_elf_flavour) + { + record_alignment (text_section, 2); + record_alignment (data_section, 2); + record_alignment (bss_section, 2); + } +#endif +} + +void +i386_print_statistics (file) + FILE *file; +{ + hash_print_statistics (file, "i386 opcode", op_hash); + hash_print_statistics (file, "i386 register", reg_hash); +} + +#ifdef DEBUG386 + +/* Debugging routines for md_assemble. */ +static void pi PARAMS ((char *, i386_insn *)); +static void pte PARAMS ((template *)); +static void pt PARAMS ((unsigned int)); +static void pe PARAMS ((expressionS *)); +static void ps PARAMS ((symbolS *)); + +static void +pi (line, x) + char *line; + i386_insn *x; +{ + unsigned int i; + + fprintf (stdout, "%s: template ", line); + pte (&x->tm); + fprintf (stdout, " address: base %s index %s scale %x\n", + x->base_reg ? x->base_reg->reg_name : "none", + x->index_reg ? x->index_reg->reg_name : "none", + x->log2_scale_factor); + fprintf (stdout, " modrm: mode %x reg %x reg/mem %x\n", + x->rm.mode, x->rm.reg, x->rm.regmem); + fprintf (stdout, " sib: base %x index %x scale %x\n", + x->sib.base, x->sib.index, x->sib.scale); + fprintf (stdout, " rex: 64bit %x extX %x extY %x extZ %x\n", + (x->rex & REX_MODE64) != 0, + (x->rex & REX_EXTX) != 0, + (x->rex & REX_EXTY) != 0, + (x->rex & REX_EXTZ) != 0); + for (i = 0; i < x->operands; i++) + { + fprintf (stdout, " #%d: ", i + 1); + pt (x->types[i]); + fprintf (stdout, "\n"); + if (x->types[i] + & (Reg | SReg2 | SReg3 | Control | Debug | Test | RegMMX | RegXMM)) + fprintf (stdout, "%s\n", x->op[i].regs->reg_name); + if (x->types[i] & Imm) + pe (x->op[i].imms); + if (x->types[i] & Disp) + pe (x->op[i].disps); + } +} + +static void +pte (t) + template *t; +{ + unsigned int i; + fprintf (stdout, " %d operands ", t->operands); + fprintf (stdout, "opcode %x ", t->base_opcode); + if (t->extension_opcode != None) + fprintf (stdout, "ext %x ", t->extension_opcode); + if (t->opcode_modifier & D) + fprintf (stdout, "D"); + if (t->opcode_modifier & W) + fprintf (stdout, "W"); + fprintf (stdout, "\n"); + for (i = 0; i < t->operands; i++) + { + fprintf (stdout, " #%d type ", i + 1); + pt (t->operand_types[i]); + fprintf (stdout, "\n"); + } +} + +static void +pe (e) + expressionS *e; +{ + fprintf (stdout, " operation %d\n", e->X_op); + fprintf (stdout, " add_number %ld (%lx)\n", + (long) e->X_add_number, (long) e->X_add_number); + if (e->X_add_symbol) + { + fprintf (stdout, " add_symbol "); + ps (e->X_add_symbol); + fprintf (stdout, "\n"); + } + if (e->X_op_symbol) + { + fprintf (stdout, " op_symbol "); + ps (e->X_op_symbol); + fprintf (stdout, "\n"); + } +} + +static void +ps (s) + symbolS *s; +{ + fprintf (stdout, "%s type %s%s", + S_GET_NAME (s), + S_IS_EXTERNAL (s) ? "EXTERNAL " : "", + segment_name (S_GET_SEGMENT (s))); +} + +struct type_name + { + unsigned int mask; + char *tname; + } + +static const type_names[] = +{ + { Reg8, "r8" }, + { Reg16, "r16" }, + { Reg32, "r32" }, + { Reg64, "r64" }, + { Imm8, "i8" }, + { Imm8S, "i8s" }, + { Imm16, "i16" }, + { Imm32, "i32" }, + { Imm32S, "i32s" }, + { Imm64, "i64" }, + { Imm1, "i1" }, + { BaseIndex, "BaseIndex" }, + { Disp8, "d8" }, + { Disp16, "d16" }, + { Disp32, "d32" }, + { Disp32S, "d32s" }, + { Disp64, "d64" }, + { InOutPortReg, "InOutPortReg" }, + { ShiftCount, "ShiftCount" }, + { Control, "control reg" }, + { Test, "test reg" }, + { Debug, "debug reg" }, + { FloatReg, "FReg" }, + { FloatAcc, "FAcc" }, + { SReg2, "SReg2" }, + { SReg3, "SReg3" }, + { Acc, "Acc" }, + { JumpAbsolute, "Jump Absolute" }, + { RegMMX, "rMMX" }, + { RegXMM, "rXMM" }, + { EsSeg, "es" }, + { 0, "" } +}; + +static void +pt (t) + unsigned int t; +{ + const struct type_name *ty; + + for (ty = type_names; ty->mask; ty++) + if (t & ty->mask) + fprintf (stdout, "%s, ", ty->tname); + fflush (stdout); +} + +#endif /* DEBUG386 */ + +#ifdef BFD_ASSEMBLER +static bfd_reloc_code_real_type reloc + PARAMS ((int, int, int, bfd_reloc_code_real_type)); + +static bfd_reloc_code_real_type +reloc (size, pcrel, sign, other) + int size; + int pcrel; + int sign; + bfd_reloc_code_real_type other; +{ + if (other != NO_RELOC) + return other; + + if (pcrel) + { + if (!sign) + as_bad (_("There are no unsigned pc-relative relocations")); + switch (size) + { + case 1: return BFD_RELOC_8_PCREL; + case 2: return BFD_RELOC_16_PCREL; + case 4: return BFD_RELOC_32_PCREL; + } + as_bad (_("can not do %d byte pc-relative relocation"), size); + } + else + { + if (sign) + switch (size) + { + case 4: return BFD_RELOC_X86_64_32S; + } + else + switch (size) + { + case 1: return BFD_RELOC_8; + case 2: return BFD_RELOC_16; + case 4: return BFD_RELOC_32; + case 8: return BFD_RELOC_64; + } + as_bad (_("can not do %s %d byte relocation"), + sign ? "signed" : "unsigned", size); + } + + abort (); + return BFD_RELOC_NONE; +} + +/* Here we decide which fixups can be adjusted to make them relative to + the beginning of the section instead of the symbol. Basically we need + to make sure that the dynamic relocations are done correctly, so in + some cases we force the original symbol to be used. */ + +int +tc_i386_fix_adjustable (fixP) + fixS *fixP ATTRIBUTE_UNUSED; +{ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (OUTPUT_FLAVOR != bfd_target_elf_flavour) + return 1; + + /* Don't adjust pc-relative references to merge sections in 64-bit + mode. */ + if (use_rela_relocations + && (S_GET_SEGMENT (fixP->fx_addsy)->flags & SEC_MERGE) != 0 + && fixP->fx_pcrel) + return 0; + + /* adjust_reloc_syms doesn't know about the GOT. */ + if (fixP->fx_r_type == BFD_RELOC_386_GOTOFF + || fixP->fx_r_type == BFD_RELOC_386_PLT32 + || fixP->fx_r_type == BFD_RELOC_386_GOT32 + || fixP->fx_r_type == BFD_RELOC_386_TLS_GD + || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM + || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32 + || fixP->fx_r_type == BFD_RELOC_386_TLS_IE_32 + || fixP->fx_r_type == BFD_RELOC_386_TLS_IE + || fixP->fx_r_type == BFD_RELOC_386_TLS_GOTIE + || fixP->fx_r_type == BFD_RELOC_386_TLS_LE_32 + || fixP->fx_r_type == BFD_RELOC_386_TLS_LE + || fixP->fx_r_type == BFD_RELOC_X86_64_PLT32 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOT32 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTPCREL + || fixP->fx_r_type == BFD_RELOC_X86_64_TLSGD + || fixP->fx_r_type == BFD_RELOC_X86_64_TLSLD + || fixP->fx_r_type == BFD_RELOC_X86_64_DTPOFF32 + || fixP->fx_r_type == BFD_RELOC_X86_64_GOTTPOFF + || fixP->fx_r_type == BFD_RELOC_X86_64_TPOFF32 + || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 0; +#endif + return 1; +} +#else +#define reloc(SIZE,PCREL,SIGN,OTHER) 0 +#define BFD_RELOC_8 0 +#define BFD_RELOC_16 0 +#define BFD_RELOC_32 0 +#define BFD_RELOC_8_PCREL 0 +#define BFD_RELOC_16_PCREL 0 +#define BFD_RELOC_32_PCREL 0 +#define BFD_RELOC_386_PLT32 0 +#define BFD_RELOC_386_GOT32 0 +#define BFD_RELOC_386_GOTOFF 0 +#define BFD_RELOC_386_TLS_GD 0 +#define BFD_RELOC_386_TLS_LDM 0 +#define BFD_RELOC_386_TLS_LDO_32 0 +#define BFD_RELOC_386_TLS_IE_32 0 +#define BFD_RELOC_386_TLS_IE 0 +#define BFD_RELOC_386_TLS_GOTIE 0 +#define BFD_RELOC_386_TLS_LE_32 0 +#define BFD_RELOC_386_TLS_LE 0 +#define BFD_RELOC_X86_64_PLT32 0 +#define BFD_RELOC_X86_64_GOT32 0 +#define BFD_RELOC_X86_64_GOTPCREL 0 +#define BFD_RELOC_X86_64_TLSGD 0 +#define BFD_RELOC_X86_64_TLSLD 0 +#define BFD_RELOC_X86_64_DTPOFF32 0 +#define BFD_RELOC_X86_64_GOTTPOFF 0 +#define BFD_RELOC_X86_64_TPOFF32 0 +#endif + +static int intel_float_operand PARAMS ((const char *mnemonic)); + +static int +intel_float_operand (mnemonic) + const char *mnemonic; +{ + if (mnemonic[0] == 'f' && mnemonic[1] == 'i') + return 2; + + if (mnemonic[0] == 'f') + return 1; + + return 0; +} + +/* This is the guts of the machine-dependent assembler. LINE points to a + machine dependent instruction. This function is supposed to emit + the frags/bytes it assembles to. */ + +void +md_assemble (line) + char *line; +{ + int j; + char mnemonic[MAX_MNEM_SIZE]; + + /* Initialize globals. */ + memset (&i, '\0', sizeof (i)); + for (j = 0; j < MAX_OPERANDS; j++) + i.reloc[j] = NO_RELOC; + memset (disp_expressions, '\0', sizeof (disp_expressions)); + memset (im_expressions, '\0', sizeof (im_expressions)); + save_stack_p = save_stack; + + /* First parse an instruction mnemonic & call i386_operand for the operands. + We assume that the scrubber has arranged it so that line[0] is the valid + start of a (possibly prefixed) mnemonic. */ + + line = parse_insn (line, mnemonic); + if (line == NULL) + return; + + line = parse_operands (line, mnemonic); + if (line == NULL) + return; + + /* Now we've parsed the mnemonic into a set of templates, and have the + operands at hand. */ + + /* All intel opcodes have reversed operands except for "bound" and + "enter". We also don't reverse intersegment "jmp" and "call" + instructions with 2 immediate operands so that the immediate segment + precedes the offset, as it does when in AT&T mode. "enter" and the + intersegment "jmp" and "call" instructions are the only ones that + have two immediate operands. */ + if (intel_syntax && i.operands > 1 + && (strcmp (mnemonic, "bound") != 0) + && !((i.types[0] & Imm) && (i.types[1] & Imm))) + swap_operands (); + + if (i.imm_operands) + optimize_imm (); + + if (i.disp_operands) + optimize_disp (); + + /* Next, we find a template that matches the given insn, + making sure the overlap of the given operands types is consistent + with the template operand types. */ + + if (!match_template ()) + return; + + if (intel_syntax) + { + /* Undo SYSV386_COMPAT brokenness when in Intel mode. See i386.h */ + if (SYSV386_COMPAT + && (i.tm.base_opcode & 0xfffffde0) == 0xdce0) + i.tm.base_opcode ^= FloatR; + + /* Zap movzx and movsx suffix. The suffix may have been set from + "word ptr" or "byte ptr" on the source operand, but we'll use + the suffix later to choose the destination register. */ + if ((i.tm.base_opcode & ~9) == 0x0fb6) + i.suffix = 0; + } + + if (i.tm.opcode_modifier & FWait) + if (!add_prefix (FWAIT_OPCODE)) + return; + + /* Check string instruction segment overrides. */ + if ((i.tm.opcode_modifier & IsString) != 0 && i.mem_operands != 0) + { + if (!check_string ()) + return; + } + + if (!process_suffix ()) + return; + + /* Make still unresolved immediate matches conform to size of immediate + given in i.suffix. */ + if (!finalize_imm ()) + return; + + if (i.types[0] & Imm1) + i.imm_operands = 0; /* kludge for shift insns. */ + if (i.types[0] & ImplicitRegister) + i.reg_operands--; + if (i.types[1] & ImplicitRegister) + i.reg_operands--; + if (i.types[2] & ImplicitRegister) + i.reg_operands--; + + if (i.tm.opcode_modifier & ImmExt) + { + /* These AMD 3DNow! and Intel Katmai New Instructions have an + opcode suffix which is coded in the same place as an 8-bit + immediate field would be. Here we fake an 8-bit immediate + operand from the opcode suffix stored in tm.extension_opcode. */ + + expressionS *exp; + + assert (i.imm_operands == 0 && i.operands <= 2 && 2 < MAX_OPERANDS); + + exp = &im_expressions[i.imm_operands++]; + i.op[i.operands].imms = exp; + i.types[i.operands++] = Imm8; + exp->X_op = O_constant; + exp->X_add_number = i.tm.extension_opcode; + i.tm.extension_opcode = None; + } + + /* For insns with operands there are more diddles to do to the opcode. */ + if (i.operands) + { + if (!process_operands ()) + return; + } + else if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0) + { + /* UnixWare fsub no args is alias for fsubp, fadd -> faddp, etc. */ + as_warn (_("translating to `%sp'"), i.tm.name); + } + + /* Handle conversion of 'int $3' --> special int3 insn. */ + if (i.tm.base_opcode == INT_OPCODE && i.op[0].imms->X_add_number == 3) + { + i.tm.base_opcode = INT3_OPCODE; + i.imm_operands = 0; + } + + if ((i.tm.opcode_modifier & (Jump | JumpByte | JumpDword)) + && i.op[0].disps->X_op == O_constant) + { + /* Convert "jmp constant" (and "call constant") to a jump (call) to + the absolute address given by the constant. Since ix86 jumps and + calls are pc relative, we need to generate a reloc. */ + i.op[0].disps->X_add_symbol = &abs_symbol; + i.op[0].disps->X_op = O_symbol; + } + + if ((i.tm.opcode_modifier & Rex64) != 0) + i.rex |= REX_MODE64; + + /* For 8 bit registers we need an empty rex prefix. Also if the + instruction already has a prefix, we need to convert old + registers to new ones. */ + + if (((i.types[0] & Reg8) != 0 + && (i.op[0].regs->reg_flags & RegRex64) != 0) + || ((i.types[1] & Reg8) != 0 + && (i.op[1].regs->reg_flags & RegRex64) != 0) + || (((i.types[0] & Reg8) != 0 || (i.types[1] & Reg8) != 0) + && i.rex != 0)) + { + int x; + + i.rex |= REX_OPCODE; + for (x = 0; x < 2; x++) + { + /* Look for 8 bit operand that uses old registers. */ + if ((i.types[x] & Reg8) != 0 + && (i.op[x].regs->reg_flags & RegRex64) == 0) + { + /* In case it is "hi" register, give up. */ + if (i.op[x].regs->reg_num > 3) + as_bad (_("can't encode register '%%%s' in an instruction requiring REX prefix.\n"), + i.op[x].regs->reg_name); + + /* Otherwise it is equivalent to the extended register. + Since the encoding doesn't change this is merely + cosmetic cleanup for debug output. */ + + i.op[x].regs = i.op[x].regs + 8; + } + } + } + + if (i.rex != 0) + add_prefix (REX_OPCODE | i.rex); + + /* We are ready to output the insn. */ + output_insn (); +} + +static char * +parse_insn (line, mnemonic) + char *line; + char *mnemonic; +{ + char *l = line; + char *token_start = l; + char *mnem_p; + + /* Non-zero if we found a prefix only acceptable with string insns. */ + const char *expecting_string_instruction = NULL; + + while (1) + { + mnem_p = mnemonic; + while ((*mnem_p = mnemonic_chars[(unsigned char) *l]) != 0) + { + mnem_p++; + if (mnem_p >= mnemonic + MAX_MNEM_SIZE) + { + as_bad (_("no such instruction: `%s'"), token_start); + return NULL; + } + l++; + } + if (!is_space_char (*l) + && *l != END_OF_INSN + && *l != PREFIX_SEPARATOR + && *l != ',') + { + as_bad (_("invalid character %s in mnemonic"), + output_invalid (*l)); + return NULL; + } + if (token_start == l) + { + if (*l == PREFIX_SEPARATOR) + as_bad (_("expecting prefix; got nothing")); + else + as_bad (_("expecting mnemonic; got nothing")); + return NULL; + } + + /* Look up instruction (or prefix) via hash table. */ + current_templates = hash_find (op_hash, mnemonic); + + if (*l != END_OF_INSN + && (!is_space_char (*l) || l[1] != END_OF_INSN) + && current_templates + && (current_templates->start->opcode_modifier & IsPrefix)) + { + /* If we are in 16-bit mode, do not allow addr16 or data16. + Similarly, in 32-bit mode, do not allow addr32 or data32. */ + if ((current_templates->start->opcode_modifier & (Size16 | Size32)) + && flag_code != CODE_64BIT + && (((current_templates->start->opcode_modifier & Size32) != 0) + ^ (flag_code == CODE_16BIT))) + { + as_bad (_("redundant %s prefix"), + current_templates->start->name); + return NULL; + } + /* Add prefix, checking for repeated prefixes. */ + switch (add_prefix (current_templates->start->base_opcode)) + { + case 0: + return NULL; + case 2: + expecting_string_instruction = current_templates->start->name; + break; + } + /* Skip past PREFIX_SEPARATOR and reset token_start. */ + token_start = ++l; + } + else + break; + } + + if (!current_templates) + { + /* See if we can get a match by trimming off a suffix. */ + switch (mnem_p[-1]) + { + case WORD_MNEM_SUFFIX: + case BYTE_MNEM_SUFFIX: + case QWORD_MNEM_SUFFIX: + i.suffix = mnem_p[-1]; + mnem_p[-1] = '\0'; + current_templates = hash_find (op_hash, mnemonic); + break; + case SHORT_MNEM_SUFFIX: + case LONG_MNEM_SUFFIX: + if (!intel_syntax) + { + i.suffix = mnem_p[-1]; + mnem_p[-1] = '\0'; + current_templates = hash_find (op_hash, mnemonic); + } + break; + + /* Intel Syntax. */ + case 'd': + if (intel_syntax) + { + if (intel_float_operand (mnemonic)) + i.suffix = SHORT_MNEM_SUFFIX; + else + i.suffix = LONG_MNEM_SUFFIX; + mnem_p[-1] = '\0'; + current_templates = hash_find (op_hash, mnemonic); + } + break; + } + if (!current_templates) + { + as_bad (_("no such instruction: `%s'"), token_start); + return NULL; + } + } + + if (current_templates->start->opcode_modifier & (Jump | JumpByte)) + { + /* Check for a branch hint. We allow ",pt" and ",pn" for + predict taken and predict not taken respectively. + I'm not sure that branch hints actually do anything on loop + and jcxz insns (JumpByte) for current Pentium4 chips. They + may work in the future and it doesn't hurt to accept them + now. */ + if (l[0] == ',' && l[1] == 'p') + { + if (l[2] == 't') + { + if (!add_prefix (DS_PREFIX_OPCODE)) + return NULL; + l += 3; + } + else if (l[2] == 'n') + { + if (!add_prefix (CS_PREFIX_OPCODE)) + return NULL; + l += 3; + } + } + } + /* Any other comma loses. */ + if (*l == ',') + { + as_bad (_("invalid character %s in mnemonic"), + output_invalid (*l)); + return NULL; + } + + /* Check if instruction is supported on specified architecture. */ + if ((current_templates->start->cpu_flags & ~(Cpu64 | CpuNo64)) + & ~(cpu_arch_flags & ~(Cpu64 | CpuNo64))) + { + as_warn (_("`%s' is not supported on `%s'"), + current_templates->start->name, cpu_arch_name); + } + else if ((Cpu386 & ~cpu_arch_flags) && (flag_code != CODE_16BIT)) + { + as_warn (_("use .code16 to ensure correct addressing mode")); + } + + /* Check for rep/repne without a string instruction. */ + if (expecting_string_instruction + && !(current_templates->start->opcode_modifier & IsString)) + { + as_bad (_("expecting string instruction after `%s'"), + expecting_string_instruction); + return NULL; + } + + return l; +} + +static char * +parse_operands (l, mnemonic) + char *l; + const char *mnemonic; +{ + char *token_start; + + /* 1 if operand is pending after ','. */ + unsigned int expecting_operand = 0; + + /* Non-zero if operand parens not balanced. */ + unsigned int paren_not_balanced; + + while (*l != END_OF_INSN) + { + /* Skip optional white space before operand. */ + if (is_space_char (*l)) + ++l; + if (!is_operand_char (*l) && *l != END_OF_INSN) + { + as_bad (_("invalid character %s before operand %d"), + output_invalid (*l), + i.operands + 1); + return NULL; + } + token_start = l; /* after white space */ + paren_not_balanced = 0; + while (paren_not_balanced || *l != ',') + { + if (*l == END_OF_INSN) + { + if (paren_not_balanced) + { + if (!intel_syntax) + as_bad (_("unbalanced parenthesis in operand %d."), + i.operands + 1); + else + as_bad (_("unbalanced brackets in operand %d."), + i.operands + 1); + return NULL; + } + else + break; /* we are done */ + } + else if (!is_operand_char (*l) && !is_space_char (*l)) + { + as_bad (_("invalid character %s in operand %d"), + output_invalid (*l), + i.operands + 1); + return NULL; + } + if (!intel_syntax) + { + if (*l == '(') + ++paren_not_balanced; + if (*l == ')') + --paren_not_balanced; + } + else + { + if (*l == '[') + ++paren_not_balanced; + if (*l == ']') + --paren_not_balanced; + } + l++; + } + if (l != token_start) + { /* Yes, we've read in another operand. */ + unsigned int operand_ok; + this_operand = i.operands++; + if (i.operands > MAX_OPERANDS) + { + as_bad (_("spurious operands; (%d operands/instruction max)"), + MAX_OPERANDS); + return NULL; + } + /* Now parse operand adding info to 'i' as we go along. */ + END_STRING_AND_SAVE (l); + + if (intel_syntax) + operand_ok = + i386_intel_operand (token_start, + intel_float_operand (mnemonic)); + else + operand_ok = i386_operand (token_start); + + RESTORE_END_STRING (l); + if (!operand_ok) + return NULL; + } + else + { + if (expecting_operand) + { + expecting_operand_after_comma: + as_bad (_("expecting operand after ','; got nothing")); + return NULL; + } + if (*l == ',') + { + as_bad (_("expecting operand before ','; got nothing")); + return NULL; + } + } + + /* Now *l must be either ',' or END_OF_INSN. */ + if (*l == ',') + { + if (*++l == END_OF_INSN) + { + /* Just skip it, if it's \n complain. */ + goto expecting_operand_after_comma; + } + expecting_operand = 1; + } + } + return l; +} + +static void +swap_operands () +{ + union i386_op temp_op; + unsigned int temp_type; + RELOC_ENUM temp_reloc; + int xchg1 = 0; + int xchg2 = 0; + + if (i.operands == 2) + { + xchg1 = 0; + xchg2 = 1; + } + else if (i.operands == 3) + { + xchg1 = 0; + xchg2 = 2; + } + temp_type = i.types[xchg2]; + i.types[xchg2] = i.types[xchg1]; + i.types[xchg1] = temp_type; + temp_op = i.op[xchg2]; + i.op[xchg2] = i.op[xchg1]; + i.op[xchg1] = temp_op; + temp_reloc = i.reloc[xchg2]; + i.reloc[xchg2] = i.reloc[xchg1]; + i.reloc[xchg1] = temp_reloc; + + if (i.mem_operands == 2) + { + const seg_entry *temp_seg; + temp_seg = i.seg[0]; + i.seg[0] = i.seg[1]; + i.seg[1] = temp_seg; + } +} + +/* Try to ensure constant immediates are represented in the smallest + opcode possible. */ +static void +optimize_imm () +{ + char guess_suffix = 0; + int op; + + if (i.suffix) + guess_suffix = i.suffix; + else if (i.reg_operands) + { + /* Figure out a suffix from the last register operand specified. + We can't do this properly yet, ie. excluding InOutPortReg, + but the following works for instructions with immediates. + In any case, we can't set i.suffix yet. */ + for (op = i.operands; --op >= 0;) + if (i.types[op] & Reg) + { + if (i.types[op] & Reg8) + guess_suffix = BYTE_MNEM_SUFFIX; + else if (i.types[op] & Reg16) + guess_suffix = WORD_MNEM_SUFFIX; + else if (i.types[op] & Reg32) + guess_suffix = LONG_MNEM_SUFFIX; + else if (i.types[op] & Reg64) + guess_suffix = QWORD_MNEM_SUFFIX; + break; + } + } + else if ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0)) + guess_suffix = WORD_MNEM_SUFFIX; + + for (op = i.operands; --op >= 0;) + if (i.types[op] & Imm) + { + switch (i.op[op].imms->X_op) + { + case O_constant: + /* If a suffix is given, this operand may be shortened. */ + switch (guess_suffix) + { + case LONG_MNEM_SUFFIX: + i.types[op] |= Imm32 | Imm64; + break; + case WORD_MNEM_SUFFIX: + i.types[op] |= Imm16 | Imm32S | Imm32 | Imm64; + break; + case BYTE_MNEM_SUFFIX: + i.types[op] |= Imm16 | Imm8 | Imm8S | Imm32S | Imm32 | Imm64; + break; + } + + /* If this operand is at most 16 bits, convert it + to a signed 16 bit number before trying to see + whether it will fit in an even smaller size. + This allows a 16-bit operand such as $0xffe0 to + be recognised as within Imm8S range. */ + if ((i.types[op] & Imm16) + && (i.op[op].imms->X_add_number & ~(offsetT) 0xffff) == 0) + { + i.op[op].imms->X_add_number = + (((i.op[op].imms->X_add_number & 0xffff) ^ 0x8000) - 0x8000); + } + if ((i.types[op] & Imm32) + && ((i.op[op].imms->X_add_number & ~(((offsetT) 2 << 31) - 1)) + == 0)) + { + i.op[op].imms->X_add_number = ((i.op[op].imms->X_add_number + ^ ((offsetT) 1 << 31)) + - ((offsetT) 1 << 31)); + } + i.types[op] |= smallest_imm_type (i.op[op].imms->X_add_number); + + /* We must avoid matching of Imm32 templates when 64bit + only immediate is available. */ + if (guess_suffix == QWORD_MNEM_SUFFIX) + i.types[op] &= ~Imm32; + break; + + case O_absent: + case O_register: + abort (); + + /* Symbols and expressions. */ + default: + /* Convert symbolic operand to proper sizes for matching. */ + switch (guess_suffix) + { + case QWORD_MNEM_SUFFIX: + i.types[op] = Imm64 | Imm32S; + break; + case LONG_MNEM_SUFFIX: + i.types[op] = Imm32 | Imm64; + break; + case WORD_MNEM_SUFFIX: + i.types[op] = Imm16 | Imm32 | Imm64; + break; + break; + case BYTE_MNEM_SUFFIX: + i.types[op] = Imm8 | Imm8S | Imm16 | Imm32S | Imm32; + break; + break; + } + break; + } + } +} + +/* Try to use the smallest displacement type too. */ +static void +optimize_disp () +{ + int op; + + for (op = i.operands; --op >= 0;) + if ((i.types[op] & Disp) && i.op[op].disps->X_op == O_constant) + { + offsetT disp = i.op[op].disps->X_add_number; + + if (i.types[op] & Disp16) + { + /* We know this operand is at most 16 bits, so + convert to a signed 16 bit number before trying + to see whether it will fit in an even smaller + size. */ + + disp = (((disp & 0xffff) ^ 0x8000) - 0x8000); + } + else if (i.types[op] & Disp32) + { + /* We know this operand is at most 32 bits, so convert to a + signed 32 bit number before trying to see whether it will + fit in an even smaller size. */ + disp &= (((offsetT) 2 << 31) - 1); + disp = (disp ^ ((offsetT) 1 << 31)) - ((addressT) 1 << 31); + } + if (flag_code == CODE_64BIT) + { + if (fits_in_signed_long (disp)) + i.types[op] |= Disp32S; + if (fits_in_unsigned_long (disp)) + i.types[op] |= Disp32; + } + if ((i.types[op] & (Disp32 | Disp32S | Disp16)) + && fits_in_signed_byte (disp)) + i.types[op] |= Disp8; + } +} + +static int +match_template () +{ + /* Points to template once we've found it. */ + const template *t; + unsigned int overlap0, overlap1, overlap2; + unsigned int found_reverse_match; + int suffix_check; + +#define MATCH(overlap, given, template) \ + ((overlap & ~JumpAbsolute) \ + && (((given) & (BaseIndex | JumpAbsolute)) \ + == ((overlap) & (BaseIndex | JumpAbsolute)))) + + /* If given types r0 and r1 are registers they must be of the same type + unless the expected operand type register overlap is null. + Note that Acc in a template matches every size of reg. */ +#define CONSISTENT_REGISTER_MATCH(m0, g0, t0, m1, g1, t1) \ + (((g0) & Reg) == 0 || ((g1) & Reg) == 0 \ + || ((g0) & Reg) == ((g1) & Reg) \ + || ((((m0) & Acc) ? Reg : (t0)) & (((m1) & Acc) ? Reg : (t1)) & Reg) == 0 ) + + overlap0 = 0; + overlap1 = 0; + overlap2 = 0; + found_reverse_match = 0; + suffix_check = (i.suffix == BYTE_MNEM_SUFFIX + ? No_bSuf + : (i.suffix == WORD_MNEM_SUFFIX + ? No_wSuf + : (i.suffix == SHORT_MNEM_SUFFIX + ? No_sSuf + : (i.suffix == LONG_MNEM_SUFFIX + ? No_lSuf + : (i.suffix == QWORD_MNEM_SUFFIX + ? No_qSuf + : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX + ? No_xSuf : 0)))))); + + for (t = current_templates->start; + t < current_templates->end; + t++) + { + /* Must have right number of operands. */ + if (i.operands != t->operands) + continue; + + /* Check the suffix, except for some instructions in intel mode. */ + if ((t->opcode_modifier & suffix_check) + && !(intel_syntax + && (t->opcode_modifier & IgnoreSize)) + && !(intel_syntax + && t->base_opcode == 0xd9 + && (t->extension_opcode == 5 /* 0xd9,5 "fldcw" */ + || t->extension_opcode == 7))) /* 0xd9,7 "f{n}stcw" */ + continue; + + /* Do not verify operands when there are none. */ + else if (!t->operands) + { + if (t->cpu_flags & ~cpu_arch_flags) + continue; + /* We've found a match; break out of loop. */ + break; + } + + overlap0 = i.types[0] & t->operand_types[0]; + switch (t->operands) + { + case 1: + if (!MATCH (overlap0, i.types[0], t->operand_types[0])) + continue; + break; + case 2: + case 3: + overlap1 = i.types[1] & t->operand_types[1]; + if (!MATCH (overlap0, i.types[0], t->operand_types[0]) + || !MATCH (overlap1, i.types[1], t->operand_types[1]) + || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], + t->operand_types[0], + overlap1, i.types[1], + t->operand_types[1])) + { + /* Check if other direction is valid ... */ + if ((t->opcode_modifier & (D | FloatD)) == 0) + continue; + + /* Try reversing direction of operands. */ + overlap0 = i.types[0] & t->operand_types[1]; + overlap1 = i.types[1] & t->operand_types[0]; + if (!MATCH (overlap0, i.types[0], t->operand_types[1]) + || !MATCH (overlap1, i.types[1], t->operand_types[0]) + || !CONSISTENT_REGISTER_MATCH (overlap0, i.types[0], + t->operand_types[1], + overlap1, i.types[1], + t->operand_types[0])) + { + /* Does not match either direction. */ + continue; + } + /* found_reverse_match holds which of D or FloatDR + we've found. */ + found_reverse_match = t->opcode_modifier & (D | FloatDR); + } + /* Found a forward 2 operand match here. */ + else if (t->operands == 3) + { + /* Here we make use of the fact that there are no + reverse match 3 operand instructions, and all 3 + operand instructions only need to be checked for + register consistency between operands 2 and 3. */ + overlap2 = i.types[2] & t->operand_types[2]; + if (!MATCH (overlap2, i.types[2], t->operand_types[2]) + || !CONSISTENT_REGISTER_MATCH (overlap1, i.types[1], + t->operand_types[1], + overlap2, i.types[2], + t->operand_types[2])) + + continue; + } + /* Found either forward/reverse 2 or 3 operand match here: + slip through to break. */ + } + if (t->cpu_flags & ~cpu_arch_flags) + { + found_reverse_match = 0; + continue; + } + /* We've found a match; break out of loop. */ + break; + } + + if (t == current_templates->end) + { + /* We found no match. */ + as_bad (_("suffix or operands invalid for `%s'"), + current_templates->start->name); + return 0; + } + + if (!quiet_warnings) + { + if (!intel_syntax + && ((i.types[0] & JumpAbsolute) + != (t->operand_types[0] & JumpAbsolute))) + { + as_warn (_("indirect %s without `*'"), t->name); + } + + if ((t->opcode_modifier & (IsPrefix | IgnoreSize)) + == (IsPrefix | IgnoreSize)) + { + /* Warn them that a data or address size prefix doesn't + affect assembly of the next line of code. */ + as_warn (_("stand-alone `%s' prefix"), t->name); + } + } + + /* Copy the template we found. */ + i.tm = *t; + if (found_reverse_match) + { + /* If we found a reverse match we must alter the opcode + direction bit. found_reverse_match holds bits to change + (different for int & float insns). */ + + i.tm.base_opcode ^= found_reverse_match; + + i.tm.operand_types[0] = t->operand_types[1]; + i.tm.operand_types[1] = t->operand_types[0]; + } + + return 1; +} + +static int +check_string () +{ + int mem_op = (i.types[0] & AnyMem) ? 0 : 1; + if ((i.tm.operand_types[mem_op] & EsSeg) != 0) + { + if (i.seg[0] != NULL && i.seg[0] != &es) + { + as_bad (_("`%s' operand %d must use `%%es' segment"), + i.tm.name, + mem_op + 1); + return 0; + } + /* There's only ever one segment override allowed per instruction. + This instruction possibly has a legal segment override on the + second operand, so copy the segment to where non-string + instructions store it, allowing common code. */ + i.seg[0] = i.seg[1]; + } + else if ((i.tm.operand_types[mem_op + 1] & EsSeg) != 0) + { + if (i.seg[1] != NULL && i.seg[1] != &es) + { + as_bad (_("`%s' operand %d must use `%%es' segment"), + i.tm.name, + mem_op + 2); + return 0; + } + } + return 1; +} + +static int +process_suffix () +{ + /* If matched instruction specifies an explicit instruction mnemonic + suffix, use it. */ + if (i.tm.opcode_modifier & (Size16 | Size32 | Size64)) + { + if (i.tm.opcode_modifier & Size16) + i.suffix = WORD_MNEM_SUFFIX; + else if (i.tm.opcode_modifier & Size64) + i.suffix = QWORD_MNEM_SUFFIX; + else + i.suffix = LONG_MNEM_SUFFIX; + } + else if (i.reg_operands) + { + /* If there's no instruction mnemonic suffix we try to invent one + based on register operands. */ + if (!i.suffix) + { + /* We take i.suffix from the last register operand specified, + Destination register type is more significant than source + register type. */ + int op; + for (op = i.operands; --op >= 0;) + if ((i.types[op] & Reg) + && !(i.tm.operand_types[op] & InOutPortReg)) + { + i.suffix = ((i.types[op] & Reg8) ? BYTE_MNEM_SUFFIX : + (i.types[op] & Reg16) ? WORD_MNEM_SUFFIX : + (i.types[op] & Reg64) ? QWORD_MNEM_SUFFIX : + LONG_MNEM_SUFFIX); + break; + } + } + else if (i.suffix == BYTE_MNEM_SUFFIX) + { + if (!check_byte_reg ()) + return 0; + } + else if (i.suffix == LONG_MNEM_SUFFIX) + { + if (!check_long_reg ()) + return 0; + } + else if (i.suffix == QWORD_MNEM_SUFFIX) + { + if (!check_qword_reg ()) + return 0; + } + else if (i.suffix == WORD_MNEM_SUFFIX) + { + if (!check_word_reg ()) + return 0; + } + else if (intel_syntax && (i.tm.opcode_modifier & IgnoreSize)) + /* Do nothing if the instruction is going to ignore the prefix. */ + ; + else + abort (); + } + else if ((i.tm.opcode_modifier & DefaultSize) && !i.suffix) + { + i.suffix = stackop_size; + } + + /* Change the opcode based on the operand size given by i.suffix; + We need not change things for byte insns. */ + + if (!i.suffix && (i.tm.opcode_modifier & W)) + { + as_bad (_("no instruction mnemonic suffix given and no register operands; can't size instruction")); + return 0; + } + + if (i.suffix && i.suffix != BYTE_MNEM_SUFFIX) + { + /* It's not a byte, select word/dword operation. */ + if (i.tm.opcode_modifier & W) + { + if (i.tm.opcode_modifier & ShortForm) + i.tm.base_opcode |= 8; + else + i.tm.base_opcode |= 1; + } + + /* Now select between word & dword operations via the operand + size prefix, except for instructions that will ignore this + prefix anyway. */ + if (i.suffix != QWORD_MNEM_SUFFIX + && !(i.tm.opcode_modifier & IgnoreSize) + && ((i.suffix == LONG_MNEM_SUFFIX) == (flag_code == CODE_16BIT) + || (flag_code == CODE_64BIT + && (i.tm.opcode_modifier & JumpByte)))) + { + unsigned int prefix = DATA_PREFIX_OPCODE; + if (i.tm.opcode_modifier & JumpByte) /* jcxz, loop */ + prefix = ADDR_PREFIX_OPCODE; + + if (!add_prefix (prefix)) + return 0; + } + + /* Set mode64 for an operand. */ + if (i.suffix == QWORD_MNEM_SUFFIX + && flag_code == CODE_64BIT + && (i.tm.opcode_modifier & NoRex64) == 0) + i.rex |= REX_MODE64; + + /* Size floating point instruction. */ + if (i.suffix == LONG_MNEM_SUFFIX) + { + if (i.tm.opcode_modifier & FloatMF) + i.tm.base_opcode ^= 4; + } + } + + return 1; +} + +static int +check_byte_reg () +{ + int op; + for (op = i.operands; --op >= 0;) + { + /* If this is an eight bit register, it's OK. If it's the 16 or + 32 bit version of an eight bit register, we will just use the + low portion, and that's OK too. */ + if (i.types[op] & Reg8) + continue; + + /* movzx and movsx should not generate this warning. */ + if (intel_syntax + && (i.tm.base_opcode == 0xfb7 + || i.tm.base_opcode == 0xfb6 + || i.tm.base_opcode == 0x63 + || i.tm.base_opcode == 0xfbe + || i.tm.base_opcode == 0xfbf)) + continue; + + if ((i.types[op] & WordReg) && i.op[op].regs->reg_num < 4 +#if 0 + /* Check that the template allows eight bit regs. This + kills insns such as `orb $1,%edx', which maybe should be + allowed. */ + && (i.tm.operand_types[op] & (Reg8 | InOutPortReg)) +#endif + ) + { + /* Prohibit these changes in the 64bit mode, since the + lowering is more complicated. */ + if (flag_code == CODE_64BIT + && (i.tm.operand_types[op] & InOutPortReg) == 0) + { + as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), + i.op[op].regs->reg_name, + i.suffix); + return 0; + } +#if REGISTER_WARNINGS + if (!quiet_warnings + && (i.tm.operand_types[op] & InOutPortReg) == 0) + as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), + (i.op[op].regs + (i.types[op] & Reg16 + ? REGNAM_AL - REGNAM_AX + : REGNAM_AL - REGNAM_EAX))->reg_name, + i.op[op].regs->reg_name, + i.suffix); +#endif + continue; + } + /* Any other register is bad. */ + if (i.types[op] & (Reg | RegMMX | RegXMM + | SReg2 | SReg3 + | Control | Debug | Test + | FloatReg | FloatAcc)) + { + as_bad (_("`%%%s' not allowed with `%s%c'"), + i.op[op].regs->reg_name, + i.tm.name, + i.suffix); + return 0; + } + } + return 1; +} + +static int +check_long_reg () +{ + int op; + + for (op = i.operands; --op >= 0;) + /* Reject eight bit registers, except where the template requires + them. (eg. movzb) */ + if ((i.types[op] & Reg8) != 0 + && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) + { + as_bad (_("`%%%s' not allowed with `%s%c'"), + i.op[op].regs->reg_name, + i.tm.name, + i.suffix); + return 0; + } + /* Warn if the e prefix on a general reg is missing. */ + else if ((!quiet_warnings || flag_code == CODE_64BIT) + && (i.types[op] & Reg16) != 0 + && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0) + { + /* Prohibit these changes in the 64bit mode, since the + lowering is more complicated. */ + if (flag_code == CODE_64BIT) + { + as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), + i.op[op].regs->reg_name, + i.suffix); + return 0; + } +#if REGISTER_WARNINGS + else + as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), + (i.op[op].regs + REGNAM_EAX - REGNAM_AX)->reg_name, + i.op[op].regs->reg_name, + i.suffix); +#endif + } + /* Warn if the r prefix on a general reg is missing. */ + else if ((i.types[op] & Reg64) != 0 + && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0) + { + as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), + i.op[op].regs->reg_name, + i.suffix); + return 0; + } + return 1; +} + +static int +check_qword_reg () +{ + int op; + + for (op = i.operands; --op >= 0; ) + /* Reject eight bit registers, except where the template requires + them. (eg. movzb) */ + if ((i.types[op] & Reg8) != 0 + && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) + { + as_bad (_("`%%%s' not allowed with `%s%c'"), + i.op[op].regs->reg_name, + i.tm.name, + i.suffix); + return 0; + } + /* Warn if the e prefix on a general reg is missing. */ + else if (((i.types[op] & Reg16) != 0 + || (i.types[op] & Reg32) != 0) + && (i.tm.operand_types[op] & (Reg32 | Acc)) != 0) + { + /* Prohibit these changes in the 64bit mode, since the + lowering is more complicated. */ + as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), + i.op[op].regs->reg_name, + i.suffix); + return 0; + } + return 1; +} + +static int +check_word_reg () +{ + int op; + for (op = i.operands; --op >= 0;) + /* Reject eight bit registers, except where the template requires + them. (eg. movzb) */ + if ((i.types[op] & Reg8) != 0 + && (i.tm.operand_types[op] & (Reg16 | Reg32 | Acc)) != 0) + { + as_bad (_("`%%%s' not allowed with `%s%c'"), + i.op[op].regs->reg_name, + i.tm.name, + i.suffix); + return 0; + } + /* Warn if the e prefix on a general reg is present. */ + else if ((!quiet_warnings || flag_code == CODE_64BIT) + && (i.types[op] & Reg32) != 0 + && (i.tm.operand_types[op] & (Reg16 | Acc)) != 0) + { + /* Prohibit these changes in the 64bit mode, since the + lowering is more complicated. */ + if (flag_code == CODE_64BIT) + { + as_bad (_("Incorrect register `%%%s' used with `%c' suffix"), + i.op[op].regs->reg_name, + i.suffix); + return 0; + } + else +#if REGISTER_WARNINGS + as_warn (_("using `%%%s' instead of `%%%s' due to `%c' suffix"), + (i.op[op].regs + REGNAM_AX - REGNAM_EAX)->reg_name, + i.op[op].regs->reg_name, + i.suffix); +#endif + } + return 1; +} + +static int +finalize_imm () +{ + unsigned int overlap0, overlap1, overlap2; + + overlap0 = i.types[0] & i.tm.operand_types[0]; + if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S)) + && overlap0 != Imm8 && overlap0 != Imm8S + && overlap0 != Imm16 && overlap0 != Imm32S + && overlap0 != Imm32 && overlap0 != Imm64) + { + if (i.suffix) + { + overlap0 &= (i.suffix == BYTE_MNEM_SUFFIX + ? Imm8 | Imm8S + : (i.suffix == WORD_MNEM_SUFFIX + ? Imm16 + : (i.suffix == QWORD_MNEM_SUFFIX + ? Imm64 | Imm32S + : Imm32))); + } + else if (overlap0 == (Imm16 | Imm32S | Imm32) + || overlap0 == (Imm16 | Imm32) + || overlap0 == (Imm16 | Imm32S)) + { + overlap0 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0) + ? Imm16 : Imm32S); + } + if (overlap0 != Imm8 && overlap0 != Imm8S + && overlap0 != Imm16 && overlap0 != Imm32S + && overlap0 != Imm32 && overlap0 != Imm64) + { + as_bad (_("no instruction mnemonic suffix given; can't determine immediate size")); + return 0; + } + } + i.types[0] = overlap0; + + overlap1 = i.types[1] & i.tm.operand_types[1]; + if ((overlap1 & (Imm8 | Imm8S | Imm16 | Imm32S | Imm32)) + && overlap1 != Imm8 && overlap1 != Imm8S + && overlap1 != Imm16 && overlap1 != Imm32S + && overlap1 != Imm32 && overlap1 != Imm64) + { + if (i.suffix) + { + overlap1 &= (i.suffix == BYTE_MNEM_SUFFIX + ? Imm8 | Imm8S + : (i.suffix == WORD_MNEM_SUFFIX + ? Imm16 + : (i.suffix == QWORD_MNEM_SUFFIX + ? Imm64 | Imm32S + : Imm32))); + } + else if (overlap1 == (Imm16 | Imm32 | Imm32S) + || overlap1 == (Imm16 | Imm32) + || overlap1 == (Imm16 | Imm32S)) + { + overlap1 = ((flag_code == CODE_16BIT) ^ (i.prefix[DATA_PREFIX] != 0) + ? Imm16 : Imm32S); + } + if (overlap1 != Imm8 && overlap1 != Imm8S + && overlap1 != Imm16 && overlap1 != Imm32S + && overlap1 != Imm32 && overlap1 != Imm64) + { + as_bad (_("no instruction mnemonic suffix given; can't determine immediate size %x %c"),overlap1, i.suffix); + return 0; + } + } + i.types[1] = overlap1; + + overlap2 = i.types[2] & i.tm.operand_types[2]; + assert ((overlap2 & Imm) == 0); + i.types[2] = overlap2; + + return 1; +} + +static int +process_operands () +{ + /* Default segment register this instruction will use for memory + accesses. 0 means unknown. This is only for optimizing out + unnecessary segment overrides. */ + const seg_entry *default_seg = 0; + + /* The imul $imm, %reg instruction is converted into + imul $imm, %reg, %reg, and the clr %reg instruction + is converted into xor %reg, %reg. */ + if (i.tm.opcode_modifier & regKludge) + { + unsigned int first_reg_op = (i.types[0] & Reg) ? 0 : 1; + /* Pretend we saw the extra register operand. */ + assert (i.op[first_reg_op + 1].regs == 0); + i.op[first_reg_op + 1].regs = i.op[first_reg_op].regs; + i.types[first_reg_op + 1] = i.types[first_reg_op]; + i.reg_operands = 2; + } + + if (i.tm.opcode_modifier & ShortForm) + { + /* The register or float register operand is in operand 0 or 1. */ + unsigned int op = (i.types[0] & (Reg | FloatReg)) ? 0 : 1; + /* Register goes in low 3 bits of opcode. */ + i.tm.base_opcode |= i.op[op].regs->reg_num; + if ((i.op[op].regs->reg_flags & RegRex) != 0) + i.rex |= REX_EXTZ; + if (!quiet_warnings && (i.tm.opcode_modifier & Ugh) != 0) + { + /* Warn about some common errors, but press on regardless. + The first case can be generated by gcc (<= 2.8.1). */ + if (i.operands == 2) + { + /* Reversed arguments on faddp, fsubp, etc. */ + as_warn (_("translating to `%s %%%s,%%%s'"), i.tm.name, + i.op[1].regs->reg_name, + i.op[0].regs->reg_name); + } + else + { + /* Extraneous `l' suffix on fp insn. */ + as_warn (_("translating to `%s %%%s'"), i.tm.name, + i.op[0].regs->reg_name); + } + } + } + else if (i.tm.opcode_modifier & Modrm) + { + /* The opcode is completed (modulo i.tm.extension_opcode which + must be put into the modrm byte). Now, we make the modrm and + index base bytes based on all the info we've collected. */ + + default_seg = build_modrm_byte (); + } + else if (i.tm.opcode_modifier & (Seg2ShortForm | Seg3ShortForm)) + { + if (i.tm.base_opcode == POP_SEG_SHORT + && i.op[0].regs->reg_num == 1) + { + as_bad (_("you can't `pop %%cs'")); + return 0; + } + i.tm.base_opcode |= (i.op[0].regs->reg_num << 3); + if ((i.op[0].regs->reg_flags & RegRex) != 0) + i.rex |= REX_EXTZ; + } + else if ((i.tm.base_opcode & ~(D | W)) == MOV_AX_DISP32) + { + default_seg = &ds; + } + else if ((i.tm.opcode_modifier & IsString) != 0) + { + /* For the string instructions that allow a segment override + on one of their operands, the default segment is ds. */ + default_seg = &ds; + } + + if (i.tm.base_opcode == 0x8d /* lea */ && i.seg[0] && !quiet_warnings) + as_warn (_("segment override on `lea' is ineffectual")); + + /* If a segment was explicitly specified, and the specified segment + is not the default, use an opcode prefix to select it. If we + never figured out what the default segment is, then default_seg + will be zero at this point, and the specified segment prefix will + always be used. */ + if ((i.seg[0]) && (i.seg[0] != default_seg)) + { + if (!add_prefix (i.seg[0]->seg_prefix)) + return 0; + } + return 1; +} + +static const seg_entry * +build_modrm_byte () +{ + const seg_entry *default_seg = 0; + + /* i.reg_operands MUST be the number of real register operands; + implicit registers do not count. */ + if (i.reg_operands == 2) + { + unsigned int source, dest; + source = ((i.types[0] + & (Reg | RegMMX | RegXMM + | SReg2 | SReg3 + | Control | Debug | Test)) + ? 0 : 1); + dest = source + 1; + + i.rm.mode = 3; + /* One of the register operands will be encoded in the i.tm.reg + field, the other in the combined i.tm.mode and i.tm.regmem + fields. If no form of this instruction supports a memory + destination operand, then we assume the source operand may + sometimes be a memory operand and so we need to store the + destination in the i.rm.reg field. */ + if ((i.tm.operand_types[dest] & AnyMem) == 0) + { + i.rm.reg = i.op[dest].regs->reg_num; + i.rm.regmem = i.op[source].regs->reg_num; + if ((i.op[dest].regs->reg_flags & RegRex) != 0) + i.rex |= REX_EXTX; + if ((i.op[source].regs->reg_flags & RegRex) != 0) + i.rex |= REX_EXTZ; + } + else + { + i.rm.reg = i.op[source].regs->reg_num; + i.rm.regmem = i.op[dest].regs->reg_num; + if ((i.op[dest].regs->reg_flags & RegRex) != 0) + i.rex |= REX_EXTZ; + if ((i.op[source].regs->reg_flags & RegRex) != 0) + i.rex |= REX_EXTX; + } + } + else + { /* If it's not 2 reg operands... */ + if (i.mem_operands) + { + unsigned int fake_zero_displacement = 0; + unsigned int op = ((i.types[0] & AnyMem) + ? 0 + : (i.types[1] & AnyMem) ? 1 : 2); + + default_seg = &ds; + + if (i.base_reg == 0) + { + i.rm.mode = 0; + if (!i.disp_operands) + fake_zero_displacement = 1; + if (i.index_reg == 0) + { + /* Operand is just */ + if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0) + && (flag_code != CODE_64BIT)) + { + i.rm.regmem = NO_BASE_REGISTER_16; + i.types[op] &= ~Disp; + i.types[op] |= Disp16; + } + else if (flag_code != CODE_64BIT + || (i.prefix[ADDR_PREFIX] != 0)) + { + i.rm.regmem = NO_BASE_REGISTER; + i.types[op] &= ~Disp; + i.types[op] |= Disp32; + } + else + { + /* 64bit mode overwrites the 32bit absolute + addressing by RIP relative addressing and + absolute addressing is encoded by one of the + redundant SIB forms. */ + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.sib.base = NO_BASE_REGISTER; + i.sib.index = NO_INDEX_REGISTER; + i.types[op] &= ~Disp; + i.types[op] |= Disp32S; + } + } + else /* !i.base_reg && i.index_reg */ + { + i.sib.index = i.index_reg->reg_num; + i.sib.base = NO_BASE_REGISTER; + i.sib.scale = i.log2_scale_factor; + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + i.types[op] &= ~Disp; + if (flag_code != CODE_64BIT) + i.types[op] |= Disp32; /* Must be 32 bit */ + else + i.types[op] |= Disp32S; + if ((i.index_reg->reg_flags & RegRex) != 0) + i.rex |= REX_EXTY; + } + } + /* RIP addressing for 64bit mode. */ + else if (i.base_reg->reg_type == BaseIndex) + { + i.rm.regmem = NO_BASE_REGISTER; + i.types[op] &= ~Disp; + i.types[op] |= Disp32S; + i.flags[op] = Operand_PCrel; + } + else if (i.base_reg->reg_type & Reg16) + { + switch (i.base_reg->reg_num) + { + case 3: /* (%bx) */ + if (i.index_reg == 0) + i.rm.regmem = 7; + else /* (%bx,%si) -> 0, or (%bx,%di) -> 1 */ + i.rm.regmem = i.index_reg->reg_num - 6; + break; + case 5: /* (%bp) */ + default_seg = &ss; + if (i.index_reg == 0) + { + i.rm.regmem = 6; + if ((i.types[op] & Disp) == 0) + { + /* fake (%bp) into 0(%bp) */ + i.types[op] |= Disp8; + fake_zero_displacement = 1; + } + } + else /* (%bp,%si) -> 2, or (%bp,%di) -> 3 */ + i.rm.regmem = i.index_reg->reg_num - 6 + 2; + break; + default: /* (%si) -> 4 or (%di) -> 5 */ + i.rm.regmem = i.base_reg->reg_num - 6 + 4; + } + i.rm.mode = mode_from_disp_size (i.types[op]); + } + else /* i.base_reg and 32/64 bit mode */ + { + if (flag_code == CODE_64BIT + && (i.types[op] & Disp)) + { + if (i.types[op] & Disp8) + i.types[op] = Disp8 | Disp32S; + else + i.types[op] = Disp32S; + } + i.rm.regmem = i.base_reg->reg_num; + if ((i.base_reg->reg_flags & RegRex) != 0) + i.rex |= REX_EXTZ; + i.sib.base = i.base_reg->reg_num; + /* x86-64 ignores REX prefix bit here to avoid decoder + complications. */ + if ((i.base_reg->reg_num & 7) == EBP_REG_NUM) + { + default_seg = &ss; + if (i.disp_operands == 0) + { + fake_zero_displacement = 1; + i.types[op] |= Disp8; + } + } + else if (i.base_reg->reg_num == ESP_REG_NUM) + { + default_seg = &ss; + } + i.sib.scale = i.log2_scale_factor; + if (i.index_reg == 0) + { + /* (%esp) becomes two byte modrm with no index + register. We've already stored the code for esp + in i.rm.regmem ie. ESCAPE_TO_TWO_BYTE_ADDRESSING. + Any base register besides %esp will not use the + extra modrm byte. */ + i.sib.index = NO_INDEX_REGISTER; +#if !SCALE1_WHEN_NO_INDEX + /* Another case where we force the second modrm byte. */ + if (i.log2_scale_factor) + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; +#endif + } + else + { + i.sib.index = i.index_reg->reg_num; + i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; + if ((i.index_reg->reg_flags & RegRex) != 0) + i.rex |= REX_EXTY; + } + i.rm.mode = mode_from_disp_size (i.types[op]); + } + + if (fake_zero_displacement) + { + /* Fakes a zero displacement assuming that i.types[op] + holds the correct displacement size. */ + expressionS *exp; + + assert (i.op[op].disps == 0); + exp = &disp_expressions[i.disp_operands++]; + i.op[op].disps = exp; + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + } + } + + /* Fill in i.rm.reg or i.rm.regmem field with register operand + (if any) based on i.tm.extension_opcode. Again, we must be + careful to make sure that segment/control/debug/test/MMX + registers are coded into the i.rm.reg field. */ + if (i.reg_operands) + { + unsigned int op = + ((i.types[0] + & (Reg | RegMMX | RegXMM + | SReg2 | SReg3 + | Control | Debug | Test)) + ? 0 + : ((i.types[1] + & (Reg | RegMMX | RegXMM + | SReg2 | SReg3 + | Control | Debug | Test)) + ? 1 + : 2)); + /* If there is an extension opcode to put here, the register + number must be put into the regmem field. */ + if (i.tm.extension_opcode != None) + { + i.rm.regmem = i.op[op].regs->reg_num; + if ((i.op[op].regs->reg_flags & RegRex) != 0) + i.rex |= REX_EXTZ; + } + else + { + i.rm.reg = i.op[op].regs->reg_num; + if ((i.op[op].regs->reg_flags & RegRex) != 0) + i.rex |= REX_EXTX; + } + + /* Now, if no memory operand has set i.rm.mode = 0, 1, 2 we + must set it to 3 to indicate this is a register operand + in the regmem field. */ + if (!i.mem_operands) + i.rm.mode = 3; + } + + /* Fill in i.rm.reg field with extension opcode (if any). */ + if (i.tm.extension_opcode != None) + i.rm.reg = i.tm.extension_opcode; + } + return default_seg; +} + +static void +output_branch () +{ + char *p; + int code16; + int prefix; + relax_substateT subtype; + symbolS *sym; + offsetT off; + + code16 = 0; + if (flag_code == CODE_16BIT) + code16 = CODE16; + + prefix = 0; + if (i.prefix[DATA_PREFIX] != 0) + { + prefix = 1; + i.prefixes -= 1; + code16 ^= CODE16; + } + /* Pentium4 branch hints. */ + if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */ + || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */) + { + prefix++; + i.prefixes--; + } + if (i.prefix[REX_PREFIX] != 0) + { + prefix++; + i.prefixes--; + } + + if (i.prefixes != 0 && !intel_syntax) + as_warn (_("skipping prefixes on this instruction")); + + /* It's always a symbol; End frag & setup for relax. + Make sure there is enough room in this frag for the largest + instruction we may generate in md_convert_frag. This is 2 + bytes for the opcode and room for the prefix and largest + displacement. */ + frag_grow (prefix + 2 + 4); + /* Prefix and 1 opcode byte go in fr_fix. */ + p = frag_more (prefix + 1); + if (i.prefix[DATA_PREFIX] != 0) + *p++ = DATA_PREFIX_OPCODE; + if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE + || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE) + *p++ = i.prefix[SEG_PREFIX]; + if (i.prefix[REX_PREFIX] != 0) + *p++ = i.prefix[REX_PREFIX]; + *p = i.tm.base_opcode; + + if ((unsigned char) *p == JUMP_PC_RELATIVE) + subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL); + else if ((cpu_arch_flags & Cpu386) != 0) + subtype = ENCODE_RELAX_STATE (COND_JUMP, SMALL); + else + subtype = ENCODE_RELAX_STATE (COND_JUMP86, SMALL); + subtype |= code16; + + sym = i.op[0].disps->X_add_symbol; + off = i.op[0].disps->X_add_number; + + if (i.op[0].disps->X_op != O_constant + && i.op[0].disps->X_op != O_symbol) + { + /* Handle complex expressions. */ + sym = make_expr_symbol (i.op[0].disps); + off = 0; + } + + /* 1 possible extra opcode + 4 byte displacement go in var part. + Pass reloc in fr_var. */ + frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p); +} + +static void +output_jump () +{ + char *p; + int size; + fixS *fixP; + + if (i.tm.opcode_modifier & JumpByte) + { + /* This is a loop or jecxz type instruction. */ + size = 1; + if (i.prefix[ADDR_PREFIX] != 0) + { + FRAG_APPEND_1_CHAR (ADDR_PREFIX_OPCODE); + i.prefixes -= 1; + } + /* Pentium4 branch hints. */ + if (i.prefix[SEG_PREFIX] == CS_PREFIX_OPCODE /* not taken */ + || i.prefix[SEG_PREFIX] == DS_PREFIX_OPCODE /* taken */) + { + FRAG_APPEND_1_CHAR (i.prefix[SEG_PREFIX]); + i.prefixes--; + } + } + else + { + int code16; + + code16 = 0; + if (flag_code == CODE_16BIT) + code16 = CODE16; + + if (i.prefix[DATA_PREFIX] != 0) + { + FRAG_APPEND_1_CHAR (DATA_PREFIX_OPCODE); + i.prefixes -= 1; + code16 ^= CODE16; + } + + size = 4; + if (code16) + size = 2; + } + + if (i.prefix[REX_PREFIX] != 0) + { + FRAG_APPEND_1_CHAR (i.prefix[REX_PREFIX]); + i.prefixes -= 1; + } + + if (i.prefixes != 0 && !intel_syntax) + as_warn (_("skipping prefixes on this instruction")); + + p = frag_more (1 + size); + *p++ = i.tm.base_opcode; + + fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.op[0].disps, 1, reloc (size, 1, 1, i.reloc[0])); + + /* All jumps handled here are signed, but don't use a signed limit + check for 32 and 16 bit jumps as we want to allow wrap around at + 4G and 64k respectively. */ + if (size == 1) + fixP->fx_signed = 1; +} + +static void +output_interseg_jump () +{ + char *p; + int size; + int prefix; + int code16; + + code16 = 0; + if (flag_code == CODE_16BIT) + code16 = CODE16; + + prefix = 0; + if (i.prefix[DATA_PREFIX] != 0) + { + prefix = 1; + i.prefixes -= 1; + code16 ^= CODE16; + } + if (i.prefix[REX_PREFIX] != 0) + { + prefix++; + i.prefixes -= 1; + } + + size = 4; + if (code16) + size = 2; + + if (i.prefixes != 0 && !intel_syntax) + as_warn (_("skipping prefixes on this instruction")); + + /* 1 opcode; 2 segment; offset */ + p = frag_more (prefix + 1 + 2 + size); + + if (i.prefix[DATA_PREFIX] != 0) + *p++ = DATA_PREFIX_OPCODE; + + if (i.prefix[REX_PREFIX] != 0) + *p++ = i.prefix[REX_PREFIX]; + + *p++ = i.tm.base_opcode; + if (i.op[1].imms->X_op == O_constant) + { + offsetT n = i.op[1].imms->X_add_number; + + if (size == 2 + && !fits_in_unsigned_word (n) + && !fits_in_signed_word (n)) + { + as_bad (_("16-bit jump out of range")); + return; + } + md_number_to_chars (p, n, size); + } + else + fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.op[1].imms, 0, reloc (size, 0, 0, i.reloc[1])); + if (i.op[0].imms->X_op != O_constant) + as_bad (_("can't handle non absolute segment in `%s'"), + i.tm.name); + md_number_to_chars (p + size, (valueT) i.op[0].imms->X_add_number, 2); +} + + +static void +output_insn () +{ + fragS *insn_start_frag; + offsetT insn_start_off; + + /* Tie dwarf2 debug info to the address at the start of the insn. + We can't do this after the insn has been output as the current + frag may have been closed off. eg. by frag_var. */ + dwarf2_emit_insn (0); + + insn_start_frag = frag_now; + insn_start_off = frag_now_fix (); + + /* Output jumps. */ + if (i.tm.opcode_modifier & Jump) + output_branch (); + else if (i.tm.opcode_modifier & (JumpByte | JumpDword)) + output_jump (); + else if (i.tm.opcode_modifier & JumpInterSegment) + output_interseg_jump (); + else + { + /* Output normal instructions here. */ + char *p; + unsigned char *q; + + /* All opcodes on i386 have either 1 or 2 bytes. We may use third + byte for the SSE instructions to specify a prefix they require. */ + if (i.tm.base_opcode & 0xff0000) + add_prefix ((i.tm.base_opcode >> 16) & 0xff); + + /* The prefix bytes. */ + for (q = i.prefix; + q < i.prefix + sizeof (i.prefix) / sizeof (i.prefix[0]); + q++) + { + if (*q) + { + p = frag_more (1); + md_number_to_chars (p, (valueT) *q, 1); + } + } + + /* Now the opcode; be careful about word order here! */ + if (fits_in_unsigned_byte (i.tm.base_opcode)) + { + FRAG_APPEND_1_CHAR (i.tm.base_opcode); + } + else + { + p = frag_more (2); + /* Put out high byte first: can't use md_number_to_chars! */ + *p++ = (i.tm.base_opcode >> 8) & 0xff; + *p = i.tm.base_opcode & 0xff; + } + + /* Now the modrm byte and sib byte (if present). */ + if (i.tm.opcode_modifier & Modrm) + { + p = frag_more (1); + md_number_to_chars (p, + (valueT) (i.rm.regmem << 0 + | i.rm.reg << 3 + | i.rm.mode << 6), + 1); + /* If i.rm.regmem == ESP (4) + && i.rm.mode != (Register mode) + && not 16 bit + ==> need second modrm byte. */ + if (i.rm.regmem == ESCAPE_TO_TWO_BYTE_ADDRESSING + && i.rm.mode != 3 + && !(i.base_reg && (i.base_reg->reg_type & Reg16) != 0)) + { + p = frag_more (1); + md_number_to_chars (p, + (valueT) (i.sib.base << 0 + | i.sib.index << 3 + | i.sib.scale << 6), + 1); + } + } + + if (i.disp_operands) + output_disp (insn_start_frag, insn_start_off); + + if (i.imm_operands) + output_imm (insn_start_frag, insn_start_off); + } + +#ifdef DEBUG386 + if (flag_debug) + { + pi (line, &i); + } +#endif /* DEBUG386 */ +} + +static void +output_disp (insn_start_frag, insn_start_off) + fragS *insn_start_frag; + offsetT insn_start_off; +{ + char *p; + unsigned int n; + + for (n = 0; n < i.operands; n++) + { + if (i.types[n] & Disp) + { + if (i.op[n].disps->X_op == O_constant) + { + int size; + offsetT val; + + size = 4; + if (i.types[n] & (Disp8 | Disp16 | Disp64)) + { + size = 2; + if (i.types[n] & Disp8) + size = 1; + if (i.types[n] & Disp64) + size = 8; + } + val = offset_in_range (i.op[n].disps->X_add_number, + size); + p = frag_more (size); + md_number_to_chars (p, val, size); + } + else + { + RELOC_ENUM reloc_type; + int size = 4; + int sign = 0; + int pcrel = (i.flags[n] & Operand_PCrel) != 0; + + /* The PC relative address is computed relative + to the instruction boundary, so in case immediate + fields follows, we need to adjust the value. */ + if (pcrel && i.imm_operands) + { + int imm_size = 4; + unsigned int n1; + + for (n1 = 0; n1 < i.operands; n1++) + if (i.types[n1] & Imm) + { + if (i.types[n1] & (Imm8 | Imm8S | Imm16 | Imm64)) + { + imm_size = 2; + if (i.types[n1] & (Imm8 | Imm8S)) + imm_size = 1; + if (i.types[n1] & Imm64) + imm_size = 8; + } + break; + } + /* We should find the immediate. */ + if (n1 == i.operands) + abort (); + i.op[n].disps->X_add_number -= imm_size; + } + + if (i.types[n] & Disp32S) + sign = 1; + + if (i.types[n] & (Disp16 | Disp64)) + { + size = 2; + if (i.types[n] & Disp64) + size = 8; + } + + p = frag_more (size); + reloc_type = reloc (size, pcrel, sign, i.reloc[n]); +#ifdef BFD_ASSEMBLER + if (reloc_type == BFD_RELOC_32 + && GOT_symbol + && GOT_symbol == i.op[n].disps->X_add_symbol + && (i.op[n].disps->X_op == O_symbol + || (i.op[n].disps->X_op == O_add + && ((symbol_get_value_expression + (i.op[n].disps->X_op_symbol)->X_op) + == O_subtract)))) + { + offsetT add; + + if (insn_start_frag == frag_now) + add = (p - frag_now->fr_literal) - insn_start_off; + else + { + fragS *fr; + + add = insn_start_frag->fr_fix - insn_start_off; + for (fr = insn_start_frag->fr_next; + fr && fr != frag_now; fr = fr->fr_next) + add += fr->fr_fix; + add += p - frag_now->fr_literal; + } + + /* We don't support dynamic linking on x86-64 yet. */ + if (flag_code == CODE_64BIT) + abort (); + reloc_type = BFD_RELOC_386_GOTPC; + i.op[n].disps->X_add_number += add; + } +#endif + fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.op[n].disps, pcrel, reloc_type); + } + } + } +} + +static void +output_imm (insn_start_frag, insn_start_off) + fragS *insn_start_frag; + offsetT insn_start_off; +{ + char *p; + unsigned int n; + + for (n = 0; n < i.operands; n++) + { + if (i.types[n] & Imm) + { + if (i.op[n].imms->X_op == O_constant) + { + int size; + offsetT val; + + size = 4; + if (i.types[n] & (Imm8 | Imm8S | Imm16 | Imm64)) + { + size = 2; + if (i.types[n] & (Imm8 | Imm8S)) + size = 1; + else if (i.types[n] & Imm64) + size = 8; + } + val = offset_in_range (i.op[n].imms->X_add_number, + size); + p = frag_more (size); + md_number_to_chars (p, val, size); + } + else + { + /* Not absolute_section. + Need a 32-bit fixup (don't support 8bit + non-absolute imms). Try to support other + sizes ... */ + RELOC_ENUM reloc_type; + int size = 4; + int sign = 0; + + if ((i.types[n] & (Imm32S)) + && i.suffix == QWORD_MNEM_SUFFIX) + sign = 1; + if (i.types[n] & (Imm8 | Imm8S | Imm16 | Imm64)) + { + size = 2; + if (i.types[n] & (Imm8 | Imm8S)) + size = 1; + if (i.types[n] & Imm64) + size = 8; + } + + p = frag_more (size); + reloc_type = reloc (size, 0, sign, i.reloc[n]); +#ifdef BFD_ASSEMBLER + /* This is tough to explain. We end up with this one if we + * have operands that look like + * "_GLOBAL_OFFSET_TABLE_+[.-.L284]". The goal here is to + * obtain the absolute address of the GOT, and it is strongly + * preferable from a performance point of view to avoid using + * a runtime relocation for this. The actual sequence of + * instructions often look something like: + * + * call .L66 + * .L66: + * popl %ebx + * addl $_GLOBAL_OFFSET_TABLE_+[.-.L66],%ebx + * + * The call and pop essentially return the absolute address + * of the label .L66 and store it in %ebx. The linker itself + * will ultimately change the first operand of the addl so + * that %ebx points to the GOT, but to keep things simple, the + * .o file must have this operand set so that it generates not + * the absolute address of .L66, but the absolute address of + * itself. This allows the linker itself simply treat a GOTPC + * relocation as asking for a pcrel offset to the GOT to be + * added in, and the addend of the relocation is stored in the + * operand field for the instruction itself. + * + * Our job here is to fix the operand so that it would add + * the correct offset so that %ebx would point to itself. The + * thing that is tricky is that .-.L66 will point to the + * beginning of the instruction, so we need to further modify + * the operand so that it will point to itself. There are + * other cases where you have something like: + * + * .long $_GLOBAL_OFFSET_TABLE_+[.-.L66] + * + * and here no correction would be required. Internally in + * the assembler we treat operands of this form as not being + * pcrel since the '.' is explicitly mentioned, and I wonder + * whether it would simplify matters to do it this way. Who + * knows. In earlier versions of the PIC patches, the + * pcrel_adjust field was used to store the correction, but + * since the expression is not pcrel, I felt it would be + * confusing to do it this way. */ + + if (reloc_type == BFD_RELOC_32 + && GOT_symbol + && GOT_symbol == i.op[n].imms->X_add_symbol + && (i.op[n].imms->X_op == O_symbol + || (i.op[n].imms->X_op == O_add + && ((symbol_get_value_expression + (i.op[n].imms->X_op_symbol)->X_op) + == O_subtract)))) + { + offsetT add; + + if (insn_start_frag == frag_now) + add = (p - frag_now->fr_literal) - insn_start_off; + else + { + fragS *fr; + + add = insn_start_frag->fr_fix - insn_start_off; + for (fr = insn_start_frag->fr_next; + fr && fr != frag_now; fr = fr->fr_next) + add += fr->fr_fix; + add += p - frag_now->fr_literal; + } + + /* We don't support dynamic linking on x86-64 yet. */ + if (flag_code == CODE_64BIT) + abort (); + reloc_type = BFD_RELOC_386_GOTPC; + i.op[n].imms->X_add_number += add; + } +#endif + fix_new_exp (frag_now, p - frag_now->fr_literal, size, + i.op[n].imms, 0, reloc_type); + } + } + } +} + +#ifndef LEX_AT +static char *lex_got PARAMS ((RELOC_ENUM *, int *)); + +/* Parse operands of the form + @GOTOFF+ + and similar .plt or .got references. + + If we find one, set up the correct relocation in RELOC and copy the + input string, minus the `@GOTOFF' into a malloc'd buffer for + parsing by the calling routine. Return this buffer, and if ADJUST + is non-null set it to the length of the string we removed from the + input line. Otherwise return NULL. */ +static char * +lex_got (reloc, adjust) + RELOC_ENUM *reloc; + int *adjust; +{ + static const char * const mode_name[NUM_FLAG_CODE] = { "32", "16", "64" }; + static const struct { + const char *str; + const RELOC_ENUM rel[NUM_FLAG_CODE]; + } gotrel[] = { + { "PLT", { BFD_RELOC_386_PLT32, 0, BFD_RELOC_X86_64_PLT32 } }, + { "GOTOFF", { BFD_RELOC_386_GOTOFF, 0, 0 } }, + { "GOTPCREL", { 0, 0, BFD_RELOC_X86_64_GOTPCREL } }, + { "TLSGD", { BFD_RELOC_386_TLS_GD, 0, BFD_RELOC_X86_64_TLSGD } }, + { "TLSLDM", { BFD_RELOC_386_TLS_LDM, 0, 0 } }, + { "TLSLD", { 0, 0, BFD_RELOC_X86_64_TLSLD } }, + { "GOTTPOFF", { BFD_RELOC_386_TLS_IE_32, 0, BFD_RELOC_X86_64_GOTTPOFF } }, + { "TPOFF", { BFD_RELOC_386_TLS_LE_32, 0, BFD_RELOC_X86_64_TPOFF32 } }, + { "NTPOFF", { BFD_RELOC_386_TLS_LE, 0, 0 } }, + { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, 0, BFD_RELOC_X86_64_DTPOFF32 } }, + { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, 0, 0 } }, + { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, 0, 0 } }, + { "GOT", { BFD_RELOC_386_GOT32, 0, BFD_RELOC_X86_64_GOT32 } } + }; + char *cp; + unsigned int j; + + for (cp = input_line_pointer; *cp != '@'; cp++) + if (is_end_of_line[(unsigned char) *cp]) + return NULL; + + for (j = 0; j < sizeof (gotrel) / sizeof (gotrel[0]); j++) + { + int len; + + len = strlen (gotrel[j].str); + if (strncasecmp (cp + 1, gotrel[j].str, len) == 0) + { + if (gotrel[j].rel[(unsigned int) flag_code] != 0) + { + int first, second; + char *tmpbuf, *past_reloc; + + *reloc = gotrel[j].rel[(unsigned int) flag_code]; + if (adjust) + *adjust = len; + + if (GOT_symbol == NULL) + GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME); + + /* Replace the relocation token with ' ', so that + errors like foo@GOTOFF1 will be detected. */ + + /* The length of the first part of our input line. */ + first = cp - input_line_pointer; + + /* The second part goes from after the reloc token until + (and including) an end_of_line char. Don't use strlen + here as the end_of_line char may not be a NUL. */ + past_reloc = cp + 1 + len; + for (cp = past_reloc; !is_end_of_line[(unsigned char) *cp++]; ) + ; + second = cp - past_reloc; + + /* Allocate and copy string. The trailing NUL shouldn't + be necessary, but be safe. */ + tmpbuf = xmalloc (first + second + 2); + memcpy (tmpbuf, input_line_pointer, first); + tmpbuf[first] = ' '; + memcpy (tmpbuf + first + 1, past_reloc, second); + tmpbuf[first + second + 1] = '\0'; + return tmpbuf; + } + + as_bad (_("@%s reloc is not supported in %s bit mode"), + gotrel[j].str, mode_name[(unsigned int) flag_code]); + return NULL; + } + } + + /* Might be a symbol version string. Don't as_bad here. */ + return NULL; +} + +/* x86_cons_fix_new is called via the expression parsing code when a + reloc is needed. We use this hook to get the correct .got reloc. */ +static RELOC_ENUM got_reloc = NO_RELOC; + +void +x86_cons_fix_new (frag, off, len, exp) + fragS *frag; + unsigned int off; + unsigned int len; + expressionS *exp; +{ + RELOC_ENUM r = reloc (len, 0, 0, got_reloc); + got_reloc = NO_RELOC; + fix_new_exp (frag, off, len, exp, 0, r); +} + +void +x86_cons (exp, size) + expressionS *exp; + int size; +{ + if (size == 4) + { + /* Handle @GOTOFF and the like in an expression. */ + char *save; + char *gotfree_input_line; + int adjust; + + save = input_line_pointer; + gotfree_input_line = lex_got (&got_reloc, &adjust); + if (gotfree_input_line) + input_line_pointer = gotfree_input_line; + + expression (exp); + + if (gotfree_input_line) + { + /* expression () has merrily parsed up to the end of line, + or a comma - in the wrong buffer. Transfer how far + input_line_pointer has moved to the right buffer. */ + input_line_pointer = (save + + (input_line_pointer - gotfree_input_line) + + adjust); + free (gotfree_input_line); + } + } + else + expression (exp); +} +#endif + +static int i386_immediate PARAMS ((char *)); + +static int +i386_immediate (imm_start) + char *imm_start; +{ + char *save_input_line_pointer; +#ifndef LEX_AT + char *gotfree_input_line; +#endif + segT exp_seg = 0; + expressionS *exp; + + if (i.imm_operands == MAX_IMMEDIATE_OPERANDS) + { + as_bad (_("only 1 or 2 immediate operands are allowed")); + return 0; + } + + exp = &im_expressions[i.imm_operands++]; + i.op[this_operand].imms = exp; + + if (is_space_char (*imm_start)) + ++imm_start; + + save_input_line_pointer = input_line_pointer; + input_line_pointer = imm_start; + +#ifndef LEX_AT + gotfree_input_line = lex_got (&i.reloc[this_operand], NULL); + if (gotfree_input_line) + input_line_pointer = gotfree_input_line; +#endif + + exp_seg = expression (exp); + + SKIP_WHITESPACE (); + if (*input_line_pointer) + as_bad (_("junk `%s' after expression"), input_line_pointer); + + input_line_pointer = save_input_line_pointer; +#ifndef LEX_AT + if (gotfree_input_line) + free (gotfree_input_line); +#endif + + if (exp->X_op == O_absent || exp->X_op == O_big) + { + /* Missing or bad expr becomes absolute 0. */ + as_bad (_("missing or invalid immediate expression `%s' taken as 0"), + imm_start); + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + } + else if (exp->X_op == O_constant) + { + /* Size it properly later. */ + i.types[this_operand] |= Imm64; + /* If BFD64, sign extend val. */ + if (!use_rela_relocations) + if ((exp->X_add_number & ~(((addressT) 2 << 31) - 1)) == 0) + exp->X_add_number = (exp->X_add_number ^ ((addressT) 1 << 31)) - ((addressT) 1 << 31); + } +#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) + else if (1 +#ifdef BFD_ASSEMBLER + && OUTPUT_FLAVOR == bfd_target_aout_flavour +#endif + && exp_seg != absolute_section + && exp_seg != text_section + && exp_seg != data_section + && exp_seg != bss_section + && exp_seg != undefined_section +#ifdef BFD_ASSEMBLER + && !bfd_is_com_section (exp_seg) +#endif + ) + { +#ifdef BFD_ASSEMBLER + as_bad (_("unimplemented segment %s in operand"), exp_seg->name); +#else + as_bad (_("unimplemented segment type %d in operand"), exp_seg); +#endif + return 0; + } +#endif + else + { + /* This is an address. The size of the address will be + determined later, depending on destination register, + suffix, or the default for the section. */ + i.types[this_operand] |= Imm8 | Imm16 | Imm32 | Imm32S | Imm64; + } + + return 1; +} + +static char *i386_scale PARAMS ((char *)); + +static char * +i386_scale (scale) + char *scale; +{ + offsetT val; + char *save = input_line_pointer; + + input_line_pointer = scale; + val = get_absolute_expression (); + + switch (val) + { + case 0: + case 1: + i.log2_scale_factor = 0; + break; + case 2: + i.log2_scale_factor = 1; + break; + case 4: + i.log2_scale_factor = 2; + break; + case 8: + i.log2_scale_factor = 3; + break; + default: + as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), + scale); + input_line_pointer = save; + return NULL; + } + if (i.log2_scale_factor != 0 && i.index_reg == 0) + { + as_warn (_("scale factor of %d without an index register"), + 1 << i.log2_scale_factor); +#if SCALE1_WHEN_NO_INDEX + i.log2_scale_factor = 0; +#endif + } + scale = input_line_pointer; + input_line_pointer = save; + return scale; +} + +static int i386_displacement PARAMS ((char *, char *)); + +static int +i386_displacement (disp_start, disp_end) + char *disp_start; + char *disp_end; +{ + expressionS *exp; + segT exp_seg = 0; + char *save_input_line_pointer; +#ifndef LEX_AT + char *gotfree_input_line; +#endif + int bigdisp = Disp32; + + if (flag_code == CODE_64BIT) + { + if (i.prefix[ADDR_PREFIX] == 0) + bigdisp = Disp64; + } + else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)) + bigdisp = Disp16; + i.types[this_operand] |= bigdisp; + + exp = &disp_expressions[i.disp_operands]; + i.op[this_operand].disps = exp; + i.disp_operands++; + save_input_line_pointer = input_line_pointer; + input_line_pointer = disp_start; + END_STRING_AND_SAVE (disp_end); + +#ifndef GCC_ASM_O_HACK +#define GCC_ASM_O_HACK 0 +#endif +#if GCC_ASM_O_HACK + END_STRING_AND_SAVE (disp_end + 1); + if ((i.types[this_operand] & BaseIndex) != 0 + && displacement_string_end[-1] == '+') + { + /* This hack is to avoid a warning when using the "o" + constraint within gcc asm statements. + For instance: + + #define _set_tssldt_desc(n,addr,limit,type) \ + __asm__ __volatile__ ( \ + "movw %w2,%0\n\t" \ + "movw %w1,2+%0\n\t" \ + "rorl $16,%1\n\t" \ + "movb %b1,4+%0\n\t" \ + "movb %4,5+%0\n\t" \ + "movb $0,6+%0\n\t" \ + "movb %h1,7+%0\n\t" \ + "rorl $16,%1" \ + : "=o"(*(n)) : "q" (addr), "ri"(limit), "i"(type)) + + This works great except that the output assembler ends + up looking a bit weird if it turns out that there is + no offset. You end up producing code that looks like: + + #APP + movw $235,(%eax) + movw %dx,2+(%eax) + rorl $16,%edx + movb %dl,4+(%eax) + movb $137,5+(%eax) + movb $0,6+(%eax) + movb %dh,7+(%eax) + rorl $16,%edx + #NO_APP + + So here we provide the missing zero. */ + + *displacement_string_end = '0'; + } +#endif +#ifndef LEX_AT + gotfree_input_line = lex_got (&i.reloc[this_operand], NULL); + if (gotfree_input_line) + input_line_pointer = gotfree_input_line; +#endif + + exp_seg = expression (exp); + + SKIP_WHITESPACE (); + if (*input_line_pointer) + as_bad (_("junk `%s' after expression"), input_line_pointer); +#if GCC_ASM_O_HACK + RESTORE_END_STRING (disp_end + 1); +#endif + RESTORE_END_STRING (disp_end); + input_line_pointer = save_input_line_pointer; +#ifndef LEX_AT + if (gotfree_input_line) + free (gotfree_input_line); +#endif + +#ifdef BFD_ASSEMBLER + /* We do this to make sure that the section symbol is in + the symbol table. We will ultimately change the relocation + to be relative to the beginning of the section. */ + if (i.reloc[this_operand] == BFD_RELOC_386_GOTOFF + || i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL) + { + if (exp->X_op != O_symbol) + { + as_bad (_("bad expression used with @%s"), + (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL + ? "GOTPCREL" + : "GOTOFF")); + return 0; + } + + if (S_IS_LOCAL (exp->X_add_symbol) + && S_GET_SEGMENT (exp->X_add_symbol) != undefined_section) + section_symbol (S_GET_SEGMENT (exp->X_add_symbol)); + exp->X_op = O_subtract; + exp->X_op_symbol = GOT_symbol; + if (i.reloc[this_operand] == BFD_RELOC_X86_64_GOTPCREL) + i.reloc[this_operand] = BFD_RELOC_32_PCREL; + else + i.reloc[this_operand] = BFD_RELOC_32; + } +#endif + + if (exp->X_op == O_absent || exp->X_op == O_big) + { + /* Missing or bad expr becomes absolute 0. */ + as_bad (_("missing or invalid displacement expression `%s' taken as 0"), + disp_start); + exp->X_op = O_constant; + exp->X_add_number = 0; + exp->X_add_symbol = (symbolS *) 0; + exp->X_op_symbol = (symbolS *) 0; + } + +#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) + if (exp->X_op != O_constant +#ifdef BFD_ASSEMBLER + && OUTPUT_FLAVOR == bfd_target_aout_flavour +#endif + && exp_seg != absolute_section + && exp_seg != text_section + && exp_seg != data_section + && exp_seg != bss_section + && exp_seg != undefined_section +#ifdef BFD_ASSEMBLER + && !bfd_is_com_section (exp_seg) +#endif + ) + { +#ifdef BFD_ASSEMBLER + as_bad (_("unimplemented segment %s in operand"), exp_seg->name); +#else + as_bad (_("unimplemented segment type %d in operand"), exp_seg); +#endif + return 0; + } +#endif + else if (flag_code == CODE_64BIT) + i.types[this_operand] |= Disp32S | Disp32; + return 1; +} + +static int i386_index_check PARAMS ((const char *)); + +/* Make sure the memory operand we've been dealt is valid. + Return 1 on success, 0 on a failure. */ + +static int +i386_index_check (operand_string) + const char *operand_string; +{ + int ok; +#if INFER_ADDR_PREFIX + int fudged = 0; + + tryprefix: +#endif + ok = 1; + if (flag_code == CODE_64BIT) + { + if (i.prefix[ADDR_PREFIX] == 0) + { + /* 64bit checks. */ + if ((i.base_reg + && ((i.base_reg->reg_type & Reg64) == 0) + && (i.base_reg->reg_type != BaseIndex + || i.index_reg)) + || (i.index_reg + && ((i.index_reg->reg_type & (Reg64 | BaseIndex)) + != (Reg64 | BaseIndex)))) + ok = 0; + } + else + { + /* 32bit checks. */ + if ((i.base_reg + && (i.base_reg->reg_type & (Reg32 | RegRex)) != Reg32) + || (i.index_reg + && ((i.index_reg->reg_type & (Reg32 | BaseIndex | RegRex)) + != (Reg32 | BaseIndex)))) + ok = 0; + } + } + else + { + if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)) + { + /* 16bit checks. */ + if ((i.base_reg + && ((i.base_reg->reg_type & (Reg16 | BaseIndex | RegRex)) + != (Reg16 | BaseIndex))) + || (i.index_reg + && (((i.index_reg->reg_type & (Reg16 | BaseIndex)) + != (Reg16 | BaseIndex)) + || !(i.base_reg + && i.base_reg->reg_num < 6 + && i.index_reg->reg_num >= 6 + && i.log2_scale_factor == 0)))) + ok = 0; + } + else + { + /* 32bit checks. */ + if ((i.base_reg + && (i.base_reg->reg_type & (Reg32 | RegRex)) != Reg32) + || (i.index_reg + && ((i.index_reg->reg_type & (Reg32 | BaseIndex | RegRex)) + != (Reg32 | BaseIndex)))) + ok = 0; + } + } + if (!ok) + { +#if INFER_ADDR_PREFIX + if (flag_code != CODE_64BIT + && i.prefix[ADDR_PREFIX] == 0 && stackop_size != '\0') + { + i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE; + i.prefixes += 1; + /* Change the size of any displacement too. At most one of + Disp16 or Disp32 is set. + FIXME. There doesn't seem to be any real need for separate + Disp16 and Disp32 flags. The same goes for Imm16 and Imm32. + Removing them would probably clean up the code quite a lot. */ + if (i.types[this_operand] & (Disp16 | Disp32)) + i.types[this_operand] ^= (Disp16 | Disp32); + fudged = 1; + goto tryprefix; + } + if (fudged) + as_bad (_("`%s' is not a valid base/index expression"), + operand_string); + else +#endif + as_bad (_("`%s' is not a valid %s bit base/index expression"), + operand_string, + flag_code_names[flag_code]); + return 0; + } + return 1; +} + +/* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero + on error. */ + +static int +i386_operand (operand_string) + char *operand_string; +{ + const reg_entry *r; + char *end_op; + char *op_string = operand_string; + + if (is_space_char (*op_string)) + ++op_string; + + /* We check for an absolute prefix (differentiating, + for example, 'jmp pc_relative_label' from 'jmp *absolute_label'. */ + if (*op_string == ABSOLUTE_PREFIX) + { + ++op_string; + if (is_space_char (*op_string)) + ++op_string; + i.types[this_operand] |= JumpAbsolute; + } + + /* Check if operand is a register. */ + if ((*op_string == REGISTER_PREFIX || allow_naked_reg) + && (r = parse_register (op_string, &end_op)) != NULL) + { + /* Check for a segment override by searching for ':' after a + segment register. */ + op_string = end_op; + if (is_space_char (*op_string)) + ++op_string; + if (*op_string == ':' && (r->reg_type & (SReg2 | SReg3))) + { + switch (r->reg_num) + { + case 0: + i.seg[i.mem_operands] = &es; + break; + case 1: + i.seg[i.mem_operands] = &cs; + break; + case 2: + i.seg[i.mem_operands] = &ss; + break; + case 3: + i.seg[i.mem_operands] = &ds; + break; + case 4: + i.seg[i.mem_operands] = &fs; + break; + case 5: + i.seg[i.mem_operands] = &gs; + break; + } + + /* Skip the ':' and whitespace. */ + ++op_string; + if (is_space_char (*op_string)) + ++op_string; + + if (!is_digit_char (*op_string) + && !is_identifier_char (*op_string) + && *op_string != '(' + && *op_string != ABSOLUTE_PREFIX) + { + as_bad (_("bad memory operand `%s'"), op_string); + return 0; + } + /* Handle case of %es:*foo. */ + if (*op_string == ABSOLUTE_PREFIX) + { + ++op_string; + if (is_space_char (*op_string)) + ++op_string; + i.types[this_operand] |= JumpAbsolute; + } + goto do_memory_reference; + } + if (*op_string) + { + as_bad (_("junk `%s' after register"), op_string); + return 0; + } + i.types[this_operand] |= r->reg_type & ~BaseIndex; + i.op[this_operand].regs = r; + i.reg_operands++; + } + else if (*op_string == REGISTER_PREFIX) + { + as_bad (_("bad register name `%s'"), op_string); + return 0; + } + else if (*op_string == IMMEDIATE_PREFIX) + { + ++op_string; + if (i.types[this_operand] & JumpAbsolute) + { + as_bad (_("immediate operand illegal with absolute jump")); + return 0; + } + if (!i386_immediate (op_string)) + return 0; + } + else if (is_digit_char (*op_string) + || is_identifier_char (*op_string) + || *op_string == '(') + { + /* This is a memory reference of some sort. */ + char *base_string; + + /* Start and end of displacement string expression (if found). */ + char *displacement_string_start; + char *displacement_string_end; + + do_memory_reference: + if ((i.mem_operands == 1 + && (current_templates->start->opcode_modifier & IsString) == 0) + || i.mem_operands == 2) + { + as_bad (_("too many memory references for `%s'"), + current_templates->start->name); + return 0; + } + + /* Check for base index form. We detect the base index form by + looking for an ')' at the end of the operand, searching + for the '(' matching it, and finding a REGISTER_PREFIX or ',' + after the '('. */ + base_string = op_string + strlen (op_string); + + --base_string; + if (is_space_char (*base_string)) + --base_string; + + /* If we only have a displacement, set-up for it to be parsed later. */ + displacement_string_start = op_string; + displacement_string_end = base_string + 1; + + if (*base_string == ')') + { + char *temp_string; + unsigned int parens_balanced = 1; + /* We've already checked that the number of left & right ()'s are + equal, so this loop will not be infinite. */ + do + { + base_string--; + if (*base_string == ')') + parens_balanced++; + if (*base_string == '(') + parens_balanced--; + } + while (parens_balanced); + + temp_string = base_string; + + /* Skip past '(' and whitespace. */ + ++base_string; + if (is_space_char (*base_string)) + ++base_string; + + if (*base_string == ',' + || ((*base_string == REGISTER_PREFIX || allow_naked_reg) + && (i.base_reg = parse_register (base_string, &end_op)) != NULL)) + { + displacement_string_end = temp_string; + + i.types[this_operand] |= BaseIndex; + + if (i.base_reg) + { + base_string = end_op; + if (is_space_char (*base_string)) + ++base_string; + } + + /* There may be an index reg or scale factor here. */ + if (*base_string == ',') + { + ++base_string; + if (is_space_char (*base_string)) + ++base_string; + + if ((*base_string == REGISTER_PREFIX || allow_naked_reg) + && (i.index_reg = parse_register (base_string, &end_op)) != NULL) + { + base_string = end_op; + if (is_space_char (*base_string)) + ++base_string; + if (*base_string == ',') + { + ++base_string; + if (is_space_char (*base_string)) + ++base_string; + } + else if (*base_string != ')') + { + as_bad (_("expecting `,' or `)' after index register in `%s'"), + operand_string); + return 0; + } + } + else if (*base_string == REGISTER_PREFIX) + { + as_bad (_("bad register name `%s'"), base_string); + return 0; + } + + /* Check for scale factor. */ + if (*base_string != ')') + { + char *end_scale = i386_scale (base_string); + + if (!end_scale) + return 0; + + base_string = end_scale; + if (is_space_char (*base_string)) + ++base_string; + if (*base_string != ')') + { + as_bad (_("expecting `)' after scale factor in `%s'"), + operand_string); + return 0; + } + } + else if (!i.index_reg) + { + as_bad (_("expecting index register or scale factor after `,'; got '%c'"), + *base_string); + return 0; + } + } + else if (*base_string != ')') + { + as_bad (_("expecting `,' or `)' after base register in `%s'"), + operand_string); + return 0; + } + } + else if (*base_string == REGISTER_PREFIX) + { + as_bad (_("bad register name `%s'"), base_string); + return 0; + } + } + + /* If there's an expression beginning the operand, parse it, + assuming displacement_string_start and + displacement_string_end are meaningful. */ + if (displacement_string_start != displacement_string_end) + { + if (!i386_displacement (displacement_string_start, + displacement_string_end)) + return 0; + } + + /* Special case for (%dx) while doing input/output op. */ + if (i.base_reg + && i.base_reg->reg_type == (Reg16 | InOutPortReg) + && i.index_reg == 0 + && i.log2_scale_factor == 0 + && i.seg[i.mem_operands] == 0 + && (i.types[this_operand] & Disp) == 0) + { + i.types[this_operand] = InOutPortReg; + return 1; + } + + if (i386_index_check (operand_string) == 0) + return 0; + i.mem_operands++; + } + else + { + /* It's not a memory operand; argh! */ + as_bad (_("invalid char %s beginning operand %d `%s'"), + output_invalid (*op_string), + this_operand + 1, + op_string); + return 0; + } + return 1; /* Normal return. */ +} + +/* md_estimate_size_before_relax() + + Called just before relax() for rs_machine_dependent frags. The x86 + assembler uses these frags to handle variable size jump + instructions. + + Any symbol that is now undefined will not become defined. + Return the correct fr_subtype in the frag. + Return the initial "guess for variable size of frag" to caller. + The guess is actually the growth beyond the fixed part. Whatever + we do to grow the fixed or variable part contributes to our + returned value. */ + +int +md_estimate_size_before_relax (fragP, segment) + fragS *fragP; + segT segment; +{ + /* We've already got fragP->fr_subtype right; all we have to do is + check for un-relaxable symbols. On an ELF system, we can't relax + an externally visible symbol, because it may be overridden by a + shared library. */ + if (S_GET_SEGMENT (fragP->fr_symbol) != segment +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + || (OUTPUT_FLAVOR == bfd_target_elf_flavour + && (S_IS_EXTERNAL (fragP->fr_symbol) + || S_IS_WEAK (fragP->fr_symbol))) +#endif + ) + { + /* Symbol is undefined in this segment, or we need to keep a + reloc so that weak symbols can be overridden. */ + int size = (fragP->fr_subtype & CODE16) ? 2 : 4; + RELOC_ENUM reloc_type; + unsigned char *opcode; + int old_fr_fix; + + if (fragP->fr_var != NO_RELOC) + reloc_type = fragP->fr_var; + else if (size == 2) + reloc_type = BFD_RELOC_16_PCREL; + else + reloc_type = BFD_RELOC_32_PCREL; + + old_fr_fix = fragP->fr_fix; + opcode = (unsigned char *) fragP->fr_opcode; + + switch (TYPE_FROM_RELAX_STATE (fragP->fr_subtype)) + { + case UNCOND_JUMP: + /* Make jmp (0xeb) a (d)word displacement jump. */ + opcode[0] = 0xe9; + fragP->fr_fix += size; + fix_new (fragP, old_fr_fix, size, + fragP->fr_symbol, + fragP->fr_offset, 1, + reloc_type); + break; + + case COND_JUMP86: + if (size == 2 + && (!no_cond_jump_promotion || fragP->fr_var != NO_RELOC)) + { + /* Negate the condition, and branch past an + unconditional jump. */ + opcode[0] ^= 1; + opcode[1] = 3; + /* Insert an unconditional jump. */ + opcode[2] = 0xe9; + /* We added two extra opcode bytes, and have a two byte + offset. */ + fragP->fr_fix += 2 + 2; + fix_new (fragP, old_fr_fix + 2, 2, + fragP->fr_symbol, + fragP->fr_offset, 1, + reloc_type); + break; + } + /* Fall through. */ + + case COND_JUMP: + if (no_cond_jump_promotion && fragP->fr_var == NO_RELOC) + { + fixS *fixP; + + fragP->fr_fix += 1; + fixP = fix_new (fragP, old_fr_fix, 1, + fragP->fr_symbol, + fragP->fr_offset, 1, + BFD_RELOC_8_PCREL); + fixP->fx_signed = 1; + break; + } + + /* This changes the byte-displacement jump 0x7N + to the (d)word-displacement jump 0x0f,0x8N. */ + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + /* We've added an opcode byte. */ + fragP->fr_fix += 1 + size; + fix_new (fragP, old_fr_fix + 1, size, + fragP->fr_symbol, + fragP->fr_offset, 1, + reloc_type); + break; + + default: + BAD_CASE (fragP->fr_subtype); + break; + } + frag_wane (fragP); + return fragP->fr_fix - old_fr_fix; + } + + /* Guess size depending on current relax state. Initially the relax + state will correspond to a short jump and we return 1, because + the variable part of the frag (the branch offset) is one byte + long. However, we can relax a section more than once and in that + case we must either set fr_subtype back to the unrelaxed state, + or return the value for the appropriate branch. */ + return md_relax_table[fragP->fr_subtype].rlx_length; +} + +/* Called after relax() is finished. + + In: Address of frag. + fr_type == rs_machine_dependent. + fr_subtype is what the address relaxed to. + + Out: Any fixSs and constants are set up. + Caller will turn frag into a ".space 0". */ + +#ifndef BFD_ASSEMBLER +void +md_convert_frag (headers, sec, fragP) + object_headers *headers ATTRIBUTE_UNUSED; + segT sec ATTRIBUTE_UNUSED; + fragS *fragP; +#else +void +md_convert_frag (abfd, sec, fragP) + bfd *abfd ATTRIBUTE_UNUSED; + segT sec ATTRIBUTE_UNUSED; + fragS *fragP; +#endif +{ + unsigned char *opcode; + unsigned char *where_to_put_displacement = NULL; + offsetT target_address; + offsetT opcode_address; + unsigned int extension = 0; + offsetT displacement_from_opcode_start; + + opcode = (unsigned char *) fragP->fr_opcode; + + /* Address we want to reach in file space. */ + target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset; + + /* Address opcode resides at in file space. */ + opcode_address = fragP->fr_address + fragP->fr_fix; + + /* Displacement from opcode start to fill into instruction. */ + displacement_from_opcode_start = target_address - opcode_address; + + if ((fragP->fr_subtype & BIG) == 0) + { + /* Don't have to change opcode. */ + extension = 1; /* 1 opcode + 1 displacement */ + where_to_put_displacement = &opcode[1]; + } + else + { + if (no_cond_jump_promotion + && TYPE_FROM_RELAX_STATE (fragP->fr_subtype) != UNCOND_JUMP) + as_warn_where (fragP->fr_file, fragP->fr_line, _("long jump required")); + + switch (fragP->fr_subtype) + { + case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG): + extension = 4; /* 1 opcode + 4 displacement */ + opcode[0] = 0xe9; + where_to_put_displacement = &opcode[1]; + break; + + case ENCODE_RELAX_STATE (UNCOND_JUMP, BIG16): + extension = 2; /* 1 opcode + 2 displacement */ + opcode[0] = 0xe9; + where_to_put_displacement = &opcode[1]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, BIG): + case ENCODE_RELAX_STATE (COND_JUMP86, BIG): + extension = 5; /* 2 opcode + 4 displacement */ + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP, BIG16): + extension = 3; /* 2 opcode + 2 displacement */ + opcode[1] = opcode[0] + 0x10; + opcode[0] = TWO_BYTE_OPCODE_ESCAPE; + where_to_put_displacement = &opcode[2]; + break; + + case ENCODE_RELAX_STATE (COND_JUMP86, BIG16): + extension = 4; + opcode[0] ^= 1; + opcode[1] = 3; + opcode[2] = 0xe9; + where_to_put_displacement = &opcode[3]; + break; + + default: + BAD_CASE (fragP->fr_subtype); + break; + } + } + + /* Now put displacement after opcode. */ + md_number_to_chars ((char *) where_to_put_displacement, + (valueT) (displacement_from_opcode_start - extension), + DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype)); + fragP->fr_fix += extension; +} + +/* Size of byte displacement jmp. */ +int md_short_jump_size = 2; + +/* Size of dword displacement jmp. */ +int md_long_jump_size = 5; + +/* Size of relocation record. */ +const int md_reloc_size = 8; + +void +md_create_short_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag ATTRIBUTE_UNUSED; + symbolS *to_symbol ATTRIBUTE_UNUSED; +{ + offsetT offset; + + offset = to_addr - (from_addr + 2); + /* Opcode for byte-disp jump. */ + md_number_to_chars (ptr, (valueT) 0xeb, 1); + md_number_to_chars (ptr + 1, (valueT) offset, 1); +} + +void +md_create_long_jump (ptr, from_addr, to_addr, frag, to_symbol) + char *ptr; + addressT from_addr, to_addr; + fragS *frag ATTRIBUTE_UNUSED; + symbolS *to_symbol ATTRIBUTE_UNUSED; +{ + offsetT offset; + + offset = to_addr - (from_addr + 5); + md_number_to_chars (ptr, (valueT) 0xe9, 1); + md_number_to_chars (ptr + 1, (valueT) offset, 4); +} + +/* Apply a fixup (fixS) to segment data, once it has been determined + by our caller that we have all the info we need to fix it up. + + On the 386, immediates, displacements, and data pointers are all in + the same (little-endian) format, so we don't need to care about which + we are handling. */ + +void +md_apply_fix3 (fixP, valP, seg) + /* The fix we're to put in. */ + fixS *fixP; + /* Pointer to the value of the bits. */ + valueT *valP; + /* Segment fix is from. */ + segT seg ATTRIBUTE_UNUSED; +{ + char *p = fixP->fx_where + fixP->fx_frag->fr_literal; + valueT value = *valP; + +#if defined (BFD_ASSEMBLER) && !defined (TE_Mach) + if (fixP->fx_pcrel) + { + switch (fixP->fx_r_type) + { + default: + break; + + case BFD_RELOC_32: + fixP->fx_r_type = BFD_RELOC_32_PCREL; + break; + case BFD_RELOC_16: + fixP->fx_r_type = BFD_RELOC_16_PCREL; + break; + case BFD_RELOC_8: + fixP->fx_r_type = BFD_RELOC_8_PCREL; + break; + } + } + + if (fixP->fx_addsy != NULL + && (fixP->fx_r_type == BFD_RELOC_32_PCREL + || fixP->fx_r_type == BFD_RELOC_16_PCREL + || fixP->fx_r_type == BFD_RELOC_8_PCREL) + && !use_rela_relocations) + { + /* This is a hack. There should be a better way to handle this. + This covers for the fact that bfd_install_relocation will + subtract the current location (for partial_inplace, PC relative + relocations); see more below. */ +#ifndef OBJ_AOUT + if (OUTPUT_FLAVOR == bfd_target_elf_flavour +#ifdef TE_PE + || OUTPUT_FLAVOR == bfd_target_coff_flavour +#endif + ) + value += fixP->fx_where + fixP->fx_frag->fr_address; +#endif +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (OUTPUT_FLAVOR == bfd_target_elf_flavour) + { + segT sym_seg = S_GET_SEGMENT (fixP->fx_addsy); + + if ((sym_seg == seg + || (symbol_section_p (fixP->fx_addsy) + && sym_seg != absolute_section)) + && !generic_force_reloc (fixP)) + { + /* Yes, we add the values in twice. This is because + bfd_install_relocation subtracts them out again. I think + bfd_install_relocation is broken, but I don't dare change + it. FIXME. */ + value += fixP->fx_where + fixP->fx_frag->fr_address; + } + } +#endif +#if defined (OBJ_COFF) && defined (TE_PE) + /* For some reason, the PE format does not store a section + address offset for a PC relative symbol. */ + if (S_GET_SEGMENT (fixP->fx_addsy) != seg) + value += md_pcrel_from (fixP); +#endif + } + + /* Fix a few things - the dynamic linker expects certain values here, + and we must not dissappoint it. */ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (OUTPUT_FLAVOR == bfd_target_elf_flavour + && fixP->fx_addsy) + switch (fixP->fx_r_type) + { + case BFD_RELOC_386_PLT32: + case BFD_RELOC_X86_64_PLT32: + /* Make the jump instruction point to the address of the operand. At + runtime we merely add the offset to the actual PLT entry. */ + value = -4; + break; + + case BFD_RELOC_386_TLS_GD: + case BFD_RELOC_386_TLS_LDM: + case BFD_RELOC_386_TLS_IE_32: + case BFD_RELOC_386_TLS_IE: + case BFD_RELOC_386_TLS_GOTIE: + case BFD_RELOC_X86_64_TLSGD: + case BFD_RELOC_X86_64_TLSLD: + case BFD_RELOC_X86_64_GOTTPOFF: + value = 0; /* Fully resolved at runtime. No addend. */ + /* Fallthrough */ + case BFD_RELOC_386_TLS_LE: + case BFD_RELOC_386_TLS_LDO_32: + case BFD_RELOC_386_TLS_LE_32: + case BFD_RELOC_X86_64_DTPOFF32: + case BFD_RELOC_X86_64_TPOFF32: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + break; + + case BFD_RELOC_386_GOT32: + case BFD_RELOC_X86_64_GOT32: + value = 0; /* Fully resolved at runtime. No addend. */ + break; + + case BFD_RELOC_VTABLE_INHERIT: + case BFD_RELOC_VTABLE_ENTRY: + fixP->fx_done = 0; + return; + + default: + break; + } +#endif /* defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) */ + *valP = value; +#endif /* defined (BFD_ASSEMBLER) && !defined (TE_Mach) */ + + /* Are we finished with this relocation now? */ + if (fixP->fx_addsy == NULL) + fixP->fx_done = 1; +#ifdef BFD_ASSEMBLER + else if (use_rela_relocations) + { + fixP->fx_no_overflow = 1; + /* Remember value for tc_gen_reloc. */ + fixP->fx_addnumber = value; + value = 0; + } +#endif + md_number_to_chars (p, value, fixP->fx_size); +} + +#define MAX_LITTLENUMS 6 + +/* Turn the string pointed to by litP into a floating point constant + of type TYPE, and emit the appropriate bytes. The number of + LITTLENUMS emitted is stored in *SIZEP. An error message is + returned, or NULL on OK. */ + +char * +md_atof (type, litP, sizeP) + int type; + char *litP; + int *sizeP; +{ + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + LITTLENUM_TYPE *wordP; + char *t; + + switch (type) + { + case 'f': + case 'F': + prec = 2; + break; + + case 'd': + case 'D': + prec = 4; + break; + + case 'x': + case 'X': + prec = 5; + break; + + default: + *sizeP = 0; + return _("Bad call to md_atof ()"); + } + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + + *sizeP = prec * sizeof (LITTLENUM_TYPE); + /* This loops outputs the LITTLENUMs in REVERSE order; in accord with + the bigendian 386. */ + for (wordP = words + prec - 1; prec--;) + { + md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + return 0; +} + +char output_invalid_buf[8]; + +static char * +output_invalid (c) + int c; +{ + if (ISPRINT (c)) + sprintf (output_invalid_buf, "'%c'", c); + else + sprintf (output_invalid_buf, "(0x%x)", (unsigned) c); + return output_invalid_buf; +} + +/* REG_STRING starts *before* REGISTER_PREFIX. */ + +static const reg_entry * +parse_register (reg_string, end_op) + char *reg_string; + char **end_op; +{ + char *s = reg_string; + char *p; + char reg_name_given[MAX_REG_NAME_SIZE + 1]; + const reg_entry *r; + + /* Skip possible REGISTER_PREFIX and possible whitespace. */ + if (*s == REGISTER_PREFIX) + ++s; + + if (is_space_char (*s)) + ++s; + + p = reg_name_given; + while ((*p++ = register_chars[(unsigned char) *s]) != '\0') + { + if (p >= reg_name_given + MAX_REG_NAME_SIZE) + return (const reg_entry *) NULL; + s++; + } + + /* For naked regs, make sure that we are not dealing with an identifier. + This prevents confusing an identifier like `eax_var' with register + `eax'. */ + if (allow_naked_reg && identifier_chars[(unsigned char) *s]) + return (const reg_entry *) NULL; + + *end_op = s; + + r = (const reg_entry *) hash_find (reg_hash, reg_name_given); + + /* Handle floating point regs, allowing spaces in the (i) part. */ + if (r == i386_regtab /* %st is first entry of table */) + { + if (is_space_char (*s)) + ++s; + if (*s == '(') + { + ++s; + if (is_space_char (*s)) + ++s; + if (*s >= '0' && *s <= '7') + { + r = &i386_float_regtab[*s - '0']; + ++s; + if (is_space_char (*s)) + ++s; + if (*s == ')') + { + *end_op = s + 1; + return r; + } + } + /* We have "%st(" then garbage. */ + return (const reg_entry *) NULL; + } + } + + if (r != NULL + && (r->reg_flags & (RegRex64 | RegRex)) != 0 + && flag_code != CODE_64BIT) + { + return (const reg_entry *) NULL; + } + + return r; +} + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +const char *md_shortopts = "kVQ:sq"; +#else +const char *md_shortopts = "q"; +#endif + +struct option md_longopts[] = { +#define OPTION_32 (OPTION_MD_BASE + 0) + {"32", no_argument, NULL, OPTION_32}, +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) +#define OPTION_64 (OPTION_MD_BASE + 1) + {"64", no_argument, NULL, OPTION_64}, +#endif + {NULL, no_argument, NULL, 0} +}; +size_t md_longopts_size = sizeof (md_longopts); + +int +md_parse_option (c, arg) + int c; + char *arg ATTRIBUTE_UNUSED; +{ + switch (c) + { + case 'q': + quiet_warnings = 1; + break; + +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + /* -Qy, -Qn: SVR4 arguments controlling whether a .comment section + should be emitted or not. FIXME: Not implemented. */ + case 'Q': + break; + + /* -V: SVR4 argument to print version ID. */ + case 'V': + print_version_id (); + break; + + /* -k: Ignore for FreeBSD compatibility. */ + case 'k': + break; + + case 's': + /* -s: On i386 Solaris, this tells the native assembler to use + .stab instead of .stab.excl. We always use .stab anyhow. */ + break; + + case OPTION_64: + { + const char **list, **l; + + list = bfd_target_list (); + for (l = list; *l != NULL; l++) + if (strcmp (*l, "elf64-x86-64") == 0) + { + default_arch = "x86_64"; + break; + } + if (*l == NULL) + as_fatal (_("No compiled in support for x86_64")); + free (list); + } + break; +#endif + + case OPTION_32: + default_arch = "i386"; + break; + + default: + return 0; + } + return 1; +} + +void +md_show_usage (stream) + FILE *stream; +{ +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + fprintf (stream, _("\ + -Q ignored\n\ + -V print assembler version number\n\ + -k ignored\n\ + -q quieten some warnings\n\ + -s ignored\n")); +#else + fprintf (stream, _("\ + -q quieten some warnings\n")); +#endif +} + +#ifdef BFD_ASSEMBLER +#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \ + || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) + +/* Pick the target format to use. */ + +const char * +i386_target_format () +{ + if (!strcmp (default_arch, "x86_64")) + set_code_flag (CODE_64BIT); + else if (!strcmp (default_arch, "i386")) + set_code_flag (CODE_32BIT); + else + as_fatal (_("Unknown architecture")); + switch (OUTPUT_FLAVOR) + { +#ifdef OBJ_MAYBE_AOUT + case bfd_target_aout_flavour: + return AOUT_TARGET_FORMAT; +#endif +#ifdef OBJ_MAYBE_COFF + case bfd_target_coff_flavour: + return "coff-i386"; +#endif +#if defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF) + case bfd_target_elf_flavour: + { + if (flag_code == CODE_64BIT) + use_rela_relocations = 1; + return flag_code == CODE_64BIT ? "elf64-x86-64" : ELF_TARGET_FORMAT; + } +#endif + default: + abort (); + return NULL; + } +} + +#endif /* OBJ_MAYBE_ more than one */ + +#if (defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) +void i386_elf_emit_arch_note () +{ + if (OUTPUT_FLAVOR == bfd_target_elf_flavour + && cpu_arch_name != NULL) + { + char *p; + asection *seg = now_seg; + subsegT subseg = now_subseg; + Elf_Internal_Note i_note; + Elf_External_Note e_note; + asection *note_secp; + int len; + + /* Create the .note section. */ + note_secp = subseg_new (".note", 0); + bfd_set_section_flags (stdoutput, + note_secp, + SEC_HAS_CONTENTS | SEC_READONLY); + + /* Process the arch string. */ + len = strlen (cpu_arch_name); + + i_note.namesz = len + 1; + i_note.descsz = 0; + i_note.type = NT_ARCH; + p = frag_more (sizeof (e_note.namesz)); + md_number_to_chars (p, (valueT) i_note.namesz, sizeof (e_note.namesz)); + p = frag_more (sizeof (e_note.descsz)); + md_number_to_chars (p, (valueT) i_note.descsz, sizeof (e_note.descsz)); + p = frag_more (sizeof (e_note.type)); + md_number_to_chars (p, (valueT) i_note.type, sizeof (e_note.type)); + p = frag_more (len + 1); + strcpy (p, cpu_arch_name); + + frag_align (2, 0, 0); + + subseg_set (seg, subseg); + } +} +#endif +#endif /* BFD_ASSEMBLER */ + +symbolS * +md_undefined_symbol (name) + char *name; +{ + if (name[0] == GLOBAL_OFFSET_TABLE_NAME[0] + && name[1] == GLOBAL_OFFSET_TABLE_NAME[1] + && name[2] == GLOBAL_OFFSET_TABLE_NAME[2] + && strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0) + { + if (!GOT_symbol) + { + if (symbol_find (name)) + as_bad (_("GOT already in symbol table")); + GOT_symbol = symbol_new (name, undefined_section, + (valueT) 0, &zero_address_frag); + }; + return GOT_symbol; + } + return 0; +} + +/* Round up a section size to the appropriate boundary. */ + +valueT +md_section_align (segment, size) + segT segment ATTRIBUTE_UNUSED; + valueT size; +{ +#ifdef BFD_ASSEMBLER +#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT)) + if (OUTPUT_FLAVOR == bfd_target_aout_flavour) + { + /* For a.out, force the section size to be aligned. If we don't do + this, BFD will align it for us, but it will not write out the + final bytes of the section. This may be a bug in BFD, but it is + easier to fix it here since that is how the other a.out targets + work. */ + int align; + + align = bfd_get_section_alignment (stdoutput, segment); + size = ((size + (1 << align) - 1) & ((valueT) -1 << align)); + } +#endif +#endif + + return size; +} + +/* On the i386, PC-relative offsets are relative to the start of the + next instruction. That is, the address of the offset, plus its + size, since the offset is always the last part of the insn. */ + +long +md_pcrel_from (fixP) + fixS *fixP; +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address; +} + +#ifndef I386COFF + +static void +s_bss (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + int temp; + + temp = get_absolute_expression (); + subseg_set (bss_section, (subsegT) temp); + demand_empty_rest_of_line (); +} + +#endif + +#ifdef BFD_ASSEMBLER + +void +i386_validate_fix (fixp) + fixS *fixp; +{ + if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) + { + /* GOTOFF relocation are nonsense in 64bit mode. */ + if (fixp->fx_r_type == BFD_RELOC_32_PCREL) + { + if (flag_code != CODE_64BIT) + abort (); + fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; + } + else + { + if (flag_code == CODE_64BIT) + abort (); + fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + } + fixp->fx_subsy = 0; + } +} + +arelent * +tc_gen_reloc (section, fixp) + asection *section ATTRIBUTE_UNUSED; + fixS *fixp; +{ + arelent *rel; + bfd_reloc_code_real_type code; + + switch (fixp->fx_r_type) + { + case BFD_RELOC_X86_64_PLT32: + case BFD_RELOC_X86_64_GOT32: + case BFD_RELOC_X86_64_GOTPCREL: + case BFD_RELOC_386_PLT32: + case BFD_RELOC_386_GOT32: + case BFD_RELOC_386_GOTOFF: + case BFD_RELOC_386_GOTPC: + case BFD_RELOC_386_TLS_GD: + case BFD_RELOC_386_TLS_LDM: + case BFD_RELOC_386_TLS_LDO_32: + case BFD_RELOC_386_TLS_IE_32: + case BFD_RELOC_386_TLS_IE: + case BFD_RELOC_386_TLS_GOTIE: + case BFD_RELOC_386_TLS_LE_32: + case BFD_RELOC_386_TLS_LE: + case BFD_RELOC_X86_64_32S: + case BFD_RELOC_X86_64_TLSGD: + case BFD_RELOC_X86_64_TLSLD: + case BFD_RELOC_X86_64_DTPOFF32: + case BFD_RELOC_X86_64_GOTTPOFF: + case BFD_RELOC_X86_64_TPOFF32: + case BFD_RELOC_RVA: + case BFD_RELOC_VTABLE_ENTRY: + case BFD_RELOC_VTABLE_INHERIT: + code = fixp->fx_r_type; + break; + default: + if (fixp->fx_pcrel) + { + switch (fixp->fx_size) + { + default: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("can not do %d byte pc-relative relocation"), + fixp->fx_size); + code = BFD_RELOC_32_PCREL; + break; + case 1: code = BFD_RELOC_8_PCREL; break; + case 2: code = BFD_RELOC_16_PCREL; break; + case 4: code = BFD_RELOC_32_PCREL; break; + } + } + else + { + switch (fixp->fx_size) + { + default: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("can not do %d byte relocation"), + fixp->fx_size); + code = BFD_RELOC_32; + break; + case 1: code = BFD_RELOC_8; break; + case 2: code = BFD_RELOC_16; break; + case 4: code = BFD_RELOC_32; break; +#ifdef BFD64 + case 8: code = BFD_RELOC_64; break; +#endif + } + } + break; + } + + if (code == BFD_RELOC_32 + && GOT_symbol + && fixp->fx_addsy == GOT_symbol) + { + /* We don't support GOTPC on 64bit targets. */ + if (flag_code == CODE_64BIT) + abort (); + code = BFD_RELOC_386_GOTPC; + } + + rel = (arelent *) xmalloc (sizeof (arelent)); + rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); + + rel->address = fixp->fx_frag->fr_address + fixp->fx_where; + if (!use_rela_relocations) + { + /* HACK: Since i386 ELF uses Rel instead of Rela, encode the + vtable entry to be used in the relocation's section offset. */ + if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + rel->address = fixp->fx_offset; + + rel->addend = 0; + } + /* Use the rela in 64bit mode. */ + else + { + if (!fixp->fx_pcrel) + rel->addend = fixp->fx_offset; + else + switch (code) + { + case BFD_RELOC_X86_64_PLT32: + case BFD_RELOC_X86_64_GOT32: + case BFD_RELOC_X86_64_GOTPCREL: + case BFD_RELOC_X86_64_TLSGD: + case BFD_RELOC_X86_64_TLSLD: + case BFD_RELOC_X86_64_GOTTPOFF: + rel->addend = fixp->fx_offset - fixp->fx_size; + break; + default: + rel->addend = (section->vma + - fixp->fx_size + + fixp->fx_addnumber + + md_pcrel_from (fixp)); + break; + } + } + + rel->howto = bfd_reloc_type_lookup (stdoutput, code); + if (rel->howto == NULL) + { + as_bad_where (fixp->fx_file, fixp->fx_line, + _("cannot represent relocation type %s"), + bfd_get_reloc_code_name (code)); + /* Set howto to a garbage value so that we can keep going. */ + rel->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); + assert (rel->howto != NULL); + } + + return rel; +} + +#else /* !BFD_ASSEMBLER */ + +#if (defined(OBJ_AOUT) | defined(OBJ_BOUT)) +void +tc_aout_fix_to_chars (where, fixP, segment_address_in_file) + char *where; + fixS *fixP; + relax_addressT segment_address_in_file; +{ + /* In: length of relocation (or of address) in chars: 1, 2 or 4. + Out: GNU LD relocation length code: 0, 1, or 2. */ + + static const unsigned char nbytes_r_length[] = { 42, 0, 1, 42, 2 }; + long r_symbolnum; + + know (fixP->fx_addsy != NULL); + + md_number_to_chars (where, + (valueT) (fixP->fx_frag->fr_address + + fixP->fx_where - segment_address_in_file), + 4); + + r_symbolnum = (S_IS_DEFINED (fixP->fx_addsy) + ? S_GET_TYPE (fixP->fx_addsy) + : fixP->fx_addsy->sy_number); + + where[6] = (r_symbolnum >> 16) & 0x0ff; + where[5] = (r_symbolnum >> 8) & 0x0ff; + where[4] = r_symbolnum & 0x0ff; + where[7] = ((((!S_IS_DEFINED (fixP->fx_addsy)) << 3) & 0x08) + | ((nbytes_r_length[fixP->fx_size] << 1) & 0x06) + | (((fixP->fx_pcrel << 0) & 0x01) & 0x0f)); +} + +#endif /* OBJ_AOUT or OBJ_BOUT. */ + +#if defined (I386COFF) + +short +tc_coff_fix2rtype (fixP) + fixS *fixP; +{ + if (fixP->fx_r_type == R_IMAGEBASE) + return R_IMAGEBASE; + + return (fixP->fx_pcrel ? + (fixP->fx_size == 1 ? R_PCRBYTE : + fixP->fx_size == 2 ? R_PCRWORD : + R_PCRLONG) : + (fixP->fx_size == 1 ? R_RELBYTE : + fixP->fx_size == 2 ? R_RELWORD : + R_DIR32)); +} + +int +tc_coff_sizemachdep (frag) + fragS *frag; +{ + if (frag->fr_next) + return (frag->fr_next->fr_address - frag->fr_address); + else + return 0; +} + +#endif /* I386COFF */ + +#endif /* !BFD_ASSEMBLER */ + +/* Parse operands using Intel syntax. This implements a recursive descent + parser based on the BNF grammar published in Appendix B of the MASM 6.1 + Programmer's Guide. + + FIXME: We do not recognize the full operand grammar defined in the MASM + documentation. In particular, all the structure/union and + high-level macro operands are missing. + + Uppercase words are terminals, lower case words are non-terminals. + Objects surrounded by double brackets '[[' ']]' are optional. Vertical + bars '|' denote choices. Most grammar productions are implemented in + functions called 'intel_'. + + Initial production is 'expr'. + + addOp + | - + + alpha [a-zA-Z] + + byteRegister AL | AH | BL | BH | CL | CH | DL | DH + + constant digits [[ radixOverride ]] + + dataType BYTE | WORD | DWORD | QWORD | XWORD + + digits decdigit + | digits decdigit + | digits hexdigit + + decdigit [0-9] + + e05 e05 addOp e06 + | e06 + + e06 e06 mulOp e09 + | e09 + + e09 OFFSET e10 + | e09 PTR e10 + | e09 : e10 + | e10 + + e10 e10 [ expr ] + | e11 + + e11 ( expr ) + | [ expr ] + | constant + | dataType + | id + | $ + | register + + => expr SHORT e05 + | e05 + + gpRegister AX | EAX | BX | EBX | CX | ECX | DX | EDX + | BP | EBP | SP | ESP | DI | EDI | SI | ESI + + hexdigit a | b | c | d | e | f + | A | B | C | D | E | F + + id alpha + | id alpha + | id decdigit + + mulOp * | / | MOD + + quote " | ' + + register specialRegister + | gpRegister + | byteRegister + + segmentRegister CS | DS | ES | FS | GS | SS + + specialRegister CR0 | CR2 | CR3 + | DR0 | DR1 | DR2 | DR3 | DR6 | DR7 + | TR3 | TR4 | TR5 | TR6 | TR7 + + We simplify the grammar in obvious places (e.g., register parsing is + done by calling parse_register) and eliminate immediate left recursion + to implement a recursive-descent parser. + + expr SHORT e05 + | e05 + + e05 e06 e05' + + e05' addOp e06 e05' + | Empty + + e06 e09 e06' + + e06' mulOp e09 e06' + | Empty + + e09 OFFSET e10 e09' + | e10 e09' + + e09' PTR e10 e09' + | : e10 e09' + | Empty + + e10 e11 e10' + + e10' [ expr ] e10' + | Empty + + e11 ( expr ) + | [ expr ] + | BYTE + | WORD + | DWORD + | QWORD + | XWORD + | . + | $ + | register + | id + | constant */ + +/* Parsing structure for the intel syntax parser. Used to implement the + semantic actions for the operand grammar. */ +struct intel_parser_s + { + char *op_string; /* The string being parsed. */ + int got_a_float; /* Whether the operand is a float. */ + int op_modifier; /* Operand modifier. */ + int is_mem; /* 1 if operand is memory reference. */ + const reg_entry *reg; /* Last register reference found. */ + char *disp; /* Displacement string being built. */ + }; + +static struct intel_parser_s intel_parser; + +/* Token structure for parsing intel syntax. */ +struct intel_token + { + int code; /* Token code. */ + const reg_entry *reg; /* Register entry for register tokens. */ + char *str; /* String representation. */ + }; + +static struct intel_token cur_token, prev_token; + +/* Token codes for the intel parser. Since T_SHORT is already used + by COFF, undefine it first to prevent a warning. */ +#define T_NIL -1 +#define T_CONST 1 +#define T_REG 2 +#define T_BYTE 3 +#define T_WORD 4 +#define T_DWORD 5 +#define T_QWORD 6 +#define T_XWORD 7 +#undef T_SHORT +#define T_SHORT 8 +#define T_OFFSET 9 +#define T_PTR 10 +#define T_ID 11 + +/* Prototypes for intel parser functions. */ +static int intel_match_token PARAMS ((int code)); +static void intel_get_token PARAMS ((void)); +static void intel_putback_token PARAMS ((void)); +static int intel_expr PARAMS ((void)); +static int intel_e05 PARAMS ((void)); +static int intel_e05_1 PARAMS ((void)); +static int intel_e06 PARAMS ((void)); +static int intel_e06_1 PARAMS ((void)); +static int intel_e09 PARAMS ((void)); +static int intel_e09_1 PARAMS ((void)); +static int intel_e10 PARAMS ((void)); +static int intel_e10_1 PARAMS ((void)); +static int intel_e11 PARAMS ((void)); + +static int +i386_intel_operand (operand_string, got_a_float) + char *operand_string; + int got_a_float; +{ + int ret; + char *p; + + /* Initialize token holders. */ + cur_token.code = prev_token.code = T_NIL; + cur_token.reg = prev_token.reg = NULL; + cur_token.str = prev_token.str = NULL; + + /* Initialize parser structure. */ + p = intel_parser.op_string = (char *) malloc (strlen (operand_string) + 1); + if (p == NULL) + abort (); + strcpy (intel_parser.op_string, operand_string); + intel_parser.got_a_float = got_a_float; + intel_parser.op_modifier = -1; + intel_parser.is_mem = 0; + intel_parser.reg = NULL; + intel_parser.disp = (char *) malloc (strlen (operand_string) + 1); + if (intel_parser.disp == NULL) + abort (); + intel_parser.disp[0] = '\0'; + + /* Read the first token and start the parser. */ + intel_get_token (); + ret = intel_expr (); + + if (ret) + { + /* If we found a memory reference, hand it over to i386_displacement + to fill in the rest of the operand fields. */ + if (intel_parser.is_mem) + { + if ((i.mem_operands == 1 + && (current_templates->start->opcode_modifier & IsString) == 0) + || i.mem_operands == 2) + { + as_bad (_("too many memory references for '%s'"), + current_templates->start->name); + ret = 0; + } + else + { + char *s = intel_parser.disp; + i.mem_operands++; + + /* Add the displacement expression. */ + if (*s != '\0') + ret = i386_displacement (s, s + strlen (s)) + && i386_index_check (s); + } + } + + /* Constant and OFFSET expressions are handled by i386_immediate. */ + else if (intel_parser.op_modifier == OFFSET_FLAT + || intel_parser.reg == NULL) + ret = i386_immediate (intel_parser.disp); + } + + free (p); + free (intel_parser.disp); + + return ret; +} + +/* expr SHORT e05 + | e05 */ +static int +intel_expr () +{ + /* expr SHORT e05 */ + if (cur_token.code == T_SHORT) + { + intel_parser.op_modifier = SHORT; + intel_match_token (T_SHORT); + + return (intel_e05 ()); + } + + /* expr e05 */ + else + return intel_e05 (); +} + +/* e05 e06 e05' + + e05' addOp e06 e05' + | Empty */ +static int +intel_e05 () +{ + return (intel_e06 () && intel_e05_1 ()); +} + +static int +intel_e05_1 () +{ + /* e05' addOp e06 e05' */ + if (cur_token.code == '+' || cur_token.code == '-') + { + strcat (intel_parser.disp, cur_token.str); + intel_match_token (cur_token.code); + + return (intel_e06 () && intel_e05_1 ()); + } + + /* e05' Empty */ + else + return 1; +} + +/* e06 e09 e06' + + e06' mulOp e09 e06' + | Empty */ +static int +intel_e06 () +{ + return (intel_e09 () && intel_e06_1 ()); +} + +static int +intel_e06_1 () +{ + /* e06' mulOp e09 e06' */ + if (cur_token.code == '*' || cur_token.code == '/') + { + strcat (intel_parser.disp, cur_token.str); + intel_match_token (cur_token.code); + + return (intel_e09 () && intel_e06_1 ()); + } + + /* e06' Empty */ + else + return 1; +} + +/* e09 OFFSET e10 e09' + | e10 e09' + + e09' PTR e10 e09' + | : e10 e09' + | Empty */ +static int +intel_e09 () +{ + /* e09 OFFSET e10 e09' */ + if (cur_token.code == T_OFFSET) + { + intel_parser.is_mem = 0; + intel_parser.op_modifier = OFFSET_FLAT; + intel_match_token (T_OFFSET); + + return (intel_e10 () && intel_e09_1 ()); + } + + /* e09 e10 e09' */ + else + return (intel_e10 () && intel_e09_1 ()); +} + +static int +intel_e09_1 () +{ + /* e09' PTR e10 e09' */ + if (cur_token.code == T_PTR) + { + if (prev_token.code == T_BYTE) + i.suffix = BYTE_MNEM_SUFFIX; + + else if (prev_token.code == T_WORD) + { + if (intel_parser.got_a_float == 2) /* "fi..." */ + i.suffix = SHORT_MNEM_SUFFIX; + else + i.suffix = WORD_MNEM_SUFFIX; + } + + else if (prev_token.code == T_DWORD) + { + if (intel_parser.got_a_float == 1) /* "f..." */ + i.suffix = SHORT_MNEM_SUFFIX; + else + i.suffix = LONG_MNEM_SUFFIX; + } + + else if (prev_token.code == T_QWORD) + { + if (intel_parser.got_a_float == 1) /* "f..." */ + i.suffix = LONG_MNEM_SUFFIX; + else + i.suffix = QWORD_MNEM_SUFFIX; + } + + else if (prev_token.code == T_XWORD) + i.suffix = LONG_DOUBLE_MNEM_SUFFIX; + + else + { + as_bad (_("Unknown operand modifier `%s'\n"), prev_token.str); + return 0; + } + + intel_match_token (T_PTR); + + return (intel_e10 () && intel_e09_1 ()); + } + + /* e09 : e10 e09' */ + else if (cur_token.code == ':') + { + /* Mark as a memory operand only if it's not already known to be an + offset expression. */ + if (intel_parser.op_modifier != OFFSET_FLAT) + intel_parser.is_mem = 1; + + return (intel_match_token (':') && intel_e10 () && intel_e09_1 ()); + } + + /* e09' Empty */ + else + return 1; +} + +/* e10 e11 e10' + + e10' [ expr ] e10' + | Empty */ +static int +intel_e10 () +{ + return (intel_e11 () && intel_e10_1 ()); +} + +static int +intel_e10_1 () +{ + /* e10' [ expr ] e10' */ + if (cur_token.code == '[') + { + intel_match_token ('['); + + /* Mark as a memory operand only if it's not already known to be an + offset expression. If it's an offset expression, we need to keep + the brace in. */ + if (intel_parser.op_modifier != OFFSET_FLAT) + intel_parser.is_mem = 1; + else + strcat (intel_parser.disp, "["); + + /* Add a '+' to the displacement string if necessary. */ + if (*intel_parser.disp != '\0' + && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+') + strcat (intel_parser.disp, "+"); + + if (intel_expr () && intel_match_token (']')) + { + /* Preserve brackets when the operand is an offset expression. */ + if (intel_parser.op_modifier == OFFSET_FLAT) + strcat (intel_parser.disp, "]"); + + return intel_e10_1 (); + } + else + return 0; + } + + /* e10' Empty */ + else + return 1; +} + +/* e11 ( expr ) + | [ expr ] + | BYTE + | WORD + | DWORD + | QWORD + | XWORD + | $ + | . + | register + | id + | constant */ +static int +intel_e11 () +{ + /* e11 ( expr ) */ + if (cur_token.code == '(') + { + intel_match_token ('('); + strcat (intel_parser.disp, "("); + + if (intel_expr () && intel_match_token (')')) + { + strcat (intel_parser.disp, ")"); + return 1; + } + else + return 0; + } + + /* e11 [ expr ] */ + else if (cur_token.code == '[') + { + intel_match_token ('['); + + /* Mark as a memory operand only if it's not already known to be an + offset expression. If it's an offset expression, we need to keep + the brace in. */ + if (intel_parser.op_modifier != OFFSET_FLAT) + intel_parser.is_mem = 1; + else + strcat (intel_parser.disp, "["); + + /* Operands for jump/call inside brackets denote absolute addresses. */ + if (current_templates->start->opcode_modifier & Jump + || current_templates->start->opcode_modifier & JumpDword + || current_templates->start->opcode_modifier & JumpByte + || current_templates->start->opcode_modifier & JumpInterSegment) + i.types[this_operand] |= JumpAbsolute; + + /* Add a '+' to the displacement string if necessary. */ + if (*intel_parser.disp != '\0' + && *(intel_parser.disp + strlen (intel_parser.disp) - 1) != '+') + strcat (intel_parser.disp, "+"); + + if (intel_expr () && intel_match_token (']')) + { + /* Preserve brackets when the operand is an offset expression. */ + if (intel_parser.op_modifier == OFFSET_FLAT) + strcat (intel_parser.disp, "]"); + + return 1; + } + else + return 0; + } + + /* e11 BYTE + | WORD + | DWORD + | QWORD + | XWORD */ + else if (cur_token.code == T_BYTE + || cur_token.code == T_WORD + || cur_token.code == T_DWORD + || cur_token.code == T_QWORD + || cur_token.code == T_XWORD) + { + intel_match_token (cur_token.code); + + return 1; + } + + /* e11 $ + | . */ + else if (cur_token.code == '$' || cur_token.code == '.') + { + strcat (intel_parser.disp, cur_token.str); + intel_match_token (cur_token.code); + + /* Mark as a memory operand only if it's not already known to be an + offset expression. */ + if (intel_parser.op_modifier != OFFSET_FLAT) + intel_parser.is_mem = 1; + + return 1; + } + + /* e11 register */ + else if (cur_token.code == T_REG) + { + const reg_entry *reg = intel_parser.reg = cur_token.reg; + + intel_match_token (T_REG); + + /* Check for segment change. */ + if (cur_token.code == ':') + { + if (reg->reg_type & (SReg2 | SReg3)) + { + switch (reg->reg_num) + { + case 0: + i.seg[i.mem_operands] = &es; + break; + case 1: + i.seg[i.mem_operands] = &cs; + break; + case 2: + i.seg[i.mem_operands] = &ss; + break; + case 3: + i.seg[i.mem_operands] = &ds; + break; + case 4: + i.seg[i.mem_operands] = &fs; + break; + case 5: + i.seg[i.mem_operands] = &gs; + break; + } + } + else + { + as_bad (_("`%s' is not a valid segment register"), reg->reg_name); + return 0; + } + } + + /* Not a segment register. Check for register scaling. */ + else if (cur_token.code == '*') + { + if (!intel_parser.is_mem) + { + as_bad (_("Register scaling only allowed in memory operands.")); + return 0; + } + + /* What follows must be a valid scale. */ + if (intel_match_token ('*') + && strchr ("01248", *cur_token.str)) + { + i.index_reg = reg; + i.types[this_operand] |= BaseIndex; + + /* Set the scale after setting the register (otherwise, + i386_scale will complain) */ + i386_scale (cur_token.str); + intel_match_token (T_CONST); + } + else + { + as_bad (_("expecting scale factor of 1, 2, 4, or 8: got `%s'"), + cur_token.str); + return 0; + } + } + + /* No scaling. If this is a memory operand, the register is either a + base register (first occurrence) or an index register (second + occurrence). */ + else if (intel_parser.is_mem && !(reg->reg_type & (SReg2 | SReg3))) + { + if (i.base_reg && i.index_reg) + { + as_bad (_("Too many register references in memory operand.\n")); + return 0; + } + + if (i.base_reg == NULL) + i.base_reg = reg; + else + i.index_reg = reg; + + i.types[this_operand] |= BaseIndex; + } + + /* Offset modifier. Add the register to the displacement string to be + parsed as an immediate expression after we're done. */ + else if (intel_parser.op_modifier == OFFSET_FLAT) + strcat (intel_parser.disp, reg->reg_name); + + /* It's neither base nor index nor offset. */ + else + { + i.types[this_operand] |= reg->reg_type & ~BaseIndex; + i.op[this_operand].regs = reg; + i.reg_operands++; + } + + /* Since registers are not part of the displacement string (except + when we're parsing offset operands), we may need to remove any + preceding '+' from the displacement string. */ + if (*intel_parser.disp != '\0' + && intel_parser.op_modifier != OFFSET_FLAT) + { + char *s = intel_parser.disp; + s += strlen (s) - 1; + if (*s == '+') + *s = '\0'; + } + + return 1; + } + + /* e11 id */ + else if (cur_token.code == T_ID) + { + /* Add the identifier to the displacement string. */ + strcat (intel_parser.disp, cur_token.str); + intel_match_token (T_ID); + + /* The identifier represents a memory reference only if it's not + preceded by an offset modifier. */ + if (intel_parser.op_modifier != OFFSET_FLAT) + intel_parser.is_mem = 1; + + return 1; + } + + /* e11 constant */ + else if (cur_token.code == T_CONST + || cur_token.code == '-' + || cur_token.code == '+') + { + char *save_str; + + /* Allow constants that start with `+' or `-'. */ + if (cur_token.code == '-' || cur_token.code == '+') + { + strcat (intel_parser.disp, cur_token.str); + intel_match_token (cur_token.code); + if (cur_token.code != T_CONST) + { + as_bad (_("Syntax error. Expecting a constant. Got `%s'.\n"), + cur_token.str); + return 0; + } + } + + save_str = (char *) malloc (strlen (cur_token.str) + 1); + if (save_str == NULL) + abort (); + strcpy (save_str, cur_token.str); + + /* Get the next token to check for register scaling. */ + intel_match_token (cur_token.code); + + /* Check if this constant is a scaling factor for an index register. */ + if (cur_token.code == '*') + { + if (intel_match_token ('*') && cur_token.code == T_REG) + { + if (!intel_parser.is_mem) + { + as_bad (_("Register scaling only allowed in memory operands.")); + return 0; + } + + /* The constant is followed by `* reg', so it must be + a valid scale. */ + if (strchr ("01248", *save_str)) + { + i.index_reg = cur_token.reg; + i.types[this_operand] |= BaseIndex; + + /* Set the scale after setting the register (otherwise, + i386_scale will complain) */ + i386_scale (save_str); + intel_match_token (T_REG); + + /* Since registers are not part of the displacement + string, we may need to remove any preceding '+' from + the displacement string. */ + if (*intel_parser.disp != '\0') + { + char *s = intel_parser.disp; + s += strlen (s) - 1; + if (*s == '+') + *s = '\0'; + } + + free (save_str); + + return 1; + } + else + return 0; + } + + /* The constant was not used for register scaling. Since we have + already consumed the token following `*' we now need to put it + back in the stream. */ + else + intel_putback_token (); + } + + /* Add the constant to the displacement string. */ + strcat (intel_parser.disp, save_str); + free (save_str); + + return 1; + } + + as_bad (_("Unrecognized token '%s'"), cur_token.str); + return 0; +} + +/* Match the given token against cur_token. If they match, read the next + token from the operand string. */ +static int +intel_match_token (code) + int code; +{ + if (cur_token.code == code) + { + intel_get_token (); + return 1; + } + else + { + as_bad (_("Unexpected token `%s'\n"), cur_token.str); + return 0; + } +} + +/* Read a new token from intel_parser.op_string and store it in cur_token. */ +static void +intel_get_token () +{ + char *end_op; + const reg_entry *reg; + struct intel_token new_token; + + new_token.code = T_NIL; + new_token.reg = NULL; + new_token.str = NULL; + + /* Free the memory allocated to the previous token and move + cur_token to prev_token. */ + if (prev_token.str) + free (prev_token.str); + + prev_token = cur_token; + + /* Skip whitespace. */ + while (is_space_char (*intel_parser.op_string)) + intel_parser.op_string++; + + /* Return an empty token if we find nothing else on the line. */ + if (*intel_parser.op_string == '\0') + { + cur_token = new_token; + return; + } + + /* The new token cannot be larger than the remainder of the operand + string. */ + new_token.str = (char *) malloc (strlen (intel_parser.op_string) + 1); + if (new_token.str == NULL) + abort (); + new_token.str[0] = '\0'; + + if (strchr ("0123456789", *intel_parser.op_string)) + { + char *p = new_token.str; + char *q = intel_parser.op_string; + new_token.code = T_CONST; + + /* Allow any kind of identifier char to encompass floating point and + hexadecimal numbers. */ + while (is_identifier_char (*q)) + *p++ = *q++; + *p = '\0'; + + /* Recognize special symbol names [0-9][bf]. */ + if (strlen (intel_parser.op_string) == 2 + && (intel_parser.op_string[1] == 'b' + || intel_parser.op_string[1] == 'f')) + new_token.code = T_ID; + } + + else if (strchr ("+-/*:[]()", *intel_parser.op_string)) + { + new_token.code = *intel_parser.op_string; + new_token.str[0] = *intel_parser.op_string; + new_token.str[1] = '\0'; + } + + else if ((*intel_parser.op_string == REGISTER_PREFIX || allow_naked_reg) + && ((reg = parse_register (intel_parser.op_string, &end_op)) != NULL)) + { + new_token.code = T_REG; + new_token.reg = reg; + + if (*intel_parser.op_string == REGISTER_PREFIX) + { + new_token.str[0] = REGISTER_PREFIX; + new_token.str[1] = '\0'; + } + + strcat (new_token.str, reg->reg_name); + } + + else if (is_identifier_char (*intel_parser.op_string)) + { + char *p = new_token.str; + char *q = intel_parser.op_string; + + /* A '.' or '$' followed by an identifier char is an identifier. + Otherwise, it's operator '.' followed by an expression. */ + if ((*q == '.' || *q == '$') && !is_identifier_char (*(q + 1))) + { + new_token.code = *q; + new_token.str[0] = *q; + new_token.str[1] = '\0'; + } + else + { + while (is_identifier_char (*q) || *q == '@') + *p++ = *q++; + *p = '\0'; + + if (strcasecmp (new_token.str, "BYTE") == 0) + new_token.code = T_BYTE; + + else if (strcasecmp (new_token.str, "WORD") == 0) + new_token.code = T_WORD; + + else if (strcasecmp (new_token.str, "DWORD") == 0) + new_token.code = T_DWORD; + + else if (strcasecmp (new_token.str, "QWORD") == 0) + new_token.code = T_QWORD; + + else if (strcasecmp (new_token.str, "XWORD") == 0) + new_token.code = T_XWORD; + + else if (strcasecmp (new_token.str, "PTR") == 0) + new_token.code = T_PTR; + + else if (strcasecmp (new_token.str, "SHORT") == 0) + new_token.code = T_SHORT; + + else if (strcasecmp (new_token.str, "OFFSET") == 0) + { + new_token.code = T_OFFSET; + + /* ??? This is not mentioned in the MASM grammar but gcc + makes use of it with -mintel-syntax. OFFSET may be + followed by FLAT: */ + if (strncasecmp (q, " FLAT:", 6) == 0) + strcat (new_token.str, " FLAT:"); + } + + /* ??? This is not mentioned in the MASM grammar. */ + else if (strcasecmp (new_token.str, "FLAT") == 0) + new_token.code = T_OFFSET; + + else + new_token.code = T_ID; + } + } + + else + as_bad (_("Unrecognized token `%s'\n"), intel_parser.op_string); + + intel_parser.op_string += strlen (new_token.str); + cur_token = new_token; +} + +/* Put cur_token back into the token stream and make cur_token point to + prev_token. */ +static void +intel_putback_token () +{ + intel_parser.op_string -= strlen (cur_token.str); + free (cur_token.str); + cur_token = prev_token; + + /* Forget prev_token. */ + prev_token.code = T_NIL; + prev_token.reg = NULL; + prev_token.str = NULL; +} diff --git a/contrib/binutils-2.14/gas/config/tc-i386.h b/contrib/binutils-2.14/gas/config/tc-i386.h new file mode 100644 index 0000000000..45c3acf626 --- /dev/null +++ b/contrib/binutils-2.14/gas/config/tc-i386.h @@ -0,0 +1,548 @@ +/* tc-i386.h -- Header file for tc-i386.c + Copyright 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef TC_I386 +#define TC_I386 1 + +#ifdef ANSI_PROTOTYPES +struct fix; +#endif + +#define TARGET_BYTES_BIG_ENDIAN 0 + +#ifdef TE_LYNX +#define TARGET_FORMAT "coff-i386-lynx" +#endif + +#ifdef BFD_ASSEMBLER +#define TARGET_ARCH bfd_arch_i386 +#define TARGET_MACH (i386_mach ()) +extern unsigned long i386_mach PARAMS ((void)); + +#ifdef TE_FreeBSD +#define AOUT_TARGET_FORMAT "a.out-i386-freebsd" +#endif +#ifdef TE_NetBSD +#define AOUT_TARGET_FORMAT "a.out-i386-netbsd" +#endif +#ifdef TE_386BSD +#define AOUT_TARGET_FORMAT "a.out-i386-bsd" +#endif +#ifdef TE_LINUX +#define AOUT_TARGET_FORMAT "a.out-i386-linux" +#endif +#ifdef TE_Mach +#define AOUT_TARGET_FORMAT "a.out-mach3" +#endif +#ifdef TE_DYNIX +#define AOUT_TARGET_FORMAT "a.out-i386-dynix" +#endif +#ifndef AOUT_TARGET_FORMAT +#define AOUT_TARGET_FORMAT "a.out-i386" +#endif + +#ifdef TE_FreeBSD +#define ELF_TARGET_FORMAT "elf32-i386-freebsd" +#endif +#ifndef ELF_TARGET_FORMAT +#define ELF_TARGET_FORMAT "elf32-i386" +#endif + +#if ((defined (OBJ_MAYBE_COFF) && defined (OBJ_MAYBE_AOUT)) \ + || defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)) +extern const char *i386_target_format PARAMS ((void)); +#define TARGET_FORMAT i386_target_format () +#else +#ifdef OBJ_ELF +#define TARGET_FORMAT ELF_TARGET_FORMAT +#endif +#ifdef OBJ_AOUT +#define TARGET_FORMAT AOUT_TARGET_FORMAT +#endif +#endif + +#if (defined (OBJ_MAYBE_ELF) || defined (OBJ_ELF)) +#define md_end i386_elf_emit_arch_note +extern void i386_elf_emit_arch_note PARAMS ((void)); +#endif + +#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0 + +#else /* ! BFD_ASSEMBLER */ + +/* COFF STUFF */ + +#define COFF_MAGIC I386MAGIC +#define BFD_ARCH bfd_arch_i386 +#define COFF_FLAGS F_AR32WR +#define TC_COUNT_RELOC(x) ((x)->fx_addsy || (x)->fx_r_type==7) +#define TC_COFF_FIX2RTYPE(FIX) tc_coff_fix2rtype(FIX) +extern short tc_coff_fix2rtype PARAMS ((struct fix *)); +#define TC_COFF_SIZEMACHDEP(frag) tc_coff_sizemachdep (frag) +extern int tc_coff_sizemachdep PARAMS ((fragS *frag)); + +#ifdef TE_GO32 +/* DJGPP now expects some sections to be 2**4 aligned. */ +#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) \ + ((strcmp (obj_segment_name (SEG), ".text") == 0 \ + || strcmp (obj_segment_name (SEG), ".data") == 0 \ + || strcmp (obj_segment_name (SEG), ".bss") == 0 \ + || strncmp (obj_segment_name (SEG), ".gnu.linkonce.t", 15) == 0 \ + || strncmp (obj_segment_name (SEG), ".gnu.linkonce.d", 15) == 0 \ + || strncmp (obj_segment_name (SEG), ".gnu.linkonce.r", 15) == 0) \ + ? 4 \ + : 2) +#else +#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 2 +#endif + +#ifdef TE_386BSD +/* The BSDI linker apparently rejects objects with a machine type of + M_386 (100). */ +#define AOUT_MACHTYPE 0 +#else +#define AOUT_MACHTYPE 100 +#endif + +#ifndef OBJ_AOUT +#ifndef TE_PE +#ifndef TE_GO32 +/* Local labels starts with .L */ +#define LOCAL_LABEL(name) (name[0] == '.' \ + && (name[1] == 'L' || name[1] == 'X' || name[1] == '.')) +#endif +#endif +#endif + +#define tc_aout_pre_write_hook(x) {;} /* not used */ +#define tc_crawl_symbol_chain(a) {;} /* not used */ +#define tc_headers_hook(a) {;} /* not used */ +#define tc_coff_symbol_emit_hook(a) {;} /* not used */ + +#endif /* ! BFD_ASSEMBLER */ + +#define LOCAL_LABELS_FB 1 + +extern const char extra_symbol_chars[]; +#define tc_symbol_chars extra_symbol_chars + +#define MAX_OPERANDS 3 /* max operands per insn */ +#define MAX_IMMEDIATE_OPERANDS 2/* max immediates per insn (lcall, ljmp) */ +#define MAX_MEMORY_OPERANDS 2 /* max memory refs per insn (string ops) */ + +/* Prefixes will be emitted in the order defined below. + WAIT_PREFIX must be the first prefix since FWAIT is really is an + instruction, and so must come before any prefixes. */ +#define WAIT_PREFIX 0 +#define LOCKREP_PREFIX 1 +#define ADDR_PREFIX 2 +#define DATA_PREFIX 3 +#define SEG_PREFIX 4 +#define REX_PREFIX 5 /* must come last. */ +#define MAX_PREFIXES 6 /* max prefixes per opcode */ + +/* we define the syntax here (modulo base,index,scale syntax) */ +#define REGISTER_PREFIX '%' +#define IMMEDIATE_PREFIX '$' +#define ABSOLUTE_PREFIX '*' + +#define TWO_BYTE_OPCODE_ESCAPE 0x0f +#define NOP_OPCODE (char) 0x90 + +/* register numbers */ +#define EBP_REG_NUM 5 +#define ESP_REG_NUM 4 + +/* modrm_byte.regmem for twobyte escape */ +#define ESCAPE_TO_TWO_BYTE_ADDRESSING ESP_REG_NUM +/* index_base_byte.index for no index register addressing */ +#define NO_INDEX_REGISTER ESP_REG_NUM +/* index_base_byte.base for no base register addressing */ +#define NO_BASE_REGISTER EBP_REG_NUM +#define NO_BASE_REGISTER_16 6 + +/* these are the instruction mnemonic suffixes. */ +#define WORD_MNEM_SUFFIX 'w' +#define BYTE_MNEM_SUFFIX 'b' +#define SHORT_MNEM_SUFFIX 's' +#define LONG_MNEM_SUFFIX 'l' +#define QWORD_MNEM_SUFFIX 'q' +/* Intel Syntax */ +#define LONG_DOUBLE_MNEM_SUFFIX 'x' + +/* modrm.mode = REGMEM_FIELD_HAS_REG when a register is in there */ +#define REGMEM_FIELD_HAS_REG 0x3/* always = 0x3 */ +#define REGMEM_FIELD_HAS_MEM (~REGMEM_FIELD_HAS_REG) + +#define END_OF_INSN '\0' + +/* Intel Syntax */ +/* Values 0-4 map onto scale factor */ +#define BYTE_PTR 0 +#define WORD_PTR 1 +#define DWORD_PTR 2 +#define QWORD_PTR 3 +#define XWORD_PTR 4 +#define SHORT 5 +#define OFFSET_FLAT 6 +#define FLAT 7 +#define NONE_FOUND 8 + +typedef struct +{ + /* instruction name sans width suffix ("mov" for movl insns) */ + char *name; + + /* how many operands */ + unsigned int operands; + + /* base_opcode is the fundamental opcode byte without optional + prefix(es). */ + unsigned int base_opcode; + + /* extension_opcode is the 3 bit extension for group insns. + This field is also used to store the 8-bit opcode suffix for the + AMD 3DNow! instructions. + If this template has no extension opcode (the usual case) use None */ + unsigned int extension_opcode; +#define None 0xffff /* If no extension_opcode is possible. */ + + /* cpu feature flags */ + unsigned int cpu_flags; +#define Cpu086 0x1 /* Any old cpu will do, 0 does the same */ +#define Cpu186 0x2 /* i186 or better required */ +#define Cpu286 0x4 /* i286 or better required */ +#define Cpu386 0x8 /* i386 or better required */ +#define Cpu486 0x10 /* i486 or better required */ +#define Cpu586 0x20 /* i585 or better required */ +#define Cpu686 0x40 /* i686 or better required */ +#define CpuP4 0x80 /* Pentium4 or better required */ +#define CpuK6 0x100 /* AMD K6 or better required*/ +#define CpuAthlon 0x200 /* AMD Athlon or better required*/ +#define CpuSledgehammer 0x400 /* Sledgehammer or better required */ +#define CpuMMX 0x800 /* MMX support required */ +#define CpuSSE 0x1000 /* Streaming SIMD extensions required */ +#define CpuSSE2 0x2000 /* Streaming SIMD extensions 2 required */ +#define Cpu3dnow 0x4000 /* 3dnow! support required */ + + /* These flags are set by gas depending on the flag_code. */ +#define Cpu64 0x4000000 /* 64bit support required */ +#define CpuNo64 0x8000000 /* Not supported in the 64bit mode */ + + /* The default value for unknown CPUs - enable all features to avoid problems. */ +#define CpuUnknownFlags (Cpu086|Cpu186|Cpu286|Cpu386|Cpu486|Cpu586|Cpu686|CpuP4|CpuSledgehammer|CpuMMX|CpuSSE|CpuSSE2|Cpu3dnow|CpuK6|CpuAthlon) + + /* the bits in opcode_modifier are used to generate the final opcode from + the base_opcode. These bits also are used to detect alternate forms of + the same instruction */ + unsigned int opcode_modifier; + + /* opcode_modifier bits: */ +#define W 0x1 /* set if operands can be words or dwords + encoded the canonical way */ +#define D 0x2 /* D = 0 if Reg --> Regmem; + D = 1 if Regmem --> Reg: MUST BE 0x2 */ +#define Modrm 0x4 +#define FloatR 0x8 /* src/dest swap for floats: MUST BE 0x8 */ +#define ShortForm 0x10 /* register is in low 3 bits of opcode */ +#define FloatMF 0x20 /* FP insn memory format bit, sized by 0x4 */ +#define Jump 0x40 /* special case for jump insns. */ +#define JumpDword 0x80 /* call and jump */ +#define JumpByte 0x100 /* loop and jecxz */ +#define JumpInterSegment 0x200 /* special case for intersegment leaps/calls */ +#define FloatD 0x400 /* direction for float insns: MUST BE 0x400 */ +#define Seg2ShortForm 0x800 /* encoding of load segment reg insns */ +#define Seg3ShortForm 0x1000 /* fs/gs segment register insns. */ +#define Size16 0x2000 /* needs size prefix if in 32-bit mode */ +#define Size32 0x4000 /* needs size prefix if in 16-bit mode */ +#define Size64 0x8000 /* needs size prefix if in 16-bit mode */ +#define IgnoreSize 0x10000 /* instruction ignores operand size prefix */ +#define DefaultSize 0x20000 /* default insn size depends on mode */ +#define No_bSuf 0x40000 /* b suffix on instruction illegal */ +#define No_wSuf 0x80000 /* w suffix on instruction illegal */ +#define No_lSuf 0x100000 /* l suffix on instruction illegal */ +#define No_sSuf 0x200000 /* s suffix on instruction illegal */ +#define No_qSuf 0x400000 /* q suffix on instruction illegal */ +#define No_xSuf 0x800000 /* x suffix on instruction illegal */ +#define FWait 0x1000000 /* instruction needs FWAIT */ +#define IsString 0x2000000 /* quick test for string instructions */ +#define regKludge 0x4000000 /* fake an extra reg operand for clr, imul */ +#define IsPrefix 0x8000000 /* opcode is a prefix */ +#define ImmExt 0x10000000 /* instruction has extension in 8 bit imm */ +#define NoRex64 0x20000000 /* instruction don't need Rex64 prefix. */ +#define Rex64 0x40000000 /* instruction require Rex64 prefix. */ +#define Ugh 0x80000000 /* deprecated fp insn, gets a warning */ + + /* operand_types[i] describes the type of operand i. This is made + by OR'ing together all of the possible type masks. (e.g. + 'operand_types[i] = Reg|Imm' specifies that operand i can be + either a register or an immediate operand. */ + unsigned int operand_types[3]; + + /* operand_types[i] bits */ + /* register */ +#define Reg8 0x1 /* 8 bit reg */ +#define Reg16 0x2 /* 16 bit reg */ +#define Reg32 0x4 /* 32 bit reg */ +#define Reg64 0x8 /* 64 bit reg */ + /* immediate */ +#define Imm8 0x10 /* 8 bit immediate */ +#define Imm8S 0x20 /* 8 bit immediate sign extended */ +#define Imm16 0x40 /* 16 bit immediate */ +#define Imm32 0x80 /* 32 bit immediate */ +#define Imm32S 0x100 /* 32 bit immediate sign extended */ +#define Imm64 0x200 /* 64 bit immediate */ +#define Imm1 0x400 /* 1 bit immediate */ + /* memory */ +#define BaseIndex 0x800 + /* Disp8,16,32 are used in different ways, depending on the + instruction. For jumps, they specify the size of the PC relative + displacement, for baseindex type instructions, they specify the + size of the offset relative to the base register, and for memory + offset instructions such as `mov 1234,%al' they specify the size of + the offset relative to the segment base. */ +#define Disp8 0x1000 /* 8 bit displacement */ +#define Disp16 0x2000 /* 16 bit displacement */ +#define Disp32 0x4000 /* 32 bit displacement */ +#define Disp32S 0x8000 /* 32 bit signed displacement */ +#define Disp64 0x10000 /* 64 bit displacement */ + /* specials */ +#define InOutPortReg 0x20000 /* register to hold in/out port addr = dx */ +#define ShiftCount 0x40000 /* register to hold shift cound = cl */ +#define Control 0x80000 /* Control register */ +#define Debug 0x100000 /* Debug register */ +#define Test 0x200000 /* Test register */ +#define FloatReg 0x400000 /* Float register */ +#define FloatAcc 0x800000 /* Float stack top %st(0) */ +#define SReg2 0x1000000 /* 2 bit segment register */ +#define SReg3 0x2000000 /* 3 bit segment register */ +#define Acc 0x4000000 /* Accumulator %al or %ax or %eax */ +#define JumpAbsolute 0x8000000 +#define RegMMX 0x10000000 /* MMX register */ +#define RegXMM 0x20000000 /* XMM registers in PIII */ +#define EsSeg 0x40000000 /* String insn operand with fixed es segment */ + + /* InvMem is for instructions with a modrm byte that only allow a + general register encoding in the i.tm.mode and i.tm.regmem fields, + eg. control reg moves. They really ought to support a memory form, + but don't, so we add an InvMem flag to the register operand to + indicate that it should be encoded in the i.tm.regmem field. */ +#define InvMem 0x80000000 + +#define Reg (Reg8|Reg16|Reg32|Reg64) /* gen'l register */ +#define WordReg (Reg16|Reg32|Reg64) +#define ImplicitRegister (InOutPortReg|ShiftCount|Acc|FloatAcc) +#define Imm (Imm8|Imm8S|Imm16|Imm32S|Imm32|Imm64) /* gen'l immediate */ +#define EncImm (Imm8|Imm16|Imm32|Imm32S) /* Encodable gen'l immediate */ +#define Disp (Disp8|Disp16|Disp32|Disp32S|Disp64) /* General displacement */ +#define AnyMem (Disp8|Disp16|Disp32|Disp32S|BaseIndex|InvMem) /* General memory */ + /* The following aliases are defined because the opcode table + carefully specifies the allowed memory types for each instruction. + At the moment we can only tell a memory reference size by the + instruction suffix, so there's not much point in defining Mem8, + Mem16, Mem32 and Mem64 opcode modifiers - We might as well just use + the suffix directly to check memory operands. */ +#define LLongMem AnyMem /* 64 bits (or more) */ +#define LongMem AnyMem /* 32 bit memory ref */ +#define ShortMem AnyMem /* 16 bit memory ref */ +#define WordMem AnyMem /* 16 or 32 bit memory ref */ +#define ByteMem AnyMem /* 8 bit memory ref */ +} +template; + +/* + 'templates' is for grouping together 'template' structures for opcodes + of the same name. This is only used for storing the insns in the grand + ole hash table of insns. + The templates themselves start at START and range up to (but not including) + END. + */ +typedef struct +{ + const template *start; + const template *end; +} +templates; + +/* these are for register name --> number & type hash lookup */ +typedef struct +{ + char *reg_name; + unsigned int reg_type; + unsigned int reg_flags; +#define RegRex 0x1 /* Extended register. */ +#define RegRex64 0x2 /* Extended 8 bit register. */ + unsigned int reg_num; +} +reg_entry; + +typedef struct +{ + char *seg_name; + unsigned int seg_prefix; +} +seg_entry; + +/* 386 operand encoding bytes: see 386 book for details of this. */ +typedef struct +{ + unsigned int regmem; /* codes register or memory operand */ + unsigned int reg; /* codes register operand (or extended opcode) */ + unsigned int mode; /* how to interpret regmem & reg */ +} +modrm_byte; + +/* x86-64 extension prefix. */ +typedef int rex_byte; +#define REX_OPCODE 0x40 + +/* Indicates 64 bit operand size. */ +#define REX_MODE64 8 +/* High extension to reg field of modrm byte. */ +#define REX_EXTX 4 +/* High extension to SIB index field. */ +#define REX_EXTY 2 +/* High extension to base field of modrm or SIB, or reg field of opcode. */ +#define REX_EXTZ 1 + +/* 386 opcode byte to code indirect addressing. */ +typedef struct +{ + unsigned base; + unsigned index; + unsigned scale; +} +sib_byte; + +/* x86 arch names and features */ +typedef struct +{ + const char *name; /* arch name */ + unsigned int flags; /* cpu feature flags */ +} +arch_entry; + +/* The name of the global offset table generated by the compiler. Allow + this to be overridden if need be. */ +#ifndef GLOBAL_OFFSET_TABLE_NAME +#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_" +#endif + +#ifndef LEX_AT +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) x86_cons (EXP, NBYTES) +extern void x86_cons PARAMS ((expressionS *, int)); + +#define TC_CONS_FIX_NEW(FRAG,OFF,LEN,EXP) x86_cons_fix_new(FRAG, OFF, LEN, EXP) +extern void x86_cons_fix_new + PARAMS ((fragS *, unsigned int, unsigned int, expressionS *)); +#endif + +#define DIFF_EXPR_OK /* foo-. gets turned into PC relative relocs */ + +#ifdef BFD_ASSEMBLER +#define NO_RELOC BFD_RELOC_NONE + +void i386_validate_fix PARAMS ((struct fix *)); +#define TC_VALIDATE_FIX(FIX,SEGTYPE,SKIP) i386_validate_fix(FIX) + +#define tc_fix_adjustable(X) tc_i386_fix_adjustable(X) +extern int tc_i386_fix_adjustable PARAMS ((struct fix *)); + +/* Values passed to md_apply_fix3 don't include the symbol value. */ +#define MD_APPLY_SYM_VALUE(FIX) 0 + +/* ELF wants external syms kept, as does PE COFF. */ +#if defined (TE_PE) && defined (STRICT_PE_FORMAT) +#define EXTERN_FORCE_RELOC \ + (OUTPUT_FLAVOR == bfd_target_elf_flavour \ + || OUTPUT_FLAVOR == bfd_target_coff_flavour) +#else +#define EXTERN_FORCE_RELOC \ + (OUTPUT_FLAVOR == bfd_target_elf_flavour) +#endif + +/* This expression evaluates to true if the relocation is for a local + object for which we still want to do the relocation at runtime. + False if we are willing to perform this relocation while building + the .o file. GOTOFF does not need to be checked here because it is + not pcrel. I am not sure if some of the others are ever used with + pcrel, but it is easier to be safe than sorry. */ + +#define TC_FORCE_RELOCATION_LOCAL(FIX) \ + (!(FIX)->fx_pcrel \ + || (FIX)->fx_plt \ + || (FIX)->fx_r_type == BFD_RELOC_386_PLT32 \ + || (FIX)->fx_r_type == BFD_RELOC_386_GOT32 \ + || (FIX)->fx_r_type == BFD_RELOC_386_GOTPC \ + || TC_FORCE_RELOCATION (FIX)) + +#else /* ! BFD_ASSEMBLER */ + +#define NO_RELOC 0 + +#define TC_RVA_RELOC 7 + +/* Need this for PIC relocations */ +#define NEED_FX_R_TYPE + +#undef REVERSE_SORT_RELOCS + +/* For COFF. */ +#define TC_FORCE_RELOCATION(FIX) \ + ((FIX)->fx_r_type == 7 || generic_force_reloc (FIX)) +#endif /* ! BFD_ASSEMBLER */ + +#define md_operand(x) + +extern const struct relax_type md_relax_table[]; +#define TC_GENERIC_RELAX_TABLE md_relax_table + +#define md_do_align(n, fill, len, max, around) \ +if ((n) && !need_pass_2 \ + && (!(fill) || ((char)*(fill) == (char)0x90 && (len) == 1)) \ + && subseg_text_p (now_seg)) \ + { \ + frag_align_code ((n), (max)); \ + goto around; \ + } + +#define MAX_MEM_FOR_RS_ALIGN_CODE 15 + +extern void i386_align_code PARAMS ((fragS *, int)); + +#define HANDLE_ALIGN(fragP) \ +if (fragP->fr_type == rs_align_code) \ + i386_align_code (fragP, (fragP->fr_next->fr_address \ + - fragP->fr_address \ + - fragP->fr_fix)); + +void i386_print_statistics PARAMS ((FILE *)); +#define tc_print_statistics i386_print_statistics + +#define md_number_to_chars number_to_chars_littleendian + +#ifdef SCO_ELF +#define tc_init_after_args() sco_id () +extern void sco_id PARAMS ((void)); +#endif + +#endif /* TC_I386 */ diff --git a/contrib/binutils-2.14/gas/depend.c b/contrib/binutils-2.14/gas/depend.c new file mode 100644 index 0000000000..3c6049d4c3 --- /dev/null +++ b/contrib/binutils-2.14/gas/depend.c @@ -0,0 +1,213 @@ +/* depend.c - Handle dependency tracking. + Copyright 1997, 1998, 2000, 2001 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" + +/* The file to write to, or NULL if no dependencies being kept. */ +static char * dep_file = NULL; + +struct dependency + { + char * file; + struct dependency * next; + }; + +/* All the files we depend on. */ +static struct dependency * dep_chain = NULL; + +/* Current column in output file. */ +static int column = 0; + +static int quote_string_for_make PARAMS ((FILE *, char *)); +static void wrap_output PARAMS ((FILE *, char *, int)); + +/* Number of columns allowable. */ +#define MAX_COLUMNS 72 + +/* Start saving dependencies, to be written to FILENAME. If this is + never called, then dependency tracking is simply skipped. */ + +void +start_dependencies (filename) + char *filename; +{ + dep_file = filename; +} + +/* Noticed a new filename, so try to register it. */ + +void +register_dependency (filename) + char *filename; +{ + struct dependency *dep; + + if (dep_file == NULL) + return; + + for (dep = dep_chain; dep != NULL; dep = dep->next) + { + if (!strcmp (filename, dep->file)) + return; + } + + dep = (struct dependency *) xmalloc (sizeof (struct dependency)); + dep->file = xstrdup (filename); + dep->next = dep_chain; + dep_chain = dep; +} + +/* Quote a file name the way `make' wants it, and print it to FILE. + If FILE is NULL, do no printing, but return the length of the + quoted string. + + This code is taken from gcc with only minor changes. */ + +static int +quote_string_for_make (file, src) + FILE *file; + char *src; +{ + char *p = src; + int i = 0; + + for (;;) + { + char c = *p++; + + switch (c) + { + case '\0': + case ' ': + case '\t': + { + /* GNU make uses a weird quoting scheme for white space. + A space or tab preceded by 2N+1 backslashes represents + N backslashes followed by space; a space or tab + preceded by 2N backslashes represents N backslashes at + the end of a file name; and backslashes in other + contexts should not be doubled. */ + char *q; + + for (q = p - 1; src < q && q[-1] == '\\'; q--) + { + if (file) + putc ('\\', file); + i++; + } + } + if (!c) + return i; + if (file) + putc ('\\', file); + i++; + goto ordinary_char; + + case '$': + if (file) + putc (c, file); + i++; + /* Fall through. This can mishandle things like "$(" but + there's no easy fix. */ + default: + ordinary_char: + /* This can mishandle characters in the string "\0\n%*?[\\~"; + exactly which chars are mishandled depends on the `make' version. + We know of no portable solution for this; + even GNU make 3.76.1 doesn't solve the problem entirely. + (Also, '\0' is mishandled due to our calling conventions.) */ + if (file) + putc (c, file); + i++; + break; + } + } +} + +/* Append some output to the file, keeping track of columns and doing + wrapping as necessary. */ + +static void +wrap_output (f, string, spacer) + FILE *f; + char *string; + int spacer; +{ + int len = quote_string_for_make (NULL, string); + + if (len == 0) + return; + + if (column + && (MAX_COLUMNS + - 1 /* spacer */ + - 2 /* ` \' */ + < column + len)) + { + fprintf (f, " \\\n "); + column = 0; + if (spacer == ' ') + spacer = '\0'; + } + + if (spacer == ' ') + { + putc (spacer, f); + ++column; + } + + quote_string_for_make (f, string); + column += len; + + if (spacer == ':') + { + putc (spacer, f); + ++column; + } +} + +/* Print dependency file. */ + +void +print_dependencies () +{ + FILE *f; + struct dependency *dep; + + if (dep_file == NULL) + return; + + f = fopen (dep_file, FOPEN_WT); + if (f == NULL) + { + as_warn (_("can't open `%s' for writing"), dep_file); + return; + } + + column = 0; + wrap_output (f, out_file_name, ':'); + for (dep = dep_chain; dep != NULL; dep = dep->next) + wrap_output (f, dep->file, ' '); + + putc ('\n', f); + + if (fclose (f)) + as_warn (_("can't close `%s'"), dep_file); +} diff --git a/contrib/binutils-2.14/gas/doc/as.info b/contrib/binutils-2.14/gas/doc/as.info new file mode 100644 index 0000000000..9f368370f4 --- /dev/null +++ b/contrib/binutils-2.14/gas/doc/as.info @@ -0,0 +1,480 @@ +This is as.info, produced by makeinfo version 4.3 from as.texinfo. + +START-INFO-DIR-ENTRY +* As: (as). The GNU assembler. +* Gas: (as). The GNU assembler. +END-INFO-DIR-ENTRY + + This file documents the GNU Assembler "as". + + Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002 +Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 or +any later version published by the Free Software Foundation; with no +Invariant Sections, with no Front-Cover Texts, and with no Back-Cover +Texts. A copy of the license is included in the section entitled "GNU +Free Documentation License". + + +Indirect: +as.info-1: 746 +as.info-2: 50403 +as.info-3: 99518 +as.info-4: 149019 +as.info-5: 200539 +as.info-6: 243961 +as.info-7: 293741 +as.info-8: 342907 +as.info-9: 392750 +as.info-10: 441695 +as.info-11: 491168 +as.info-12: 515814 + +Tag Table: +(Indirect) +Node: Top746 +Node: Overview1666 +Node: Manual23653 +Node: GNU Assembler24592 +Node: Object Formats25758 +Node: Command Line26205 +Node: Input Files27287 +Node: Object29266 +Node: Errors30213 +Node: Invoking31403 +Node: a33291 +Node: D35050 +Node: f35270 +Node: I35773 +Node: K36312 +Node: L36611 +Node: listing37443 +Node: M39030 +Node: MD43426 +Node: o43845 +Node: R44293 +Node: statistics45316 +Node: traditional-format45716 +Node: v46182 +Node: W46450 +Node: Z47350 +Node: Syntax47865 +Node: Preprocessing48455 +Node: Whitespace50013 +Node: Comments50403 +Node: Symbol Intro52596 +Node: Statements53279 +Node: Constants55193 +Node: Characters55819 +Node: Strings56312 +Node: Chars58465 +Node: Numbers59206 +Node: Integers59737 +Node: Bignums60380 +Node: Flonums60723 +Node: Sections62465 +Node: Secs Background62839 +Node: Ld Sections67881 +Node: As Sections70280 +Node: Sub-Sections71185 +Node: bss74191 +Node: Symbols75136 +Node: Labels75783 +Node: Setting Symbols76509 +Node: Symbol Names76874 +Node: Dot81347 +Node: Symbol Attributes81789 +Node: Symbol Value82521 +Node: Symbol Type83557 +Node: a.out Symbols83936 +Node: Symbol Desc84186 +Node: Symbol Other84468 +Node: COFF Symbols84624 +Node: SOM Symbols85253 +Node: Expressions85686 +Node: Empty Exprs86434 +Node: Integer Exprs86776 +Node: Arguments87166 +Node: Operators88263 +Node: Prefix Ops88589 +Node: Infix Ops88908 +Node: Pseudo Ops91296 +Node: Abort96108 +Node: ABORT96509 +Node: Align96771 +Node: Ascii98977 +Node: Asciz99278 +Node: Balign99518 +Node: Byte101376 +Node: Comm101609 +Node: Data102968 +Node: Def103278 +Node: Desc103646 +Node: Dim104139 +Node: Double104530 +Node: Eject104861 +Node: Else105029 +Node: Elseif105319 +Node: End105603 +Node: Endef105811 +Node: Endfunc106134 +Node: Endif106302 +Node: Equ106555 +Node: Equiv106858 +Node: Err107351 +Node: Exitm107654 +Node: Extern107814 +Node: Fail108068 +Node: File108506 +Node: Fill109115 +Node: Float110072 +Node: Func110406 +Node: Global110986 +Node: Hidden111729 +Node: hword112298 +Node: Ident112619 +Node: If112919 +Node: Incbin115708 +Node: Include116396 +Node: Int116940 +Node: Internal117314 +Node: Irp117952 +Node: Irpc118751 +Node: Lcomm119570 +Node: Lflags120311 +Node: Line120498 +Node: Linkonce121521 +Node: Ln122741 +Node: MRI122889 +Node: List123216 +Node: Long123819 +Node: Macro123989 +Node: Nolist126373 +Node: Octa126789 +Node: Org127115 +Node: P2align128390 +Node: Previous130311 +Node: PopSection130998 +Node: Print131499 +Node: Protected131721 +Node: Psize132358 +Node: Purgem133035 +Node: PushSection133249 +Node: Quad133832 +Node: Rept134278 +Node: Sbttl134684 +Node: Scl135042 +Node: Section135538 +Node: Set139427 +Node: Short139979 +Node: Single140292 +Node: Size140629 +Node: Sleb128141436 +Node: Skip141751 +Node: Space142066 +Node: Stab142951 +Node: String144946 +Node: Struct145365 +Node: SubSection146081 +Node: Symver146635 +Node: Tag149019 +Node: Text149527 +Node: Title149839 +Node: Type150211 +Node: Uleb128151441 +Node: Val151756 +Node: Version152117 +Node: VTableEntry152383 +Node: VTableInherit152664 +Node: Weak153098 +Node: Word153359 +Node: Deprecated155193 +Node: Machine Dependencies155418 +Node: AMD29K-Dependent158133 +Node: AMD29K Options158516 +Node: AMD29K Syntax158690 +Node: AMD29K-Macros158954 +Node: AMD29K-Chars159205 +Node: AMD29K-Regs159468 +Node: AMD29K Floating Point160732 +Node: AMD29K Directives160938 +Node: AMD29K Opcodes162346 +Node: Alpha-Dependent162682 +Node: Alpha Notes163113 +Node: Alpha Options163385 +Node: Alpha Syntax165571 +Node: Alpha-Chars166031 +Node: Alpha-Regs166249 +Node: Alpha-Relocs166620 +Node: Alpha Floating Point172597 +Node: Alpha Directives172810 +Node: Alpha Opcodes177837 +Node: ARC-Dependent178123 +Node: ARC Options178498 +Node: ARC Syntax179550 +Node: ARC-Chars179770 +Node: ARC-Regs179889 +Node: ARC Floating Point180000 +Node: ARC Directives180302 +Node: ARC Opcodes181584 +Node: ARM-Dependent181784 +Node: ARM Options182158 +Node: ARM Syntax187399 +Node: ARM-Chars187619 +Node: ARM-Regs188130 +Node: ARM Floating Point188302 +Node: ARM Directives188492 +Node: ARM Opcodes191062 +Node: CRIS-Dependent193112 +Node: CRIS-Opts193414 +Node: CRIS-Expand195152 +Node: CRIS-Syntax195977 +Node: CRIS-Chars196303 +Node: CRIS-Pic196841 +Ref: crispic197024 +Node: CRIS-Regs200539 +Node: CRIS-Pseudos200943 +Ref: crisnous201706 +Node: D10V-Dependent202768 +Node: D10V-Opts203111 +Node: D10V-Syntax204065 +Node: D10V-Size204585 +Node: D10V-Subs205545 +Node: D10V-Chars206567 +Node: D10V-Regs208153 +Node: D10V-Addressing209184 +Node: D10V-Word209857 +Node: D10V-Float210359 +Node: D10V-Opcodes210661 +Node: D30V-Dependent211045 +Node: D30V-Opts211390 +Node: D30V-Syntax212056 +Node: D30V-Size212579 +Node: D30V-Subs213537 +Node: D30V-Chars214559 +Node: D30V-Guarded216844 +Node: D30V-Regs217512 +Node: D30V-Addressing218638 +Node: D30V-Float219293 +Node: D30V-Opcodes219595 +Node: H8/300-Dependent219979 +Node: H8/300 Options220383 +Node: H8/300 Syntax220583 +Node: H8/300-Chars220870 +Node: H8/300-Regs221154 +Node: H8/300-Addressing222058 +Node: H8/300 Floating Point223084 +Node: H8/300 Directives223400 +Node: H8/300 Opcodes224517 +Node: H8/500-Dependent232848 +Node: H8/500 Options233252 +Node: H8/500 Syntax233452 +Node: H8/500-Chars233739 +Node: H8/500-Regs234030 +Node: H8/500-Addressing234786 +Node: H8/500 Floating Point235403 +Node: H8/500 Directives235719 +Node: H8/500 Opcodes236038 +Node: HPPA-Dependent241151 +Node: HPPA Notes241576 +Node: HPPA Options242323 +Node: HPPA Syntax242507 +Node: HPPA Floating Point243766 +Node: HPPA Directives243961 +Node: HPPA Opcodes250552 +Node: ESA/390-Dependent250800 +Node: ESA/390 Notes251250 +Node: ESA/390 Options252030 +Node: ESA/390 Syntax252229 +Node: ESA/390 Floating Point254391 +Node: ESA/390 Directives254659 +Node: ESA/390 Opcodes257936 +Node: i386-Dependent258187 +Node: i386-Options259245 +Node: i386-Syntax259856 +Node: i386-Mnemonics262259 +Node: i386-Regs264713 +Node: i386-Prefixes266747 +Node: i386-Memory269495 +Node: i386-Jumps272421 +Node: i386-Float273531 +Node: i386-SIMD275349 +Node: i386-16bit276447 +Node: i386-Bugs278472 +Node: i386-Arch279211 +Node: i386-Notes281075 +Node: i860-Dependent281920 +Node: Notes-i860282306 +Node: Options-i860282800 +Node: Directives-i860283805 +Node: Opcodes for i860284467 +Node: i960-Dependent286586 +Node: Options-i960286978 +Node: Floating Point-i960290858 +Node: Directives-i960291115 +Node: Opcodes for i960293135 +Node: callj-i960293741 +Node: Compare-and-branch-i960294216 +Node: IP2K-Dependent296105 +Node: IP2K-Opts296322 +Node: M32R-Dependent296790 +Node: M32R-Opts297053 +Node: M32R-Warnings298799 +Node: M68K-Dependent301787 +Node: M68K-Opts302244 +Node: M68K-Syntax308535 +Node: M68K-Moto-Syntax310363 +Node: M68K-Float312941 +Node: M68K-Directives313450 +Node: M68K-opcodes314045 +Node: M68K-Branch314257 +Node: M68K-Chars318443 +Node: M68HC11-Dependent318838 +Node: M68HC11-Opts319359 +Node: M68HC11-Syntax323164 +Node: M68HC11-Modifiers325366 +Node: M68HC11-Directives327182 +Node: M68HC11-Float328546 +Node: M68HC11-opcodes329063 +Node: M68HC11-Branch329231 +Node: M88K-Dependent331662 +Node: M88K Directives331903 +Node: MIPS-Dependent333411 +Node: MIPS Opts334421 +Node: MIPS Object340641 +Node: MIPS Stabs342196 +Node: MIPS ISA342907 +Node: MIPS autoextend344038 +Node: MIPS insn344749 +Node: MIPS option stack345235 +Node: MIPS ASE instruction generation overrides345998 +Node: MMIX-Dependent346760 +Node: MMIX-Opts347130 +Node: MMIX-Expand349950 +Node: MMIX-Syntax351254 +Ref: mmixsite351600 +Node: MMIX-Chars352441 +Node: MMIX-Symbols353080 +Node: MMIX-Regs355133 +Node: MMIX-Pseudos356143 +Ref: MMIX-loc356266 +Ref: MMIX-local357346 +Ref: MMIX-is357878 +Ref: MMIX-greg358149 +Ref: GREG-base359068 +Ref: MMIX-byte360385 +Ref: MMIX-constants360856 +Ref: MMIX-prefix361501 +Ref: MMIX-spec361875 +Node: MMIX-mmixal362209 +Node: MSP430-Dependent365695 +Node: MSP430 Options366098 +Node: MSP430 Syntax366279 +Node: MSP430-Macros366581 +Node: MSP430-Chars367296 +Node: MSP430-Regs367594 +Node: MSP430-Ext368139 +Node: MSP430 Floating Point368475 +Node: MSP430 Directives368688 +Node: MSP430 Opcodes369361 +Node: PDP-11-Dependent369709 +Node: PDP-11-Options370088 +Node: PDP-11-Pseudos375085 +Node: PDP-11-Syntax375419 +Node: PDP-11-Mnemonics376159 +Node: PDP-11-Synthetic376450 +Node: PJ-Dependent376657 +Node: PJ Options376872 +Node: PPC-Dependent377138 +Node: PowerPC-Opts377354 +Node: SH-Dependent379206 +Node: SH Options379608 +Node: SH Syntax380068 +Node: SH-Chars380327 +Node: SH-Regs380606 +Node: SH-Addressing381205 +Node: SH Floating Point382099 +Node: SH Directives382395 +Node: SH Opcodes382751 +Node: SH64-Dependent387072 +Node: SH64 Options387425 +Node: SH64 Syntax388850 +Node: SH64-Chars389119 +Node: SH64-Regs389404 +Node: SH64-Addressing390485 +Node: SH64 Directives391653 +Node: SH64 Opcodes392750 +Node: Sparc-Dependent393454 +Node: Sparc-Opts393829 +Node: Sparc-Aligned-Data396075 +Node: Sparc-Float396919 +Node: Sparc-Directives397109 +Node: TIC54X-Dependent399058 +Node: TIC54X-Opts399774 +Node: TIC54X-Block400806 +Node: TIC54X-Env401155 +Node: TIC54X-Constants401492 +Node: TIC54X-Subsyms401883 +Node: TIC54X-Locals403781 +Node: TIC54X-Builtins404514 +Node: TIC54X-Ext406973 +Node: TIC54X-Directives407533 +Node: TIC54X-Macros418421 +Node: TIC54X-MMRegs420517 +Node: Z8000-Dependent420719 +Node: Z8000 Options421680 +Node: Z8000 Syntax421855 +Node: Z8000-Chars422131 +Node: Z8000-Regs422349 +Node: Z8000-Addressing423139 +Node: Z8000 Directives424082 +Node: Z8000 Opcodes425680 +Node: Vax-Dependent435616 +Node: VAX-Opts436123 +Node: VAX-float439847 +Node: VAX-directives440468 +Node: VAX-opcodes441317 +Node: VAX-branch441695 +Node: VAX-operands444191 +Node: VAX-no444943 +Node: V850-Dependent445169 +Node: V850 Options445557 +Node: V850 Syntax447705 +Node: V850-Chars447931 +Node: V850-Regs448081 +Node: V850 Floating Point449618 +Node: V850 Directives449813 +Node: V850 Opcodes450713 +Node: Xtensa-Dependent456593 +Node: Xtensa Options457314 +Node: Xtensa Syntax460265 +Node: Xtensa Opcodes460869 +Node: Xtensa Registers463122 +Node: Xtensa Optimizations463592 +Node: Density Instructions464033 +Node: Xtensa Automatic Alignment465107 +Node: Xtensa Relaxation466840 +Node: Xtensa Branch Relaxation467737 +Node: Xtensa Call Relaxation468406 +Node: Xtensa Immediate Relaxation470077 +Node: Xtensa Directives472323 +Node: Density Directive474953 +Node: Relax Directive475495 +Node: Longcalls Directive476083 +Node: Generics Directive476520 +Node: Literal Directive477233 +Node: Literal Position Directive478921 +Node: Literal Prefix Directive480486 +Node: Freeregs Directive481392 +Node: Frame Directive482146 +Node: Reporting Bugs483056 +Node: Bug Criteria483779 +Node: Bug Reporting484539 +Node: Acknowledgements491168 +Ref: Acknowledgements-Footnote-1496086 +Node: GNU Free Documentation License496112 +Node: Index515814 + +End Tag Table diff --git a/contrib/binutils-2.14/gas/doc/as.texinfo b/contrib/binutils-2.14/gas/doc/as.texinfo new file mode 100644 index 0000000000..dd78d68cb0 --- /dev/null +++ b/contrib/binutils-2.14/gas/doc/as.texinfo @@ -0,0 +1,6412 @@ +\input texinfo @c -*-Texinfo-*- +@c Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +@c 2001, 2002 +@c Free Software Foundation, Inc. +@c UPDATE!! On future updates-- +@c (1) check for new machine-dep cmdline options in +@c md_parse_option definitions in config/tc-*.c +@c (2) for platform-specific directives, examine md_pseudo_op +@c in config/tc-*.c +@c (3) for object-format specific directives, examine obj_pseudo_op +@c in config/obj-*.c +@c (4) portable directives in potable[] in read.c +@c %**start of header +@setfilename as.info +@c ---config--- +@macro gcctabopt{body} +@code{\body\} +@end macro +@c defaults, config file may override: +@set have-stabs +@c --- +@include asconfig.texi +@include gasver.texi +@c --- +@c man begin NAME +@ifset man +@c Configure for the generation of man pages +@set AS as +@set TARGET TARGET +@set GENERIC +@set A29K +@set ALPHA +@set ARC +@set ARM +@set CRIS +@set D10V +@set D30V +@set H8/300 +@set H8/500 +@set HPPA +@set I370 +@set I80386 +@set I860 +@set I960 +@set IA-64 +@set IP2K +@set M32R +@set M68HC11 +@set M680X0 +@set M880X0 +@set MCORE +@set MIPS +@set MMIX +@set PDP11 +@set PJ +@set PPC +@set SH +@set SPARC +@set TIC54X +@set V850 +@set VAX +@set XTENSA +@end ifset +@c man end +@c common OR combinations of conditions +@ifset COFF +@set COFF-ELF +@end ifset +@ifset ELF +@set COFF-ELF +@end ifset +@ifset AOUT +@set aout-bout +@end ifset +@ifset ARM/Thumb +@set ARM +@end ifset +@ifset BOUT +@set aout-bout +@end ifset +@ifset H8/300 +@set H8 +@end ifset +@ifset H8/500 +@set H8 +@end ifset +@ifset SH +@set H8 +@end ifset +@ifset HPPA +@set abnormal-separator +@end ifset +@c ------------ +@ifset GENERIC +@settitle Using @value{AS} +@end ifset +@ifclear GENERIC +@settitle Using @value{AS} (@value{TARGET}) +@end ifclear +@setchapternewpage odd +@c %**end of header + +@c @smallbook +@c @set SMALL +@c WARE! Some of the machine-dependent sections contain tables of machine +@c instructions. Except in multi-column format, these tables look silly. +@c Unfortunately, Texinfo doesn't have a general-purpose multi-col format, so +@c the multi-col format is faked within @example sections. +@c +@c Again unfortunately, the natural size that fits on a page, for these tables, +@c is different depending on whether or not smallbook is turned on. +@c This matters, because of order: text flow switches columns at each page +@c break. +@c +@c The format faked in this source works reasonably well for smallbook, +@c not well for the default large-page format. This manual expects that if you +@c turn on @smallbook, you will also uncomment the "@set SMALL" to enable the +@c tables in question. You can turn on one without the other at your +@c discretion, of course. +@ifinfo +@set SMALL +@c the insn tables look just as silly in info files regardless of smallbook, +@c might as well show 'em anyways. +@end ifinfo + +@ifinfo +@format +START-INFO-DIR-ENTRY +* As: (as). The GNU assembler. +* Gas: (as). The GNU assembler. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@finalout +@syncodeindex ky cp + +@ifinfo +This file documents the GNU Assembler "@value{AS}". + +@c man begin COPYRIGHT +Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``GNU Free Documentation License''. + +@c man end + +@ignore +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +@end ifinfo + +@titlepage +@title Using @value{AS} +@subtitle The @sc{gnu} Assembler +@ifclear GENERIC +@subtitle for the @value{TARGET} family +@end ifclear +@sp 1 +@subtitle Version @value{VERSION} +@sp 1 +@sp 13 +The Free Software Foundation Inc. thanks The Nice Computer +Company of Australia for loaning Dean Elsner to write the +first (Vax) version of @command{as} for Project @sc{gnu}. +The proprietors, management and staff of TNCCA thank FSF for +distracting the boss while they got some work +done. +@sp 3 +@author Dean Elsner, Jay Fenlason & friends +@page +@tex +{\parskip=0pt +\hfill {\it Using {\tt @value{AS}}}\par +\hfill Edited by Cygnus Support\par +} +%"boxit" macro for figures: +%Modified from Knuth's ``boxit'' macro from TeXbook (answer to exercise 21.3) +\gdef\boxit#1#2{\vbox{\hrule\hbox{\vrule\kern3pt + \vbox{\parindent=0pt\parskip=0pt\hsize=#1\kern3pt\strut\hfil +#2\hfil\strut\kern3pt}\kern3pt\vrule}\hrule}}%box with visible outline +\gdef\ibox#1#2{\hbox to #1{#2\hfil}\kern8pt}% invisible box +@end tex + +@vskip 0pt plus 1filll +Copyright @copyright{} 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002 Free Software Foundation, Inc. + + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.1 + or any later version published by the Free Software Foundation; + with no Invariant Sections, with no Front-Cover Texts, and with no + Back-Cover Texts. A copy of the license is included in the + section entitled ``GNU Free Documentation License''. + +@end titlepage + +@ifnottex +@node Top +@top Using @value{AS} + +This file is a user guide to the @sc{gnu} assembler @command{@value{AS}} version +@value{VERSION}. +@ifclear GENERIC +This version of the file describes @command{@value{AS}} configured to generate +code for @value{TARGET} architectures. +@end ifclear + +This document is distributed under the terms of the GNU Free +Documentation License. A copy of the license is included in the +section entitled ``GNU Free Documentation License''. + +@menu +* Overview:: Overview +* Invoking:: Command-Line Options +* Syntax:: Syntax +* Sections:: Sections and Relocation +* Symbols:: Symbols +* Expressions:: Expressions +* Pseudo Ops:: Assembler Directives +* Machine Dependencies:: Machine Dependent Features +* Reporting Bugs:: Reporting Bugs +* Acknowledgements:: Who Did What +* GNU Free Documentation License:: GNU Free Documentation License +* Index:: Index +@end menu +@end ifnottex + +@node Overview +@chapter Overview +@iftex +This manual is a user guide to the @sc{gnu} assembler @command{@value{AS}}. +@ifclear GENERIC +This version of the manual describes @command{@value{AS}} configured to generate +code for @value{TARGET} architectures. +@end ifclear +@end iftex + +@cindex invocation summary +@cindex option summary +@cindex summary of options +Here is a brief summary of how to invoke @command{@value{AS}}. For details, +@pxref{Invoking,,Command-Line Options}. + +@c man title AS the portable GNU assembler. + +@ignore +@c man begin SEEALSO +gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}. +@c man end +@end ignore + +@c We don't use deffn and friends for the following because they seem +@c to be limited to one line for the header. +@smallexample +@c man begin SYNOPSIS +@value{AS} [@b{-a}[@b{cdhlns}][=@var{file}]] [@b{-D}] [@b{--defsym} @var{sym}=@var{val}] + [@b{-f}] [@b{--gstabs}] [@b{--gdwarf2}] [@b{--help}] [@b{-I} @var{dir}] + [@b{-J}] [@b{-K}] [@b{-L}] + [@b{--listing-lhs-width}=@var{NUM}] [@b{--listing-lhs-width2}=@var{NUM}] + [@b{--listing-rhs-width}=@var{NUM}] [@b{--listing-cont-lines}=@var{NUM}] + [@b{--keep-locals}] [@b{-o} @var{objfile}] [@b{-R}] [@b{--statistics}] [@b{-v}] + [@b{-version}] [@b{--version}] [@b{-W}] [@b{--warn}] [@b{--fatal-warnings}] + [@b{-w}] [@b{-x}] [@b{-Z}] [@b{--target-help}] [@var{target-options}] + [@b{--}|@var{files} @dots{}] +@c +@c Target dependent options are listed below. Keep the list sorted. +@c Add an empty line for separation. +@ifset A29K +@c am29k has no machine-dependent assembler options +@end ifset +@ifset ALPHA + +@emph{Target Alpha options:} + [@b{-m@var{cpu}}] + [@b{-mdebug} | @b{-no-mdebug}] + [@b{-relax}] [@b{-g}] [@b{-G@var{size}}] + [@b{-F}] [@b{-32addr}] +@end ifset +@ifset ARC + +@emph{Target ARC options:} + [@b{-marc[5|6|7|8]}] + [@b{-EB}|@b{-EL}] +@end ifset +@ifset ARM + +@emph{Target ARM options:} +@c Don't document the deprecated options + [@b{-mcpu}=@var{processor}[+@var{extension}@dots{}]] + [@b{-march}=@var{architecture}[+@var{extension}@dots{}]] + [@b{-mfpu}=@var{floating-point-fromat}] + [@b{-mthumb}] + [@b{-EB}|@b{-EL}] + [@b{-mapcs-32}|@b{-mapcs-26}|@b{-mapcs-float}| + @b{-mapcs-reentrant}] + [@b{-mthumb-interwork}] [@b{-moabi}] [@b{-k}] +@end ifset +@ifset CRIS + +@emph{Target CRIS options:} + [@b{--underscore} | @b{--no-underscore}] + [@b{--pic}] [@b{-N}] + [@b{--emulation=criself} | @b{--emulation=crisaout}] +@c Deprecated -- deliberately not documented. +@c [@b{-h}] [@b{-H}] +@end ifset +@ifset D10V + +@emph{Target D10V options:} + [@b{-O}] +@end ifset +@ifset D30V + +@emph{Target D30V options:} + [@b{-O}|@b{-n}|@b{-N}] +@end ifset +@ifset H8 +@c Renesas family chips have no machine-dependent assembler options +@end ifset +@ifset HPPA +@c HPPA has no machine-dependent assembler options (yet). +@end ifset +@ifset I80386 + +@emph{Target i386 options:} + [@b{--32}|@b{--64}] +@end ifset +@ifset I960 + +@emph{Target i960 options:} +@c see md_parse_option in tc-i960.c + [@b{-ACA}|@b{-ACA_A}|@b{-ACB}|@b{-ACC}|@b{-AKA}|@b{-AKB}| + @b{-AKC}|@b{-AMC}] + [@b{-b}] [@b{-no-relax}] +@end ifset +@ifset IA64 + +@emph{Target IA-64 options:} + [@b{-mconstant-gp}|@b{-mauto-pic}] + [@b{-milp32}|@b{-milp64}|@b{-mlp64}|@b{-mp64}] + [@b{-mle}|@b{mbe}] + [@b{-x}|@b{-xexplicit}] [@b{-xauto}] [@b{-xdebug}] +@end ifset +@ifset IP2K + +@emph{Target IP2K options:} + [@b{-mip2022}|@b{-mip2022ext}] +@end ifset +@ifset M32R + +@emph{Target M32R options:} + [@b{--m32rx}|@b{--[no-]warn-explicit-parallel-conflicts}| + @b{--W[n]p}] +@end ifset +@ifset M680X0 + +@emph{Target M680X0 options:} + [@b{-l}] [@b{-m68000}|@b{-m68010}|@b{-m68020}|@dots{}] +@end ifset +@ifset M68HC11 + +@emph{Target M68HC11 options:} + [@b{-m68hc11}|@b{-m68hc12}|@b{-m68hcs12}] + [@b{-mshort}|@b{-mlong}] + [@b{-mshort-double}|@b{-mlong-double}] + [@b{--force-long-branchs}] [@b{--short-branchs}] + [@b{--strict-direct-mode}] [@b{--print-insn-syntax}] + [@b{--print-opcodes}] [@b{--generate-example}] +@end ifset +@ifset MCORE + +@emph{Target MCORE options:} + [@b{-jsri2bsr}] [@b{-sifilter}] [@b{-relax}] + [@b{-mcpu=[210|340]}] +@end ifset +@ifset MIPS + +@emph{Target MIPS options:} + [@b{-nocpp}] [@b{-EL}] [@b{-EB}] [@b{-n}] [@b{-O}[@var{optimization level}]] + [@b{-g}[@var{debug level}]] [@b{-G} @var{num}] [@b{-KPIC}] [@b{-call_shared}] + [@b{-non_shared}] [@b{-xgot}] [@b{--membedded-pic}] + [@b{-mabi}=@var{ABI}] [@b{-32}] [@b{-n32}] [@b{-64}] [@b{-mfp32}] [@b{-mgp32}] + [@b{-march}=@var{CPU}] [@b{-mtune}=@var{CPU}] [@b{-mips1}] [@b{-mips2}] + [@b{-mips3}] [@b{-mips4}] [@b{-mips5}] [@b{-mips32}] [@b{-mips32r2}] + [@b{-mips64}] + [@b{-construct-floats}] [@b{-no-construct-floats}] + [@b{-trap}] [@b{-no-break}] [@b{-break}] [@b{-no-trap}] + [@b{-mfix7000}] [@b{-mno-fix7000}] + [@b{-mips16}] [@b{-no-mips16}] + [@b{-mips3d}] [@b{-no-mips3d}] + [@b{-mdmx}] [@b{-no-mdmx}] + [@b{-mdebug}] [@b{-no-mdebug}] +@end ifset +@ifset MMIX + +@emph{Target MMIX options:} + [@b{--fixed-special-register-names}] [@b{--globalize-symbols}] + [@b{--gnu-syntax}] [@b{--relax}] [@b{--no-predefined-symbols}] + [@b{--no-expand}] [@b{--no-merge-gregs}] [@b{-x}] + [@b{--linker-allocated-gregs}] +@end ifset +@ifset PDP11 + +@emph{Target PDP11 options:} + [@b{-mpic}|@b{-mno-pic}] [@b{-mall}] [@b{-mno-extensions}] + [@b{-m}@var{extension}|@b{-mno-}@var{extension}] + [@b{-m}@var{cpu}] [@b{-m}@var{machine}] +@end ifset +@ifset PJ + +@emph{Target picoJava options:} + [@b{-mb}|@b{-me}] +@end ifset +@ifset PPC + +@emph{Target PowerPC options:} + [@b{-mpwrx}|@b{-mpwr2}|@b{-mpwr}|@b{-m601}|@b{-mppc}|@b{-mppc32}|@b{-m603}|@b{-m604}| + @b{-m403}|@b{-m405}|@b{-mppc64}|@b{-m620}|@b{-mppc64bridge}|@b{-mbooke}| + @b{-mbooke32}|@b{-mbooke64}] + [@b{-mcom}|@b{-many}|@b{-maltivec}] [@b{-memb}] + [@b{-mregnames}|@b{-mno-regnames}] + [@b{-mrelocatable}|@b{-mrelocatable-lib}] + [@b{-mlittle}|@b{-mlittle-endian}|@b{-mbig}|@b{-mbig-endian}] + [@b{-msolaris}|@b{-mno-solaris}] +@end ifset +@ifset SPARC + +@emph{Target SPARC options:} +@c The order here is important. See c-sparc.texi. + [@b{-Av6}|@b{-Av7}|@b{-Av8}|@b{-Asparclet}|@b{-Asparclite} + @b{-Av8plus}|@b{-Av8plusa}|@b{-Av9}|@b{-Av9a}] + [@b{-xarch=v8plus}|@b{-xarch=v8plusa}] [@b{-bump}] + [@b{-32}|@b{-64}] +@end ifset +@ifset TIC54X + +@emph{Target TIC54X options:} + [@b{-mcpu=54[123589]}|@b{-mcpu=54[56]lp}] [@b{-mfar-mode}|@b{-mf}] + [@b{-merrors-to-file} @var{}|@b{-me} @var{}] +@end ifset +@ifset Z8000 +@c Z8000 has no machine-dependent assembler options +@end ifset +@ifset XTENSA + +@emph{Target Xtensa options:} + [@b{--[no-]density}] [@b{--[no-]relax}] [@b{--[no-]generics}] + [@b{--[no-]text-section-literals}] + [@b{--[no-]target-align}] [@b{--[no-]longcalls}] +@end ifset +@c man end +@end smallexample + +@c man begin OPTIONS + +@table @gcctabopt +@item -a[cdhlmns] +Turn on listings, in any of a variety of ways: + +@table @gcctabopt +@item -ac +omit false conditionals + +@item -ad +omit debugging directives + +@item -ah +include high-level source + +@item -al +include assembly + +@item -am +include macro expansions + +@item -an +omit forms processing + +@item -as +include symbols + +@item =file +set the name of the listing file +@end table + +You may combine these options; for example, use @samp{-aln} for assembly +listing without forms processing. The @samp{=file} option, if used, must be +the last one. By itself, @samp{-a} defaults to @samp{-ahls}. + +@item -D +Ignored. This option is accepted for script compatibility with calls to +other assemblers. + +@item --defsym @var{sym}=@var{value} +Define the symbol @var{sym} to be @var{value} before assembling the input file. +@var{value} must be an integer constant. As in C, a leading @samp{0x} +indicates a hexadecimal value, and a leading @samp{0} indicates an octal value. + +@item -f +``fast''---skip whitespace and comment preprocessing (assume source is +compiler output). + +@item --gstabs +Generate stabs debugging information for each assembler line. This +may help debugging assembler code, if the debugger can handle it. + +@item --gdwarf2 +Generate DWARF2 debugging information for each assembler line. This +may help debugging assembler code, if the debugger can handle it. Note---this +option is only supported by some targets, not all of them. + +@item --help +Print a summary of the command line options and exit. + +@item --target-help +Print a summary of all target specific options and exit. + +@item -I @var{dir} +Add directory @var{dir} to the search list for @code{.include} directives. + +@item -J +Don't warn about signed overflow. + +@item -K +@ifclear DIFF-TBL-KLUGE +This option is accepted but has no effect on the @value{TARGET} family. +@end ifclear +@ifset DIFF-TBL-KLUGE +Issue warnings when difference tables altered for long displacements. +@end ifset + +@item -L +@itemx --keep-locals +Keep (in the symbol table) local symbols. On traditional a.out systems +these start with @samp{L}, but different systems have different local +label prefixes. + +@item --listing-lhs-width=@var{number} +Set the maximum width, in words, of the output data column for an assembler +listing to @var{number}. + +@item --listing-lhs-width2=@var{number} +Set the maximum width, in words, of the output data column for continuation +lines in an assembler listing to @var{number}. + +@item --listing-rhs-width=@var{number} +Set the maximum width of an input source line, as displayed in a listing, to +@var{number} bytes. + +@item --listing-cont-lines=@var{number} +Set the maximum number of lines printed in a listing for a single line of input +to @var{number} + 1. + +@item -o @var{objfile} +Name the object-file output from @command{@value{AS}} @var{objfile}. + +@item -R +Fold the data section into the text section. + +@item --statistics +Print the maximum space (in bytes) and total time (in seconds) used by +assembly. + +@item --strip-local-absolute +Remove local absolute symbols from the outgoing symbol table. + +@item -v +@itemx -version +Print the @command{as} version. + +@item --version +Print the @command{as} version and exit. + +@item -W +@itemx --no-warn +Suppress warning messages. + +@item --fatal-warnings +Treat warnings as errors. + +@item --warn +Don't suppress warning messages or treat them as errors. + +@item -w +Ignored. + +@item -x +Ignored. + +@item -Z +Generate an object file even after errors. + +@item -- | @var{files} @dots{} +Standard input, or source files to assemble. + +@end table + +@ifset ARC +The following options are available when @value{AS} is configured for +an ARC processor. + +@table @gcctabopt +@item -marc[5|6|7|8] +This option selects the core processor variant. +@item -EB | -EL +Select either big-endian (-EB) or little-endian (-EL) output. +@end table +@end ifset + +@ifset ARM +The following options are available when @value{AS} is configured for the ARM +processor family. + +@table @gcctabopt +@item -mcpu=@var{processor}[+@var{extension}@dots{}] +Specify which ARM processor variant is the target. +@item -march=@var{architecture}[+@var{extension}@dots{}] +Specify which ARM architecture variant is used by the target. +@item -mfpu=@var{floating-point-format} +Select which Floating Point architecture is the target. +@item -mthumb +Enable Thumb only instruction decoding. +@item -mapcs-32 | -mapcs-26 | -mapcs-float | -mapcs-reentrant | -moabi +Select which procedure calling convention is in use. +@item -EB | -EL +Select either big-endian (-EB) or little-endian (-EL) output. +@item -mthumb-interwork +Specify that the code has been generated with interworking between Thumb and +ARM code in mind. +@item -k +Specify that PIC code has been generated. +@end table +@end ifset + +@ifset CRIS +See the info pages for documentation of the CRIS-specific options. +@end ifset + +@ifset D10V +The following options are available when @value{AS} is configured for +a D10V processor. +@table @gcctabopt +@cindex D10V optimization +@cindex optimization, D10V +@item -O +Optimize output by parallelizing instructions. +@end table +@end ifset + +@ifset D30V +The following options are available when @value{AS} is configured for a D30V +processor. +@table @gcctabopt +@cindex D30V optimization +@cindex optimization, D30V +@item -O +Optimize output by parallelizing instructions. + +@cindex D30V nops +@item -n +Warn when nops are generated. + +@cindex D30V nops after 32-bit multiply +@item -N +Warn when a nop after a 32-bit multiply instruction is generated. +@end table +@end ifset + +@ifset I960 +The following options are available when @value{AS} is configured for the +Intel 80960 processor. + +@table @gcctabopt +@item -ACA | -ACA_A | -ACB | -ACC | -AKA | -AKB | -AKC | -AMC +Specify which variant of the 960 architecture is the target. + +@item -b +Add code to collect statistics about branches taken. + +@item -no-relax +Do not alter compare-and-branch instructions for long displacements; +error if necessary. + +@end table +@end ifset + +@ifset IP2K +The following options are available when @value{AS} is configured for the +Ubicom IP2K series. + +@table @gcctabopt + +@item -mip2022ext +Specifies that the extended IP2022 instructions are allowed. + +@item -mip2022 +Restores the default behaviour, which restricts the permitted instructions to +just the basic IP2022 ones. + +@end table +@end ifset + +@ifset M32R +The following options are available when @value{AS} is configured for the +Renesas M32R (formerly Mitsubishi M32R) series. + +@table @gcctabopt + +@item --m32rx +Specify which processor in the M32R family is the target. The default +is normally the M32R, but this option changes it to the M32RX. + +@item --warn-explicit-parallel-conflicts or --Wp +Produce warning messages when questionable parallel constructs are +encountered. + +@item --no-warn-explicit-parallel-conflicts or --Wnp +Do not produce warning messages when questionable parallel constructs are +encountered. + +@end table +@end ifset + +@ifset M680X0 +The following options are available when @value{AS} is configured for the +Motorola 68000 series. + +@table @gcctabopt + +@item -l +Shorten references to undefined symbols, to one word instead of two. + +@item -m68000 | -m68008 | -m68010 | -m68020 | -m68030 +@itemx | -m68040 | -m68060 | -m68302 | -m68331 | -m68332 +@itemx | -m68333 | -m68340 | -mcpu32 | -m5200 +Specify what processor in the 68000 family is the target. The default +is normally the 68020, but this can be changed at configuration time. + +@item -m68881 | -m68882 | -mno-68881 | -mno-68882 +The target machine does (or does not) have a floating-point coprocessor. +The default is to assume a coprocessor for 68020, 68030, and cpu32. Although +the basic 68000 is not compatible with the 68881, a combination of the +two can be specified, since it's possible to do emulation of the +coprocessor instructions with the main processor. + +@item -m68851 | -mno-68851 +The target machine does (or does not) have a memory-management +unit coprocessor. The default is to assume an MMU for 68020 and up. + +@end table +@end ifset + +@ifset PDP11 + +For details about the PDP-11 machine dependent features options, +see @ref{PDP-11-Options}. + +@table @gcctabopt +@item -mpic | -mno-pic +Generate position-independent (or position-dependent) code. The +default is @option{-mpic}. + +@item -mall +@itemx -mall-extensions +Enable all instruction set extensions. This is the default. + +@item -mno-extensions +Disable all instruction set extensions. + +@item -m@var{extension} | -mno-@var{extension} +Enable (or disable) a particular instruction set extension. + +@item -m@var{cpu} +Enable the instruction set extensions supported by a particular CPU, and +disable all other extensions. + +@item -m@var{machine} +Enable the instruction set extensions supported by a particular machine +model, and disable all other extensions. +@end table + +@end ifset + +@ifset PJ +The following options are available when @value{AS} is configured for +a picoJava processor. + +@table @gcctabopt + +@cindex PJ endianness +@cindex endianness, PJ +@cindex big endian output, PJ +@item -mb +Generate ``big endian'' format output. + +@cindex little endian output, PJ +@item -ml +Generate ``little endian'' format output. + +@end table +@end ifset + +@ifset M68HC11 +The following options are available when @value{AS} is configured for the +Motorola 68HC11 or 68HC12 series. + +@table @gcctabopt + +@item -m68hc11 | -m68hc12 | -m68hcs12 +Specify what processor is the target. The default is +defined by the configuration option when building the assembler. + +@item -mshort +Specify to use the 16-bit integer ABI. + +@item -mlong +Specify to use the 32-bit integer ABI. + +@item -mshort-double +Specify to use the 32-bit double ABI. + +@item -mlong-double +Specify to use the 64-bit double ABI. + +@item --force-long-branchs +Relative branches are turned into absolute ones. This concerns +conditional branches, unconditional branches and branches to a +sub routine. + +@item -S | --short-branchs +Do not turn relative branchs into absolute ones +when the offset is out of range. + +@item --strict-direct-mode +Do not turn the direct addressing mode into extended addressing mode +when the instruction does not support direct addressing mode. + +@item --print-insn-syntax +Print the syntax of instruction in case of error. + +@item --print-opcodes +print the list of instructions with syntax and then exit. + +@item --generate-example +print an example of instruction for each possible instruction and then exit. +This option is only useful for testing @command{@value{AS}}. + +@end table +@end ifset + +@ifset SPARC +The following options are available when @command{@value{AS}} is configured +for the SPARC architecture: + +@table @gcctabopt +@item -Av6 | -Av7 | -Av8 | -Asparclet | -Asparclite +@itemx -Av8plus | -Av8plusa | -Av9 | -Av9a +Explicitly select a variant of the SPARC architecture. + +@samp{-Av8plus} and @samp{-Av8plusa} select a 32 bit environment. +@samp{-Av9} and @samp{-Av9a} select a 64 bit environment. + +@samp{-Av8plusa} and @samp{-Av9a} enable the SPARC V9 instruction set with +UltraSPARC extensions. + +@item -xarch=v8plus | -xarch=v8plusa +For compatibility with the Solaris v9 assembler. These options are +equivalent to -Av8plus and -Av8plusa, respectively. + +@item -bump +Warn when the assembler switches to another architecture. +@end table +@end ifset + +@ifset TIC54X +The following options are available when @value{AS} is configured for the 'c54x +architecture. + +@table @gcctabopt +@item -mfar-mode +Enable extended addressing mode. All addresses and relocations will assume +extended addressing (usually 23 bits). +@item -mcpu=@var{CPU_VERSION} +Sets the CPU version being compiled for. +@item -merrors-to-file @var{FILENAME} +Redirect error output to a file, for broken systems which don't support such +behaviour in the shell. +@end table +@end ifset + +@ifset MIPS +The following options are available when @value{AS} is configured for +a @sc{mips} processor. + +@table @gcctabopt +@item -G @var{num} +This option sets the largest size of an object that can be referenced +implicitly with the @code{gp} register. It is only accepted for targets that +use ECOFF format, such as a DECstation running Ultrix. The default value is 8. + +@cindex MIPS endianness +@cindex endianness, MIPS +@cindex big endian output, MIPS +@item -EB +Generate ``big endian'' format output. + +@cindex little endian output, MIPS +@item -EL +Generate ``little endian'' format output. + +@cindex MIPS ISA +@item -mips1 +@itemx -mips2 +@itemx -mips3 +@itemx -mips4 +@itemx -mips5 +@itemx -mips32 +@itemx -mips32r2 +@itemx -mips64 +Generate code for a particular @sc{mips} Instruction Set Architecture level. +@samp{-mips1} is an alias for @samp{-march=r3000}, @samp{-mips2} is an +alias for @samp{-march=r6000}, @samp{-mips3} is an alias for +@samp{-march=r4000} and @samp{-mips4} is an alias for @samp{-march=r8000}. +@samp{-mips5}, @samp{-mips32}, @samp{-mips32r2}, and @samp{-mips64} +correspond to generic +@samp{MIPS V}, @samp{MIPS32}, @samp{MIPS32 Release 2}, and +@samp{MIPS64} ISA processors, +respectively. + +@item -march=@var{CPU} +Generate code for a particular @sc{mips} cpu. + +@item -mtune=@var{cpu} +Schedule and tune for a particular @sc{mips} cpu. + +@item -mfix7000 +@itemx -mno-fix7000 +Cause nops to be inserted if the read of the destination register +of an mfhi or mflo instruction occurs in the following two instructions. + +@item -mdebug +@itemx -no-mdebug +Cause stabs-style debugging output to go into an ECOFF-style .mdebug +section instead of the standard ELF .stabs sections. + +@item -mgp32 +@itemx -mfp32 +The register sizes are normally inferred from the ISA and ABI, but these +flags force a certain group of registers to be treated as 32 bits wide at +all times. @samp{-mgp32} controls the size of general-purpose registers +and @samp{-mfp32} controls the size of floating-point registers. + +@item -mips16 +@itemx -no-mips16 +Generate code for the MIPS 16 processor. This is equivalent to putting +@code{.set mips16} at the start of the assembly file. @samp{-no-mips16} +turns off this option. + +@item -mips3d +@itemx -no-mips3d +Generate code for the MIPS-3D Application Specific Extension. +This tells the assembler to accept MIPS-3D instructions. +@samp{-no-mips3d} turns off this option. + +@item -mdmx +@itemx -no-mdmx +Generate code for the MDMX Application Specific Extension. +This tells the assembler to accept MDMX instructions. +@samp{-no-mdmx} turns off this option. + +@item --construct-floats +@itemx --no-construct-floats +The @samp{--no-construct-floats} option disables the construction of +double width floating point constants by loading the two halves of the +value into the two single width floating point registers that make up +the double width register. By default @samp{--construct-floats} is +selected, allowing construction of these floating point constants. + +@cindex emulation +@item --emulation=@var{name} +This option causes @command{@value{AS}} to emulate @command{@value{AS}} configured +for some other target, in all respects, including output format (choosing +between ELF and ECOFF only), handling of pseudo-opcodes which may generate +debugging information or store symbol table information, and default +endianness. The available configuration names are: @samp{mipsecoff}, +@samp{mipself}, @samp{mipslecoff}, @samp{mipsbecoff}, @samp{mipslelf}, +@samp{mipsbelf}. The first two do not alter the default endianness from that +of the primary target for which the assembler was configured; the others change +the default to little- or big-endian as indicated by the @samp{b} or @samp{l} +in the name. Using @samp{-EB} or @samp{-EL} will override the endianness +selection in any case. + +This option is currently supported only when the primary target +@command{@value{AS}} is configured for is a @sc{mips} ELF or ECOFF target. +Furthermore, the primary target or others specified with +@samp{--enable-targets=@dots{}} at configuration time must include support for +the other format, if both are to be available. For example, the Irix 5 +configuration includes support for both. + +Eventually, this option will support more configurations, with more +fine-grained control over the assembler's behavior, and will be supported for +more processors. + +@item -nocpp +@command{@value{AS}} ignores this option. It is accepted for compatibility with +the native tools. + +@item --trap +@itemx --no-trap +@itemx --break +@itemx --no-break +Control how to deal with multiplication overflow and division by zero. +@samp{--trap} or @samp{--no-break} (which are synonyms) take a trap exception +(and only work for Instruction Set Architecture level 2 and higher); +@samp{--break} or @samp{--no-trap} (also synonyms, and the default) take a +break exception. + +@item -n +When this option is used, @command{@value{AS}} will issue a warning every +time it generates a nop instruction from a macro. +@end table +@end ifset + +@ifset MCORE +The following options are available when @value{AS} is configured for +an MCore processor. + +@table @gcctabopt +@item -jsri2bsr +@itemx -nojsri2bsr +Enable or disable the JSRI to BSR transformation. By default this is enabled. +The command line option @samp{-nojsri2bsr} can be used to disable it. + +@item -sifilter +@itemx -nosifilter +Enable or disable the silicon filter behaviour. By default this is disabled. +The default can be overridden by the @samp{-sifilter} command line option. + +@item -relax +Alter jump instructions for long displacements. + +@item -mcpu=[210|340] +Select the cpu type on the target hardware. This controls which instructions +can be assembled. + +@item -EB +Assemble for a big endian target. + +@item -EL +Assemble for a little endian target. + +@end table +@end ifset + +@ifset MMIX +See the info pages for documentation of the MMIX-specific options. +@end ifset + +@ifset XTENSA +The following options are available when @value{AS} is configured for +an Xtensa processor. + +@table @gcctabopt +@item --density | --no-density +Enable or disable use of instructions from the Xtensa code density +option. This is enabled by default when the Xtensa processor supports +the code density option. + +@item --relax | --no-relax +Enable or disable instruction relaxation. This is enabled by default. +Note: In the current implementation, these options also control whether +assembler optimizations are performed, making these options equivalent +to @option{--generics} and @option{--no-generics}. + +@item --generics | --no-generics +Enable or disable all assembler transformations of Xtensa instructions. +The default is @option{--generics}; +@option{--no-generics} should be used only in the rare cases when the +instructions must be exactly as specified in the assembly source. + +@item --text-section-literals | --no-text-section-literals +With @option{--text-@-section-@-literals}, literal pools are interspersed +in the text section. The default is +@option{--no-@-text-@-section-@-literals}, which places literals in a +separate section in the output file. + +@item --target-align | --no-target-align +Enable or disable automatic alignment to reduce branch penalties at the +expense of some code density. The default is @option{--target-@-align}. + +@item --longcalls | --no-longcalls +Enable or disable transformation of call instructions to allow calls +across a greater range of addresses. The default is +@option{--no-@-longcalls}. +@end table +@end ifset + +@c man end + +@menu +* Manual:: Structure of this Manual +* GNU Assembler:: The GNU Assembler +* Object Formats:: Object File Formats +* Command Line:: Command Line +* Input Files:: Input Files +* Object:: Output (Object) File +* Errors:: Error and Warning Messages +@end menu + +@node Manual +@section Structure of this Manual + +@cindex manual, structure and purpose +This manual is intended to describe what you need to know to use +@sc{gnu} @command{@value{AS}}. We cover the syntax expected in source files, including +notation for symbols, constants, and expressions; the directives that +@command{@value{AS}} understands; and of course how to invoke @command{@value{AS}}. + +@ifclear GENERIC +We also cover special features in the @value{TARGET} +configuration of @command{@value{AS}}, including assembler directives. +@end ifclear +@ifset GENERIC +This manual also describes some of the machine-dependent features of +various flavors of the assembler. +@end ifset + +@cindex machine instructions (not covered) +On the other hand, this manual is @emph{not} intended as an introduction +to programming in assembly language---let alone programming in general! +In a similar vein, we make no attempt to introduce the machine +architecture; we do @emph{not} describe the instruction set, standard +mnemonics, registers or addressing modes that are standard to a +particular architecture. +@ifset GENERIC +You may want to consult the manufacturer's +machine architecture manual for this information. +@end ifset +@ifclear GENERIC +@ifset H8/300 +For information on the H8/300 machine instruction set, see @cite{H8/300 +Series Programming Manual}. For the H8/300H, see @cite{H8/300H Series +Programming Manual} (Renesas). +@end ifset +@ifset H8/500 +For information on the H8/500 machine instruction set, see @cite{H8/500 +Series Programming Manual} (Renesas M21T001). +@end ifset +@ifset SH +For information on the Renesas (formerly Hitachi) / SuperH SH machine instruction set, +see @cite{SH-Microcomputer User's Manual} (Renesas) or +@cite{SH-4 32-bit CPU Core Architecture} (SuperH) and +@cite{SuperH (SH) 64-Bit RISC Series} (SuperH). +@end ifset +@ifset Z8000 +For information on the Z8000 machine instruction set, see @cite{Z8000 CPU Technical Manual} +@end ifset +@end ifclear + +@c I think this is premature---doc@cygnus.com, 17jan1991 +@ignore +Throughout this manual, we assume that you are running @dfn{GNU}, +the portable operating system from the @dfn{Free Software +Foundation, Inc.}. This restricts our attention to certain kinds of +computer (in particular, the kinds of computers that @sc{gnu} can run on); +once this assumption is granted examples and definitions need less +qualification. + +@command{@value{AS}} is part of a team of programs that turn a high-level +human-readable series of instructions into a low-level +computer-readable series of instructions. Different versions of +@command{@value{AS}} are used for different kinds of computer. +@end ignore + +@c There used to be a section "Terminology" here, which defined +@c "contents", "byte", "word", and "long". Defining "word" to any +@c particular size is confusing when the .word directive may generate 16 +@c bits on one machine and 32 bits on another; in general, for the user +@c version of this manual, none of these terms seem essential to define. +@c They were used very little even in the former draft of the manual; +@c this draft makes an effort to avoid them (except in names of +@c directives). + +@node GNU Assembler +@section The GNU Assembler + +@c man begin DESCRIPTION + +@sc{gnu} @command{as} is really a family of assemblers. +@ifclear GENERIC +This manual describes @command{@value{AS}}, a member of that family which is +configured for the @value{TARGET} architectures. +@end ifclear +If you use (or have used) the @sc{gnu} assembler on one architecture, you +should find a fairly similar environment when you use it on another +architecture. Each version has much in common with the others, +including object file formats, most assembler directives (often called +@dfn{pseudo-ops}) and assembler syntax.@refill + +@cindex purpose of @sc{gnu} assembler +@command{@value{AS}} is primarily intended to assemble the output of the +@sc{gnu} C compiler @code{@value{GCC}} for use by the linker +@code{@value{LD}}. Nevertheless, we've tried to make @command{@value{AS}} +assemble correctly everything that other assemblers for the same +machine would assemble. +@ifset VAX +Any exceptions are documented explicitly (@pxref{Machine Dependencies}). +@end ifset +@ifset M680X0 +@c This remark should appear in generic version of manual; assumption +@c here is that generic version sets M680x0. +This doesn't mean @command{@value{AS}} always uses the same syntax as another +assembler for the same architecture; for example, we know of several +incompatible versions of 680x0 assembly language syntax. +@end ifset + +@c man end + +Unlike older assemblers, @command{@value{AS}} is designed to assemble a source +program in one pass of the source file. This has a subtle impact on the +@kbd{.org} directive (@pxref{Org,,@code{.org}}). + +@node Object Formats +@section Object File Formats + +@cindex object file format +The @sc{gnu} assembler can be configured to produce several alternative +object file formats. For the most part, this does not affect how you +write assembly language programs; but directives for debugging symbols +are typically different in different file formats. @xref{Symbol +Attributes,,Symbol Attributes}. +@ifclear GENERIC +@ifclear MULTI-OBJ +For the @value{TARGET} target, @command{@value{AS}} is configured to produce +@value{OBJ-NAME} format object files. +@end ifclear +@c The following should exhaust all configs that set MULTI-OBJ, ideally +@ifset A29K +On the @value{TARGET}, @command{@value{AS}} can be configured to produce either +@code{a.out} or COFF format object files. +@end ifset +@ifset I960 +On the @value{TARGET}, @command{@value{AS}} can be configured to produce either +@code{b.out} or COFF format object files. +@end ifset +@ifset HPPA +On the @value{TARGET}, @command{@value{AS}} can be configured to produce either +SOM or ELF format object files. +@end ifset +@end ifclear + +@node Command Line +@section Command Line + +@cindex command line conventions + +After the program name @command{@value{AS}}, the command line may contain +options and file names. Options may appear in any order, and may be +before, after, or between file names. The order of file names is +significant. + +@cindex standard input, as input file +@kindex -- +@file{--} (two hyphens) by itself names the standard input file +explicitly, as one of the files for @command{@value{AS}} to assemble. + +@cindex options, command line +Except for @samp{--} any command line argument that begins with a +hyphen (@samp{-}) is an option. Each option changes the behavior of +@command{@value{AS}}. No option changes the way another option works. An +option is a @samp{-} followed by one or more letters; the case of +the letter is important. All options are optional. + +Some options expect exactly one file name to follow them. The file +name may either immediately follow the option's letter (compatible +with older assemblers) or it may be the next command argument (@sc{gnu} +standard). These two command lines are equivalent: + +@smallexample +@value{AS} -o my-object-file.o mumble.s +@value{AS} -omy-object-file.o mumble.s +@end smallexample + +@node Input Files +@section Input Files + +@cindex input +@cindex source program +@cindex files, input +We use the phrase @dfn{source program}, abbreviated @dfn{source}, to +describe the program input to one run of @command{@value{AS}}. The program may +be in one or more files; how the source is partitioned into files +doesn't change the meaning of the source. + +@c I added "con" prefix to "catenation" just to prove I can overcome my +@c APL training... doc@cygnus.com +The source program is a concatenation of the text in all the files, in the +order specified. + +@c man begin DESCRIPTION +Each time you run @command{@value{AS}} it assembles exactly one source +program. The source program is made up of one or more files. +(The standard input is also a file.) + +You give @command{@value{AS}} a command line that has zero or more input file +names. The input files are read (from left file name to right). A +command line argument (in any position) that has no special meaning +is taken to be an input file name. + +If you give @command{@value{AS}} no file names it attempts to read one input file +from the @command{@value{AS}} standard input, which is normally your terminal. You +may have to type @key{ctl-D} to tell @command{@value{AS}} there is no more program +to assemble. + +Use @samp{--} if you need to explicitly name the standard input file +in your command line. + +If the source is empty, @command{@value{AS}} produces a small, empty object +file. + +@c man end + +@subheading Filenames and Line-numbers + +@cindex input file linenumbers +@cindex line numbers, in input files +There are two ways of locating a line in the input file (or files) and +either may be used in reporting error messages. One way refers to a line +number in a physical file; the other refers to a line number in a +``logical'' file. @xref{Errors, ,Error and Warning Messages}. + +@dfn{Physical files} are those files named in the command line given +to @command{@value{AS}}. + +@dfn{Logical files} are simply names declared explicitly by assembler +directives; they bear no relation to physical files. Logical file names help +error messages reflect the original source file, when @command{@value{AS}} source +is itself synthesized from other files. @command{@value{AS}} understands the +@samp{#} directives emitted by the @code{@value{GCC}} preprocessor. See also +@ref{File,,@code{.file}}. + +@node Object +@section Output (Object) File + +@cindex object file +@cindex output file +@kindex a.out +@kindex .o +Every time you run @command{@value{AS}} it produces an output file, which is +your assembly language program translated into numbers. This file +is the object file. Its default name is +@ifclear BOUT +@code{a.out}. +@end ifclear +@ifset BOUT +@ifset GENERIC +@code{a.out}, or +@end ifset +@code{b.out} when @command{@value{AS}} is configured for the Intel 80960. +@end ifset +You can give it another name by using the @option{-o} option. Conventionally, +object file names end with @file{.o}. The default name is used for historical +reasons: older assemblers were capable of assembling self-contained programs +directly into a runnable program. (For some formats, this isn't currently +possible, but it can be done for the @code{a.out} format.) + +@cindex linker +@kindex ld +The object file is meant for input to the linker @code{@value{LD}}. It contains +assembled program code, information to help @code{@value{LD}} integrate +the assembled program into a runnable file, and (optionally) symbolic +information for the debugger. + +@c link above to some info file(s) like the description of a.out. +@c don't forget to describe @sc{gnu} info as well as Unix lossage. + +@node Errors +@section Error and Warning Messages + +@c man begin DESCRIPTION + +@cindex error messages +@cindex warning messages +@cindex messages from assembler +@command{@value{AS}} may write warnings and error messages to the standard error +file (usually your terminal). This should not happen when a compiler +runs @command{@value{AS}} automatically. Warnings report an assumption made so +that @command{@value{AS}} could keep assembling a flawed program; errors report a +grave problem that stops the assembly. + +@c man end + +@cindex format of warning messages +Warning messages have the format + +@smallexample +file_name:@b{NNN}:Warning Message Text +@end smallexample + +@noindent +@cindex line numbers, in warnings/errors +(where @b{NNN} is a line number). If a logical file name has been given +(@pxref{File,,@code{.file}}) it is used for the filename, otherwise the name of +the current input file is used. If a logical line number was given +@ifset GENERIC +(@pxref{Line,,@code{.line}}) +@end ifset +@ifclear GENERIC +@ifclear A29K +(@pxref{Line,,@code{.line}}) +@end ifclear +@ifset A29K +(@pxref{Ln,,@code{.ln}}) +@end ifset +@end ifclear +then it is used to calculate the number printed, +otherwise the actual line in the current source file is printed. The +message text is intended to be self explanatory (in the grand Unix +tradition). + +@cindex format of error messages +Error messages have the format +@smallexample +file_name:@b{NNN}:FATAL:Error Message Text +@end smallexample +The file name and line number are derived as for warning +messages. The actual message text may be rather less explanatory +because many of them aren't supposed to happen. + +@node Invoking +@chapter Command-Line Options + +@cindex options, all versions of assembler +This chapter describes command-line options available in @emph{all} +versions of the @sc{gnu} assembler; @pxref{Machine Dependencies}, for options specific +@ifclear GENERIC +to the @value{TARGET} target. +@end ifclear +@ifset GENERIC +to particular machine architectures. +@end ifset + +@c man begin DESCRIPTION + +If you are invoking @command{@value{AS}} via the @sc{gnu} C compiler, +you can use the @samp{-Wa} option to pass arguments through to the assembler. +The assembler arguments must be separated from each other (and the @samp{-Wa}) +by commas. For example: + +@smallexample +gcc -c -g -O -Wa,-alh,-L file.c +@end smallexample + +@noindent +This passes two options to the assembler: @samp{-alh} (emit a listing to +standard output with high-level and assembly source) and @samp{-L} (retain +local symbols in the symbol table). + +Usually you do not need to use this @samp{-Wa} mechanism, since many compiler +command-line options are automatically passed to the assembler by the compiler. +(You can call the @sc{gnu} compiler driver with the @samp{-v} option to see +precisely what options it passes to each compilation pass, including the +assembler.) + +@c man end + +@menu +* a:: -a[cdhlns] enable listings +* D:: -D for compatibility +* f:: -f to work faster +* I:: -I for .include search path +@ifclear DIFF-TBL-KLUGE +* K:: -K for compatibility +@end ifclear +@ifset DIFF-TBL-KLUGE +* K:: -K for difference tables +@end ifset + +* L:: -L to retain local labels +* listing:: --listing-XXX to configure listing output +* M:: -M or --mri to assemble in MRI compatibility mode +* MD:: --MD for dependency tracking +* o:: -o to name the object file +* R:: -R to join data and text sections +* statistics:: --statistics to see statistics about assembly +* traditional-format:: --traditional-format for compatible output +* v:: -v to announce version +* W:: -W, --no-warn, --warn, --fatal-warnings to control warnings +* Z:: -Z to make object file even after errors +@end menu + +@node a +@section Enable Listings: @option{-a[cdhlns]} + +@kindex -a +@kindex -ac +@kindex -ad +@kindex -ah +@kindex -al +@kindex -an +@kindex -as +@cindex listings, enabling +@cindex assembly listings, enabling + +These options enable listing output from the assembler. By itself, +@samp{-a} requests high-level, assembly, and symbols listing. +You can use other letters to select specific options for the list: +@samp{-ah} requests a high-level language listing, +@samp{-al} requests an output-program assembly listing, and +@samp{-as} requests a symbol table listing. +High-level listings require that a compiler debugging option like +@samp{-g} be used, and that assembly listings (@samp{-al}) be requested +also. + +Use the @samp{-ac} option to omit false conditionals from a listing. Any lines +which are not assembled because of a false @code{.if} (or @code{.ifdef}, or any +other conditional), or a true @code{.if} followed by an @code{.else}, will be +omitted from the listing. + +Use the @samp{-ad} option to omit debugging directives from the +listing. + +Once you have specified one of these options, you can further control +listing output and its appearance using the directives @code{.list}, +@code{.nolist}, @code{.psize}, @code{.eject}, @code{.title}, and +@code{.sbttl}. +The @samp{-an} option turns off all forms processing. +If you do not request listing output with one of the @samp{-a} options, the +listing-control directives have no effect. + +The letters after @samp{-a} may be combined into one option, +@emph{e.g.}, @samp{-aln}. + +Note if the assembler source is coming from the standard input (eg because it +is being created by @code{@value{GCC}} and the @samp{-pipe} command line switch +is being used) then the listing will not contain any comments or preprocessor +directives. This is because the listing code buffers input source lines from +stdin only after they have been preprocessed by the assembler. This reduces +memory usage and makes the code more efficient. + +@node D +@section @option{-D} + +@kindex -D +This option has no effect whatsoever, but it is accepted to make it more +likely that scripts written for other assemblers also work with +@command{@value{AS}}. + +@node f +@section Work Faster: @option{-f} + +@kindex -f +@cindex trusted compiler +@cindex faster processing (@option{-f}) +@samp{-f} should only be used when assembling programs written by a +(trusted) compiler. @samp{-f} stops the assembler from doing whitespace +and comment preprocessing on +the input file(s) before assembling them. @xref{Preprocessing, +,Preprocessing}. + +@quotation +@emph{Warning:} if you use @samp{-f} when the files actually need to be +preprocessed (if they contain comments, for example), @command{@value{AS}} does +not work correctly. +@end quotation + +@node I +@section @code{.include} Search Path: @option{-I} @var{path} + +@kindex -I @var{path} +@cindex paths for @code{.include} +@cindex search path for @code{.include} +@cindex @code{include} directive search path +Use this option to add a @var{path} to the list of directories +@command{@value{AS}} searches for files specified in @code{.include} +directives (@pxref{Include,,@code{.include}}). You may use @option{-I} as +many times as necessary to include a variety of paths. The current +working directory is always searched first; after that, @command{@value{AS}} +searches any @samp{-I} directories in the same order as they were +specified (left to right) on the command line. + +@node K +@section Difference Tables: @option{-K} + +@kindex -K +@ifclear DIFF-TBL-KLUGE +On the @value{TARGET} family, this option is allowed, but has no effect. It is +permitted for compatibility with the @sc{gnu} assembler on other platforms, +where it can be used to warn when the assembler alters the machine code +generated for @samp{.word} directives in difference tables. The @value{TARGET} +family does not have the addressing limitations that sometimes lead to this +alteration on other platforms. +@end ifclear + +@ifset DIFF-TBL-KLUGE +@cindex difference tables, warning +@cindex warning for altered difference tables +@command{@value{AS}} sometimes alters the code emitted for directives of the form +@samp{.word @var{sym1}-@var{sym2}}; @pxref{Word,,@code{.word}}. +You can use the @samp{-K} option if you want a warning issued when this +is done. +@end ifset + +@node L +@section Include Local Labels: @option{-L} + +@kindex -L +@cindex local labels, retaining in output +Labels beginning with @samp{L} (upper case only) are called @dfn{local +labels}. @xref{Symbol Names}. Normally you do not see such labels when +debugging, because they are intended for the use of programs (like +compilers) that compose assembler programs, not for your notice. +Normally both @command{@value{AS}} and @code{@value{LD}} discard such labels, so you do not +normally debug with them. + +This option tells @command{@value{AS}} to retain those @samp{L@dots{}} symbols +in the object file. Usually if you do this you also tell the linker +@code{@value{LD}} to preserve symbols whose names begin with @samp{L}. + +By default, a local label is any label beginning with @samp{L}, but each +target is allowed to redefine the local label prefix. +@ifset HPPA +On the HPPA local labels begin with @samp{L$}. +@end ifset + +@node listing +@section Configuring listing output: @option{--listing} + +The listing feature of the assembler can be enabled via the command line switch +@samp{-a} (@pxref{a}). This feature combines the input source file(s) with a +hex dump of the corresponding locations in the output object file, and displays +them as a listing file. The format of this listing can be controlled by pseudo +ops inside the assembler source (@pxref{List} @pxref{Title} @pxref{Sbttl} +@pxref{Psize} @pxref{Eject}) and also by the following switches: + +@table @gcctabopt +@item --listing-lhs-width=@samp{number} +@kindex --listing-lhs-width +@cindex Width of first line disassembly output +Sets the maximum width, in words, of the first line of the hex byte dump. This +dump appears on the left hand side of the listing output. + +@item --listing-lhs-width2=@samp{number} +@kindex --listing-lhs-width2 +@cindex Width of continuation lines of disassembly output +Sets the maximum width, in words, of any further lines of the hex byte dump for +a given input source line. If this value is not specified, it defaults to being +the same as the value specified for @samp{--listing-lhs-width}. If neither +switch is used the default is to one. + +@item --listing-rhs-width=@samp{number} +@kindex --listing-rhs-width +@cindex Width of source line output +Sets the maximum width, in characters, of the source line that is displayed +alongside the hex dump. The default value for this parameter is 100. The +source line is displayed on the right hand side of the listing output. + +@item --listing-cont-lines=@samp{number} +@kindex --listing-cont-lines +@cindex Maximum number of continuation lines +Sets the maximum number of continuation lines of hex dump that will be +displayed for a given single line of source input. The default value is 4. +@end table + +@node M +@section Assemble in MRI Compatibility Mode: @option{-M} + +@kindex -M +@cindex MRI compatibility mode +The @option{-M} or @option{--mri} option selects MRI compatibility mode. This +changes the syntax and pseudo-op handling of @command{@value{AS}} to make it +compatible with the @code{ASM68K} or the @code{ASM960} (depending upon the +configured target) assembler from Microtec Research. The exact nature of the +MRI syntax will not be documented here; see the MRI manuals for more +information. Note in particular that the handling of macros and macro +arguments is somewhat different. The purpose of this option is to permit +assembling existing MRI assembler code using @command{@value{AS}}. + +The MRI compatibility is not complete. Certain operations of the MRI assembler +depend upon its object file format, and can not be supported using other object +file formats. Supporting these would require enhancing each object file format +individually. These are: + +@itemize @bullet +@item global symbols in common section + +The m68k MRI assembler supports common sections which are merged by the linker. +Other object file formats do not support this. @command{@value{AS}} handles +common sections by treating them as a single common symbol. It permits local +symbols to be defined within a common section, but it can not support global +symbols, since it has no way to describe them. + +@item complex relocations + +The MRI assemblers support relocations against a negated section address, and +relocations which combine the start addresses of two or more sections. These +are not support by other object file formats. + +@item @code{END} pseudo-op specifying start address + +The MRI @code{END} pseudo-op permits the specification of a start address. +This is not supported by other object file formats. The start address may +instead be specified using the @option{-e} option to the linker, or in a linker +script. + +@item @code{IDNT}, @code{.ident} and @code{NAME} pseudo-ops + +The MRI @code{IDNT}, @code{.ident} and @code{NAME} pseudo-ops assign a module +name to the output file. This is not supported by other object file formats. + +@item @code{ORG} pseudo-op + +The m68k MRI @code{ORG} pseudo-op begins an absolute section at a given +address. This differs from the usual @command{@value{AS}} @code{.org} pseudo-op, +which changes the location within the current section. Absolute sections are +not supported by other object file formats. The address of a section may be +assigned within a linker script. +@end itemize + +There are some other features of the MRI assembler which are not supported by +@command{@value{AS}}, typically either because they are difficult or because they +seem of little consequence. Some of these may be supported in future releases. + +@itemize @bullet + +@item EBCDIC strings + +EBCDIC strings are not supported. + +@item packed binary coded decimal + +Packed binary coded decimal is not supported. This means that the @code{DC.P} +and @code{DCB.P} pseudo-ops are not supported. + +@item @code{FEQU} pseudo-op + +The m68k @code{FEQU} pseudo-op is not supported. + +@item @code{NOOBJ} pseudo-op + +The m68k @code{NOOBJ} pseudo-op is not supported. + +@item @code{OPT} branch control options + +The m68k @code{OPT} branch control options---@code{B}, @code{BRS}, @code{BRB}, +@code{BRL}, and @code{BRW}---are ignored. @command{@value{AS}} automatically +relaxes all branches, whether forward or backward, to an appropriate size, so +these options serve no purpose. + +@item @code{OPT} list control options + +The following m68k @code{OPT} list control options are ignored: @code{C}, +@code{CEX}, @code{CL}, @code{CRE}, @code{E}, @code{G}, @code{I}, @code{M}, +@code{MEX}, @code{MC}, @code{MD}, @code{X}. + +@item other @code{OPT} options + +The following m68k @code{OPT} options are ignored: @code{NEST}, @code{O}, +@code{OLD}, @code{OP}, @code{P}, @code{PCO}, @code{PCR}, @code{PCS}, @code{R}. + +@item @code{OPT} @code{D} option is default + +The m68k @code{OPT} @code{D} option is the default, unlike the MRI assembler. +@code{OPT NOD} may be used to turn it off. + +@item @code{XREF} pseudo-op. + +The m68k @code{XREF} pseudo-op is ignored. + +@item @code{.debug} pseudo-op + +The i960 @code{.debug} pseudo-op is not supported. + +@item @code{.extended} pseudo-op + +The i960 @code{.extended} pseudo-op is not supported. + +@item @code{.list} pseudo-op. + +The various options of the i960 @code{.list} pseudo-op are not supported. + +@item @code{.optimize} pseudo-op + +The i960 @code{.optimize} pseudo-op is not supported. + +@item @code{.output} pseudo-op + +The i960 @code{.output} pseudo-op is not supported. + +@item @code{.setreal} pseudo-op + +The i960 @code{.setreal} pseudo-op is not supported. + +@end itemize + +@node MD +@section Dependency Tracking: @option{--MD} + +@kindex --MD +@cindex dependency tracking +@cindex make rules + +@command{@value{AS}} can generate a dependency file for the file it creates. This +file consists of a single rule suitable for @code{make} describing the +dependencies of the main source file. + +The rule is written to the file named in its argument. + +This feature is used in the automatic updating of makefiles. + +@node o +@section Name the Object File: @option{-o} + +@kindex -o +@cindex naming object file +@cindex object file name +There is always one object file output when you run @command{@value{AS}}. By +default it has the name +@ifset GENERIC +@ifset I960 +@file{a.out} (or @file{b.out}, for Intel 960 targets only). +@end ifset +@ifclear I960 +@file{a.out}. +@end ifclear +@end ifset +@ifclear GENERIC +@ifset I960 +@file{b.out}. +@end ifset +@ifclear I960 +@file{a.out}. +@end ifclear +@end ifclear +You use this option (which takes exactly one filename) to give the +object file a different name. + +Whatever the object file is called, @command{@value{AS}} overwrites any +existing file of the same name. + +@node R +@section Join Data and Text Sections: @option{-R} + +@kindex -R +@cindex data and text sections, joining +@cindex text and data sections, joining +@cindex joining text and data sections +@cindex merging text and data sections +@option{-R} tells @command{@value{AS}} to write the object file as if all +data-section data lives in the text section. This is only done at +the very last moment: your binary data are the same, but data +section parts are relocated differently. The data section part of +your object file is zero bytes long because all its bytes are +appended to the text section. (@xref{Sections,,Sections and Relocation}.) + +When you specify @option{-R} it would be possible to generate shorter +address displacements (because we do not have to cross between text and +data section). We refrain from doing this simply for compatibility with +older versions of @command{@value{AS}}. In future, @option{-R} may work this way. + +@ifset COFF-ELF +When @command{@value{AS}} is configured for COFF or ELF output, +this option is only useful if you use sections named @samp{.text} and +@samp{.data}. +@end ifset + +@ifset HPPA +@option{-R} is not supported for any of the HPPA targets. Using +@option{-R} generates a warning from @command{@value{AS}}. +@end ifset + +@node statistics +@section Display Assembly Statistics: @option{--statistics} + +@kindex --statistics +@cindex statistics, about assembly +@cindex time, total for assembly +@cindex space used, maximum for assembly +Use @samp{--statistics} to display two statistics about the resources used by +@command{@value{AS}}: the maximum amount of space allocated during the assembly +(in bytes), and the total execution time taken for the assembly (in @sc{cpu} +seconds). + +@node traditional-format +@section Compatible Output: @option{--traditional-format} + +@kindex --traditional-format +For some targets, the output of @command{@value{AS}} is different in some ways +from the output of some existing assembler. This switch requests +@command{@value{AS}} to use the traditional format instead. + +For example, it disables the exception frame optimizations which +@command{@value{AS}} normally does by default on @code{@value{GCC}} output. + +@node v +@section Announce Version: @option{-v} + +@kindex -v +@kindex -version +@cindex assembler version +@cindex version of assembler +You can find out what version of as is running by including the +option @samp{-v} (which you can also spell as @samp{-version}) on the +command line. + +@node W +@section Control Warnings: @option{-W}, @option{--warn}, @option{--no-warn}, @option{--fatal-warnings} + +@command{@value{AS}} should never give a warning or error message when +assembling compiler output. But programs written by people often +cause @command{@value{AS}} to give a warning that a particular assumption was +made. All such warnings are directed to the standard error file. + +@kindex -W +@kindex --no-warn +@cindex suppressing warnings +@cindex warnings, suppressing +If you use the @option{-W} and @option{--no-warn} options, no warnings are issued. +This only affects the warning messages: it does not change any particular of +how @command{@value{AS}} assembles your file. Errors, which stop the assembly, +are still reported. + +@kindex --fatal-warnings +@cindex errors, caused by warnings +@cindex warnings, causing error +If you use the @option{--fatal-warnings} option, @command{@value{AS}} considers +files that generate warnings to be in error. + +@kindex --warn +@cindex warnings, switching on +You can switch these options off again by specifying @option{--warn}, which +causes warnings to be output as usual. + +@node Z +@section Generate Object File in Spite of Errors: @option{-Z} +@cindex object file, after errors +@cindex errors, continuing after +After an error message, @command{@value{AS}} normally produces no output. If for +some reason you are interested in object file output even after +@command{@value{AS}} gives an error message on your program, use the @samp{-Z} +option. If there are any errors, @command{@value{AS}} continues anyways, and +writes an object file after a final warning message of the form @samp{@var{n} +errors, @var{m} warnings, generating bad object file.} + +@node Syntax +@chapter Syntax + +@cindex machine-independent syntax +@cindex syntax, machine-independent +This chapter describes the machine-independent syntax allowed in a +source file. @command{@value{AS}} syntax is similar to what many other +assemblers use; it is inspired by the BSD 4.2 +@ifclear VAX +assembler. +@end ifclear +@ifset VAX +assembler, except that @command{@value{AS}} does not assemble Vax bit-fields. +@end ifset + +@menu +* Preprocessing:: Preprocessing +* Whitespace:: Whitespace +* Comments:: Comments +* Symbol Intro:: Symbols +* Statements:: Statements +* Constants:: Constants +@end menu + +@node Preprocessing +@section Preprocessing + +@cindex preprocessing +The @command{@value{AS}} internal preprocessor: +@itemize @bullet +@cindex whitespace, removed by preprocessor +@item +adjusts and removes extra whitespace. It leaves one space or tab before +the keywords on a line, and turns any other whitespace on the line into +a single space. + +@cindex comments, removed by preprocessor +@item +removes all comments, replacing them with a single space, or an +appropriate number of newlines. + +@cindex constants, converted by preprocessor +@item +converts character constants into the appropriate numeric values. +@end itemize + +It does not do macro processing, include file handling, or +anything else you may get from your C compiler's preprocessor. You can +do include file processing with the @code{.include} directive +(@pxref{Include,,@code{.include}}). You can use the @sc{gnu} C compiler driver +to get other ``CPP'' style preprocessing by giving the input file a +@samp{.S} suffix. @xref{Overall Options,, Options Controlling the Kind of +Output, gcc.info, Using GNU CC}. + +Excess whitespace, comments, and character constants +cannot be used in the portions of the input text that are not +preprocessed. + +@cindex turning preprocessing on and off +@cindex preprocessing, turning on and off +@kindex #NO_APP +@kindex #APP +If the first line of an input file is @code{#NO_APP} or if you use the +@samp{-f} option, whitespace and comments are not removed from the input file. +Within an input file, you can ask for whitespace and comment removal in +specific portions of the by putting a line that says @code{#APP} before the +text that may contain whitespace or comments, and putting a line that says +@code{#NO_APP} after this text. This feature is mainly intend to support +@code{asm} statements in compilers whose output is otherwise free of comments +and whitespace. + +@node Whitespace +@section Whitespace + +@cindex whitespace +@dfn{Whitespace} is one or more blanks or tabs, in any order. +Whitespace is used to separate symbols, and to make programs neater for +people to read. Unless within character constants +(@pxref{Characters,,Character Constants}), any whitespace means the same +as exactly one space. + +@node Comments +@section Comments + +@cindex comments +There are two ways of rendering comments to @command{@value{AS}}. In both +cases the comment is equivalent to one space. + +Anything from @samp{/*} through the next @samp{*/} is a comment. +This means you may not nest these comments. + +@smallexample +/* + The only way to include a newline ('\n') in a comment + is to use this sort of comment. +*/ + +/* This sort of comment does not nest. */ +@end smallexample + +@cindex line comment character +Anything from the @dfn{line comment} character to the next newline +is considered a comment and is ignored. The line comment character is +@ifset A29K +@samp{;} for the AMD 29K family; +@end ifset +@ifset ARC +@samp{;} on the ARC; +@end ifset +@ifset ARM +@samp{@@} on the ARM; +@end ifset +@ifset H8/300 +@samp{;} for the H8/300 family; +@end ifset +@ifset H8/500 +@samp{!} for the H8/500 family; +@end ifset +@ifset HPPA +@samp{;} for the HPPA; +@end ifset +@ifset I80386 +@samp{#} on the i386 and x86-64; +@end ifset +@ifset I960 +@samp{#} on the i960; +@end ifset +@ifset PDP11 +@samp{;} for the PDP-11; +@end ifset +@ifset PJ +@samp{;} for picoJava; +@end ifset +@ifset PPC +@samp{;} for Motorola PowerPC; +@end ifset +@ifset SH +@samp{!} for the Renesas / SuperH SH; +@end ifset +@ifset SPARC +@samp{!} on the SPARC; +@end ifset +@ifset IP2K +@samp{#} on the ip2k; +@end ifset +@ifset M32R +@samp{#} on the m32r; +@end ifset +@ifset M680X0 +@samp{|} on the 680x0; +@end ifset +@ifset M68HC11 +@samp{#} on the 68HC11 and 68HC12; +@end ifset +@ifset M880X0 +@samp{;} on the M880x0; +@end ifset +@ifset VAX +@samp{#} on the Vax; +@end ifset +@ifset Z8000 +@samp{!} for the Z8000; +@end ifset +@ifset V850 +@samp{#} on the V850; +@end ifset +@ifset XTENSA +@samp{#} for Xtensa systems; +@end ifset +see @ref{Machine Dependencies}. @refill +@c FIXME What about i860? + +@ifset GENERIC +On some machines there are two different line comment characters. One +character only begins a comment if it is the first non-whitespace character on +a line, while the other always begins a comment. +@end ifset + +@ifset V850 +The V850 assembler also supports a double dash as starting a comment that +extends to the end of the line. + +@samp{--}; +@end ifset + +@kindex # +@cindex lines starting with @code{#} +@cindex logical line numbers +To be compatible with past assemblers, lines that begin with @samp{#} have a +special interpretation. Following the @samp{#} should be an absolute +expression (@pxref{Expressions}): the logical line number of the @emph{next} +line. Then a string (@pxref{Strings,, Strings}) is allowed: if present it is a +new logical file name. The rest of the line, if any, should be whitespace. + +If the first non-whitespace characters on the line are not numeric, +the line is ignored. (Just like a comment.) + +@smallexample + # This is an ordinary comment. +# 42-6 "new_file_name" # New logical file name + # This is logical line # 36. +@end smallexample +This feature is deprecated, and may disappear from future versions +of @command{@value{AS}}. + +@node Symbol Intro +@section Symbols + +@cindex characters used in symbols +@ifclear SPECIAL-SYMS +A @dfn{symbol} is one or more characters chosen from the set of all +letters (both upper and lower case), digits and the three characters +@samp{_.$}. +@end ifclear +@ifset SPECIAL-SYMS +@ifclear GENERIC +@ifset H8 +A @dfn{symbol} is one or more characters chosen from the set of all +letters (both upper and lower case), digits and the three characters +@samp{._$}. (Save that, on the H8/300 only, you may not use @samp{$} in +symbol names.) +@end ifset +@end ifclear +@end ifset +@ifset GENERIC +On most machines, you can also use @code{$} in symbol names; exceptions +are noted in @ref{Machine Dependencies}. +@end ifset +No symbol may begin with a digit. Case is significant. +There is no length limit: all characters are significant. Symbols are +delimited by characters not in that set, or by the beginning of a file +(since the source program must end with a newline, the end of a file is +not a possible symbol delimiter). @xref{Symbols}. +@cindex length of symbols + +@node Statements +@section Statements + +@cindex statements, structure of +@cindex line separator character +@cindex statement separator character +@ifclear GENERIC +@ifclear abnormal-separator +A @dfn{statement} ends at a newline character (@samp{\n}) or at a +semicolon (@samp{;}). The newline or semicolon is considered part of +the preceding statement. Newlines and semicolons within character +constants are an exception: they do not end statements. +@end ifclear +@ifset abnormal-separator +@ifset A29K +A @dfn{statement} ends at a newline character (@samp{\n}) or an ``at'' +sign (@samp{@@}). The newline or at sign is considered part of the +preceding statement. Newlines and at signs within character constants +are an exception: they do not end statements. +@end ifset +@ifset HPPA +A @dfn{statement} ends at a newline character (@samp{\n}) or an exclamation +point (@samp{!}). The newline or exclamation point is considered part of the +preceding statement. Newlines and exclamation points within character +constants are an exception: they do not end statements. +@end ifset +@ifset H8 +A @dfn{statement} ends at a newline character (@samp{\n}); or (for the +H8/300) a dollar sign (@samp{$}); or (for the +Renesas-SH or the +H8/500) a semicolon +(@samp{;}). The newline or separator character is considered part of +the preceding statement. Newlines and separators within character +constants are an exception: they do not end statements. +@end ifset +@end ifset +@end ifclear +@ifset GENERIC +A @dfn{statement} ends at a newline character (@samp{\n}) or line +separator character. (The line separator is usually @samp{;}, unless +this conflicts with the comment character; @pxref{Machine Dependencies}.) The +newline or separator character is considered part of the preceding +statement. Newlines and separators within character constants are an +exception: they do not end statements. +@end ifset + +@cindex newline, required at file end +@cindex EOF, newline must precede +It is an error to end any statement with end-of-file: the last +character of any input file should be a newline.@refill + +An empty statement is allowed, and may include whitespace. It is ignored. + +@cindex instructions and directives +@cindex directives and instructions +@c "key symbol" is not used elsewhere in the document; seems pedantic to +@c @defn{} it in that case, as was done previously... doc@cygnus.com, +@c 13feb91. +A statement begins with zero or more labels, optionally followed by a +key symbol which determines what kind of statement it is. The key +symbol determines the syntax of the rest of the statement. If the +symbol begins with a dot @samp{.} then the statement is an assembler +directive: typically valid for any computer. If the symbol begins with +a letter the statement is an assembly language @dfn{instruction}: it +assembles into a machine language instruction. +@ifset GENERIC +Different versions of @command{@value{AS}} for different computers +recognize different instructions. In fact, the same symbol may +represent a different instruction in a different computer's assembly +language.@refill +@end ifset + +@cindex @code{:} (label) +@cindex label (@code{:}) +A label is a symbol immediately followed by a colon (@code{:}). +Whitespace before a label or after a colon is permitted, but you may not +have whitespace between a label's symbol and its colon. @xref{Labels}. + +@ifset HPPA +For HPPA targets, labels need not be immediately followed by a colon, but +the definition of a label must begin in column zero. This also implies that +only one label may be defined on each line. +@end ifset + +@smallexample +label: .directive followed by something +another_label: # This is an empty statement. + instruction operand_1, operand_2, @dots{} +@end smallexample + +@node Constants +@section Constants + +@cindex constants +A constant is a number, written so that its value is known by +inspection, without knowing any context. Like this: +@smallexample +@group +.byte 74, 0112, 092, 0x4A, 0X4a, 'J, '\J # All the same value. +.ascii "Ring the bell\7" # A string constant. +.octa 0x123456789abcdef0123456789ABCDEF0 # A bignum. +.float 0f-314159265358979323846264338327\ +95028841971.693993751E-40 # - pi, a flonum. +@end group +@end smallexample + +@menu +* Characters:: Character Constants +* Numbers:: Number Constants +@end menu + +@node Characters +@subsection Character Constants + +@cindex character constants +@cindex constants, character +There are two kinds of character constants. A @dfn{character} stands +for one character in one byte and its value may be used in +numeric expressions. String constants (properly called string +@emph{literals}) are potentially many bytes and their values may not be +used in arithmetic expressions. + +@menu +* Strings:: Strings +* Chars:: Characters +@end menu + +@node Strings +@subsubsection Strings + +@cindex string constants +@cindex constants, string +A @dfn{string} is written between double-quotes. It may contain +double-quotes or null characters. The way to get special characters +into a string is to @dfn{escape} these characters: precede them with +a backslash @samp{\} character. For example @samp{\\} represents +one backslash: the first @code{\} is an escape which tells +@command{@value{AS}} to interpret the second character literally as a backslash +(which prevents @command{@value{AS}} from recognizing the second @code{\} as an +escape character). The complete list of escapes follows. + +@cindex escape codes, character +@cindex character escape codes +@table @kbd +@c @item \a +@c Mnemonic for ACKnowledge; for ASCII this is octal code 007. +@c +@cindex @code{\b} (backspace character) +@cindex backspace (@code{\b}) +@item \b +Mnemonic for backspace; for ASCII this is octal code 010. + +@c @item \e +@c Mnemonic for EOText; for ASCII this is octal code 004. +@c +@cindex @code{\f} (formfeed character) +@cindex formfeed (@code{\f}) +@item \f +Mnemonic for FormFeed; for ASCII this is octal code 014. + +@cindex @code{\n} (newline character) +@cindex newline (@code{\n}) +@item \n +Mnemonic for newline; for ASCII this is octal code 012. + +@c @item \p +@c Mnemonic for prefix; for ASCII this is octal code 033, usually known as @code{escape}. +@c +@cindex @code{\r} (carriage return character) +@cindex carriage return (@code{\r}) +@item \r +Mnemonic for carriage-Return; for ASCII this is octal code 015. + +@c @item \s +@c Mnemonic for space; for ASCII this is octal code 040. Included for compliance with +@c other assemblers. +@c +@cindex @code{\t} (tab) +@cindex tab (@code{\t}) +@item \t +Mnemonic for horizontal Tab; for ASCII this is octal code 011. + +@c @item \v +@c Mnemonic for Vertical tab; for ASCII this is octal code 013. +@c @item \x @var{digit} @var{digit} @var{digit} +@c A hexadecimal character code. The numeric code is 3 hexadecimal digits. +@c +@cindex @code{\@var{ddd}} (octal character code) +@cindex octal character code (@code{\@var{ddd}}) +@item \ @var{digit} @var{digit} @var{digit} +An octal character code. The numeric code is 3 octal digits. +For compatibility with other Unix systems, 8 and 9 are accepted as digits: +for example, @code{\008} has the value 010, and @code{\009} the value 011. + +@cindex @code{\@var{xd...}} (hex character code) +@cindex hex character code (@code{\@var{xd...}}) +@item \@code{x} @var{hex-digits...} +A hex character code. All trailing hex digits are combined. Either upper or +lower case @code{x} works. + +@cindex @code{\\} (@samp{\} character) +@cindex backslash (@code{\\}) +@item \\ +Represents one @samp{\} character. + +@c @item \' +@c Represents one @samp{'} (accent acute) character. +@c This is needed in single character literals +@c (@xref{Characters,,Character Constants}.) to represent +@c a @samp{'}. +@c +@cindex @code{\"} (doublequote character) +@cindex doublequote (@code{\"}) +@item \" +Represents one @samp{"} character. Needed in strings to represent +this character, because an unescaped @samp{"} would end the string. + +@item \ @var{anything-else} +Any other character when escaped by @kbd{\} gives a warning, but +assembles as if the @samp{\} was not present. The idea is that if +you used an escape sequence you clearly didn't want the literal +interpretation of the following character. However @command{@value{AS}} has no +other interpretation, so @command{@value{AS}} knows it is giving you the wrong +code and warns you of the fact. +@end table + +Which characters are escapable, and what those escapes represent, +varies widely among assemblers. The current set is what we think +the BSD 4.2 assembler recognizes, and is a subset of what most C +compilers recognize. If you are in doubt, do not use an escape +sequence. + +@node Chars +@subsubsection Characters + +@cindex single character constant +@cindex character, single +@cindex constant, single character +A single character may be written as a single quote immediately +followed by that character. The same escapes apply to characters as +to strings. So if you want to write the character backslash, you +must write @kbd{'\\} where the first @code{\} escapes the second +@code{\}. As you can see, the quote is an acute accent, not a +grave accent. A newline +@ifclear GENERIC +@ifclear abnormal-separator +(or semicolon @samp{;}) +@end ifclear +@ifset abnormal-separator +@ifset A29K +(or at sign @samp{@@}) +@end ifset +@ifset H8 +(or dollar sign @samp{$}, for the H8/300; or semicolon @samp{;} for the +Renesas SH or H8/500) +@end ifset +@end ifset +@end ifclear +immediately following an acute accent is taken as a literal character +and does not count as the end of a statement. The value of a character +constant in a numeric expression is the machine's byte-wide code for +that character. @command{@value{AS}} assumes your character code is ASCII: +@kbd{'A} means 65, @kbd{'B} means 66, and so on. @refill + +@node Numbers +@subsection Number Constants + +@cindex constants, number +@cindex number constants +@command{@value{AS}} distinguishes three kinds of numbers according to how they +are stored in the target machine. @emph{Integers} are numbers that +would fit into an @code{int} in the C language. @emph{Bignums} are +integers, but they are stored in more than 32 bits. @emph{Flonums} +are floating point numbers, described below. + +@menu +* Integers:: Integers +* Bignums:: Bignums +* Flonums:: Flonums +@ifclear GENERIC +@ifset I960 +* Bit Fields:: Bit Fields +@end ifset +@end ifclear +@end menu + +@node Integers +@subsubsection Integers +@cindex integers +@cindex constants, integer + +@cindex binary integers +@cindex integers, binary +A binary integer is @samp{0b} or @samp{0B} followed by zero or more of +the binary digits @samp{01}. + +@cindex octal integers +@cindex integers, octal +An octal integer is @samp{0} followed by zero or more of the octal +digits (@samp{01234567}). + +@cindex decimal integers +@cindex integers, decimal +A decimal integer starts with a non-zero digit followed by zero or +more digits (@samp{0123456789}). + +@cindex hexadecimal integers +@cindex integers, hexadecimal +A hexadecimal integer is @samp{0x} or @samp{0X} followed by one or +more hexadecimal digits chosen from @samp{0123456789abcdefABCDEF}. + +Integers have the usual values. To denote a negative integer, use +the prefix operator @samp{-} discussed under expressions +(@pxref{Prefix Ops,,Prefix Operators}). + +@node Bignums +@subsubsection Bignums + +@cindex bignums +@cindex constants, bignum +A @dfn{bignum} has the same syntax and semantics as an integer +except that the number (or its negative) takes more than 32 bits to +represent in binary. The distinction is made because in some places +integers are permitted while bignums are not. + +@node Flonums +@subsubsection Flonums +@cindex flonums +@cindex floating point numbers +@cindex constants, floating point + +@cindex precision, floating point +A @dfn{flonum} represents a floating point number. The translation is +indirect: a decimal floating point number from the text is converted by +@command{@value{AS}} to a generic binary floating point number of more than +sufficient precision. This generic floating point number is converted +to a particular computer's floating point format (or formats) by a +portion of @command{@value{AS}} specialized to that computer. + +A flonum is written by writing (in order) +@itemize @bullet +@item +The digit @samp{0}. +@ifset HPPA +(@samp{0} is optional on the HPPA.) +@end ifset + +@item +A letter, to tell @command{@value{AS}} the rest of the number is a flonum. +@ifset GENERIC +@kbd{e} is recommended. Case is not important. +@ignore +@c FIXME: verify if flonum syntax really this vague for most cases +(Any otherwise illegal letter works here, but that might be changed. Vax BSD +4.2 assembler seems to allow any of @samp{defghDEFGH}.) +@end ignore + +On the H8/300, H8/500, +Renesas / SuperH SH, +and AMD 29K architectures, the letter must be +one of the letters @samp{DFPRSX} (in upper or lower case). + +On the ARC, the letter must be one of the letters @samp{DFRS} +(in upper or lower case). + +On the Intel 960 architecture, the letter must be +one of the letters @samp{DFT} (in upper or lower case). + +On the HPPA architecture, the letter must be @samp{E} (upper case only). +@end ifset +@ifclear GENERIC +@ifset A29K +One of the letters @samp{DFPRSX} (in upper or lower case). +@end ifset +@ifset ARC +One of the letters @samp{DFRS} (in upper or lower case). +@end ifset +@ifset H8 +One of the letters @samp{DFPRSX} (in upper or lower case). +@end ifset +@ifset HPPA +The letter @samp{E} (upper case only). +@end ifset +@ifset I960 +One of the letters @samp{DFT} (in upper or lower case). +@end ifset +@end ifclear + +@item +An optional sign: either @samp{+} or @samp{-}. + +@item +An optional @dfn{integer part}: zero or more decimal digits. + +@item +An optional @dfn{fractional part}: @samp{.} followed by zero +or more decimal digits. + +@item +An optional exponent, consisting of: + +@itemize @bullet +@item +An @samp{E} or @samp{e}. +@c I can't find a config where "EXP_CHARS" is other than 'eE', but in +@c principle this can perfectly well be different on different targets. +@item +Optional sign: either @samp{+} or @samp{-}. +@item +One or more decimal digits. +@end itemize + +@end itemize + +At least one of the integer part or the fractional part must be +present. The floating point number has the usual base-10 value. + +@command{@value{AS}} does all processing using integers. Flonums are computed +independently of any floating point hardware in the computer running +@command{@value{AS}}. + +@ifclear GENERIC +@ifset I960 +@c Bit fields are written as a general facility but are also controlled +@c by a conditional-compilation flag---which is as of now (21mar91) +@c turned on only by the i960 config of GAS. +@node Bit Fields +@subsubsection Bit Fields + +@cindex bit fields +@cindex constants, bit field +You can also define numeric constants as @dfn{bit fields}. +specify two numbers separated by a colon--- +@example +@var{mask}:@var{value} +@end example +@noindent +@command{@value{AS}} applies a bitwise @sc{and} between @var{mask} and +@var{value}. + +The resulting number is then packed +@ifset GENERIC +@c this conditional paren in case bit fields turned on elsewhere than 960 +(in host-dependent byte order) +@end ifset +into a field whose width depends on which assembler directive has the +bit-field as its argument. Overflow (a result from the bitwise and +requiring more binary digits to represent) is not an error; instead, +more constants are generated, of the specified width, beginning with the +least significant digits.@refill + +The directives @code{.byte}, @code{.hword}, @code{.int}, @code{.long}, +@code{.short}, and @code{.word} accept bit-field arguments. +@end ifset +@end ifclear + +@node Sections +@chapter Sections and Relocation +@cindex sections +@cindex relocation + +@menu +* Secs Background:: Background +* Ld Sections:: Linker Sections +* As Sections:: Assembler Internal Sections +* Sub-Sections:: Sub-Sections +* bss:: bss Section +@end menu + +@node Secs Background +@section Background + +Roughly, a section is a range of addresses, with no gaps; all data +``in'' those addresses is treated the same for some particular purpose. +For example there may be a ``read only'' section. + +@cindex linker, and assembler +@cindex assembler, and linker +The linker @code{@value{LD}} reads many object files (partial programs) and +combines their contents to form a runnable program. When @command{@value{AS}} +emits an object file, the partial program is assumed to start at address 0. +@code{@value{LD}} assigns the final addresses for the partial program, so that +different partial programs do not overlap. This is actually an +oversimplification, but it suffices to explain how @command{@value{AS}} uses +sections. + +@code{@value{LD}} moves blocks of bytes of your program to their run-time +addresses. These blocks slide to their run-time addresses as rigid +units; their length does not change and neither does the order of bytes +within them. Such a rigid unit is called a @emph{section}. Assigning +run-time addresses to sections is called @dfn{relocation}. It includes +the task of adjusting mentions of object-file addresses so they refer to +the proper run-time addresses. +@ifset H8 +For the H8/300 and H8/500, +and for the Renesas / SuperH SH, +@command{@value{AS}} pads sections if needed to +ensure they end on a word (sixteen bit) boundary. +@end ifset + +@cindex standard assembler sections +An object file written by @command{@value{AS}} has at least three sections, any +of which may be empty. These are named @dfn{text}, @dfn{data} and +@dfn{bss} sections. + +@ifset COFF-ELF +@ifset GENERIC +When it generates COFF or ELF output, +@end ifset +@command{@value{AS}} can also generate whatever other named sections you specify +using the @samp{.section} directive (@pxref{Section,,@code{.section}}). +If you do not use any directives that place output in the @samp{.text} +or @samp{.data} sections, these sections still exist, but are empty. +@end ifset + +@ifset HPPA +@ifset GENERIC +When @command{@value{AS}} generates SOM or ELF output for the HPPA, +@end ifset +@command{@value{AS}} can also generate whatever other named sections you +specify using the @samp{.space} and @samp{.subspace} directives. See +@cite{HP9000 Series 800 Assembly Language Reference Manual} +(HP 92432-90001) for details on the @samp{.space} and @samp{.subspace} +assembler directives. + +@ifset SOM +Additionally, @command{@value{AS}} uses different names for the standard +text, data, and bss sections when generating SOM output. Program text +is placed into the @samp{$CODE$} section, data into @samp{$DATA$}, and +BSS into @samp{$BSS$}. +@end ifset +@end ifset + +Within the object file, the text section starts at address @code{0}, the +data section follows, and the bss section follows the data section. + +@ifset HPPA +When generating either SOM or ELF output files on the HPPA, the text +section starts at address @code{0}, the data section at address +@code{0x4000000}, and the bss section follows the data section. +@end ifset + +To let @code{@value{LD}} know which data changes when the sections are +relocated, and how to change that data, @command{@value{AS}} also writes to the +object file details of the relocation needed. To perform relocation +@code{@value{LD}} must know, each time an address in the object +file is mentioned: +@itemize @bullet +@item +Where in the object file is the beginning of this reference to +an address? +@item +How long (in bytes) is this reference? +@item +Which section does the address refer to? What is the numeric value of +@display +(@var{address}) @minus{} (@var{start-address of section})? +@end display +@item +Is the reference to an address ``Program-Counter relative''? +@end itemize + +@cindex addresses, format of +@cindex section-relative addressing +In fact, every address @command{@value{AS}} ever uses is expressed as +@display +(@var{section}) + (@var{offset into section}) +@end display +@noindent +Further, most expressions @command{@value{AS}} computes have this section-relative +nature. +@ifset SOM +(For some object formats, such as SOM for the HPPA, some expressions are +symbol-relative instead.) +@end ifset + +In this manual we use the notation @{@var{secname} @var{N}@} to mean ``offset +@var{N} into section @var{secname}.'' + +Apart from text, data and bss sections you need to know about the +@dfn{absolute} section. When @code{@value{LD}} mixes partial programs, +addresses in the absolute section remain unchanged. For example, address +@code{@{absolute 0@}} is ``relocated'' to run-time address 0 by +@code{@value{LD}}. Although the linker never arranges two partial programs' +data sections with overlapping addresses after linking, @emph{by definition} +their absolute sections must overlap. Address @code{@{absolute@ 239@}} in one +part of a program is always the same address when the program is running as +address @code{@{absolute@ 239@}} in any other part of the program. + +The idea of sections is extended to the @dfn{undefined} section. Any +address whose section is unknown at assembly time is by definition +rendered @{undefined @var{U}@}---where @var{U} is filled in later. +Since numbers are always defined, the only way to generate an undefined +address is to mention an undefined symbol. A reference to a named +common block would be such a symbol: its value is unknown at assembly +time so it has section @emph{undefined}. + +By analogy the word @emph{section} is used to describe groups of sections in +the linked program. @code{@value{LD}} puts all partial programs' text +sections in contiguous addresses in the linked program. It is +customary to refer to the @emph{text section} of a program, meaning all +the addresses of all partial programs' text sections. Likewise for +data and bss sections. + +Some sections are manipulated by @code{@value{LD}}; others are invented for +use of @command{@value{AS}} and have no meaning except during assembly. + +@node Ld Sections +@section Linker Sections +@code{@value{LD}} deals with just four kinds of sections, summarized below. + +@table @strong + +@ifset COFF-ELF +@cindex named sections +@cindex sections, named +@item named sections +@end ifset +@ifset aout-bout +@cindex text section +@cindex data section +@itemx text section +@itemx data section +@end ifset +These sections hold your program. @command{@value{AS}} and @code{@value{LD}} treat them as +separate but equal sections. Anything you can say of one section is +true of another. +@c @ifset aout-bout +When the program is running, however, it is +customary for the text section to be unalterable. The +text section is often shared among processes: it contains +instructions, constants and the like. The data section of a running +program is usually alterable: for example, C variables would be stored +in the data section. +@c @end ifset + +@cindex bss section +@item bss section +This section contains zeroed bytes when your program begins running. It +is used to hold uninitialized variables or common storage. The length of +each partial program's bss section is important, but because it starts +out containing zeroed bytes there is no need to store explicit zero +bytes in the object file. The bss section was invented to eliminate +those explicit zeros from object files. + +@cindex absolute section +@item absolute section +Address 0 of this section is always ``relocated'' to runtime address 0. +This is useful if you want to refer to an address that @code{@value{LD}} must +not change when relocating. In this sense we speak of absolute +addresses being ``unrelocatable'': they do not change during relocation. + +@cindex undefined section +@item undefined section +This ``section'' is a catch-all for address references to objects not in +the preceding sections. +@c FIXME: ref to some other doc on obj-file formats could go here. +@end table + +@cindex relocation example +An idealized example of three relocatable sections follows. +@ifset COFF-ELF +The example uses the traditional section names @samp{.text} and @samp{.data}. +@end ifset +Memory addresses are on the horizontal axis. + +@c TEXI2ROFF-KILL +@ifnottex +@c END TEXI2ROFF-KILL +@smallexample + +-----+----+--+ +partial program # 1: |ttttt|dddd|00| + +-----+----+--+ + + text data bss + seg. seg. seg. + + +---+---+---+ +partial program # 2: |TTT|DDD|000| + +---+---+---+ + + +--+---+-----+--+----+---+-----+~~ +linked program: | |TTT|ttttt| |dddd|DDD|00000| + +--+---+-----+--+----+---+-----+~~ + + addresses: 0 @dots{} +@end smallexample +@c TEXI2ROFF-KILL +@end ifnottex +@need 5000 +@tex +\bigskip +\line{\it Partial program \#1: \hfil} +\line{\ibox{2.5cm}{\tt text}\ibox{2cm}{\tt data}\ibox{1cm}{\tt bss}\hfil} +\line{\boxit{2.5cm}{\tt ttttt}\boxit{2cm}{\tt dddd}\boxit{1cm}{\tt 00}\hfil} + +\line{\it Partial program \#2: \hfil} +\line{\ibox{1cm}{\tt text}\ibox{1.5cm}{\tt data}\ibox{1cm}{\tt bss}\hfil} +\line{\boxit{1cm}{\tt TTT}\boxit{1.5cm}{\tt DDDD}\boxit{1cm}{\tt 000}\hfil} + +\line{\it linked program: \hfil} +\line{\ibox{.5cm}{}\ibox{1cm}{\tt text}\ibox{2.5cm}{}\ibox{.75cm}{}\ibox{2cm}{\tt data}\ibox{1.5cm}{}\ibox{2cm}{\tt bss}\hfil} +\line{\boxit{.5cm}{}\boxit{1cm}{\tt TTT}\boxit{2.5cm}{\tt +ttttt}\boxit{.75cm}{}\boxit{2cm}{\tt dddd}\boxit{1.5cm}{\tt +DDDD}\boxit{2cm}{\tt 00000}\ \dots\hfil} + +\line{\it addresses: \hfil} +\line{0\dots\hfil} + +@end tex +@c END TEXI2ROFF-KILL + +@node As Sections +@section Assembler Internal Sections + +@cindex internal assembler sections +@cindex sections in messages, internal +These sections are meant only for the internal use of @command{@value{AS}}. They +have no meaning at run-time. You do not really need to know about these +sections for most purposes; but they can be mentioned in @command{@value{AS}} +warning messages, so it might be helpful to have an idea of their +meanings to @command{@value{AS}}. These sections are used to permit the +value of every expression in your assembly language program to be a +section-relative address. + +@table @b +@cindex assembler internal logic error +@item ASSEMBLER-INTERNAL-LOGIC-ERROR! +An internal assembler logic error has been found. This means there is a +bug in the assembler. + +@cindex expr (internal section) +@item expr section +The assembler stores complex expression internally as combinations of +symbols. When it needs to represent an expression as a symbol, it puts +it in the expr section. +@c FIXME item debug +@c FIXME item transfer[t] vector preload +@c FIXME item transfer[t] vector postload +@c FIXME item register +@end table + +@node Sub-Sections +@section Sub-Sections + +@cindex numbered subsections +@cindex grouping data +@ifset aout-bout +Assembled bytes +@ifset COFF-ELF +conventionally +@end ifset +fall into two sections: text and data. +@end ifset +You may have separate groups of +@ifset GENERIC +data in named sections +@end ifset +@ifclear GENERIC +@ifclear aout-bout +data in named sections +@end ifclear +@ifset aout-bout +text or data +@end ifset +@end ifclear +that you want to end up near to each other in the object file, even though they +are not contiguous in the assembler source. @command{@value{AS}} allows you to +use @dfn{subsections} for this purpose. Within each section, there can be +numbered subsections with values from 0 to 8192. Objects assembled into the +same subsection go into the object file together with other objects in the same +subsection. For example, a compiler might want to store constants in the text +section, but might not want to have them interspersed with the program being +assembled. In this case, the compiler could issue a @samp{.text 0} before each +section of code being output, and a @samp{.text 1} before each group of +constants being output. + +Subsections are optional. If you do not use subsections, everything +goes in subsection number zero. + +@ifset GENERIC +Each subsection is zero-padded up to a multiple of four bytes. +(Subsections may be padded a different amount on different flavors +of @command{@value{AS}}.) +@end ifset +@ifclear GENERIC +@ifset H8 +On the H8/300 and H8/500 platforms, each subsection is zero-padded to a word +boundary (two bytes). +The same is true on the Renesas SH. +@end ifset +@ifset I960 +@c FIXME section padding (alignment)? +@c Rich Pixley says padding here depends on target obj code format; that +@c doesn't seem particularly useful to say without further elaboration, +@c so for now I say nothing about it. If this is a generic BFD issue, +@c these paragraphs might need to vanish from this manual, and be +@c discussed in BFD chapter of binutils (or some such). +@end ifset +@ifset A29K +On the AMD 29K family, no particular padding is added to section or +subsection sizes; @value{AS} forces no alignment on this platform. +@end ifset +@end ifclear + +Subsections appear in your object file in numeric order, lowest numbered +to highest. (All this to be compatible with other people's assemblers.) +The object file contains no representation of subsections; @code{@value{LD}} and +other programs that manipulate object files see no trace of them. +They just see all your text subsections as a text section, and all your +data subsections as a data section. + +To specify which subsection you want subsequent statements assembled +into, use a numeric argument to specify it, in a @samp{.text +@var{expression}} or a @samp{.data @var{expression}} statement. +@ifset COFF-ELF +@ifset GENERIC +When generating COFF or ELF output, you +@end ifset +@ifclear GENERIC +You +@end ifclear +can also use an extra subsection +argument with arbitrary named sections: @samp{.section @var{name}, +@var{expression}}. +@end ifset +@var{Expression} should be an absolute expression. +(@xref{Expressions}.) If you just say @samp{.text} then @samp{.text 0} +is assumed. Likewise @samp{.data} means @samp{.data 0}. Assembly +begins in @code{text 0}. For instance: +@smallexample +.text 0 # The default subsection is text 0 anyway. +.ascii "This lives in the first text subsection. *" +.text 1 +.ascii "But this lives in the second text subsection." +.data 0 +.ascii "This lives in the data section," +.ascii "in the first data subsection." +.text 0 +.ascii "This lives in the first text section," +.ascii "immediately following the asterisk (*)." +@end smallexample + +Each section has a @dfn{location counter} incremented by one for every byte +assembled into that section. Because subsections are merely a convenience +restricted to @command{@value{AS}} there is no concept of a subsection location +counter. There is no way to directly manipulate a location counter---but the +@code{.align} directive changes it, and any label definition captures its +current value. The location counter of the section where statements are being +assembled is said to be the @dfn{active} location counter. + +@node bss +@section bss Section + +@cindex bss section +@cindex common variable storage +The bss section is used for local common variable storage. +You may allocate address space in the bss section, but you may +not dictate data to load into it before your program executes. When +your program starts running, all the contents of the bss +section are zeroed bytes. + +The @code{.lcomm} pseudo-op defines a symbol in the bss section; see +@ref{Lcomm,,@code{.lcomm}}. + +The @code{.comm} pseudo-op may be used to declare a common symbol, which is +another form of uninitialized symbol; see @xref{Comm,,@code{.comm}}. + +@ifset GENERIC +When assembling for a target which supports multiple sections, such as ELF or +COFF, you may switch into the @code{.bss} section and define symbols as usual; +see @ref{Section,,@code{.section}}. You may only assemble zero values into the +section. Typically the section will only contain symbol definitions and +@code{.skip} directives (@pxref{Skip,,@code{.skip}}). +@end ifset + +@node Symbols +@chapter Symbols + +@cindex symbols +Symbols are a central concept: the programmer uses symbols to name +things, the linker uses symbols to link, and the debugger uses symbols +to debug. + +@quotation +@cindex debuggers, and symbol order +@emph{Warning:} @command{@value{AS}} does not place symbols in the object file in +the same order they were declared. This may break some debuggers. +@end quotation + +@menu +* Labels:: Labels +* Setting Symbols:: Giving Symbols Other Values +* Symbol Names:: Symbol Names +* Dot:: The Special Dot Symbol +* Symbol Attributes:: Symbol Attributes +@end menu + +@node Labels +@section Labels + +@cindex labels +A @dfn{label} is written as a symbol immediately followed by a colon +@samp{:}. The symbol then represents the current value of the +active location counter, and is, for example, a suitable instruction +operand. You are warned if you use the same symbol to represent two +different locations: the first definition overrides any other +definitions. + +@ifset HPPA +On the HPPA, the usual form for a label need not be immediately followed by a +colon, but instead must start in column zero. Only one label may be defined on +a single line. To work around this, the HPPA version of @command{@value{AS}} also +provides a special directive @code{.label} for defining labels more flexibly. +@end ifset + +@node Setting Symbols +@section Giving Symbols Other Values + +@cindex assigning values to symbols +@cindex symbol values, assigning +A symbol can be given an arbitrary value by writing a symbol, followed +by an equals sign @samp{=}, followed by an expression +(@pxref{Expressions}). This is equivalent to using the @code{.set} +directive. @xref{Set,,@code{.set}}. + +@node Symbol Names +@section Symbol Names + +@cindex symbol names +@cindex names, symbol +@ifclear SPECIAL-SYMS +Symbol names begin with a letter or with one of @samp{._}. On most +machines, you can also use @code{$} in symbol names; exceptions are +noted in @ref{Machine Dependencies}. That character may be followed by any +string of digits, letters, dollar signs (unless otherwise noted in +@ref{Machine Dependencies}), and underscores. +@end ifclear +@ifset A29K +For the AMD 29K family, @samp{?} is also allowed in the +body of a symbol name, though not at its beginning. +@end ifset + +@ifset SPECIAL-SYMS +@ifset H8 +Symbol names begin with a letter or with one of @samp{._}. On the +Renesas SH or the H8/500, you can also use @code{$} in symbol names. That +character may be followed by any string of digits, letters, dollar signs (save +on the H8/300), and underscores. +@end ifset +@end ifset + +Case of letters is significant: @code{foo} is a different symbol name +than @code{Foo}. + +Each symbol has exactly one name. Each name in an assembly language program +refers to exactly one symbol. You may use that symbol name any number of times +in a program. + +@subheading Local Symbol Names + +@cindex local symbol names +@cindex symbol names, local +@cindex temporary symbol names +@cindex symbol names, temporary +Local symbols help compilers and programmers use names temporarily. +They create symbols which are guaranteed to be unique over the entire scope of +the input source code and which can be referred to by a simple notation. +To define a local symbol, write a label of the form @samp{@b{N}:} (where @b{N} +represents any positive integer). To refer to the most recent previous +definition of that symbol write @samp{@b{N}b}, using the same number as when +you defined the label. To refer to the next definition of a local label, write +@samp{@b{N}f}--- The @samp{b} stands for``backwards'' and the @samp{f} stands +for ``forwards''. + +There is no restriction on how you can use these labels, and you can reuse them +too. So that it is possible to repeatedly define the same local label (using +the same number @samp{@b{N}}), although you can only refer to the most recently +defined local label of that number (for a backwards reference) or the next +definition of a specific local label for a forward reference. It is also worth +noting that the first 10 local labels (@samp{@b{0:}}@dots{}@samp{@b{9:}}) are +implemented in a slightly more efficient manner than the others. + +Here is an example: + +@smallexample +1: branch 1f +2: branch 1b +1: branch 2f +2: branch 1b +@end smallexample + +Which is the equivalent of: + +@smallexample +label_1: branch label_3 +label_2: branch label_1 +label_3: branch label_4 +label_4: branch label_3 +@end smallexample + +Local symbol names are only a notational device. They are immediately +transformed into more conventional symbol names before the assembler uses them. +The symbol names stored in the symbol table, appearing in error messages and +optionally emitted to the object file. The names are constructed using these +parts: + +@table @code +@item L +All local labels begin with @samp{L}. Normally both @command{@value{AS}} and +@code{@value{LD}} forget symbols that start with @samp{L}. These labels are +used for symbols you are never intended to see. If you use the +@samp{-L} option then @command{@value{AS}} retains these symbols in the +object file. If you also instruct @code{@value{LD}} to retain these symbols, +you may use them in debugging. + +@item @var{number} +This is the number that was used in the local label definition. So if the +label is written @samp{55:} then the number is @samp{55}. + +@item @kbd{C-B} +This unusual character is included so you do not accidentally invent a symbol +of the same name. The character has ASCII value of @samp{\002} (control-B). + +@item @emph{ordinal number} +This is a serial number to keep the labels distinct. The first definition of +@samp{0:} gets the number @samp{1}. The 15th definition of @samp{0:} gets the +number @samp{15}, and so on. Likewise the first definition of @samp{1:} gets +the number @samp{1} and its 15th defintion gets @samp{15} as well. +@end table + +So for example, the first @code{1:} is named @code{L1@kbd{C-B}1}, the 44th +@code{3:} is named @code{L3@kbd{C-B}44}. + +@subheading Dollar Local Labels +@cindex dollar local symbols + +@code{@value{AS}} also supports an even more local form of local labels called +dollar labels. These labels go out of scope (ie they become undefined) as soon +as a non-local label is defined. Thus they remain valid for only a small +region of the input source code. Normal local labels, by contrast, remain in +scope for the entire file, or until they are redefined by another occurrence of +the same local label. + +Dollar labels are defined in exactly the same way as ordinary local labels, +except that instead of being terminated by a colon, they are terminated by a +dollar sign. eg @samp{@b{55$}}. + +They can also be distinguished from ordinary local labels by their transformed +name which uses ASCII character @samp{\001} (control-A) as the magic character +to distinguish them from ordinary labels. Thus the 5th defintion of @samp{6$} +is named @samp{L6@kbd{C-A}5}. + +@node Dot +@section The Special Dot Symbol + +@cindex dot (symbol) +@cindex @code{.} (symbol) +@cindex current address +@cindex location counter +The special symbol @samp{.} refers to the current address that +@command{@value{AS}} is assembling into. Thus, the expression @samp{melvin: +.long .} defines @code{melvin} to contain its own address. +Assigning a value to @code{.} is treated the same as a @code{.org} +directive. Thus, the expression @samp{.=.+4} is the same as saying +@ifclear no-space-dir +@samp{.space 4}. +@end ifclear +@ifset no-space-dir +@ifset A29K +@samp{.block 4}. +@end ifset +@end ifset + +@node Symbol Attributes +@section Symbol Attributes + +@cindex symbol attributes +@cindex attributes, symbol +Every symbol has, as well as its name, the attributes ``Value'' and +``Type''. Depending on output format, symbols can also have auxiliary +attributes. +@ifset INTERNALS +The detailed definitions are in @file{a.out.h}. +@end ifset + +If you use a symbol without defining it, @command{@value{AS}} assumes zero for +all these attributes, and probably won't warn you. This makes the +symbol an externally defined symbol, which is generally what you +would want. + +@menu +* Symbol Value:: Value +* Symbol Type:: Type +@ifset aout-bout +@ifset GENERIC +* a.out Symbols:: Symbol Attributes: @code{a.out} +@end ifset +@ifclear GENERIC +@ifclear BOUT +* a.out Symbols:: Symbol Attributes: @code{a.out} +@end ifclear +@ifset BOUT +* a.out Symbols:: Symbol Attributes: @code{a.out}, @code{b.out} +@end ifset +@end ifclear +@end ifset +@ifset COFF +* COFF Symbols:: Symbol Attributes for COFF +@end ifset +@ifset SOM +* SOM Symbols:: Symbol Attributes for SOM +@end ifset +@end menu + +@node Symbol Value +@subsection Value + +@cindex value of a symbol +@cindex symbol value +The value of a symbol is (usually) 32 bits. For a symbol which labels a +location in the text, data, bss or absolute sections the value is the +number of addresses from the start of that section to the label. +Naturally for text, data and bss sections the value of a symbol changes +as @code{@value{LD}} changes section base addresses during linking. Absolute +symbols' values do not change during linking: that is why they are +called absolute. + +The value of an undefined symbol is treated in a special way. If it is +0 then the symbol is not defined in this assembler source file, and +@code{@value{LD}} tries to determine its value from other files linked into the +same program. You make this kind of symbol simply by mentioning a symbol +name without defining it. A non-zero value represents a @code{.comm} +common declaration. The value is how much common storage to reserve, in +bytes (addresses). The symbol refers to the first address of the +allocated storage. + +@node Symbol Type +@subsection Type + +@cindex type of a symbol +@cindex symbol type +The type attribute of a symbol contains relocation (section) +information, any flag settings indicating that a symbol is external, and +(optionally), other information for linkers and debuggers. The exact +format depends on the object-code output format in use. + +@ifset aout-bout +@ifclear GENERIC +@ifset BOUT +@c The following avoids a "widow" subsection title. @group would be +@c better if it were available outside examples. +@need 1000 +@node a.out Symbols +@subsection Symbol Attributes: @code{a.out}, @code{b.out} + +@cindex @code{b.out} symbol attributes +@cindex symbol attributes, @code{b.out} +These symbol attributes appear only when @command{@value{AS}} is configured for +one of the Berkeley-descended object output formats---@code{a.out} or +@code{b.out}. + +@end ifset +@ifclear BOUT +@node a.out Symbols +@subsection Symbol Attributes: @code{a.out} + +@cindex @code{a.out} symbol attributes +@cindex symbol attributes, @code{a.out} + +@end ifclear +@end ifclear +@ifset GENERIC +@node a.out Symbols +@subsection Symbol Attributes: @code{a.out} + +@cindex @code{a.out} symbol attributes +@cindex symbol attributes, @code{a.out} + +@end ifset +@menu +* Symbol Desc:: Descriptor +* Symbol Other:: Other +@end menu + +@node Symbol Desc +@subsubsection Descriptor + +@cindex descriptor, of @code{a.out} symbol +This is an arbitrary 16-bit value. You may establish a symbol's +descriptor value by using a @code{.desc} statement +(@pxref{Desc,,@code{.desc}}). A descriptor value means nothing to +@command{@value{AS}}. + +@node Symbol Other +@subsubsection Other + +@cindex other attribute, of @code{a.out} symbol +This is an arbitrary 8-bit value. It means nothing to @command{@value{AS}}. +@end ifset + +@ifset COFF +@node COFF Symbols +@subsection Symbol Attributes for COFF + +@cindex COFF symbol attributes +@cindex symbol attributes, COFF + +The COFF format supports a multitude of auxiliary symbol attributes; +like the primary symbol attributes, they are set between @code{.def} and +@code{.endef} directives. + +@subsubsection Primary Attributes + +@cindex primary attributes, COFF symbols +The symbol name is set with @code{.def}; the value and type, +respectively, with @code{.val} and @code{.type}. + +@subsubsection Auxiliary Attributes + +@cindex auxiliary attributes, COFF symbols +The @command{@value{AS}} directives @code{.dim}, @code{.line}, @code{.scl}, +@code{.size}, and @code{.tag} can generate auxiliary symbol table +information for COFF. +@end ifset + +@ifset SOM +@node SOM Symbols +@subsection Symbol Attributes for SOM + +@cindex SOM symbol attributes +@cindex symbol attributes, SOM + +The SOM format for the HPPA supports a multitude of symbol attributes set with +the @code{.EXPORT} and @code{.IMPORT} directives. + +The attributes are described in @cite{HP9000 Series 800 Assembly +Language Reference Manual} (HP 92432-90001) under the @code{IMPORT} and +@code{EXPORT} assembler directive documentation. +@end ifset + +@node Expressions +@chapter Expressions + +@cindex expressions +@cindex addresses +@cindex numeric values +An @dfn{expression} specifies an address or numeric value. +Whitespace may precede and/or follow an expression. + +The result of an expression must be an absolute number, or else an offset into +a particular section. If an expression is not absolute, and there is not +enough information when @command{@value{AS}} sees the expression to know its +section, a second pass over the source program might be necessary to interpret +the expression---but the second pass is currently not implemented. +@command{@value{AS}} aborts with an error message in this situation. + +@menu +* Empty Exprs:: Empty Expressions +* Integer Exprs:: Integer Expressions +@end menu + +@node Empty Exprs +@section Empty Expressions + +@cindex empty expressions +@cindex expressions, empty +An empty expression has no value: it is just whitespace or null. +Wherever an absolute expression is required, you may omit the +expression, and @command{@value{AS}} assumes a value of (absolute) 0. This +is compatible with other assemblers. + +@node Integer Exprs +@section Integer Expressions + +@cindex integer expressions +@cindex expressions, integer +An @dfn{integer expression} is one or more @emph{arguments} delimited +by @emph{operators}. + +@menu +* Arguments:: Arguments +* Operators:: Operators +* Prefix Ops:: Prefix Operators +* Infix Ops:: Infix Operators +@end menu + +@node Arguments +@subsection Arguments + +@cindex expression arguments +@cindex arguments in expressions +@cindex operands in expressions +@cindex arithmetic operands +@dfn{Arguments} are symbols, numbers or subexpressions. In other +contexts arguments are sometimes called ``arithmetic operands''. In +this manual, to avoid confusing them with the ``instruction operands'' of +the machine language, we use the term ``argument'' to refer to parts of +expressions only, reserving the word ``operand'' to refer only to machine +instruction operands. + +Symbols are evaluated to yield @{@var{section} @var{NNN}@} where +@var{section} is one of text, data, bss, absolute, +or undefined. @var{NNN} is a signed, 2's complement 32 bit +integer. + +Numbers are usually integers. + +A number can be a flonum or bignum. In this case, you are warned +that only the low order 32 bits are used, and @command{@value{AS}} pretends +these 32 bits are an integer. You may write integer-manipulating +instructions that act on exotic constants, compatible with other +assemblers. + +@cindex subexpressions +Subexpressions are a left parenthesis @samp{(} followed by an integer +expression, followed by a right parenthesis @samp{)}; or a prefix +operator followed by an argument. + +@node Operators +@subsection Operators + +@cindex operators, in expressions +@cindex arithmetic functions +@cindex functions, in expressions +@dfn{Operators} are arithmetic functions, like @code{+} or @code{%}. Prefix +operators are followed by an argument. Infix operators appear +between their arguments. Operators may be preceded and/or followed by +whitespace. + +@node Prefix Ops +@subsection Prefix Operator + +@cindex prefix operators +@command{@value{AS}} has the following @dfn{prefix operators}. They each take +one argument, which must be absolute. + +@c the tex/end tex stuff surrounding this small table is meant to make +@c it align, on the printed page, with the similar table in the next +@c section (which is inside an enumerate). +@tex +\global\advance\leftskip by \itemindent +@end tex + +@table @code +@item - +@dfn{Negation}. Two's complement negation. +@item ~ +@dfn{Complementation}. Bitwise not. +@end table + +@tex +\global\advance\leftskip by -\itemindent +@end tex + +@node Infix Ops +@subsection Infix Operators + +@cindex infix operators +@cindex operators, permitted arguments +@dfn{Infix operators} take two arguments, one on either side. Operators +have precedence, but operations with equal precedence are performed left +to right. Apart from @code{+} or @option{-}, both arguments must be +absolute, and the result is absolute. + +@enumerate +@cindex operator precedence +@cindex precedence of operators + +@item +Highest Precedence + +@table @code +@item * +@dfn{Multiplication}. + +@item / +@dfn{Division}. Truncation is the same as the C operator @samp{/} + +@item % +@dfn{Remainder}. + +@item < +@itemx << +@dfn{Shift Left}. Same as the C operator @samp{<<}. + +@item > +@itemx >> +@dfn{Shift Right}. Same as the C operator @samp{>>}. +@end table + +@item +Intermediate precedence + +@table @code +@item | + +@dfn{Bitwise Inclusive Or}. + +@item & +@dfn{Bitwise And}. + +@item ^ +@dfn{Bitwise Exclusive Or}. + +@item ! +@dfn{Bitwise Or Not}. +@end table + +@item +Low Precedence + +@table @code +@cindex addition, permitted arguments +@cindex plus, permitted arguments +@cindex arguments for addition +@item + +@dfn{Addition}. If either argument is absolute, the result has the section of +the other argument. You may not add together arguments from different +sections. + +@cindex subtraction, permitted arguments +@cindex minus, permitted arguments +@cindex arguments for subtraction +@item - +@dfn{Subtraction}. If the right argument is absolute, the +result has the section of the left argument. +If both arguments are in the same section, the result is absolute. +You may not subtract arguments from different sections. +@c FIXME is there still something useful to say about undefined - undefined ? + +@cindex comparison expressions +@cindex expressions, comparison +@item == +@dfn{Is Equal To} +@item <> +@dfn{Is Not Equal To} +@item < +@dfn{Is Less Than} +@itemx > +@dfn{Is Greater Than} +@itemx >= +@dfn{Is Greater Than Or Equal To} +@itemx <= +@dfn{Is Less Than Or Equal To} + +The comparison operators can be used as infix operators. A true results has a +value of -1 whereas a false result has a value of 0. Note, these operators +perform signed comparisons. +@end table + +@item Lowest Precedence + +@table @code +@item && +@dfn{Logical And}. + +@item || +@dfn{Logical Or}. + +These two logical operations can be used to combine the results of sub +expressions. Note, unlike the comparison operators a true result returns a +value of 1 but a false results does still return 0. Also note that the logical +or operator has a slightly lower precedence than logical and. + +@end table +@end enumerate + +In short, it's only meaningful to add or subtract the @emph{offsets} in an +address; you can only have a defined section in one of the two arguments. + +@node Pseudo Ops +@chapter Assembler Directives + +@cindex directives, machine independent +@cindex pseudo-ops, machine independent +@cindex machine independent directives +All assembler directives have names that begin with a period (@samp{.}). +The rest of the name is letters, usually in lower case. + +This chapter discusses directives that are available regardless of the +target machine configuration for the @sc{gnu} assembler. +@ifset GENERIC +Some machine configurations provide additional directives. +@xref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset machine-directives +@xref{Machine Dependencies} for additional directives. +@end ifset +@end ifclear + +@menu +* Abort:: @code{.abort} +@ifset COFF +* ABORT:: @code{.ABORT} +@end ifset + +* Align:: @code{.align @var{abs-expr} , @var{abs-expr}} +* Ascii:: @code{.ascii "@var{string}"}@dots{} +* Asciz:: @code{.asciz "@var{string}"}@dots{} +* Balign:: @code{.balign @var{abs-expr} , @var{abs-expr}} +* Byte:: @code{.byte @var{expressions}} +* Comm:: @code{.comm @var{symbol} , @var{length} } +* Data:: @code{.data @var{subsection}} +@ifset COFF +* Def:: @code{.def @var{name}} +@end ifset +@ifset aout-bout +* Desc:: @code{.desc @var{symbol}, @var{abs-expression}} +@end ifset +@ifset COFF +* Dim:: @code{.dim} +@end ifset + +* Double:: @code{.double @var{flonums}} +* Eject:: @code{.eject} +* Else:: @code{.else} +* Elseif:: @code{.elseif} +* End:: @code{.end} +@ifset COFF +* Endef:: @code{.endef} +@end ifset + +* Endfunc:: @code{.endfunc} +* Endif:: @code{.endif} +* Equ:: @code{.equ @var{symbol}, @var{expression}} +* Equiv:: @code{.equiv @var{symbol}, @var{expression}} +* Err:: @code{.err} +* Exitm:: @code{.exitm} +* Extern:: @code{.extern} +* Fail:: @code{.fail} +@ifclear no-file-dir +* File:: @code{.file @var{string}} +@end ifclear + +* Fill:: @code{.fill @var{repeat} , @var{size} , @var{value}} +* Float:: @code{.float @var{flonums}} +* Func:: @code{.func} +* Global:: @code{.global @var{symbol}}, @code{.globl @var{symbol}} +@ifset ELF +* Hidden:: @code{.hidden @var{names}} +@end ifset + +* hword:: @code{.hword @var{expressions}} +* Ident:: @code{.ident} +* If:: @code{.if @var{absolute expression}} +* Incbin:: @code{.incbin "@var{file}"[,@var{skip}[,@var{count}]]} +* Include:: @code{.include "@var{file}"} +* Int:: @code{.int @var{expressions}} +@ifset ELF +* Internal:: @code{.internal @var{names}} +@end ifset + +* Irp:: @code{.irp @var{symbol},@var{values}}@dots{} +* Irpc:: @code{.irpc @var{symbol},@var{values}}@dots{} +* Lcomm:: @code{.lcomm @var{symbol} , @var{length}} +* Lflags:: @code{.lflags} +@ifclear no-line-dir +* Line:: @code{.line @var{line-number}} +@end ifclear + +* Ln:: @code{.ln @var{line-number}} +* Linkonce:: @code{.linkonce [@var{type}]} +* List:: @code{.list} +* Long:: @code{.long @var{expressions}} +@ignore +* Lsym:: @code{.lsym @var{symbol}, @var{expression}} +@end ignore + +* Macro:: @code{.macro @var{name} @var{args}}@dots{} +* MRI:: @code{.mri @var{val}} +* Nolist:: @code{.nolist} +* Octa:: @code{.octa @var{bignums}} +* Org:: @code{.org @var{new-lc} , @var{fill}} +* P2align:: @code{.p2align @var{abs-expr} , @var{abs-expr}} +@ifset ELF +* PopSection:: @code{.popsection} +* Previous:: @code{.previous} +@end ifset + +* Print:: @code{.print @var{string}} +@ifset ELF +* Protected:: @code{.protected @var{names}} +@end ifset + +* Psize:: @code{.psize @var{lines}, @var{columns}} +* Purgem:: @code{.purgem @var{name}} +@ifset ELF +* PushSection:: @code{.pushsection @var{name}} +@end ifset + +* Quad:: @code{.quad @var{bignums}} +* Rept:: @code{.rept @var{count}} +* Sbttl:: @code{.sbttl "@var{subheading}"} +@ifset COFF +* Scl:: @code{.scl @var{class}} +@end ifset +@ifset COFF-ELF +* Section:: @code{.section @var{name}} +@end ifset + +* Set:: @code{.set @var{symbol}, @var{expression}} +* Short:: @code{.short @var{expressions}} +* Single:: @code{.single @var{flonums}} +@ifset COFF-ELF +* Size:: @code{.size [@var{name} , @var{expression}]} +@end ifset + +* Skip:: @code{.skip @var{size} , @var{fill}} +* Sleb128:: @code{.sleb128 @var{expressions}} +* Space:: @code{.space @var{size} , @var{fill}} +@ifset have-stabs +* Stab:: @code{.stabd, .stabn, .stabs} +@end ifset + +* String:: @code{.string "@var{str}"} +* Struct:: @code{.struct @var{expression}} +@ifset ELF +* SubSection:: @code{.subsection} +* Symver:: @code{.symver @var{name},@var{name2@@nodename}} +@end ifset + +@ifset COFF +* Tag:: @code{.tag @var{structname}} +@end ifset + +* Text:: @code{.text @var{subsection}} +* Title:: @code{.title "@var{heading}"} +@ifset COFF-ELF +* Type:: @code{.type <@var{int} | @var{name} , @var{type description}>} +@end ifset + +* Uleb128:: @code{.uleb128 @var{expressions}} +@ifset COFF +* Val:: @code{.val @var{addr}} +@end ifset + +@ifset ELF +* Version:: @code{.version "@var{string}"} +* VTableEntry:: @code{.vtable_entry @var{table}, @var{offset}} +* VTableInherit:: @code{.vtable_inherit @var{child}, @var{parent}} +* Weak:: @code{.weak @var{names}} +@end ifset + +* Word:: @code{.word @var{expressions}} +* Deprecated:: Deprecated Directives +@end menu + +@node Abort +@section @code{.abort} + +@cindex @code{abort} directive +@cindex stopping the assembly +This directive stops the assembly immediately. It is for +compatibility with other assemblers. The original idea was that the +assembly language source would be piped into the assembler. If the sender +of the source quit, it could use this directive tells @command{@value{AS}} to +quit also. One day @code{.abort} will not be supported. + +@ifset COFF +@node ABORT +@section @code{.ABORT} + +@cindex @code{ABORT} directive +When producing COFF output, @command{@value{AS}} accepts this directive as a +synonym for @samp{.abort}. + +@ifset BOUT +When producing @code{b.out} output, @command{@value{AS}} accepts this directive, +but ignores it. +@end ifset +@end ifset + +@node Align +@section @code{.align @var{abs-expr}, @var{abs-expr}, @var{abs-expr}} + +@cindex padding the location counter +@cindex @code{align} directive +Pad the location counter (in the current subsection) to a particular storage +boundary. The first expression (which must be absolute) is the alignment +required, as described below. + +The second expression (also absolute) gives the fill value to be stored in the +padding bytes. It (and the comma) may be omitted. If it is omitted, the +padding bytes are normally zero. However, on some systems, if the section is +marked as containing code and the fill value is omitted, the space is filled +with no-op instructions. + +The third expression is also absolute, and is also optional. If it is present, +it is the maximum number of bytes that should be skipped by this alignment +directive. If doing the alignment would require skipping more bytes than the +specified maximum, then the alignment is not done at all. You can omit the +fill value (the second argument) entirely by simply using two commas after the +required alignment; this can be useful if you want the alignment to be filled +with no-op instructions when appropriate. + +The way the required alignment is specified varies from system to system. +For the a29k, hppa, m68k, m88k, w65, sparc, Xtensa, and Renesas / SuperH SH, +and i386 using ELF format, +the first expression is the +alignment request in bytes. For example @samp{.align 8} advances +the location counter until it is a multiple of 8. If the location counter +is already a multiple of 8, no change is needed. + +For other systems, including the i386 using a.out format, and the arm and +strongarm, it is the +number of low-order zero bits the location counter must have after +advancement. For example @samp{.align 3} advances the location +counter until it a multiple of 8. If the location counter is already a +multiple of 8, no change is needed. + +This inconsistency is due to the different behaviors of the various +native assemblers for these systems which GAS must emulate. +GAS also provides @code{.balign} and @code{.p2align} directives, +described later, which have a consistent behavior across all +architectures (but are specific to GAS). + +@node Ascii +@section @code{.ascii "@var{string}"}@dots{} + +@cindex @code{ascii} directive +@cindex string literals +@code{.ascii} expects zero or more string literals (@pxref{Strings}) +separated by commas. It assembles each string (with no automatic +trailing zero byte) into consecutive addresses. + +@node Asciz +@section @code{.asciz "@var{string}"}@dots{} + +@cindex @code{asciz} directive +@cindex zero-terminated strings +@cindex null-terminated strings +@code{.asciz} is just like @code{.ascii}, but each string is followed by +a zero byte. The ``z'' in @samp{.asciz} stands for ``zero''. + +@node Balign +@section @code{.balign[wl] @var{abs-expr}, @var{abs-expr}, @var{abs-expr}} + +@cindex padding the location counter given number of bytes +@cindex @code{balign} directive +Pad the location counter (in the current subsection) to a particular +storage boundary. The first expression (which must be absolute) is the +alignment request in bytes. For example @samp{.balign 8} advances +the location counter until it is a multiple of 8. If the location counter +is already a multiple of 8, no change is needed. + +The second expression (also absolute) gives the fill value to be stored in the +padding bytes. It (and the comma) may be omitted. If it is omitted, the +padding bytes are normally zero. However, on some systems, if the section is +marked as containing code and the fill value is omitted, the space is filled +with no-op instructions. + +The third expression is also absolute, and is also optional. If it is present, +it is the maximum number of bytes that should be skipped by this alignment +directive. If doing the alignment would require skipping more bytes than the +specified maximum, then the alignment is not done at all. You can omit the +fill value (the second argument) entirely by simply using two commas after the +required alignment; this can be useful if you want the alignment to be filled +with no-op instructions when appropriate. + +@cindex @code{balignw} directive +@cindex @code{balignl} directive +The @code{.balignw} and @code{.balignl} directives are variants of the +@code{.balign} directive. The @code{.balignw} directive treats the fill +pattern as a two byte word value. The @code{.balignl} directives treats the +fill pattern as a four byte longword value. For example, @code{.balignw +4,0x368d} will align to a multiple of 4. If it skips two bytes, they will be +filled in with the value 0x368d (the exact placement of the bytes depends upon +the endianness of the processor). If it skips 1 or 3 bytes, the fill value is +undefined. + +@node Byte +@section @code{.byte @var{expressions}} + +@cindex @code{byte} directive +@cindex integers, one byte +@code{.byte} expects zero or more expressions, separated by commas. +Each expression is assembled into the next byte. + +@node Comm +@section @code{.comm @var{symbol} , @var{length} } + +@cindex @code{comm} directive +@cindex symbol, common +@code{.comm} declares a common symbol named @var{symbol}. When linking, a +common symbol in one object file may be merged with a defined or common symbol +of the same name in another object file. If @code{@value{LD}} does not see a +definition for the symbol--just one or more common symbols--then it will +allocate @var{length} bytes of uninitialized memory. @var{length} must be an +absolute expression. If @code{@value{LD}} sees multiple common symbols with +the same name, and they do not all have the same size, it will allocate space +using the largest size. + +@ifset ELF +When using ELF, the @code{.comm} directive takes an optional third argument. +This is the desired alignment of the symbol, specified as a byte boundary (for +example, an alignment of 16 means that the least significant 4 bits of the +address should be zero). The alignment must be an absolute expression, and it +must be a power of two. If @code{@value{LD}} allocates uninitialized memory +for the common symbol, it will use the alignment when placing the symbol. If +no alignment is specified, @command{@value{AS}} will set the alignment to the +largest power of two less than or equal to the size of the symbol, up to a +maximum of 16. +@end ifset + +@ifset HPPA +The syntax for @code{.comm} differs slightly on the HPPA. The syntax is +@samp{@var{symbol} .comm, @var{length}}; @var{symbol} is optional. +@end ifset + +@node Data +@section @code{.data @var{subsection}} + +@cindex @code{data} directive +@code{.data} tells @command{@value{AS}} to assemble the following statements onto the +end of the data subsection numbered @var{subsection} (which is an +absolute expression). If @var{subsection} is omitted, it defaults +to zero. + +@ifset COFF +@node Def +@section @code{.def @var{name}} + +@cindex @code{def} directive +@cindex COFF symbols, debugging +@cindex debugging COFF symbols +Begin defining debugging information for a symbol @var{name}; the +definition extends until the @code{.endef} directive is encountered. +@ifset BOUT + +This directive is only observed when @command{@value{AS}} is configured for COFF +format output; when producing @code{b.out}, @samp{.def} is recognized, +but ignored. +@end ifset +@end ifset + +@ifset aout-bout +@node Desc +@section @code{.desc @var{symbol}, @var{abs-expression}} + +@cindex @code{desc} directive +@cindex COFF symbol descriptor +@cindex symbol descriptor, COFF +This directive sets the descriptor of the symbol (@pxref{Symbol Attributes}) +to the low 16 bits of an absolute expression. + +@ifset COFF +The @samp{.desc} directive is not available when @command{@value{AS}} is +configured for COFF output; it is only for @code{a.out} or @code{b.out} +object format. For the sake of compatibility, @command{@value{AS}} accepts +it, but produces no output, when configured for COFF. +@end ifset +@end ifset + +@ifset COFF +@node Dim +@section @code{.dim} + +@cindex @code{dim} directive +@cindex COFF auxiliary symbol information +@cindex auxiliary symbol information, COFF +This directive is generated by compilers to include auxiliary debugging +information in the symbol table. It is only permitted inside +@code{.def}/@code{.endef} pairs. +@ifset BOUT + +@samp{.dim} is only meaningful when generating COFF format output; when +@command{@value{AS}} is generating @code{b.out}, it accepts this directive but +ignores it. +@end ifset +@end ifset + +@node Double +@section @code{.double @var{flonums}} + +@cindex @code{double} directive +@cindex floating point numbers (double) +@code{.double} expects zero or more flonums, separated by commas. It +assembles floating point numbers. +@ifset GENERIC +The exact kind of floating point numbers emitted depends on how +@command{@value{AS}} is configured. @xref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset IEEEFLOAT +On the @value{TARGET} family @samp{.double} emits 64-bit floating-point numbers +in @sc{ieee} format. +@end ifset +@end ifclear + +@node Eject +@section @code{.eject} + +@cindex @code{eject} directive +@cindex new page, in listings +@cindex page, in listings +@cindex listing control: new page +Force a page break at this point, when generating assembly listings. + +@node Else +@section @code{.else} + +@cindex @code{else} directive +@code{.else} is part of the @command{@value{AS}} support for conditional +assembly; @pxref{If,,@code{.if}}. It marks the beginning of a section +of code to be assembled if the condition for the preceding @code{.if} +was false. + +@node Elseif +@section @code{.elseif} + +@cindex @code{elseif} directive +@code{.elseif} is part of the @command{@value{AS}} support for conditional +assembly; @pxref{If,,@code{.if}}. It is shorthand for beginning a new +@code{.if} block that would otherwise fill the entire @code{.else} section. + +@node End +@section @code{.end} + +@cindex @code{end} directive +@code{.end} marks the end of the assembly file. @command{@value{AS}} does not +process anything in the file past the @code{.end} directive. + +@ifset COFF +@node Endef +@section @code{.endef} + +@cindex @code{endef} directive +This directive flags the end of a symbol definition begun with +@code{.def}. +@ifset BOUT + +@samp{.endef} is only meaningful when generating COFF format output; if +@command{@value{AS}} is configured to generate @code{b.out}, it accepts this +directive but ignores it. +@end ifset +@end ifset + +@node Endfunc +@section @code{.endfunc} +@cindex @code{endfunc} directive +@code{.endfunc} marks the end of a function specified with @code{.func}. + +@node Endif +@section @code{.endif} + +@cindex @code{endif} directive +@code{.endif} is part of the @command{@value{AS}} support for conditional assembly; +it marks the end of a block of code that is only assembled +conditionally. @xref{If,,@code{.if}}. + +@node Equ +@section @code{.equ @var{symbol}, @var{expression}} + +@cindex @code{equ} directive +@cindex assigning values to symbols +@cindex symbols, assigning values to +This directive sets the value of @var{symbol} to @var{expression}. +It is synonymous with @samp{.set}; @pxref{Set,,@code{.set}}. + +@ifset HPPA +The syntax for @code{equ} on the HPPA is +@samp{@var{symbol} .equ @var{expression}}. +@end ifset + +@node Equiv +@section @code{.equiv @var{symbol}, @var{expression}} +@cindex @code{equiv} directive +The @code{.equiv} directive is like @code{.equ} and @code{.set}, except that +the assembler will signal an error if @var{symbol} is already defined. Note a +symbol which has been referenced but not actually defined is considered to be +undefined. + +Except for the contents of the error message, this is roughly equivalent to +@smallexample +.ifdef SYM +.err +.endif +.equ SYM,VAL +@end smallexample + +@node Err +@section @code{.err} +@cindex @code{err} directive +If @command{@value{AS}} assembles a @code{.err} directive, it will print an error +message and, unless the @option{-Z} option was used, it will not generate an +object file. This can be used to signal error an conditionally compiled code. + +@node Exitm +@section @code{.exitm} +Exit early from the current macro definition. @xref{Macro}. + +@node Extern +@section @code{.extern} + +@cindex @code{extern} directive +@code{.extern} is accepted in the source program---for compatibility +with other assemblers---but it is ignored. @command{@value{AS}} treats +all undefined symbols as external. + +@node Fail +@section @code{.fail @var{expression}} + +@cindex @code{fail} directive +Generates an error or a warning. If the value of the @var{expression} is 500 +or more, @command{@value{AS}} will print a warning message. If the value is less +than 500, @command{@value{AS}} will print an error message. The message will +include the value of @var{expression}. This can occasionally be useful inside +complex nested macros or conditional assembly. + +@ifclear no-file-dir +@node File +@section @code{.file @var{string}} + +@cindex @code{file} directive +@cindex logical file name +@cindex file name, logical +@code{.file} tells @command{@value{AS}} that we are about to start a new logical +file. @var{string} is the new file name. In general, the filename is +recognized whether or not it is surrounded by quotes @samp{"}; but if you wish +to specify an empty file name, you must give the quotes--@code{""}. This +statement may go away in future: it is only recognized to be compatible with +old @command{@value{AS}} programs. +@ifset A29K +In some configurations of @command{@value{AS}}, @code{.file} has already been +removed to avoid conflicts with other assemblers. @xref{Machine Dependencies}. +@end ifset +@end ifclear + +@node Fill +@section @code{.fill @var{repeat} , @var{size} , @var{value}} + +@cindex @code{fill} directive +@cindex writing patterns in memory +@cindex patterns, writing in memory +@var{repeat}, @var{size} and @var{value} are absolute expressions. +This emits @var{repeat} copies of @var{size} bytes. @var{Repeat} +may be zero or more. @var{Size} may be zero or more, but if it is +more than 8, then it is deemed to have the value 8, compatible with +other people's assemblers. The contents of each @var{repeat} bytes +is taken from an 8-byte number. The highest order 4 bytes are +zero. The lowest order 4 bytes are @var{value} rendered in the +byte-order of an integer on the computer @command{@value{AS}} is assembling for. +Each @var{size} bytes in a repetition is taken from the lowest order +@var{size} bytes of this number. Again, this bizarre behavior is +compatible with other people's assemblers. + +@var{size} and @var{value} are optional. +If the second comma and @var{value} are absent, @var{value} is +assumed zero. If the first comma and following tokens are absent, +@var{size} is assumed to be 1. + +@node Float +@section @code{.float @var{flonums}} + +@cindex floating point numbers (single) +@cindex @code{float} directive +This directive assembles zero or more flonums, separated by commas. It +has the same effect as @code{.single}. +@ifset GENERIC +The exact kind of floating point numbers emitted depends on how +@command{@value{AS}} is configured. +@xref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset IEEEFLOAT +On the @value{TARGET} family, @code{.float} emits 32-bit floating point numbers +in @sc{ieee} format. +@end ifset +@end ifclear + +@node Func +@section @code{.func @var{name}[,@var{label}]} +@cindex @code{func} directive +@code{.func} emits debugging information to denote function @var{name}, and +is ignored unless the file is assembled with debugging enabled. +Only @samp{--gstabs} is currently supported. +@var{label} is the entry point of the function and if omitted @var{name} +prepended with the @samp{leading char} is used. +@samp{leading char} is usually @code{_} or nothing, depending on the target. +All functions are currently defined to have @code{void} return type. +The function must be terminated with @code{.endfunc}. + +@node Global +@section @code{.global @var{symbol}}, @code{.globl @var{symbol}} + +@cindex @code{global} directive +@cindex symbol, making visible to linker +@code{.global} makes the symbol visible to @code{@value{LD}}. If you define +@var{symbol} in your partial program, its value is made available to +other partial programs that are linked with it. Otherwise, +@var{symbol} takes its attributes from a symbol of the same name +from another file linked into the same program. + +Both spellings (@samp{.globl} and @samp{.global}) are accepted, for +compatibility with other assemblers. + +@ifset HPPA +On the HPPA, @code{.global} is not always enough to make it accessible to other +partial programs. You may need the HPPA-only @code{.EXPORT} directive as well. +@xref{HPPA Directives,, HPPA Assembler Directives}. +@end ifset + +@ifset ELF +@node Hidden +@section @code{.hidden @var{names}} + +@cindex @code{hidden} directive +@cindex visibility +This one of the ELF visibility directives. The other two are +@code{.internal} (@pxref{Internal,,@code{.internal}}) and +@code{.protected} (@pxref{Protected,,@code{.protected}}). + +This directive overrides the named symbols default visibility (which is set by +their binding: local, global or weak). The directive sets the visibility to +@code{hidden} which means that the symbols are not visible to other components. +Such symbols are always considered to be @code{protected} as well. +@end ifset + +@node hword +@section @code{.hword @var{expressions}} + +@cindex @code{hword} directive +@cindex integers, 16-bit +@cindex numbers, 16-bit +@cindex sixteen bit integers +This expects zero or more @var{expressions}, and emits +a 16 bit number for each. + +@ifset GENERIC +This directive is a synonym for @samp{.short}; depending on the target +architecture, it may also be a synonym for @samp{.word}. +@end ifset +@ifclear GENERIC +@ifset W32 +This directive is a synonym for @samp{.short}. +@end ifset +@ifset W16 +This directive is a synonym for both @samp{.short} and @samp{.word}. +@end ifset +@end ifclear + +@node Ident +@section @code{.ident} + +@cindex @code{ident} directive +This directive is used by some assemblers to place tags in object files. +@command{@value{AS}} simply accepts the directive for source-file +compatibility with such assemblers, but does not actually emit anything +for it. + +@node If +@section @code{.if @var{absolute expression}} + +@cindex conditional assembly +@cindex @code{if} directive +@code{.if} marks the beginning of a section of code which is only +considered part of the source program being assembled if the argument +(which must be an @var{absolute expression}) is non-zero. The end of +the conditional section of code must be marked by @code{.endif} +(@pxref{Endif,,@code{.endif}}); optionally, you may include code for the +alternative condition, flagged by @code{.else} (@pxref{Else,,@code{.else}}). +If you have several conditions to check, @code{.elseif} may be used to avoid +nesting blocks if/else within each subsequent @code{.else} block. + +The following variants of @code{.if} are also supported: +@table @code +@cindex @code{ifdef} directive +@item .ifdef @var{symbol} +Assembles the following section of code if the specified @var{symbol} +has been defined. Note a symbol which has been referenced but not yet defined +is considered to be undefined. + +@cindex @code{ifc} directive +@item .ifc @var{string1},@var{string2} +Assembles the following section of code if the two strings are the same. The +strings may be optionally quoted with single quotes. If they are not quoted, +the first string stops at the first comma, and the second string stops at the +end of the line. Strings which contain whitespace should be quoted. The +string comparison is case sensitive. + +@cindex @code{ifeq} directive +@item .ifeq @var{absolute expression} +Assembles the following section of code if the argument is zero. + +@cindex @code{ifeqs} directive +@item .ifeqs @var{string1},@var{string2} +Another form of @code{.ifc}. The strings must be quoted using double quotes. + +@cindex @code{ifge} directive +@item .ifge @var{absolute expression} +Assembles the following section of code if the argument is greater than or +equal to zero. + +@cindex @code{ifgt} directive +@item .ifgt @var{absolute expression} +Assembles the following section of code if the argument is greater than zero. + +@cindex @code{ifle} directive +@item .ifle @var{absolute expression} +Assembles the following section of code if the argument is less than or equal +to zero. + +@cindex @code{iflt} directive +@item .iflt @var{absolute expression} +Assembles the following section of code if the argument is less than zero. + +@cindex @code{ifnc} directive +@item .ifnc @var{string1},@var{string2}. +Like @code{.ifc}, but the sense of the test is reversed: this assembles the +following section of code if the two strings are not the same. + +@cindex @code{ifndef} directive +@cindex @code{ifnotdef} directive +@item .ifndef @var{symbol} +@itemx .ifnotdef @var{symbol} +Assembles the following section of code if the specified @var{symbol} +has not been defined. Both spelling variants are equivalent. Note a symbol +which has been referenced but not yet defined is considered to be undefined. + +@cindex @code{ifne} directive +@item .ifne @var{absolute expression} +Assembles the following section of code if the argument is not equal to zero +(in other words, this is equivalent to @code{.if}). + +@cindex @code{ifnes} directive +@item .ifnes @var{string1},@var{string2} +Like @code{.ifeqs}, but the sense of the test is reversed: this assembles the +following section of code if the two strings are not the same. +@end table + +@node Incbin +@section @code{.incbin "@var{file}"[,@var{skip}[,@var{count}]]} + +@cindex @code{incbin} directive +@cindex binary files, including +The @code{incbin} directive includes @var{file} verbatim at the current +location. You can control the search paths used with the @samp{-I} command-line +option (@pxref{Invoking,,Command-Line Options}). Quotation marks are required +around @var{file}. + +The @var{skip} argument skips a number of bytes from the start of the +@var{file}. The @var{count} argument indicates the maximum number of bytes to +read. Note that the data is not aligned in any way, so it is the user's +responsibility to make sure that proper alignment is provided both before and +after the @code{incbin} directive. + +@node Include +@section @code{.include "@var{file}"} + +@cindex @code{include} directive +@cindex supporting files, including +@cindex files, including +This directive provides a way to include supporting files at specified +points in your source program. The code from @var{file} is assembled as +if it followed the point of the @code{.include}; when the end of the +included file is reached, assembly of the original file continues. You +can control the search paths used with the @samp{-I} command-line option +(@pxref{Invoking,,Command-Line Options}). Quotation marks are required +around @var{file}. + +@node Int +@section @code{.int @var{expressions}} + +@cindex @code{int} directive +@cindex integers, 32-bit +Expect zero or more @var{expressions}, of any section, separated by commas. +For each expression, emit a number that, at run time, is the value of that +expression. The byte order and bit size of the number depends on what kind +of target the assembly is for. + +@ifclear GENERIC +@ifset H8 +On the H8/500 and most forms of the H8/300, @code{.int} emits 16-bit +integers. On the H8/300H and the Renesas SH, however, @code{.int} emits +32-bit integers. +@end ifset +@end ifclear + +@ifset ELF +@node Internal +@section @code{.internal @var{names}} + +@cindex @code{internal} directive +@cindex visibility +This one of the ELF visibility directives. The other two are +@code{.hidden} (@pxref{Hidden,,@code{.hidden}}) and +@code{.protected} (@pxref{Protected,,@code{.protected}}). + +This directive overrides the named symbols default visibility (which is set by +their binding: local, global or weak). The directive sets the visibility to +@code{internal} which means that the symbols are considered to be @code{hidden} +(i.e., not visible to other components), and that some extra, processor specific +processing must also be performed upon the symbols as well. +@end ifset + +@node Irp +@section @code{.irp @var{symbol},@var{values}}@dots{} + +@cindex @code{irp} directive +Evaluate a sequence of statements assigning different values to @var{symbol}. +The sequence of statements starts at the @code{.irp} directive, and is +terminated by an @code{.endr} directive. For each @var{value}, @var{symbol} is +set to @var{value}, and the sequence of statements is assembled. If no +@var{value} is listed, the sequence of statements is assembled once, with +@var{symbol} set to the null string. To refer to @var{symbol} within the +sequence of statements, use @var{\symbol}. + +For example, assembling + +@example + .irp param,1,2,3 + move d\param,sp@@- + .endr +@end example + +is equivalent to assembling + +@example + move d1,sp@@- + move d2,sp@@- + move d3,sp@@- +@end example + +@node Irpc +@section @code{.irpc @var{symbol},@var{values}}@dots{} + +@cindex @code{irpc} directive +Evaluate a sequence of statements assigning different values to @var{symbol}. +The sequence of statements starts at the @code{.irpc} directive, and is +terminated by an @code{.endr} directive. For each character in @var{value}, +@var{symbol} is set to the character, and the sequence of statements is +assembled. If no @var{value} is listed, the sequence of statements is +assembled once, with @var{symbol} set to the null string. To refer to +@var{symbol} within the sequence of statements, use @var{\symbol}. + +For example, assembling + +@example + .irpc param,123 + move d\param,sp@@- + .endr +@end example + +is equivalent to assembling + +@example + move d1,sp@@- + move d2,sp@@- + move d3,sp@@- +@end example + +@node Lcomm +@section @code{.lcomm @var{symbol} , @var{length}} + +@cindex @code{lcomm} directive +@cindex local common symbols +@cindex symbols, local common +Reserve @var{length} (an absolute expression) bytes for a local common +denoted by @var{symbol}. The section and value of @var{symbol} are +those of the new local common. The addresses are allocated in the bss +section, so that at run-time the bytes start off zeroed. @var{Symbol} +is not declared global (@pxref{Global,,@code{.global}}), so is normally +not visible to @code{@value{LD}}. + +@ifset GENERIC +Some targets permit a third argument to be used with @code{.lcomm}. This +argument specifies the desired alignment of the symbol in the bss section. +@end ifset + +@ifset HPPA +The syntax for @code{.lcomm} differs slightly on the HPPA. The syntax is +@samp{@var{symbol} .lcomm, @var{length}}; @var{symbol} is optional. +@end ifset + +@node Lflags +@section @code{.lflags} + +@cindex @code{lflags} directive (ignored) +@command{@value{AS}} accepts this directive, for compatibility with other +assemblers, but ignores it. + +@ifclear no-line-dir +@node Line +@section @code{.line @var{line-number}} + +@cindex @code{line} directive +@end ifclear +@ifset no-line-dir +@node Ln +@section @code{.ln @var{line-number}} + +@cindex @code{ln} directive +@end ifset +@cindex logical line number +@ifset aout-bout +Change the logical line number. @var{line-number} must be an absolute +expression. The next line has that logical line number. Therefore any other +statements on the current line (after a statement separator character) are +reported as on logical line number @var{line-number} @minus{} 1. One day +@command{@value{AS}} will no longer support this directive: it is recognized only +for compatibility with existing assembler programs. + +@ifset GENERIC +@ifset A29K +@emph{Warning:} In the AMD29K configuration of @value{AS}, this command is +not available; use the synonym @code{.ln} in that context. +@end ifset +@end ifset +@end ifset + +@ifclear no-line-dir +Even though this is a directive associated with the @code{a.out} or +@code{b.out} object-code formats, @command{@value{AS}} still recognizes it +when producing COFF output, and treats @samp{.line} as though it +were the COFF @samp{.ln} @emph{if} it is found outside a +@code{.def}/@code{.endef} pair. + +Inside a @code{.def}, @samp{.line} is, instead, one of the directives +used by compilers to generate auxiliary symbol information for +debugging. +@end ifclear + +@node Linkonce +@section @code{.linkonce [@var{type}]} +@cindex COMDAT +@cindex @code{linkonce} directive +@cindex common sections +Mark the current section so that the linker only includes a single copy of it. +This may be used to include the same section in several different object files, +but ensure that the linker will only include it once in the final output file. +The @code{.linkonce} pseudo-op must be used for each instance of the section. +Duplicate sections are detected based on the section name, so it should be +unique. + +This directive is only supported by a few object file formats; as of this +writing, the only object file format which supports it is the Portable +Executable format used on Windows NT. + +The @var{type} argument is optional. If specified, it must be one of the +following strings. For example: +@smallexample +.linkonce same_size +@end smallexample +Not all types may be supported on all object file formats. + +@table @code +@item discard +Silently discard duplicate sections. This is the default. + +@item one_only +Warn if there are duplicate sections, but still keep only one copy. + +@item same_size +Warn if any of the duplicates have different sizes. + +@item same_contents +Warn if any of the duplicates do not have exactly the same contents. +@end table + +@node Ln +@section @code{.ln @var{line-number}} + +@cindex @code{ln} directive +@ifclear no-line-dir +@samp{.ln} is a synonym for @samp{.line}. +@end ifclear +@ifset no-line-dir +Tell @command{@value{AS}} to change the logical line number. @var{line-number} +must be an absolute expression. The next line has that logical +line number, so any other statements on the current line (after a +statement separator character @code{;}) are reported as on logical +line number @var{line-number} @minus{} 1. +@ifset BOUT + +This directive is accepted, but ignored, when @command{@value{AS}} is +configured for @code{b.out}; its effect is only associated with COFF +output format. +@end ifset +@end ifset + +@node MRI +@section @code{.mri @var{val}} + +@cindex @code{mri} directive +@cindex MRI mode, temporarily +If @var{val} is non-zero, this tells @command{@value{AS}} to enter MRI mode. If +@var{val} is zero, this tells @command{@value{AS}} to exit MRI mode. This change +affects code assembled until the next @code{.mri} directive, or until the end +of the file. @xref{M, MRI mode, MRI mode}. + +@node List +@section @code{.list} + +@cindex @code{list} directive +@cindex listing control, turning on +Control (in conjunction with the @code{.nolist} directive) whether or +not assembly listings are generated. These two directives maintain an +internal counter (which is zero initially). @code{.list} increments the +counter, and @code{.nolist} decrements it. Assembly listings are +generated whenever the counter is greater than zero. + +By default, listings are disabled. When you enable them (with the +@samp{-a} command line option; @pxref{Invoking,,Command-Line Options}), +the initial value of the listing counter is one. + +@node Long +@section @code{.long @var{expressions}} + +@cindex @code{long} directive +@code{.long} is the same as @samp{.int}, @pxref{Int,,@code{.int}}. + +@ignore +@c no one seems to know what this is for or whether this description is +@c what it really ought to do +@node Lsym +@section @code{.lsym @var{symbol}, @var{expression}} + +@cindex @code{lsym} directive +@cindex symbol, not referenced in assembly +@code{.lsym} creates a new symbol named @var{symbol}, but does not put it in +the hash table, ensuring it cannot be referenced by name during the +rest of the assembly. This sets the attributes of the symbol to be +the same as the expression value: +@smallexample +@var{other} = @var{descriptor} = 0 +@var{type} = @r{(section of @var{expression})} +@var{value} = @var{expression} +@end smallexample +@noindent +The new symbol is not flagged as external. +@end ignore + +@node Macro +@section @code{.macro} + +@cindex macros +The commands @code{.macro} and @code{.endm} allow you to define macros that +generate assembly output. For example, this definition specifies a macro +@code{sum} that puts a sequence of numbers into memory: + +@example + .macro sum from=0, to=5 + .long \from + .if \to-\from + sum "(\from+1)",\to + .endif + .endm +@end example + +@noindent +With that definition, @samp{SUM 0,5} is equivalent to this assembly input: + +@example + .long 0 + .long 1 + .long 2 + .long 3 + .long 4 + .long 5 +@end example + +@ftable @code +@item .macro @var{macname} +@itemx .macro @var{macname} @var{macargs} @dots{} +@cindex @code{macro} directive +Begin the definition of a macro called @var{macname}. If your macro +definition requires arguments, specify their names after the macro name, +separated by commas or spaces. You can supply a default value for any +macro argument by following the name with @samp{=@var{deflt}}. For +example, these are all valid @code{.macro} statements: + +@table @code +@item .macro comm +Begin the definition of a macro called @code{comm}, which takes no +arguments. + +@item .macro plus1 p, p1 +@itemx .macro plus1 p p1 +Either statement begins the definition of a macro called @code{plus1}, +which takes two arguments; within the macro definition, write +@samp{\p} or @samp{\p1} to evaluate the arguments. + +@item .macro reserve_str p1=0 p2 +Begin the definition of a macro called @code{reserve_str}, with two +arguments. The first argument has a default value, but not the second. +After the definition is complete, you can call the macro either as +@samp{reserve_str @var{a},@var{b}} (with @samp{\p1} evaluating to +@var{a} and @samp{\p2} evaluating to @var{b}), or as @samp{reserve_str +,@var{b}} (with @samp{\p1} evaluating as the default, in this case +@samp{0}, and @samp{\p2} evaluating to @var{b}). +@end table + +When you call a macro, you can specify the argument values either by +position, or by keyword. For example, @samp{sum 9,17} is equivalent to +@samp{sum to=17, from=9}. + +@item .endm +@cindex @code{endm} directive +Mark the end of a macro definition. + +@item .exitm +@cindex @code{exitm} directive +Exit early from the current macro definition. + +@cindex number of macros executed +@cindex macros, count executed +@item \@@ +@command{@value{AS}} maintains a counter of how many macros it has +executed in this pseudo-variable; you can copy that number to your +output with @samp{\@@}, but @emph{only within a macro definition}. + +@ignore +@item LOCAL @var{name} [ , @dots{} ] +@emph{Warning: @code{LOCAL} is only available if you select ``alternate +macro syntax'' with @samp{-a} or @samp{--alternate}.} @xref{Alternate,, +Alternate macro syntax}. + +Generate a string replacement for each of the @var{name} arguments, and +replace any instances of @var{name} in each macro expansion. The +replacement string is unique in the assembly, and different for each +separate macro expansion. @code{LOCAL} allows you to write macros that +define symbols, without fear of conflict between separate macro expansions. +@end ignore +@end ftable + +@node Nolist +@section @code{.nolist} + +@cindex @code{nolist} directive +@cindex listing control, turning off +Control (in conjunction with the @code{.list} directive) whether or +not assembly listings are generated. These two directives maintain an +internal counter (which is zero initially). @code{.list} increments the +counter, and @code{.nolist} decrements it. Assembly listings are +generated whenever the counter is greater than zero. + +@node Octa +@section @code{.octa @var{bignums}} + +@c FIXME: double size emitted for "octa" on i960, others? Or warn? +@cindex @code{octa} directive +@cindex integer, 16-byte +@cindex sixteen byte integer +This directive expects zero or more bignums, separated by commas. For each +bignum, it emits a 16-byte integer. + +The term ``octa'' comes from contexts in which a ``word'' is two bytes; +hence @emph{octa}-word for 16 bytes. + +@node Org +@section @code{.org @var{new-lc} , @var{fill}} + +@cindex @code{org} directive +@cindex location counter, advancing +@cindex advancing location counter +@cindex current address, advancing +Advance the location counter of the current section to +@var{new-lc}. @var{new-lc} is either an absolute expression or an +expression with the same section as the current subsection. That is, +you can't use @code{.org} to cross sections: if @var{new-lc} has the +wrong section, the @code{.org} directive is ignored. To be compatible +with former assemblers, if the section of @var{new-lc} is absolute, +@command{@value{AS}} issues a warning, then pretends the section of @var{new-lc} +is the same as the current subsection. + +@code{.org} may only increase the location counter, or leave it +unchanged; you cannot use @code{.org} to move the location counter +backwards. + +@c double negative used below "not undefined" because this is a specific +@c reference to "undefined" (as SEG_UNKNOWN is called in this manual) +@c section. doc@cygnus.com 18feb91 +Because @command{@value{AS}} tries to assemble programs in one pass, @var{new-lc} +may not be undefined. If you really detest this restriction we eagerly await +a chance to share your improved assembler. + +Beware that the origin is relative to the start of the section, not +to the start of the subsection. This is compatible with other +people's assemblers. + +When the location counter (of the current subsection) is advanced, the +intervening bytes are filled with @var{fill} which should be an +absolute expression. If the comma and @var{fill} are omitted, +@var{fill} defaults to zero. + +@node P2align +@section @code{.p2align[wl] @var{abs-expr}, @var{abs-expr}, @var{abs-expr}} + +@cindex padding the location counter given a power of two +@cindex @code{p2align} directive +Pad the location counter (in the current subsection) to a particular +storage boundary. The first expression (which must be absolute) is the +number of low-order zero bits the location counter must have after +advancement. For example @samp{.p2align 3} advances the location +counter until it a multiple of 8. If the location counter is already a +multiple of 8, no change is needed. + +The second expression (also absolute) gives the fill value to be stored in the +padding bytes. It (and the comma) may be omitted. If it is omitted, the +padding bytes are normally zero. However, on some systems, if the section is +marked as containing code and the fill value is omitted, the space is filled +with no-op instructions. + +The third expression is also absolute, and is also optional. If it is present, +it is the maximum number of bytes that should be skipped by this alignment +directive. If doing the alignment would require skipping more bytes than the +specified maximum, then the alignment is not done at all. You can omit the +fill value (the second argument) entirely by simply using two commas after the +required alignment; this can be useful if you want the alignment to be filled +with no-op instructions when appropriate. + +@cindex @code{p2alignw} directive +@cindex @code{p2alignl} directive +The @code{.p2alignw} and @code{.p2alignl} directives are variants of the +@code{.p2align} directive. The @code{.p2alignw} directive treats the fill +pattern as a two byte word value. The @code{.p2alignl} directives treats the +fill pattern as a four byte longword value. For example, @code{.p2alignw +2,0x368d} will align to a multiple of 4. If it skips two bytes, they will be +filled in with the value 0x368d (the exact placement of the bytes depends upon +the endianness of the processor). If it skips 1 or 3 bytes, the fill value is +undefined. + +@ifset ELF +@node Previous +@section @code{.previous} + +@cindex @code{previous} directive +@cindex Section Stack +This is one of the ELF section stack manipulation directives. The others are +@code{.section} (@pxref{Section}), @code{.subsection} (@pxref{SubSection}), +@code{.pushsection} (@pxref{PushSection}), and @code{.popsection} +(@pxref{PopSection}). + +This directive swaps the current section (and subsection) with most recently +referenced section (and subsection) prior to this one. Multiple +@code{.previous} directives in a row will flip between two sections (and their +subsections). + +In terms of the section stack, this directive swaps the current section with +the top section on the section stack. +@end ifset + +@ifset ELF +@node PopSection +@section @code{.popsection} + +@cindex @code{popsection} directive +@cindex Section Stack +This is one of the ELF section stack manipulation directives. The others are +@code{.section} (@pxref{Section}), @code{.subsection} (@pxref{SubSection}), +@code{.pushsection} (@pxref{PushSection}), and @code{.previous} +(@pxref{Previous}). + +This directive replaces the current section (and subsection) with the top +section (and subsection) on the section stack. This section is popped off the +stack. +@end ifset + +@node Print +@section @code{.print @var{string}} + +@cindex @code{print} directive +@command{@value{AS}} will print @var{string} on the standard output during +assembly. You must put @var{string} in double quotes. + +@ifset ELF +@node Protected +@section @code{.protected @var{names}} + +@cindex @code{protected} directive +@cindex visibility +This one of the ELF visibility directives. The other two are +@code{.hidden} (@pxref{Hidden}) and @code{.internal} (@pxref{Internal}). + +This directive overrides the named symbols default visibility (which is set by +their binding: local, global or weak). The directive sets the visibility to +@code{protected} which means that any references to the symbols from within the +components that defines them must be resolved to the definition in that +component, even if a definition in another component would normally preempt +this. +@end ifset + +@node Psize +@section @code{.psize @var{lines} , @var{columns}} + +@cindex @code{psize} directive +@cindex listing control: paper size +@cindex paper size, for listings +Use this directive to declare the number of lines---and, optionally, the +number of columns---to use for each page, when generating listings. + +If you do not use @code{.psize}, listings use a default line-count +of 60. You may omit the comma and @var{columns} specification; the +default width is 200 columns. + +@command{@value{AS}} generates formfeeds whenever the specified number of +lines is exceeded (or whenever you explicitly request one, using +@code{.eject}). + +If you specify @var{lines} as @code{0}, no formfeeds are generated save +those explicitly specified with @code{.eject}. + +@node Purgem +@section @code{.purgem @var{name}} + +@cindex @code{purgem} directive +Undefine the macro @var{name}, so that later uses of the string will not be +expanded. @xref{Macro}. + +@ifset ELF +@node PushSection +@section @code{.pushsection @var{name} , @var{subsection}} + +@cindex @code{pushsection} directive +@cindex Section Stack +This is one of the ELF section stack manipulation directives. The others are +@code{.section} (@pxref{Section}), @code{.subsection} (@pxref{SubSection}), +@code{.popsection} (@pxref{PopSection}), and @code{.previous} +(@pxref{Previous}). + +This directive is a synonym for @code{.section}. It pushes the current section +(and subsection) onto the top of the section stack, and then replaces the +current section and subsection with @code{name} and @code{subsection}. +@end ifset + +@node Quad +@section @code{.quad @var{bignums}} + +@cindex @code{quad} directive +@code{.quad} expects zero or more bignums, separated by commas. For +each bignum, it emits +@ifclear bignum-16 +an 8-byte integer. If the bignum won't fit in 8 bytes, it prints a +warning message; and just takes the lowest order 8 bytes of the bignum. +@cindex eight-byte integer +@cindex integer, 8-byte + +The term ``quad'' comes from contexts in which a ``word'' is two bytes; +hence @emph{quad}-word for 8 bytes. +@end ifclear +@ifset bignum-16 +a 16-byte integer. If the bignum won't fit in 16 bytes, it prints a +warning message; and just takes the lowest order 16 bytes of the bignum. +@cindex sixteen-byte integer +@cindex integer, 16-byte +@end ifset + +@node Rept +@section @code{.rept @var{count}} + +@cindex @code{rept} directive +Repeat the sequence of lines between the @code{.rept} directive and the next +@code{.endr} directive @var{count} times. + +For example, assembling + +@example + .rept 3 + .long 0 + .endr +@end example + +is equivalent to assembling + +@example + .long 0 + .long 0 + .long 0 +@end example + +@node Sbttl +@section @code{.sbttl "@var{subheading}"} + +@cindex @code{sbttl} directive +@cindex subtitles for listings +@cindex listing control: subtitle +Use @var{subheading} as the title (third line, immediately after the +title line) when generating assembly listings. + +This directive affects subsequent pages, as well as the current page if +it appears within ten lines of the top of a page. + +@ifset COFF +@node Scl +@section @code{.scl @var{class}} + +@cindex @code{scl} directive +@cindex symbol storage class (COFF) +@cindex COFF symbol storage class +Set the storage-class value for a symbol. This directive may only be +used inside a @code{.def}/@code{.endef} pair. Storage class may flag +whether a symbol is static or external, or it may record further +symbolic debugging information. +@ifset BOUT + +The @samp{.scl} directive is primarily associated with COFF output; when +configured to generate @code{b.out} output format, @command{@value{AS}} +accepts this directive but ignores it. +@end ifset +@end ifset + +@ifset COFF-ELF +@node Section +@section @code{.section @var{name}} + +@cindex named section +Use the @code{.section} directive to assemble the following code into a section +named @var{name}. + +This directive is only supported for targets that actually support arbitrarily +named sections; on @code{a.out} targets, for example, it is not accepted, even +with a standard @code{a.out} section name. + +@ifset COFF +@ifset ELF +@c only print the extra heading if both COFF and ELF are set +@subheading COFF Version +@end ifset + +@cindex @code{section} directive (COFF version) +For COFF targets, the @code{.section} directive is used in one of the following +ways: + +@smallexample +.section @var{name}[, "@var{flags}"] +.section @var{name}[, @var{subsegment}] +@end smallexample + +If the optional argument is quoted, it is taken as flags to use for the +section. Each flag is a single character. The following flags are recognized: +@table @code +@item b +bss section (uninitialized data) +@item n +section is not loaded +@item w +writable section +@item d +data section +@item r +read-only section +@item x +executable section +@item s +shared section (meaningful for PE targets) +@item a +ignored. (For compatibility with the ELF version) +@end table + +If no flags are specified, the default flags depend upon the section name. If +the section name is not recognized, the default will be for the section to be +loaded and writable. Note the @code{n} and @code{w} flags remove attributes +from the section, rather than adding them, so if they are used on their own it +will be as if no flags had been specified at all. + +If the optional argument to the @code{.section} directive is not quoted, it is +taken as a subsegment number (@pxref{Sub-Sections}). +@end ifset + +@ifset ELF +@ifset COFF +@c only print the extra heading if both COFF and ELF are set +@subheading ELF Version +@end ifset + +@cindex Section Stack +This is one of the ELF section stack manipulation directives. The others are +@code{.subsection} (@pxref{SubSection}), @code{.pushsection} +(@pxref{PushSection}), @code{.popsection} (@pxref{PopSection}), and +@code{.previous} (@pxref{Previous}). + +@cindex @code{section} directive (ELF version) +For ELF targets, the @code{.section} directive is used like this: + +@smallexample +.section @var{name} [, "@var{flags}"[, @@@var{type}[, @@@var{entsize}]]] +@end smallexample + +The optional @var{flags} argument is a quoted string which may contain any +combination of the following characters: +@table @code +@item a +section is allocatable +@item w +section is writable +@item x +section is executable +@item M +section is mergeable +@item S +section contains zero terminated strings +@end table + +The optional @var{type} argument may contain one of the following constants: +@table @code +@item @@progbits +section contains data +@item @@nobits +section does not contain data (i.e., section only occupies space) +@end table + +Note on targets where the @code{@@} character is the start of a comment (eg +ARM) then another character is used instead. For example the ARM port uses the +@code{%} character. + +If @var{flags} contains @code{M} flag, @var{type} argument must be specified +as well as @var{entsize} argument. Sections with @code{M} flag but not +@code{S} flag must contain fixed size constants, each @var{entsize} octets +long. Sections with both @code{M} and @code{S} must contain zero terminated +strings where each character is @var{entsize} bytes long. The linker may remove +duplicates within sections with the same name, same entity size and same flags. + +If no flags are specified, the default flags depend upon the section name. If +the section name is not recognized, the default will be for the section to have +none of the above flags: it will not be allocated in memory, nor writable, nor +executable. The section will contain data. + +For ELF targets, the assembler supports another type of @code{.section} +directive for compatibility with the Solaris assembler: + +@smallexample +.section "@var{name}"[, @var{flags}...] +@end smallexample + +Note that the section name is quoted. There may be a sequence of comma +separated flags: +@table @code +@item #alloc +section is allocatable +@item #write +section is writable +@item #execinstr +section is executable +@end table + +This directive replaces the current section and subsection. The replaced +section and subsection are pushed onto the section stack. See the contents of +the gas testsuite directory @code{gas/testsuite/gas/elf} for some examples of +how this directive and the other section stack directives work. +@end ifset +@end ifset + +@node Set +@section @code{.set @var{symbol}, @var{expression}} + +@cindex @code{set} directive +@cindex symbol value, setting +Set the value of @var{symbol} to @var{expression}. This +changes @var{symbol}'s value and type to conform to +@var{expression}. If @var{symbol} was flagged as external, it remains +flagged (@pxref{Symbol Attributes}). + +You may @code{.set} a symbol many times in the same assembly. + +If you @code{.set} a global symbol, the value stored in the object +file is the last value stored into it. + +@ifset HPPA +The syntax for @code{set} on the HPPA is +@samp{@var{symbol} .set @var{expression}}. +@end ifset + +@node Short +@section @code{.short @var{expressions}} + +@cindex @code{short} directive +@ifset GENERIC +@code{.short} is normally the same as @samp{.word}. +@xref{Word,,@code{.word}}. + +In some configurations, however, @code{.short} and @code{.word} generate +numbers of different lengths; @pxref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset W16 +@code{.short} is the same as @samp{.word}. @xref{Word,,@code{.word}}. +@end ifset +@ifset W32 +This expects zero or more @var{expressions}, and emits +a 16 bit number for each. +@end ifset +@end ifclear + +@node Single +@section @code{.single @var{flonums}} + +@cindex @code{single} directive +@cindex floating point numbers (single) +This directive assembles zero or more flonums, separated by commas. It +has the same effect as @code{.float}. +@ifset GENERIC +The exact kind of floating point numbers emitted depends on how +@command{@value{AS}} is configured. @xref{Machine Dependencies}. +@end ifset +@ifclear GENERIC +@ifset IEEEFLOAT +On the @value{TARGET} family, @code{.single} emits 32-bit floating point +numbers in @sc{ieee} format. +@end ifset +@end ifclear + +@ifset COFF-ELF +@node Size +@section @code{.size} + +This directive is used to set the size associated with a symbol. + +@ifset COFF +@ifset ELF +@c only print the extra heading if both COFF and ELF are set +@subheading COFF Version +@end ifset + +@cindex @code{size} directive (COFF version) +For COFF targets, the @code{.size} directive is only permitted inside +@code{.def}/@code{.endef} pairs. It is used like this: + +@smallexample +.size @var{expression} +@end smallexample + +@ifset BOUT +@samp{.size} is only meaningful when generating COFF format output; when +@command{@value{AS}} is generating @code{b.out}, it accepts this directive but +ignores it. +@end ifset +@end ifset + +@ifset ELF +@ifset COFF +@c only print the extra heading if both COFF and ELF are set +@subheading ELF Version +@end ifset + +@cindex @code{size} directive (ELF version) +For ELF targets, the @code{.size} directive is used like this: + +@smallexample +.size @var{name} , @var{expression} +@end smallexample + +This directive sets the size associated with a symbol @var{name}. +The size in bytes is computed from @var{expression} which can make use of label +arithmetic. This directive is typically used to set the size of function +symbols. +@end ifset +@end ifset + +@node Sleb128 +@section @code{.sleb128 @var{expressions}} + +@cindex @code{sleb128} directive +@var{sleb128} stands for ``signed little endian base 128.'' This is a +compact, variable length representation of numbers used by the DWARF +symbolic debugging format. @xref{Uleb128,@code{.uleb128}}. + +@ifclear no-space-dir +@node Skip +@section @code{.skip @var{size} , @var{fill}} + +@cindex @code{skip} directive +@cindex filling memory +This directive emits @var{size} bytes, each of value @var{fill}. Both +@var{size} and @var{fill} are absolute expressions. If the comma and +@var{fill} are omitted, @var{fill} is assumed to be zero. This is the same as +@samp{.space}. + +@node Space +@section @code{.space @var{size} , @var{fill}} + +@cindex @code{space} directive +@cindex filling memory +This directive emits @var{size} bytes, each of value @var{fill}. Both +@var{size} and @var{fill} are absolute expressions. If the comma +and @var{fill} are omitted, @var{fill} is assumed to be zero. This is the same +as @samp{.skip}. + +@ifset HPPA +@quotation +@emph{Warning:} @code{.space} has a completely different meaning for HPPA +targets; use @code{.block} as a substitute. See @cite{HP9000 Series 800 +Assembly Language Reference Manual} (HP 92432-90001) for the meaning of the +@code{.space} directive. @xref{HPPA Directives,,HPPA Assembler Directives}, +for a summary. +@end quotation +@end ifset +@end ifclear + +@ifset A29K +@ifclear GENERIC +@node Space +@section @code{.space} +@cindex @code{space} directive +@end ifclear +On the AMD 29K, this directive is ignored; it is accepted for +compatibility with other AMD 29K assemblers. + +@quotation +@emph{Warning:} In most versions of the @sc{gnu} assembler, the directive +@code{.space} has the effect of @code{.block} @xref{Machine Dependencies}. +@end quotation +@end ifset + +@ifset have-stabs +@node Stab +@section @code{.stabd, .stabn, .stabs} + +@cindex symbolic debuggers, information for +@cindex @code{stab@var{x}} directives +There are three directives that begin @samp{.stab}. +All emit symbols (@pxref{Symbols}), for use by symbolic debuggers. +The symbols are not entered in the @command{@value{AS}} hash table: they +cannot be referenced elsewhere in the source file. +Up to five fields are required: + +@table @var +@item string +This is the symbol's name. It may contain any character except +@samp{\000}, so is more general than ordinary symbol names. Some +debuggers used to code arbitrarily complex structures into symbol names +using this field. + +@item type +An absolute expression. The symbol's type is set to the low 8 bits of +this expression. Any bit pattern is permitted, but @code{@value{LD}} +and debuggers choke on silly bit patterns. + +@item other +An absolute expression. The symbol's ``other'' attribute is set to the +low 8 bits of this expression. + +@item desc +An absolute expression. The symbol's descriptor is set to the low 16 +bits of this expression. + +@item value +An absolute expression which becomes the symbol's value. +@end table + +If a warning is detected while reading a @code{.stabd}, @code{.stabn}, +or @code{.stabs} statement, the symbol has probably already been created; +you get a half-formed symbol in your object file. This is +compatible with earlier assemblers! + +@table @code +@cindex @code{stabd} directive +@item .stabd @var{type} , @var{other} , @var{desc} + +The ``name'' of the symbol generated is not even an empty string. +It is a null pointer, for compatibility. Older assemblers used a +null pointer so they didn't waste space in object files with empty +strings. + +The symbol's value is set to the location counter, +relocatably. When your program is linked, the value of this symbol +is the address of the location counter when the @code{.stabd} was +assembled. + +@cindex @code{stabn} directive +@item .stabn @var{type} , @var{other} , @var{desc} , @var{value} +The name of the symbol is set to the empty string @code{""}. + +@cindex @code{stabs} directive +@item .stabs @var{string} , @var{type} , @var{other} , @var{desc} , @var{value} +All five fields are specified. +@end table +@end ifset +@c end have-stabs + +@node String +@section @code{.string} "@var{str}" + +@cindex string, copying to object file +@cindex @code{string} directive + +Copy the characters in @var{str} to the object file. You may specify more than +one string to copy, separated by commas. Unless otherwise specified for a +particular machine, the assembler marks the end of each string with a 0 byte. +You can use any of the escape sequences described in @ref{Strings,,Strings}. + +@node Struct +@section @code{.struct @var{expression}} + +@cindex @code{struct} directive +Switch to the absolute section, and set the section offset to @var{expression}, +which must be an absolute expression. You might use this as follows: +@smallexample + .struct 0 +field1: + .struct field1 + 4 +field2: + .struct field2 + 4 +field3: +@end smallexample +This would define the symbol @code{field1} to have the value 0, the symbol +@code{field2} to have the value 4, and the symbol @code{field3} to have the +value 8. Assembly would be left in the absolute section, and you would need to +use a @code{.section} directive of some sort to change to some other section +before further assembly. + +@ifset ELF +@node SubSection +@section @code{.subsection @var{name}} + +@cindex @code{subsection} directive +@cindex Section Stack +This is one of the ELF section stack manipulation directives. The others are +@code{.section} (@pxref{Section}), @code{.pushsection} (@pxref{PushSection}), +@code{.popsection} (@pxref{PopSection}), and @code{.previous} +(@pxref{Previous}). + +This directive replaces the current subsection with @code{name}. The current +section is not changed. The replaced subsection is put onto the section stack +in place of the then current top of stack subsection. +@end ifset + +@ifset ELF +@node Symver +@section @code{.symver} +@cindex @code{symver} directive +@cindex symbol versioning +@cindex versions of symbols +Use the @code{.symver} directive to bind symbols to specific version nodes +within a source file. This is only supported on ELF platforms, and is +typically used when assembling files to be linked into a shared library. +There are cases where it may make sense to use this in objects to be bound +into an application itself so as to override a versioned symbol from a +shared library. + +For ELF targets, the @code{.symver} directive can be used like this: +@smallexample +.symver @var{name}, @var{name2@@nodename} +@end smallexample +If the symbol @var{name} is defined within the file +being assembled, the @code{.symver} directive effectively creates a symbol +alias with the name @var{name2@@nodename}, and in fact the main reason that we +just don't try and create a regular alias is that the @var{@@} character isn't +permitted in symbol names. The @var{name2} part of the name is the actual name +of the symbol by which it will be externally referenced. The name @var{name} +itself is merely a name of convenience that is used so that it is possible to +have definitions for multiple versions of a function within a single source +file, and so that the compiler can unambiguously know which version of a +function is being mentioned. The @var{nodename} portion of the alias should be +the name of a node specified in the version script supplied to the linker when +building a shared library. If you are attempting to override a versioned +symbol from a shared library, then @var{nodename} should correspond to the +nodename of the symbol you are trying to override. + +If the symbol @var{name} is not defined within the file being assembled, all +references to @var{name} will be changed to @var{name2@@nodename}. If no +reference to @var{name} is made, @var{name2@@nodename} will be removed from the +symbol table. + +Another usage of the @code{.symver} directive is: +@smallexample +.symver @var{name}, @var{name2@@@@nodename} +@end smallexample +In this case, the symbol @var{name} must exist and be defined within +the file being assembled. It is similar to @var{name2@@nodename}. The +difference is @var{name2@@@@nodename} will also be used to resolve +references to @var{name2} by the linker. + +The third usage of the @code{.symver} directive is: +@smallexample +.symver @var{name}, @var{name2@@@@@@nodename} +@end smallexample +When @var{name} is not defined within the +file being assembled, it is treated as @var{name2@@nodename}. When +@var{name} is defined within the file being assembled, the symbol +name, @var{name}, will be changed to @var{name2@@@@nodename}. +@end ifset + +@ifset COFF +@node Tag +@section @code{.tag @var{structname}} + +@cindex COFF structure debugging +@cindex structure debugging, COFF +@cindex @code{tag} directive +This directive is generated by compilers to include auxiliary debugging +information in the symbol table. It is only permitted inside +@code{.def}/@code{.endef} pairs. Tags are used to link structure +definitions in the symbol table with instances of those structures. +@ifset BOUT + +@samp{.tag} is only used when generating COFF format output; when +@command{@value{AS}} is generating @code{b.out}, it accepts this directive but +ignores it. +@end ifset +@end ifset + +@node Text +@section @code{.text @var{subsection}} + +@cindex @code{text} directive +Tells @command{@value{AS}} to assemble the following statements onto the end of +the text subsection numbered @var{subsection}, which is an absolute +expression. If @var{subsection} is omitted, subsection number zero +is used. + +@node Title +@section @code{.title "@var{heading}"} + +@cindex @code{title} directive +@cindex listing control: title line +Use @var{heading} as the title (second line, immediately after the +source file name and pagenumber) when generating assembly listings. + +This directive affects subsequent pages, as well as the current page if +it appears within ten lines of the top of a page. + +@ifset COFF-ELF +@node Type +@section @code{.type} + +This directive is used to set the type of a symbol. + +@ifset COFF +@ifset ELF +@c only print the extra heading if both COFF and ELF are set +@subheading COFF Version +@end ifset + +@cindex COFF symbol type +@cindex symbol type, COFF +@cindex @code{type} directive (COFF version) +For COFF targets, this directive is permitted only within +@code{.def}/@code{.endef} pairs. It is used like this: + +@smallexample +.type @var{int} +@end smallexample + +This records the integer @var{int} as the type attribute of a symbol table +entry. + +@ifset BOUT +@samp{.type} is associated only with COFF format output; when +@command{@value{AS}} is configured for @code{b.out} output, it accepts this +directive but ignores it. +@end ifset +@end ifset + +@ifset ELF +@ifset COFF +@c only print the extra heading if both COFF and ELF are set +@subheading ELF Version +@end ifset + +@cindex ELF symbol type +@cindex symbol type, ELF +@cindex @code{type} directive (ELF version) +For ELF targets, the @code{.type} directive is used like this: + +@smallexample +.type @var{name} , @var{type description} +@end smallexample + +This sets the type of symbol @var{name} to be either a +function symbol or an object symbol. There are five different syntaxes +supported for the @var{type description} field, in order to provide +compatibility with various other assemblers. The syntaxes supported are: + +@smallexample + .type ,#function + .type ,#object + + .type ,@@function + .type ,@@object + + .type ,%function + .type ,%object + + .type ,"function" + .type ,"object" + + .type STT_FUNCTION + .type STT_OBJECT +@end smallexample +@end ifset +@end ifset + +@node Uleb128 +@section @code{.uleb128 @var{expressions}} + +@cindex @code{uleb128} directive +@var{uleb128} stands for ``unsigned little endian base 128.'' This is a +compact, variable length representation of numbers used by the DWARF +symbolic debugging format. @xref{Sleb128,@code{.sleb128}}. + +@ifset COFF +@node Val +@section @code{.val @var{addr}} + +@cindex @code{val} directive +@cindex COFF value attribute +@cindex value attribute, COFF +This directive, permitted only within @code{.def}/@code{.endef} pairs, +records the address @var{addr} as the value attribute of a symbol table +entry. +@ifset BOUT + +@samp{.val} is used only for COFF output; when @command{@value{AS}} is +configured for @code{b.out}, it accepts this directive but ignores it. +@end ifset +@end ifset + +@ifset ELF +@node Version +@section @code{.version "@var{string}"} + +@cindex @code{version} directive +This directive creates a @code{.note} section and places into it an ELF +formatted note of type NT_VERSION. The note's name is set to @code{string}. +@end ifset + +@ifset ELF +@node VTableEntry +@section @code{.vtable_entry @var{table}, @var{offset}} + +@cindex @code{vtable_entry} +This directive finds or creates a symbol @code{table} and creates a +@code{VTABLE_ENTRY} relocation for it with an addend of @code{offset}. + +@node VTableInherit +@section @code{.vtable_inherit @var{child}, @var{parent}} + +@cindex @code{vtable_inherit} +This directive finds the symbol @code{child} and finds or creates the symbol +@code{parent} and then creates a @code{VTABLE_INHERIT} relocation for the +parent whose addend is the value of the child symbol. As a special case the +parent name of @code{0} is treated as refering the @code{*ABS*} section. +@end ifset + +@ifset ELF +@node Weak +@section @code{.weak @var{names}} + +@cindex @code{weak} directive +This directive sets the weak attribute on the comma separated list of symbol +@code{names}. If the symbols do not already exist, they will be created. +@end ifset + +@node Word +@section @code{.word @var{expressions}} + +@cindex @code{word} directive +This directive expects zero or more @var{expressions}, of any section, +separated by commas. +@ifclear GENERIC +@ifset W32 +For each expression, @command{@value{AS}} emits a 32-bit number. +@end ifset +@ifset W16 +For each expression, @command{@value{AS}} emits a 16-bit number. +@end ifset +@end ifclear +@ifset GENERIC + +The size of the number emitted, and its byte order, +depend on what target computer the assembly is for. +@end ifset + +@c on amd29k, i960, sparc the "special treatment to support compilers" doesn't +@c happen---32-bit addressability, period; no long/short jumps. +@ifset DIFF-TBL-KLUGE +@cindex difference tables altered +@cindex altered difference tables +@quotation +@emph{Warning: Special Treatment to support Compilers} +@end quotation + +@ifset GENERIC +Machines with a 32-bit address space, but that do less than 32-bit +addressing, require the following special treatment. If the machine of +interest to you does 32-bit addressing (or doesn't require it; +@pxref{Machine Dependencies}), you can ignore this issue. + +@end ifset +In order to assemble compiler output into something that works, +@command{@value{AS}} occasionally does strange things to @samp{.word} directives. +Directives of the form @samp{.word sym1-sym2} are often emitted by +compilers as part of jump tables. Therefore, when @command{@value{AS}} assembles a +directive of the form @samp{.word sym1-sym2}, and the difference between +@code{sym1} and @code{sym2} does not fit in 16 bits, @command{@value{AS}} +creates a @dfn{secondary jump table}, immediately before the next label. +This secondary jump table is preceded by a short-jump to the +first byte after the secondary table. This short-jump prevents the flow +of control from accidentally falling into the new table. Inside the +table is a long-jump to @code{sym2}. The original @samp{.word} +contains @code{sym1} minus the address of the long-jump to +@code{sym2}. + +If there were several occurrences of @samp{.word sym1-sym2} before the +secondary jump table, all of them are adjusted. If there was a +@samp{.word sym3-sym4}, that also did not fit in sixteen bits, a +long-jump to @code{sym4} is included in the secondary jump table, +and the @code{.word} directives are adjusted to contain @code{sym3} +minus the address of the long-jump to @code{sym4}; and so on, for as many +entries in the original jump table as necessary. + +@ifset INTERNALS +@emph{This feature may be disabled by compiling @command{@value{AS}} with the +@samp{-DWORKING_DOT_WORD} option.} This feature is likely to confuse +assembly language programmers. +@end ifset +@end ifset +@c end DIFF-TBL-KLUGE + +@node Deprecated +@section Deprecated Directives + +@cindex deprecated directives +@cindex obsolescent directives +One day these directives won't work. +They are included for compatibility with older assemblers. +@table @t +@item .abort +@item .line +@end table + +@ifset GENERIC +@node Machine Dependencies +@chapter Machine Dependent Features + +@cindex machine dependencies +The machine instruction sets are (almost by definition) different on +each machine where @command{@value{AS}} runs. Floating point representations +vary as well, and @command{@value{AS}} often supports a few additional +directives or command-line options for compatibility with other +assemblers on a particular platform. Finally, some versions of +@command{@value{AS}} support special pseudo-instructions for branch +optimization. + +This chapter discusses most of these differences, though it does not +include details on any machine's instruction set. For details on that +subject, see the hardware manufacturer's manual. + +@menu +@ifset A29K +* AMD29K-Dependent:: AMD 29K Dependent Features +@end ifset +@ifset ALPHA +* Alpha-Dependent:: Alpha Dependent Features +@end ifset +@ifset ARC +* ARC-Dependent:: ARC Dependent Features +@end ifset +@ifset ARM +* ARM-Dependent:: ARM Dependent Features +@end ifset +@ifset CRIS +* CRIS-Dependent:: CRIS Dependent Features +@end ifset +@ifset D10V +* D10V-Dependent:: D10V Dependent Features +@end ifset +@ifset D30V +* D30V-Dependent:: D30V Dependent Features +@end ifset +@ifset H8/300 +* H8/300-Dependent:: Renesas H8/300 Dependent Features +@end ifset +@ifset H8/500 +* H8/500-Dependent:: Renesas H8/500 Dependent Features +@end ifset +@ifset HPPA +* HPPA-Dependent:: HPPA Dependent Features +@end ifset +@ifset I370 +* ESA/390-Dependent:: IBM ESA/390 Dependent Features +@end ifset +@ifset I80386 +* i386-Dependent:: Intel 80386 and AMD x86-64 Dependent Features +@end ifset +@ifset I860 +* i860-Dependent:: Intel 80860 Dependent Features +@end ifset +@ifset I960 +* i960-Dependent:: Intel 80960 Dependent Features +@end ifset +@ifset IP2K +* IP2K-Dependent:: IP2K Dependent Features +@end ifset +@ifset M32R +* M32R-Dependent:: M32R Dependent Features +@end ifset +@ifset M680X0 +* M68K-Dependent:: M680x0 Dependent Features +@end ifset +@ifset M68HC11 +* M68HC11-Dependent:: M68HC11 and 68HC12 Dependent Features +@end ifset +@ifset M880X0 +* M88K-Dependent:: M880x0 Dependent Features +@end ifset +@ifset MIPS +* MIPS-Dependent:: MIPS Dependent Features +@end ifset +@ifset MMIX +* MMIX-Dependent:: MMIX Dependent Features +@end ifset +@ifset MSP430 +* MSP430-Dependent:: MSP430 Dependent Features +@end ifset +@ifset SH +* SH-Dependent:: Renesas / SuperH SH Dependent Features +* SH64-Dependent:: SuperH SH64 Dependent Features +@end ifset +@ifset PDP11 +* PDP-11-Dependent:: PDP-11 Dependent Features +@end ifset +@ifset PJ +* PJ-Dependent:: picoJava Dependent Features +@end ifset +@ifset PPC +* PPC-Dependent:: PowerPC Dependent Features +@end ifset +@ifset SPARC +* Sparc-Dependent:: SPARC Dependent Features +@end ifset +@ifset TIC54X +* TIC54X-Dependent:: TI TMS320C54x Dependent Features +@end ifset +@ifset V850 +* V850-Dependent:: V850 Dependent Features +@end ifset +@ifset XTENSA +* Xtensa-Dependent:: Xtensa Dependent Features +@end ifset +@ifset Z8000 +* Z8000-Dependent:: Z8000 Dependent Features +@end ifset +@ifset VAX +* Vax-Dependent:: VAX Dependent Features +@end ifset +@end menu + +@lowersections +@end ifset + +@c The following major nodes are *sections* in the GENERIC version, *chapters* +@c in single-cpu versions. This is mainly achieved by @lowersections. There is a +@c peculiarity: to preserve cross-references, there must be a node called +@c "Machine Dependencies". Hence the conditional nodenames in each +@c major node below. Node defaulting in makeinfo requires adjacency of +@c node and sectioning commands; hence the repetition of @chapter BLAH +@c in both conditional blocks. + +@ifset A29K +@include c-a29k.texi +@end ifset + +@ifset ALPHA +@include c-alpha.texi +@end ifset + +@ifset ARC +@include c-arc.texi +@end ifset + +@ifset ARM +@include c-arm.texi +@end ifset + +@ifset CRIS +@include c-cris.texi +@end ifset + +@ifset Renesas-all +@ifclear GENERIC +@node Machine Dependencies +@chapter Machine Dependent Features + +The machine instruction sets are different on each Renesas chip family, +and there are also some syntax differences among the families. This +chapter describes the specific @command{@value{AS}} features for each +family. + +@menu +* H8/300-Dependent:: Renesas H8/300 Dependent Features +* H8/500-Dependent:: Renesas H8/500 Dependent Features +* SH-Dependent:: Renesas SH Dependent Features +@end menu +@lowersections +@end ifclear +@end ifset + +@ifset D10V +@include c-d10v.texi +@end ifset + +@ifset D30V +@include c-d30v.texi +@end ifset + +@ifset H8/300 +@include c-h8300.texi +@end ifset + +@ifset H8/500 +@include c-h8500.texi +@end ifset + +@ifset HPPA +@include c-hppa.texi +@end ifset + +@ifset I370 +@include c-i370.texi +@end ifset + +@ifset I80386 +@include c-i386.texi +@end ifset + +@ifset I860 +@include c-i860.texi +@end ifset + +@ifset I960 +@include c-i960.texi +@end ifset + +@ifset IA64 +@include c-ia64.texi +@end ifset + +@ifset IP2K +@include c-ip2k.texi +@end ifset + +@ifset M32R +@include c-m32r.texi +@end ifset + +@ifset M680X0 +@include c-m68k.texi +@end ifset + +@ifset M68HC11 +@include c-m68hc11.texi +@end ifset + +@ifset M880X0 +@include c-m88k.texi +@end ifset + +@ifset MIPS +@include c-mips.texi +@end ifset + +@ifset MMIX +@include c-mmix.texi +@end ifset + +@ifset MSP430 +@include c-msp430.texi +@end ifset + +@ifset NS32K +@include c-ns32k.texi +@end ifset + +@ifset PDP11 +@include c-pdp11.texi +@end ifset + +@ifset PJ +@include c-pj.texi +@end ifset + +@ifset PPC +@include c-ppc.texi +@end ifset + +@ifset SH +@include c-sh.texi +@include c-sh64.texi +@end ifset + +@ifset SPARC +@include c-sparc.texi +@end ifset + +@ifset TIC54X +@include c-tic54x.texi +@end ifset + +@ifset Z8000 +@include c-z8k.texi +@end ifset + +@ifset VAX +@include c-vax.texi +@end ifset + +@ifset V850 +@include c-v850.texi +@end ifset + +@ifset XTENSA +@include c-xtensa.texi +@end ifset + +@ifset GENERIC +@c reverse effect of @down at top of generic Machine-Dep chapter +@raisesections +@end ifset + +@node Reporting Bugs +@chapter Reporting Bugs +@cindex bugs in assembler +@cindex reporting bugs in assembler + +Your bug reports play an essential role in making @command{@value{AS}} reliable. + +Reporting a bug may help you by bringing a solution to your problem, or it may +not. But in any case the principal function of a bug report is to help the +entire community by making the next version of @command{@value{AS}} work better. +Bug reports are your contribution to the maintenance of @command{@value{AS}}. + +In order for a bug report to serve its purpose, you must include the +information that enables us to fix the bug. + +@menu +* Bug Criteria:: Have you found a bug? +* Bug Reporting:: How to report bugs +@end menu + +@node Bug Criteria +@section Have You Found a Bug? +@cindex bug criteria + +If you are not sure whether you have found a bug, here are some guidelines: + +@itemize @bullet +@cindex fatal signal +@cindex assembler crash +@cindex crash of assembler +@item +If the assembler gets a fatal signal, for any input whatever, that is a +@command{@value{AS}} bug. Reliable assemblers never crash. + +@cindex error on valid input +@item +If @command{@value{AS}} produces an error message for valid input, that is a bug. + +@cindex invalid input +@item +If @command{@value{AS}} does not produce an error message for invalid input, that +is a bug. However, you should note that your idea of ``invalid input'' might +be our idea of ``an extension'' or ``support for traditional practice''. + +@item +If you are an experienced user of assemblers, your suggestions for improvement +of @command{@value{AS}} are welcome in any case. +@end itemize + +@node Bug Reporting +@section How to Report Bugs +@cindex bug reports +@cindex assembler bugs, reporting + +A number of companies and individuals offer support for @sc{gnu} products. If +you obtained @command{@value{AS}} from a support organization, we recommend you +contact that organization first. + +You can find contact information for many support companies and +individuals in the file @file{etc/SERVICE} in the @sc{gnu} Emacs +distribution. + +In any event, we also recommend that you send bug reports for @command{@value{AS}} +to @samp{bug-binutils@@gnu.org}. + +The fundamental principle of reporting bugs usefully is this: +@strong{report all the facts}. If you are not sure whether to state a +fact or leave it out, state it! + +Often people omit facts because they think they know what causes the problem +and assume that some details do not matter. Thus, you might assume that the +name of a symbol you use in an example does not matter. Well, probably it does +not, but one cannot be sure. Perhaps the bug is a stray memory reference which +happens to fetch from the location where that name is stored in memory; +perhaps, if the name were different, the contents of that location would fool +the assembler into doing the right thing despite the bug. Play it safe and +give a specific, complete example. That is the easiest thing for you to do, +and the most helpful. + +Keep in mind that the purpose of a bug report is to enable us to fix the bug if +it is new to us. Therefore, always write your bug reports on the assumption +that the bug has not been reported previously. + +Sometimes people give a few sketchy facts and ask, ``Does this ring a +bell?'' This cannot help us fix a bug, so it is basically useless. We +respond by asking for enough details to enable us to investigate. +You might as well expedite matters by sending them to begin with. + +To enable us to fix the bug, you should include all these things: + +@itemize @bullet +@item +The version of @command{@value{AS}}. @command{@value{AS}} announces it if you start +it with the @samp{--version} argument. + +Without this, we will not know whether there is any point in looking for +the bug in the current version of @command{@value{AS}}. + +@item +Any patches you may have applied to the @command{@value{AS}} source. + +@item +The type of machine you are using, and the operating system name and +version number. + +@item +What compiler (and its version) was used to compile @command{@value{AS}}---e.g. +``@code{gcc-2.7}''. + +@item +The command arguments you gave the assembler to assemble your example and +observe the bug. To guarantee you will not omit something important, list them +all. A copy of the Makefile (or the output from make) is sufficient. + +If we were to try to guess the arguments, we would probably guess wrong +and then we might not encounter the bug. + +@item +A complete input file that will reproduce the bug. If the bug is observed when +the assembler is invoked via a compiler, send the assembler source, not the +high level language source. Most compilers will produce the assembler source +when run with the @samp{-S} option. If you are using @code{@value{GCC}}, use +the options @samp{-v --save-temps}; this will save the assembler source in a +file with an extension of @file{.s}, and also show you exactly how +@command{@value{AS}} is being run. + +@item +A description of what behavior you observe that you believe is +incorrect. For example, ``It gets a fatal signal.'' + +Of course, if the bug is that @command{@value{AS}} gets a fatal signal, then we +will certainly notice it. But if the bug is incorrect output, we might not +notice unless it is glaringly wrong. You might as well not give us a chance to +make a mistake. + +Even if the problem you experience is a fatal signal, you should still say so +explicitly. Suppose something strange is going on, such as, your copy of +@command{@value{AS}} is out of synch, or you have encountered a bug in the C +library on your system. (This has happened!) Your copy might crash and ours +would not. If you told us to expect a crash, then when ours fails to crash, we +would know that the bug was not happening for us. If you had not told us to +expect a crash, then we would not be able to draw any conclusion from our +observations. + +@item +If you wish to suggest changes to the @command{@value{AS}} source, send us context +diffs, as generated by @code{diff} with the @samp{-u}, @samp{-c}, or @samp{-p} +option. Always send diffs from the old file to the new file. If you even +discuss something in the @command{@value{AS}} source, refer to it by context, not +by line number. + +The line numbers in our development sources will not match those in your +sources. Your line numbers would convey no useful information to us. +@end itemize + +Here are some things that are not necessary: + +@itemize @bullet +@item +A description of the envelope of the bug. + +Often people who encounter a bug spend a lot of time investigating +which changes to the input file will make the bug go away and which +changes will not affect it. + +This is often time consuming and not very useful, because the way we +will find the bug is by running a single example under the debugger +with breakpoints, not by pure deduction from a series of examples. +We recommend that you save your time for something else. + +Of course, if you can find a simpler example to report @emph{instead} +of the original one, that is a convenience for us. Errors in the +output will be easier to spot, running under the debugger will take +less time, and so on. + +However, simplification is not vital; if you do not want to do this, +report the bug anyway and send us the entire test case you used. + +@item +A patch for the bug. + +A patch for the bug does help us if it is a good one. But do not omit +the necessary information, such as the test case, on the assumption that +a patch is all we need. We might see problems with your patch and decide +to fix the problem another way, or we might not understand it at all. + +Sometimes with a program as complicated as @command{@value{AS}} it is very hard to +construct an example that will make the program follow a certain path through +the code. If you do not send us the example, we will not be able to construct +one, so we will not be able to verify that the bug is fixed. + +And if we cannot understand what bug you are trying to fix, or why your +patch should be an improvement, we will not install it. A test case will +help us to understand. + +@item +A guess about what the bug is or what it depends on. + +Such guesses are usually wrong. Even we cannot guess right about such +things without first using the debugger to find the facts. +@end itemize + +@node Acknowledgements +@chapter Acknowledgements + +If you have contributed to @command{@value{AS}} and your name isn't listed here, +it is not meant as a slight. We just don't know about it. Send mail to the +maintainer, and we'll correct the situation. Currently +@c (January 1994), +the maintainer is Ken Raeburn (email address @code{raeburn@@cygnus.com}). + +Dean Elsner wrote the original @sc{gnu} assembler for the VAX.@footnote{Any +more details?} + +Jay Fenlason maintained GAS for a while, adding support for GDB-specific debug +information and the 68k series machines, most of the preprocessing pass, and +extensive changes in @file{messages.c}, @file{input-file.c}, @file{write.c}. + +K. Richard Pixley maintained GAS for a while, adding various enhancements and +many bug fixes, including merging support for several processors, breaking GAS +up to handle multiple object file format back ends (including heavy rewrite, +testing, an integration of the coff and b.out back ends), adding configuration +including heavy testing and verification of cross assemblers and file splits +and renaming, converted GAS to strictly ANSI C including full prototypes, added +support for m680[34]0 and cpu32, did considerable work on i960 including a COFF +port (including considerable amounts of reverse engineering), a SPARC opcode +file rewrite, DECstation, rs6000, and hp300hpux host ports, updated ``know'' +assertions and made them work, much other reorganization, cleanup, and lint. + +Ken Raeburn wrote the high-level BFD interface code to replace most of the code +in format-specific I/O modules. + +The original VMS support was contributed by David L. Kashtan. Eric Youngdale +has done much work with it since. + +The Intel 80386 machine description was written by Eliot Dresselhaus. + +Minh Tran-Le at IntelliCorp contributed some AIX 386 support. + +The Motorola 88k machine description was contributed by Devon Bowen of Buffalo +University and Torbjorn Granlund of the Swedish Institute of Computer Science. + +Keith Knowles at the Open Software Foundation wrote the original MIPS back end +(@file{tc-mips.c}, @file{tc-mips.h}), and contributed Rose format support +(which hasn't been merged in yet). Ralph Campbell worked with the MIPS code to +support a.out format. + +Support for the Zilog Z8k and Renesas H8/300 and H8/500 processors (tc-z8k, +tc-h8300, tc-h8500), and IEEE 695 object file format (obj-ieee), was written by +Steve Chamberlain of Cygnus Support. Steve also modified the COFF back end to +use BFD for some low-level operations, for use with the H8/300 and AMD 29k +targets. + +John Gilmore built the AMD 29000 support, added @code{.include} support, and +simplified the configuration of which versions accept which directives. He +updated the 68k machine description so that Motorola's opcodes always produced +fixed-size instructions (e.g., @code{jsr}), while synthetic instructions +remained shrinkable (@code{jbsr}). John fixed many bugs, including true tested +cross-compilation support, and one bug in relaxation that took a week and +required the proverbial one-bit fix. + +Ian Lance Taylor of Cygnus Support merged the Motorola and MIT syntax for the +68k, completed support for some COFF targets (68k, i386 SVR3, and SCO Unix), +added support for MIPS ECOFF and ELF targets, wrote the initial RS/6000 and +PowerPC assembler, and made a few other minor patches. + +Steve Chamberlain made @command{@value{AS}} able to generate listings. + +Hewlett-Packard contributed support for the HP9000/300. + +Jeff Law wrote GAS and BFD support for the native HPPA object format (SOM) +along with a fairly extensive HPPA testsuite (for both SOM and ELF object +formats). This work was supported by both the Center for Software Science at +the University of Utah and Cygnus Support. + +Support for ELF format files has been worked on by Mark Eichin of Cygnus +Support (original, incomplete implementation for SPARC), Pete Hoogenboom and +Jeff Law at the University of Utah (HPPA mainly), Michael Meissner of the Open +Software Foundation (i386 mainly), and Ken Raeburn of Cygnus Support (sparc, +and some initial 64-bit support). + +Linas Vepstas added GAS support for the ESA/390 ``IBM 370'' architecture. + +Richard Henderson rewrote the Alpha assembler. Klaus Kaempf wrote GAS and BFD +support for openVMS/Alpha. + +Timothy Wall, Michael Hayes, and Greg Smart contributed to the various tic* +flavors. + +David Heine, Sterling Augustine, Bob Wilson and John Ruttenberg from Tensilica, +Inc. added support for Xtensa processors. + +Several engineers at Cygnus Support have also provided many small bug fixes and +configuration enhancements. + +Many others have contributed large or small bugfixes and enhancements. If +you have contributed significant work and are not mentioned on this list, and +want to be, let us know. Some of the history has been lost; we are not +intentionally leaving anyone out. + +@include fdl.texi + +@node Index +@unnumbered Index + +@printindex cp + +@contents +@bye +@c Local Variables: +@c fill-column: 79 +@c End: diff --git a/contrib/binutils-2.14/gas/doc/c-i386.texi b/contrib/binutils-2.14/gas/doc/c-i386.texi new file mode 100644 index 0000000000..1527c8d78a --- /dev/null +++ b/contrib/binutils-2.14/gas/doc/c-i386.texi @@ -0,0 +1,750 @@ +@c Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001 +@c Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@ifset GENERIC +@page +@node i386-Dependent +@chapter 80386 Dependent Features +@end ifset +@ifclear GENERIC +@node Machine Dependencies +@chapter 80386 Dependent Features +@end ifclear + +@cindex i386 support +@cindex i80306 support +@cindex x86-64 support + +The i386 version @code{@value{AS}} supports both the original Intel 386 +architecture in both 16 and 32-bit mode as well as AMD x86-64 architecture +extending the Intel architecture to 64-bits. + +@menu +* i386-Options:: Options +* i386-Syntax:: AT&T Syntax versus Intel Syntax +* i386-Mnemonics:: Instruction Naming +* i386-Regs:: Register Naming +* i386-Prefixes:: Instruction Prefixes +* i386-Memory:: Memory References +* i386-Jumps:: Handling of Jump Instructions +* i386-Float:: Floating Point +* i386-SIMD:: Intel's MMX and AMD's 3DNow! SIMD Operations +* i386-16bit:: Writing 16-bit Code +* i386-Arch:: Specifying an x86 CPU architecture +* i386-Bugs:: AT&T Syntax bugs +* i386-Notes:: Notes +@end menu + +@node i386-Options +@section Options + +@cindex options for i386 +@cindex options for x86-64 +@cindex i386 options +@cindex x86-64 options + +The i386 version of @code{@value{AS}} has a few machine +dependent options: + +@table @code +@cindex @samp{--32} option, i386 +@cindex @samp{--32} option, x86-64 +@cindex @samp{--64} option, i386 +@cindex @samp{--64} option, x86-64 +@item --32 | --64 +Select the word size, either 32 bits or 64 bits. Selecting 32-bit +implies Intel i386 architecture, while 64-bit implies AMD x86-64 +architecture. + +These options are only available with the ELF object file format, and +require that the necessary BFD support has been included (on a 32-bit +platform you have to add --enable-64-bit-bfd to configure enable 64-bit +usage and use x86-64 as target platform). +@end table + +@node i386-Syntax +@section AT&T Syntax versus Intel Syntax + +@cindex i386 intel_syntax pseudo op +@cindex intel_syntax pseudo op, i386 +@cindex i386 att_syntax pseudo op +@cindex att_syntax pseudo op, i386 +@cindex i386 syntax compatibility +@cindex syntax compatibility, i386 +@cindex x86-64 intel_syntax pseudo op +@cindex intel_syntax pseudo op, x86-64 +@cindex x86-64 att_syntax pseudo op +@cindex att_syntax pseudo op, x86-64 +@cindex x86-64 syntax compatibility +@cindex syntax compatibility, x86-64 + +@code{@value{AS}} now supports assembly using Intel assembler syntax. +@code{.intel_syntax} selects Intel mode, and @code{.att_syntax} switches +back to the usual AT&T mode for compatibility with the output of +@code{@value{GCC}}. Either of these directives may have an optional +argument, @code{prefix}, or @code{noprefix} specifying whether registers +require a @samp{%} prefix. AT&T System V/386 assembler syntax is quite +different from Intel syntax. We mention these differences because +almost all 80386 documents use Intel syntax. Notable differences +between the two syntaxes are: + +@cindex immediate operands, i386 +@cindex i386 immediate operands +@cindex register operands, i386 +@cindex i386 register operands +@cindex jump/call operands, i386 +@cindex i386 jump/call operands +@cindex operand delimiters, i386 + +@cindex immediate operands, x86-64 +@cindex x86-64 immediate operands +@cindex register operands, x86-64 +@cindex x86-64 register operands +@cindex jump/call operands, x86-64 +@cindex x86-64 jump/call operands +@cindex operand delimiters, x86-64 +@itemize @bullet +@item +AT&T immediate operands are preceded by @samp{$}; Intel immediate +operands are undelimited (Intel @samp{push 4} is AT&T @samp{pushl $4}). +AT&T register operands are preceded by @samp{%}; Intel register operands +are undelimited. AT&T absolute (as opposed to PC relative) jump/call +operands are prefixed by @samp{*}; they are undelimited in Intel syntax. + +@cindex i386 source, destination operands +@cindex source, destination operands; i386 +@cindex x86-64 source, destination operands +@cindex source, destination operands; x86-64 +@item +AT&T and Intel syntax use the opposite order for source and destination +operands. Intel @samp{add eax, 4} is @samp{addl $4, %eax}. The +@samp{source, dest} convention is maintained for compatibility with +previous Unix assemblers. Note that instructions with more than one +source operand, such as the @samp{enter} instruction, do @emph{not} have +reversed order. @ref{i386-Bugs}. + +@cindex mnemonic suffixes, i386 +@cindex sizes operands, i386 +@cindex i386 size suffixes +@cindex mnemonic suffixes, x86-64 +@cindex sizes operands, x86-64 +@cindex x86-64 size suffixes +@item +In AT&T syntax the size of memory operands is determined from the last +character of the instruction mnemonic. Mnemonic suffixes of @samp{b}, +@samp{w}, @samp{l} and @samp{q} specify byte (8-bit), word (16-bit), long +(32-bit) and quadruple word (64-bit) memory references. Intel syntax accomplishes +this by prefixing memory operands (@emph{not} the instruction mnemonics) with +@samp{byte ptr}, @samp{word ptr}, @samp{dword ptr} and @samp{qword ptr}. Thus, +Intel @samp{mov al, byte ptr @var{foo}} is @samp{movb @var{foo}, %al} in AT&T +syntax. + +@cindex return instructions, i386 +@cindex i386 jump, call, return +@cindex return instructions, x86-64 +@cindex x86-64 jump, call, return +@item +Immediate form long jumps and calls are +@samp{lcall/ljmp $@var{section}, $@var{offset}} in AT&T syntax; the +Intel syntax is +@samp{call/jmp far @var{section}:@var{offset}}. Also, the far return +instruction +is @samp{lret $@var{stack-adjust}} in AT&T syntax; Intel syntax is +@samp{ret far @var{stack-adjust}}. + +@cindex sections, i386 +@cindex i386 sections +@cindex sections, x86-64 +@cindex x86-64 sections +@item +The AT&T assembler does not provide support for multiple section +programs. Unix style systems expect all programs to be single sections. +@end itemize + +@node i386-Mnemonics +@section Instruction Naming + +@cindex i386 instruction naming +@cindex instruction naming, i386 +@cindex x86-64 instruction naming +@cindex instruction naming, x86-64 + +Instruction mnemonics are suffixed with one character modifiers which +specify the size of operands. The letters @samp{b}, @samp{w}, @samp{l} +and @samp{q} specify byte, word, long and quadruple word operands. If +no suffix is specified by an instruction then @code{@value{AS}} tries to +fill in the missing suffix based on the destination register operand +(the last one by convention). Thus, @samp{mov %ax, %bx} is equivalent +to @samp{movw %ax, %bx}; also, @samp{mov $1, %bx} is equivalent to +@samp{movw $1, bx}. Note that this is incompatible with the AT&T Unix +assembler which assumes that a missing mnemonic suffix implies long +operand size. (This incompatibility does not affect compiler output +since compilers always explicitly specify the mnemonic suffix.) + +Almost all instructions have the same names in AT&T and Intel format. +There are a few exceptions. The sign extend and zero extend +instructions need two sizes to specify them. They need a size to +sign/zero extend @emph{from} and a size to zero extend @emph{to}. This +is accomplished by using two instruction mnemonic suffixes in AT&T +syntax. Base names for sign extend and zero extend are +@samp{movs@dots{}} and @samp{movz@dots{}} in AT&T syntax (@samp{movsx} +and @samp{movzx} in Intel syntax). The instruction mnemonic suffixes +are tacked on to this base name, the @emph{from} suffix before the +@emph{to} suffix. Thus, @samp{movsbl %al, %edx} is AT&T syntax for +``move sign extend @emph{from} %al @emph{to} %edx.'' Possible suffixes, +thus, are @samp{bl} (from byte to long), @samp{bw} (from byte to word), +@samp{wl} (from word to long), @samp{bq} (from byte to quadruple word), +@samp{wq} (from word to quadruple word), and @samp{lq} (from long to +quadruple word). + +@cindex conversion instructions, i386 +@cindex i386 conversion instructions +@cindex conversion instructions, x86-64 +@cindex x86-64 conversion instructions +The Intel-syntax conversion instructions + +@itemize @bullet +@item +@samp{cbw} --- sign-extend byte in @samp{%al} to word in @samp{%ax}, + +@item +@samp{cwde} --- sign-extend word in @samp{%ax} to long in @samp{%eax}, + +@item +@samp{cwd} --- sign-extend word in @samp{%ax} to long in @samp{%dx:%ax}, + +@item +@samp{cdq} --- sign-extend dword in @samp{%eax} to quad in @samp{%edx:%eax}, + +@item +@samp{cdqe} --- sign-extend dword in @samp{%eax} to quad in @samp{%rax} +(x86-64 only), + +@item +@samp{cdo} --- sign-extend quad in @samp{%rax} to octuple in +@samp{%rdx:%rax} (x86-64 only), +@end itemize + +@noindent +are called @samp{cbtw}, @samp{cwtl}, @samp{cwtd}, @samp{cltd}, @samp{cltq}, and +@samp{cqto} in AT&T naming. @code{@value{AS}} accepts either naming for these +instructions. + +@cindex jump instructions, i386 +@cindex call instructions, i386 +@cindex jump instructions, x86-64 +@cindex call instructions, x86-64 +Far call/jump instructions are @samp{lcall} and @samp{ljmp} in +AT&T syntax, but are @samp{call far} and @samp{jump far} in Intel +convention. + +@node i386-Regs +@section Register Naming + +@cindex i386 registers +@cindex registers, i386 +@cindex x86-64 registers +@cindex registers, x86-64 +Register operands are always prefixed with @samp{%}. The 80386 registers +consist of + +@itemize @bullet +@item +the 8 32-bit registers @samp{%eax} (the accumulator), @samp{%ebx}, +@samp{%ecx}, @samp{%edx}, @samp{%edi}, @samp{%esi}, @samp{%ebp} (the +frame pointer), and @samp{%esp} (the stack pointer). + +@item +the 8 16-bit low-ends of these: @samp{%ax}, @samp{%bx}, @samp{%cx}, +@samp{%dx}, @samp{%di}, @samp{%si}, @samp{%bp}, and @samp{%sp}. + +@item +the 8 8-bit registers: @samp{%ah}, @samp{%al}, @samp{%bh}, +@samp{%bl}, @samp{%ch}, @samp{%cl}, @samp{%dh}, and @samp{%dl} (These +are the high-bytes and low-bytes of @samp{%ax}, @samp{%bx}, +@samp{%cx}, and @samp{%dx}) + +@item +the 6 section registers @samp{%cs} (code section), @samp{%ds} +(data section), @samp{%ss} (stack section), @samp{%es}, @samp{%fs}, +and @samp{%gs}. + +@item +the 3 processor control registers @samp{%cr0}, @samp{%cr2}, and +@samp{%cr3}. + +@item +the 6 debug registers @samp{%db0}, @samp{%db1}, @samp{%db2}, +@samp{%db3}, @samp{%db6}, and @samp{%db7}. + +@item +the 2 test registers @samp{%tr6} and @samp{%tr7}. + +@item +the 8 floating point register stack @samp{%st} or equivalently +@samp{%st(0)}, @samp{%st(1)}, @samp{%st(2)}, @samp{%st(3)}, +@samp{%st(4)}, @samp{%st(5)}, @samp{%st(6)}, and @samp{%st(7)}. +These registers are overloaded by 8 MMX registers @samp{%mm0}, +@samp{%mm1}, @samp{%mm2}, @samp{%mm3}, @samp{%mm4}, @samp{%mm5}, +@samp{%mm6} and @samp{%mm7}. + +@item +the 8 SSE registers registers @samp{%xmm0}, @samp{%xmm1}, @samp{%xmm2}, +@samp{%xmm3}, @samp{%xmm4}, @samp{%xmm5}, @samp{%xmm6} and @samp{%xmm7}. +@end itemize + +The AMD x86-64 architecture extends the register set by: + +@itemize @bullet +@item +enhancing the 8 32-bit registers to 64-bit: @samp{%rax} (the +accumulator), @samp{%rbx}, @samp{%rcx}, @samp{%rdx}, @samp{%rdi}, +@samp{%rsi}, @samp{%rbp} (the frame pointer), @samp{%rsp} (the stack +pointer) + +@item +the 8 extended registers @samp{%r8}--@samp{%r15}. + +@item +the 8 32-bit low ends of the extended registers: @samp{%r8d}--@samp{%r15d} + +@item +the 8 16-bit low ends of the extended registers: @samp{%r8w}--@samp{%r15w} + +@item +the 8 8-bit low ends of the extended registers: @samp{%r8b}--@samp{%r15b} + +@item +the 4 8-bit registers: @samp{%sil}, @samp{%dil}, @samp{%bpl}, @samp{%spl}. + +@item +the 8 debug registers: @samp{%db8}--@samp{%db15}. + +@item +the 8 SSE registers: @samp{%xmm8}--@samp{%xmm15}. +@end itemize + +@node i386-Prefixes +@section Instruction Prefixes + +@cindex i386 instruction prefixes +@cindex instruction prefixes, i386 +@cindex prefixes, i386 +Instruction prefixes are used to modify the following instruction. They +are used to repeat string instructions, to provide section overrides, to +perform bus lock operations, and to change operand and address sizes. +(Most instructions that normally operate on 32-bit operands will use +16-bit operands if the instruction has an ``operand size'' prefix.) +Instruction prefixes are best written on the same line as the instruction +they act upon. For example, the @samp{scas} (scan string) instruction is +repeated with: + +@smallexample + repne scas %es:(%edi),%al +@end smallexample + +You may also place prefixes on the lines immediately preceding the +instruction, but this circumvents checks that @code{@value{AS}} does +with prefixes, and will not work with all prefixes. + +Here is a list of instruction prefixes: + +@cindex section override prefixes, i386 +@itemize @bullet +@item +Section override prefixes @samp{cs}, @samp{ds}, @samp{ss}, @samp{es}, +@samp{fs}, @samp{gs}. These are automatically added by specifying +using the @var{section}:@var{memory-operand} form for memory references. + +@cindex size prefixes, i386 +@item +Operand/Address size prefixes @samp{data16} and @samp{addr16} +change 32-bit operands/addresses into 16-bit operands/addresses, +while @samp{data32} and @samp{addr32} change 16-bit ones (in a +@code{.code16} section) into 32-bit operands/addresses. These prefixes +@emph{must} appear on the same line of code as the instruction they +modify. For example, in a 16-bit @code{.code16} section, you might +write: + +@smallexample + addr32 jmpl *(%ebx) +@end smallexample + +@cindex bus lock prefixes, i386 +@cindex inhibiting interrupts, i386 +@item +The bus lock prefix @samp{lock} inhibits interrupts during execution of +the instruction it precedes. (This is only valid with certain +instructions; see a 80386 manual for details). + +@cindex coprocessor wait, i386 +@item +The wait for coprocessor prefix @samp{wait} waits for the coprocessor to +complete the current instruction. This should never be needed for the +80386/80387 combination. + +@cindex repeat prefixes, i386 +@item +The @samp{rep}, @samp{repe}, and @samp{repne} prefixes are added +to string instructions to make them repeat @samp{%ecx} times (@samp{%cx} +times if the current address size is 16-bits). +@cindex REX prefixes, i386 +@item +The @samp{rex} family of prefixes is used by x86-64 to encode +extensions to i386 instruction set. The @samp{rex} prefix has four +bits --- an operand size overwrite (@code{64}) used to change operand size +from 32-bit to 64-bit and X, Y and Z extensions bits used to extend the +register set. + +You may write the @samp{rex} prefixes directly. The @samp{rex64xyz} +instruction emits @samp{rex} prefix with all the bits set. By omitting +the @code{64}, @code{x}, @code{y} or @code{z} you may write other +prefixes as well. Normally, there is no need to write the prefixes +explicitly, since gas will automatically generate them based on the +instruction operands. +@end itemize + +@node i386-Memory +@section Memory References + +@cindex i386 memory references +@cindex memory references, i386 +@cindex x86-64 memory references +@cindex memory references, x86-64 +An Intel syntax indirect memory reference of the form + +@smallexample +@var{section}:[@var{base} + @var{index}*@var{scale} + @var{disp}] +@end smallexample + +@noindent +is translated into the AT&T syntax + +@smallexample +@var{section}:@var{disp}(@var{base}, @var{index}, @var{scale}) +@end smallexample + +@noindent +where @var{base} and @var{index} are the optional 32-bit base and +index registers, @var{disp} is the optional displacement, and +@var{scale}, taking the values 1, 2, 4, and 8, multiplies @var{index} +to calculate the address of the operand. If no @var{scale} is +specified, @var{scale} is taken to be 1. @var{section} specifies the +optional section register for the memory operand, and may override the +default section register (see a 80386 manual for section register +defaults). Note that section overrides in AT&T syntax @emph{must} +be preceded by a @samp{%}. If you specify a section override which +coincides with the default section register, @code{@value{AS}} does @emph{not} +output any section register override prefixes to assemble the given +instruction. Thus, section overrides can be specified to emphasize which +section register is used for a given memory operand. + +Here are some examples of Intel and AT&T style memory references: + +@table @asis +@item AT&T: @samp{-4(%ebp)}, Intel: @samp{[ebp - 4]} +@var{base} is @samp{%ebp}; @var{disp} is @samp{-4}. @var{section} is +missing, and the default section is used (@samp{%ss} for addressing with +@samp{%ebp} as the base register). @var{index}, @var{scale} are both missing. + +@item AT&T: @samp{foo(,%eax,4)}, Intel: @samp{[foo + eax*4]} +@var{index} is @samp{%eax} (scaled by a @var{scale} 4); @var{disp} is +@samp{foo}. All other fields are missing. The section register here +defaults to @samp{%ds}. + +@item AT&T: @samp{foo(,1)}; Intel @samp{[foo]} +This uses the value pointed to by @samp{foo} as a memory operand. +Note that @var{base} and @var{index} are both missing, but there is only +@emph{one} @samp{,}. This is a syntactic exception. + +@item AT&T: @samp{%gs:foo}; Intel @samp{gs:foo} +This selects the contents of the variable @samp{foo} with section +register @var{section} being @samp{%gs}. +@end table + +Absolute (as opposed to PC relative) call and jump operands must be +prefixed with @samp{*}. If no @samp{*} is specified, @code{@value{AS}} +always chooses PC relative addressing for jump/call labels. + +Any instruction that has a memory operand, but no register operand, +@emph{must} specify its size (byte, word, long, or quadruple) with an +instruction mnemonic suffix (@samp{b}, @samp{w}, @samp{l} or @samp{q}, +respectively). + +The x86-64 architecture adds an RIP (instruction pointer relative) +addressing. This addressing mode is specified by using @samp{rip} as a +base register. Only constant offsets are valid. For example: + +@table @asis +@item AT&T: @samp{1234(%rip)}, Intel: @samp{[rip + 1234]} +Points to the address 1234 bytes past the end of the current +instruction. + +@item AT&T: @samp{symbol(%rip)}, Intel: @samp{[rip + symbol]} +Points to the @code{symbol} in RIP relative way, this is shorter than +the default absolute addressing. +@end table + +Other addressing modes remain unchanged in x86-64 architecture, except +registers used are 64-bit instead of 32-bit. + +@node i386-Jumps +@section Handling of Jump Instructions + +@cindex jump optimization, i386 +@cindex i386 jump optimization +@cindex jump optimization, x86-64 +@cindex x86-64 jump optimization +Jump instructions are always optimized to use the smallest possible +displacements. This is accomplished by using byte (8-bit) displacement +jumps whenever the target is sufficiently close. If a byte displacement +is insufficient a long displacement is used. We do not support +word (16-bit) displacement jumps in 32-bit mode (i.e. prefixing the jump +instruction with the @samp{data16} instruction prefix), since the 80386 +insists upon masking @samp{%eip} to 16 bits after the word displacement +is added. (See also @pxref{i386-Arch}) + +Note that the @samp{jcxz}, @samp{jecxz}, @samp{loop}, @samp{loopz}, +@samp{loope}, @samp{loopnz} and @samp{loopne} instructions only come in byte +displacements, so that if you use these instructions (@code{@value{GCC}} does +not use them) you may get an error message (and incorrect code). The AT&T +80386 assembler tries to get around this problem by expanding @samp{jcxz foo} +to + +@smallexample + jcxz cx_zero + jmp cx_nonzero +cx_zero: jmp foo +cx_nonzero: +@end smallexample + +@node i386-Float +@section Floating Point + +@cindex i386 floating point +@cindex floating point, i386 +@cindex x86-64 floating point +@cindex floating point, x86-64 +All 80387 floating point types except packed BCD are supported. +(BCD support may be added without much difficulty). These data +types are 16-, 32-, and 64- bit integers, and single (32-bit), +double (64-bit), and extended (80-bit) precision floating point. +Each supported type has an instruction mnemonic suffix and a constructor +associated with it. Instruction mnemonic suffixes specify the operand's +data type. Constructors build these data types into memory. + +@cindex @code{float} directive, i386 +@cindex @code{single} directive, i386 +@cindex @code{double} directive, i386 +@cindex @code{tfloat} directive, i386 +@cindex @code{float} directive, x86-64 +@cindex @code{single} directive, x86-64 +@cindex @code{double} directive, x86-64 +@cindex @code{tfloat} directive, x86-64 +@itemize @bullet +@item +Floating point constructors are @samp{.float} or @samp{.single}, +@samp{.double}, and @samp{.tfloat} for 32-, 64-, and 80-bit formats. +These correspond to instruction mnemonic suffixes @samp{s}, @samp{l}, +and @samp{t}. @samp{t} stands for 80-bit (ten byte) real. The 80387 +only supports this format via the @samp{fldt} (load 80-bit real to stack +top) and @samp{fstpt} (store 80-bit real and pop stack) instructions. + +@cindex @code{word} directive, i386 +@cindex @code{long} directive, i386 +@cindex @code{int} directive, i386 +@cindex @code{quad} directive, i386 +@cindex @code{word} directive, x86-64 +@cindex @code{long} directive, x86-64 +@cindex @code{int} directive, x86-64 +@cindex @code{quad} directive, x86-64 +@item +Integer constructors are @samp{.word}, @samp{.long} or @samp{.int}, and +@samp{.quad} for the 16-, 32-, and 64-bit integer formats. The +corresponding instruction mnemonic suffixes are @samp{s} (single), +@samp{l} (long), and @samp{q} (quad). As with the 80-bit real format, +the 64-bit @samp{q} format is only present in the @samp{fildq} (load +quad integer to stack top) and @samp{fistpq} (store quad integer and pop +stack) instructions. +@end itemize + +Register to register operations should not use instruction mnemonic suffixes. +@samp{fstl %st, %st(1)} will give a warning, and be assembled as if you +wrote @samp{fst %st, %st(1)}, since all register to register operations +use 80-bit floating point operands. (Contrast this with @samp{fstl %st, mem}, +which converts @samp{%st} from 80-bit to 64-bit floating point format, +then stores the result in the 4 byte location @samp{mem}) + +@node i386-SIMD +@section Intel's MMX and AMD's 3DNow! SIMD Operations + +@cindex MMX, i386 +@cindex 3DNow!, i386 +@cindex SIMD, i386 +@cindex MMX, x86-64 +@cindex 3DNow!, x86-64 +@cindex SIMD, x86-64 + +@code{@value{AS}} supports Intel's MMX instruction set (SIMD +instructions for integer data), available on Intel's Pentium MMX +processors and Pentium II processors, AMD's K6 and K6-2 processors, +Cyrix' M2 processor, and probably others. It also supports AMD's 3DNow! +instruction set (SIMD instructions for 32-bit floating point data) +available on AMD's K6-2 processor and possibly others in the future. + +Currently, @code{@value{AS}} does not support Intel's floating point +SIMD, Katmai (KNI). + +The eight 64-bit MMX operands, also used by 3DNow!, are called @samp{%mm0}, +@samp{%mm1}, ... @samp{%mm7}. They contain eight 8-bit integers, four +16-bit integers, two 32-bit integers, one 64-bit integer, or two 32-bit +floating point values. The MMX registers cannot be used at the same time +as the floating point stack. + +See Intel and AMD documentation, keeping in mind that the operand order in +instructions is reversed from the Intel syntax. + +@node i386-16bit +@section Writing 16-bit Code + +@cindex i386 16-bit code +@cindex 16-bit code, i386 +@cindex real-mode code, i386 +@cindex @code{code16gcc} directive, i386 +@cindex @code{code16} directive, i386 +@cindex @code{code32} directive, i386 +@cindex @code{code64} directive, i386 +@cindex @code{code64} directive, x86-64 +While @code{@value{AS}} normally writes only ``pure'' 32-bit i386 code +or 64-bit x86-64 code depending on the default configuration, +it also supports writing code to run in real mode or in 16-bit protected +mode code segments. To do this, put a @samp{.code16} or +@samp{.code16gcc} directive before the assembly language instructions to +be run in 16-bit mode. You can switch @code{@value{AS}} back to writing +normal 32-bit code with the @samp{.code32} directive. + +@samp{.code16gcc} provides experimental support for generating 16-bit +code from gcc, and differs from @samp{.code16} in that @samp{call}, +@samp{ret}, @samp{enter}, @samp{leave}, @samp{push}, @samp{pop}, +@samp{pusha}, @samp{popa}, @samp{pushf}, and @samp{popf} instructions +default to 32-bit size. This is so that the stack pointer is +manipulated in the same way over function calls, allowing access to +function parameters at the same stack offsets as in 32-bit mode. +@samp{.code16gcc} also automatically adds address size prefixes where +necessary to use the 32-bit addressing modes that gcc generates. + +The code which @code{@value{AS}} generates in 16-bit mode will not +necessarily run on a 16-bit pre-80386 processor. To write code that +runs on such a processor, you must refrain from using @emph{any} 32-bit +constructs which require @code{@value{AS}} to output address or operand +size prefixes. + +Note that writing 16-bit code instructions by explicitly specifying a +prefix or an instruction mnemonic suffix within a 32-bit code section +generates different machine instructions than those generated for a +16-bit code segment. In a 32-bit code section, the following code +generates the machine opcode bytes @samp{66 6a 04}, which pushes the +value @samp{4} onto the stack, decrementing @samp{%esp} by 2. + +@smallexample + pushw $4 +@end smallexample + +The same code in a 16-bit code section would generate the machine +opcode bytes @samp{6a 04} (ie. without the operand size prefix), which +is correct since the processor default operand size is assumed to be 16 +bits in a 16-bit code section. + +@node i386-Bugs +@section AT&T Syntax bugs + +The UnixWare assembler, and probably other AT&T derived ix86 Unix +assemblers, generate floating point instructions with reversed source +and destination registers in certain cases. Unfortunately, gcc and +possibly many other programs use this reversed syntax, so we're stuck +with it. + +For example + +@smallexample + fsub %st,%st(3) +@end smallexample +@noindent +results in @samp{%st(3)} being updated to @samp{%st - %st(3)} rather +than the expected @samp{%st(3) - %st}. This happens with all the +non-commutative arithmetic floating point operations with two register +operands where the source register is @samp{%st} and the destination +register is @samp{%st(i)}. + +@node i386-Arch +@section Specifying CPU Architecture + +@cindex arch directive, i386 +@cindex i386 arch directive +@cindex arch directive, x86-64 +@cindex x86-64 arch directive + +@code{@value{AS}} may be told to assemble for a particular CPU +architecture with the @code{.arch @var{cpu_type}} directive. This +directive enables a warning when gas detects an instruction that is not +supported on the CPU specified. The choices for @var{cpu_type} are: + +@multitable @columnfractions .20 .20 .20 .20 +@item @samp{i8086} @tab @samp{i186} @tab @samp{i286} @tab @samp{i386} +@item @samp{i486} @tab @samp{i586} @tab @samp{i686} @tab @samp{pentium} +@item @samp{pentiumpro} @tab @samp{pentium4} @tab @samp{k6} @tab @samp{athlon} +@item @samp{sledgehammer} +@end multitable + +Apart from the warning, there are only two other effects on +@code{@value{AS}} operation; Firstly, if you specify a CPU other than +@samp{i486}, then shift by one instructions such as @samp{sarl $1, %eax} +will automatically use a two byte opcode sequence. The larger three +byte opcode sequence is used on the 486 (and when no architecture is +specified) because it executes faster on the 486. Note that you can +explicitly request the two byte opcode by writing @samp{sarl %eax}. +Secondly, if you specify @samp{i8086}, @samp{i186}, or @samp{i286}, +@emph{and} @samp{.code16} or @samp{.code16gcc} then byte offset +conditional jumps will be promoted when necessary to a two instruction +sequence consisting of a conditional jump of the opposite sense around +an unconditional jump to the target. + +Following the CPU architecture, you may specify @samp{jumps} or +@samp{nojumps} to control automatic promotion of conditional jumps. +@samp{jumps} is the default, and enables jump promotion; All external +jumps will be of the long variety, and file-local jumps will be promoted +as necessary. (@pxref{i386-Jumps}) @samp{nojumps} leaves external +conditional jumps as byte offset jumps, and warns about file-local +conditional jumps that @code{@value{AS}} promotes. +Unconditional jumps are treated as for @samp{jumps}. + +For example + +@smallexample + .arch i8086,nojumps +@end smallexample + +@node i386-Notes +@section Notes + +@cindex i386 @code{mul}, @code{imul} instructions +@cindex @code{mul} instruction, i386 +@cindex @code{imul} instruction, i386 +@cindex @code{mul} instruction, x86-64 +@cindex @code{imul} instruction, x86-64 +There is some trickery concerning the @samp{mul} and @samp{imul} +instructions that deserves mention. The 16-, 32-, 64- and 128-bit expanding +multiplies (base opcode @samp{0xf6}; extension 4 for @samp{mul} and 5 +for @samp{imul}) can be output only in the one operand form. Thus, +@samp{imul %ebx, %eax} does @emph{not} select the expanding multiply; +the expanding multiply would clobber the @samp{%edx} register, and this +would confuse @code{@value{GCC}} output. Use @samp{imul %ebx} to get the +64-bit product in @samp{%edx:%eax}. + +We have added a two operand form of @samp{imul} when the first operand +is an immediate mode expression and the second operand is a register. +This is just a shorthand, so that, multiplying @samp{%eax} by 69, for +example, can be done with @samp{imul $69, %eax} rather than @samp{imul +$69, %eax, %eax}. + diff --git a/contrib/binutils-2.14/gas/doc/fdl.texi b/contrib/binutils-2.14/gas/doc/fdl.texi new file mode 100644 index 0000000000..c6409a3a1a --- /dev/null +++ b/contrib/binutils-2.14/gas/doc/fdl.texi @@ -0,0 +1,367 @@ +@c -*-texinfo-*- +@node GNU Free Documentation License +@appendix GNU Free Documentation License +@center Version 1.1, March 2000 + +@display +Copyright (C) 2000, Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +@end display +@sp 1 +@enumerate 0 +@item +PREAMBLE + +The purpose of this License is to make a manual, textbook, or other +written document ``free'' in the sense of freedom: to assure everyone +the effective freedom to copy and redistribute it, with or without +modifying it, either commercially or noncommercially. Secondarily, +this License preserves for the author and publisher a way to get +credit for their work, while not being considered responsible for +modifications made by others. + +This License is a kind of ``copyleft'', which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft +license designed for free software. + +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + +@sp 1 +@item +APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work that contains a +notice placed by the copyright holder saying it can be distributed +under the terms of this License. The ``Document'', below, refers to any +such manual or work. Any member of the public is a licensee, and is +addressed as ``you.'' + +A ``Modified Version'' of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. + +A ``Secondary Section'' is a named appendix or a front-matter section of +the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall subject +(or to related matters) and contains nothing that could fall directly +within that overall subject. (For example, if the Document is in part a +textbook of mathematics, a Secondary Section may not explain any +mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. + +The ``Invariant Sections'' are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. + +The ``Cover Texts'' are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. + +A ``Transparent'' copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, whose contents can be viewed and edited directly and +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup has been designed to thwart or discourage +subsequent modification by readers is not Transparent. A copy that is +not ``Transparent'' is called ``Opaque.'' + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML +or XML using a publicly available DTD, and standard-conforming simple +HTML designed for human modification. Opaque formats include +PostScript, PDF, proprietary formats that can be read and edited only +by proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the +machine-generated HTML produced by some word processors for output +purposes only. + +The ``Title Page'' means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, ``Title Page'' means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. +@sp 1 +@item +VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. +@sp 1 +@item +COPYING IN QUANTITY + +If you publish printed copies of the Document numbering more than 100, +and the Document's license notice requires Cover Texts, you must enclose +the copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a publicly-accessible computer-network location containing a complete +Transparent copy of the Document, free of added material, which the +general network-using public has access to download anonymously at no +charge using public-standard network protocols. If you use the latter +option, you must take reasonably prudent steps, when you begin +distribution of Opaque copies in quantity, to ensure that this +Transparent copy will remain thus accessible at the stated location +until at least one year after the last time you distribute an Opaque +copy (directly or through your agents or retailers) of that edition to +the public. + +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. +@sp 1 +@item +MODIFICATIONS + +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: + +A. Use in the Title Page (and on the covers, if any) a title distinct + from that of the Document, and from those of previous versions + (which should, if there were any, be listed in the History section + of the Document). You may use the same title as a previous version + if the original publisher of that version gives permission.@* +B. List on the Title Page, as authors, one or more persons or entities + responsible for authorship of the modifications in the Modified + Version, together with at least five of the principal authors of the + Document (all of its principal authors, if it has less than five).@* +C. State on the Title page the name of the publisher of the + Modified Version, as the publisher.@* +D. Preserve all the copyright notices of the Document.@* +E. Add an appropriate copyright notice for your modifications + adjacent to the other copyright notices.@* +F. Include, immediately after the copyright notices, a license notice + giving the public permission to use the Modified Version under the + terms of this License, in the form shown in the Addendum below.@* +G. Preserve in that license notice the full lists of Invariant Sections + and required Cover Texts given in the Document's license notice.@* +H. Include an unaltered copy of this License.@* +I. Preserve the section entitled ``History'', and its title, and add to + it an item stating at least the title, year, new authors, and + publisher of the Modified Version as given on the Title Page. If + there is no section entitled ``History'' in the Document, create one + stating the title, year, authors, and publisher of the Document as + given on its Title Page, then add an item describing the Modified + Version as stated in the previous sentence.@* +J. Preserve the network location, if any, given in the Document for + public access to a Transparent copy of the Document, and likewise + the network locations given in the Document for previous versions + it was based on. These may be placed in the ``History'' section. + You may omit a network location for a work that was published at + least four years before the Document itself, or if the original + publisher of the version it refers to gives permission.@* +K. In any section entitled ``Acknowledgements'' or ``Dedications'', + preserve the section's title, and preserve in the section all the + substance and tone of each of the contributor acknowledgements + and/or dedications given therein.@* +L. Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers + or the equivalent are not considered part of the section titles.@* +M. Delete any section entitled ``Endorsements.'' Such a section + may not be included in the Modified Version.@* +N. Do not retitle any existing section as ``Endorsements'' + or to conflict in title with any Invariant Section.@* +@sp 1 +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section entitled ``Endorsements'', provided it contains +nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. +@sp 1 +@item +COMBINING DOCUMENTS + +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. + +In the combination, you must combine any sections entitled ``History'' +in the various original documents, forming one section entitled +``History''; likewise combine any sections entitled ``Acknowledgements'', +and any sections entitled ``Dedications.'' You must delete all sections +entitled ``Endorsements.'' +@sp 1 +@item +COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. + +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. +@sp 1 +@item +AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, does not as a whole count as a Modified Version +of the Document, provided no compilation copyright is claimed for the +compilation. Such a compilation is called an ``aggregate'', and this +License does not apply to the other self-contained works thus compiled +with the Document, on account of their being thus compiled, if they +are not themselves derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one quarter +of the entire aggregate, the Document's Cover Texts may be placed on +covers that surround only the Document within the aggregate. +Otherwise they must appear on covers around the whole aggregate. +@sp 1 +@item +TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License provided that you also include the +original English version of this License. In case of a disagreement +between the translation and the original English version of this +License, the original English version will prevail. +@sp 1 +@item +TERMINATION + +You may not copy, modify, sublicense, or distribute the Document except +as expressly provided for under this License. Any other attempt to +copy, modify, sublicense or distribute the Document is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this +License will not have their licenses terminated so long as such +parties remain in full compliance. +@sp 1 +@item +FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions +of the GNU Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License ``or any later version'' applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + +@end enumerate + +@unnumberedsec ADDENDUM: How to use this License for your documents + +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: + +@smallexample +@group +Copyright (C) @var{year} @var{your name}. +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with the Invariant Sections being @var{list their titles}, with the +Front-Cover Texts being @var{list}, and with the Back-Cover Texts being @var{list}. +A copy of the license is included in the section entitled "GNU +Free Documentation License." +@end group +@end smallexample + +If you have no Invariant Sections, write ``with no Invariant Sections'' +instead of saying which ones are invariant. If you have no +Front-Cover Texts, write ``no Front-Cover Texts'' instead of +``Front-Cover Texts being @var{list}''; likewise for Back-Cover Texts. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the GNU General Public License, +to permit their use in free software. diff --git a/contrib/binutils-2.14/gas/dwarf2dbg.c b/contrib/binutils-2.14/gas/dwarf2dbg.c new file mode 100644 index 0000000000..e58f73a25c --- /dev/null +++ b/contrib/binutils-2.14/gas/dwarf2dbg.c @@ -0,0 +1,1539 @@ +/* dwarf2dbg.c - DWARF2 debug support + Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Logical line numbers can be controlled by the compiler via the + following two directives: + + .file FILENO "file.c" + .loc FILENO LINENO [COLUMN] + + FILENO is the filenumber. */ + +#include "ansidecl.h" +#include "as.h" + +#ifdef HAVE_LIMITS_H +#include +#else +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#ifndef INT_MAX +#define INT_MAX (int) (((unsigned) (-1)) >> 1) +#endif +#endif + +#include "dwarf2dbg.h" +#include + +#ifndef DWARF2_FORMAT +# define DWARF2_FORMAT() dwarf2_format_32bit +#endif + +#ifndef DWARF2_ADDR_SIZE +# define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8); +#endif + +#ifndef TC_DWARF2_EMIT_OFFSET +# define TC_DWARF2_EMIT_OFFSET generic_dwarf2_emit_offset +#endif + +#ifdef BFD_ASSEMBLER + +#include "subsegs.h" + +#include "elf/dwarf2.h" + +/* Since we can't generate the prolog until the body is complete, we + use three different subsegments for .debug_line: one holding the + prolog, one for the directory and filename info, and one for the + body ("statement program"). */ +#define DL_PROLOG 0 +#define DL_FILES 1 +#define DL_BODY 2 + +/* First special line opcde - leave room for the standard opcodes. + Note: If you want to change this, you'll have to update the + "standard_opcode_lengths" table that is emitted below in + dwarf2_finish(). */ +#define DWARF2_LINE_OPCODE_BASE 10 + +#ifndef DWARF2_LINE_BASE + /* Minimum line offset in a special line info. opcode. This value + was chosen to give a reasonable range of values. */ +# define DWARF2_LINE_BASE -5 +#endif + +/* Range of line offsets in a special line info. opcode. */ +#ifndef DWARF2_LINE_RANGE +# define DWARF2_LINE_RANGE 14 +#endif + +#ifndef DWARF2_LINE_MIN_INSN_LENGTH + /* Define the architecture-dependent minimum instruction length (in + bytes). This value should be rather too small than too big. */ +# define DWARF2_LINE_MIN_INSN_LENGTH 1 +#endif + +/* Flag that indicates the initial value of the is_stmt_start flag. + In the present implementation, we do not mark any lines as + the beginning of a source statement, because that information + is not made available by the GCC front-end. */ +#define DWARF2_LINE_DEFAULT_IS_STMT 1 + +/* Given a special op, return the line skip amount. */ +#define SPECIAL_LINE(op) \ + (((op) - DWARF2_LINE_OPCODE_BASE)%DWARF2_LINE_RANGE + DWARF2_LINE_BASE) + +/* Given a special op, return the address skip amount (in units of + DWARF2_LINE_MIN_INSN_LENGTH. */ +#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE) + +/* The maximum address skip amount that can be encoded with a special op. */ +#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) + +struct line_entry { + struct line_entry *next; + fragS *frag; + addressT frag_ofs; + struct dwarf2_line_info loc; +}; + +struct line_subseg { + struct line_subseg *next; + subsegT subseg; + struct line_entry *head; + struct line_entry **ptail; +}; + +struct line_seg { + struct line_seg *next; + segT seg; + struct line_subseg *head; + symbolS *text_start; + symbolS *text_end; +}; + +/* Collects data for all line table entries during assembly. */ +static struct line_seg *all_segs; + +struct file_entry { + const char *filename; + unsigned int dir; +}; + +/* Table of files used by .debug_line. */ +static struct file_entry *files; +static unsigned int files_in_use; +static unsigned int files_allocated; + +/* Table of directories used by .debug_line. */ +static char **dirs; +static unsigned int dirs_in_use; +static unsigned int dirs_allocated; + +/* TRUE when we've seen a .loc directive recently. Used to avoid + doing work when there's nothing to do. */ +static bfd_boolean loc_directive_seen; + +/* Current location as indicated by the most recent .loc directive. */ +static struct dwarf2_line_info current; + +/* Fake label name. */ +static char const fake_label_name[] = ".L0\001"; + +/* The size of an address on the target. */ +static unsigned int sizeof_address; + +static void generic_dwarf2_emit_offset PARAMS((symbolS *, unsigned int)); +static struct line_subseg *get_line_subseg PARAMS ((segT, subsegT)); +static unsigned int get_filenum PARAMS ((const char *, unsigned int)); +static struct frag *first_frag_for_seg PARAMS ((segT)); +static struct frag *last_frag_for_seg PARAMS ((segT)); +static void out_byte PARAMS ((int)); +static void out_opcode PARAMS ((int)); +static void out_two PARAMS ((int)); +static void out_four PARAMS ((int)); +static void out_abbrev PARAMS ((int, int)); +static void out_uleb128 PARAMS ((addressT)); +static symbolS *symbol_new_now PARAMS ((void)); +static void set_symbol_value_now PARAMS ((symbolS *)); +static offsetT get_frag_fix PARAMS ((fragS *)); +static void out_set_addr PARAMS ((segT, fragS *, addressT)); +static int size_inc_line_addr PARAMS ((int, addressT)); +static void emit_inc_line_addr PARAMS ((int, addressT, char *, int)); +static void out_inc_line_addr PARAMS ((int, addressT)); +static void relax_inc_line_addr PARAMS ((int, segT, fragS *, addressT, + fragS *, addressT)); +static void process_entries PARAMS ((segT, struct line_entry *)); +static void out_file_list PARAMS ((void)); +static void out_debug_line PARAMS ((segT)); +static void out_debug_aranges PARAMS ((segT, segT)); +static void out_debug_abbrev PARAMS ((segT)); +static void out_debug_info PARAMS ((segT, segT, segT)); + +/* Create an offset to .dwarf2_*. */ + +static void +generic_dwarf2_emit_offset (symbol, size) + symbolS *symbol; + unsigned int size; +{ + expressionS expr; + + expr.X_op = O_symbol; + expr.X_add_symbol = symbol; + expr.X_add_number = 0; + emit_expr (&expr, size); +} + +/* Find or create an entry for SEG+SUBSEG in ALL_SEGS. */ + +static struct line_subseg * +get_line_subseg (seg, subseg) + segT seg; + subsegT subseg; +{ + static segT last_seg; + static subsegT last_subseg; + static struct line_subseg *last_line_subseg; + + struct line_seg *s; + struct line_subseg **pss, *ss; + + if (seg == last_seg && subseg == last_subseg) + return last_line_subseg; + + for (s = all_segs; s; s = s->next) + if (s->seg == seg) + goto found_seg; + + s = (struct line_seg *) xmalloc (sizeof (*s)); + s->next = all_segs; + s->seg = seg; + s->head = NULL; + all_segs = s; + + found_seg: + for (pss = &s->head; (ss = *pss) != NULL ; pss = &ss->next) + { + if (ss->subseg == subseg) + goto found_subseg; + if (ss->subseg > subseg) + break; + } + + ss = (struct line_subseg *) xmalloc (sizeof (*ss)); + ss->next = *pss; + ss->subseg = subseg; + ss->head = NULL; + ss->ptail = &ss->head; + *pss = ss; + + found_subseg: + last_seg = seg; + last_subseg = subseg; + last_line_subseg = ss; + + return ss; +} + +/* Record an entry for LOC ocurring at OFS within the current fragment. */ + +void +dwarf2_gen_line_info (ofs, loc) + addressT ofs; + struct dwarf2_line_info *loc; +{ + struct line_subseg *ss; + struct line_entry *e; + static unsigned int line = -1; + static unsigned int filenum = -1; + + /* Early out for as-yet incomplete location information. */ + if (loc->filenum == 0 || loc->line == 0) + return; + + /* Don't emit sequences of line symbols for the same line when the + symbols apply to assembler code. It is necessary to emit + duplicate line symbols when a compiler asks for them, because GDB + uses them to determine the end of the prologue. */ + if (debug_type == DEBUG_DWARF2 + && line == loc->line && filenum == loc->filenum) + return; + + line = loc->line; + filenum = loc->filenum; + + e = (struct line_entry *) xmalloc (sizeof (*e)); + e->next = NULL; + e->frag = frag_now; + e->frag_ofs = ofs; + e->loc = *loc; + + ss = get_line_subseg (now_seg, now_subseg); + *ss->ptail = e; + ss->ptail = &e->next; +} + +void +dwarf2_where (line) + struct dwarf2_line_info *line; +{ + if (debug_type == DEBUG_DWARF2) + { + char *filename; + as_where (&filename, &line->line); + line->filenum = get_filenum (filename, 0); + line->column = 0; + line->flags = DWARF2_FLAG_BEGIN_STMT; + } + else + *line = current; +} + +/* Called for each machine instruction, or relatively atomic group of + machine instructions (ie built-in macro). The instruction or group + is SIZE bytes in length. If dwarf2 line number generation is called + for, emit a line statement appropriately. */ + +void +dwarf2_emit_insn (size) + int size; +{ + struct dwarf2_line_info loc; + + if (loc_directive_seen) + { + /* Use the last location established by a .loc directive, not + the value returned by dwarf2_where(). That calls as_where() + which will return either the logical input file name (foo.c) + or the physical input file name (foo.s) and not the file name + specified in the most recent .loc directive (eg foo.h). */ + loc = current; + + /* Unless we generate DWARF2 debugging information for each + assembler line, we only emit one line symbol for one LOC. */ + if (debug_type != DEBUG_DWARF2) + loc_directive_seen = FALSE; + } + else if (debug_type != DEBUG_DWARF2) + return; + else + dwarf2_where (& loc); + + dwarf2_gen_line_info (frag_now_fix () - size, &loc); +} + +/* Get a .debug_line file number for FILENAME. If NUM is nonzero, + allocate it on that file table slot, otherwise return the first + empty one. */ + +static unsigned int +get_filenum (filename, num) + const char *filename; + unsigned int num; +{ + static unsigned int last_used, last_used_dir_len; + const char *file; + size_t dir_len; + unsigned int i, dir; + + if (num == 0 && last_used) + { + if (! files[last_used].dir + && strcmp (filename, files[last_used].filename) == 0) + return last_used; + if (files[last_used].dir + && strncmp (filename, dirs[files[last_used].dir], + last_used_dir_len) == 0 + && IS_DIR_SEPARATOR (filename [last_used_dir_len]) + && strcmp (filename + last_used_dir_len + 1, + files[last_used].filename) == 0) + return last_used; + } + + file = lbasename (filename); + /* Don't make empty string from / or A: from A:/ . */ +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (file <= filename + 3) + file = filename; +#else + if (file == filename + 1) + file = filename; +#endif + dir_len = file - filename; + + dir = 0; + if (dir_len) + { + --dir_len; + for (dir = 1; dir < dirs_in_use; ++dir) + if (memcmp (filename, dirs[dir], dir_len) == 0 + && dirs[dir][dir_len] == '\0') + break; + + if (dir >= dirs_in_use) + { + if (dir >= dirs_allocated) + { + dirs_allocated = dir + 32; + dirs = (char **) + xrealloc (dirs, (dir + 32) * sizeof (const char *)); + } + + dirs[dir] = xmalloc (dir_len + 1); + memcpy (dirs[dir], filename, dir_len); + dirs[dir][dir_len] = '\0'; + dirs_in_use = dir + 1; + } + } + + if (num == 0) + { + for (i = 1; i < files_in_use; ++i) + if (files[i].dir == dir + && files[i].filename + && strcmp (file, files[i].filename) == 0) + { + last_used = i; + last_used_dir_len = dir_len; + return i; + } + } + else + i = num; + + if (i >= files_allocated) + { + unsigned int old = files_allocated; + + files_allocated = i + 32; + files = (struct file_entry *) + xrealloc (files, (i + 32) * sizeof (struct file_entry)); + + memset (files + old, 0, (i + 32 - old) * sizeof (struct file_entry)); + } + + files[i].filename = num ? file : xstrdup (file); + files[i].dir = dir; + files_in_use = i + 1; + last_used = i; + last_used_dir_len = dir_len; + + return i; +} + +/* Handle two forms of .file directive: + - Pass .file "source.c" to s_app_file + - Handle .file 1 "source.c" by adding an entry to the DWARF-2 file table + + If an entry is added to the file table, return a pointer to the filename. */ + +char * +dwarf2_directive_file (dummy) + int dummy ATTRIBUTE_UNUSED; +{ + offsetT num; + char *filename; + int filename_len; + + /* Continue to accept a bare string and pass it off. */ + SKIP_WHITESPACE (); + if (*input_line_pointer == '"') + { + s_app_file (0); + return NULL; + } + + num = get_absolute_expression (); + filename = demand_copy_C_string (&filename_len); + demand_empty_rest_of_line (); + + if (num < 1) + { + as_bad (_("file number less than one")); + return NULL; + } + + if (num < (int) files_in_use && files[num].filename != 0) + { + as_bad (_("file number %ld already allocated"), (long) num); + return NULL; + } + + get_filenum (filename, num); + + return filename; +} + +void +dwarf2_directive_loc (dummy) + int dummy ATTRIBUTE_UNUSED; +{ + offsetT filenum, line, column; + + filenum = get_absolute_expression (); + SKIP_WHITESPACE (); + line = get_absolute_expression (); + SKIP_WHITESPACE (); + column = get_absolute_expression (); + demand_empty_rest_of_line (); + + if (filenum < 1) + { + as_bad (_("file number less than one")); + return; + } + if (filenum >= (int) files_in_use || files[filenum].filename == 0) + { + as_bad (_("unassigned file number %ld"), (long) filenum); + return; + } + + current.filenum = filenum; + current.line = line; + current.column = column; + current.flags = DWARF2_FLAG_BEGIN_STMT; + + loc_directive_seen = TRUE; + +#ifndef NO_LISTING + if (listing) + { + if (files[filenum].dir) + { + size_t dir_len = strlen (dirs[files[filenum].dir]); + size_t file_len = strlen (files[filenum].filename); + char *cp = (char *) alloca (dir_len + 1 + file_len + 1); + + memcpy (cp, dirs[files[filenum].dir], dir_len); + cp[dir_len] = '/'; + memcpy (cp + dir_len + 1, files[filenum].filename, file_len); + cp[dir_len + file_len + 1] = '\0'; + listing_source_file (cp); + } + else + listing_source_file (files[filenum].filename); + listing_source_line (line); + } +#endif +} + +static struct frag * +first_frag_for_seg (seg) + segT seg; +{ + frchainS *f, *first = NULL; + + for (f = frchain_root; f; f = f->frch_next) + if (f->frch_seg == seg + && (! first || first->frch_subseg > f->frch_subseg)) + first = f; + + return first ? first->frch_root : NULL; +} + +static struct frag * +last_frag_for_seg (seg) + segT seg; +{ + frchainS *f, *last = NULL; + + for (f = frchain_root; f; f = f->frch_next) + if (f->frch_seg == seg + && (! last || last->frch_subseg < f->frch_subseg)) + last= f; + + return last ? last->frch_last : NULL; +} + +/* Emit a single byte into the current segment. */ + +static inline void +out_byte (byte) + int byte; +{ + FRAG_APPEND_1_CHAR (byte); +} + +/* Emit a statement program opcode into the current segment. */ + +static inline void +out_opcode (opc) + int opc; +{ + out_byte (opc); +} + +/* Emit a two-byte word into the current segment. */ + +static inline void +out_two (data) + int data; +{ + md_number_to_chars (frag_more (2), data, 2); +} + +/* Emit a four byte word into the current segment. */ + +static inline void +out_four (data) + int data; +{ + md_number_to_chars (frag_more (4), data, 4); +} + +/* Emit an unsigned "little-endian base 128" number. */ + +static void +out_uleb128 (value) + addressT value; +{ + output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0); +} + +/* Emit a tuple for .debug_abbrev. */ + +static inline void +out_abbrev (name, form) + int name, form; +{ + out_uleb128 (name); + out_uleb128 (form); +} + +/* Create a new fake symbol whose value is the current position. */ + +static symbolS * +symbol_new_now () +{ + return symbol_new (fake_label_name, now_seg, frag_now_fix (), frag_now); +} + +/* Set the value of SYM to the current position in the current segment. */ + +static void +set_symbol_value_now (sym) + symbolS *sym; +{ + S_SET_SEGMENT (sym, now_seg); + S_SET_VALUE (sym, frag_now_fix ()); + symbol_set_frag (sym, frag_now); +} + +/* Get the size of a fragment. */ + +static offsetT +get_frag_fix (frag) + fragS *frag; +{ + frchainS *fr; + + if (frag->fr_next) + return frag->fr_fix; + + /* If a fragment is the last in the chain, special measures must be + taken to find its size before relaxation, since it may be pending + on some subsegment chain. */ + for (fr = frchain_root; fr; fr = fr->frch_next) + if (fr->frch_last == frag) + { + long align_mask = -1 << get_recorded_alignment (fr->frch_seg); + return (((char *) obstack_next_free (&fr->frch_obstack) + - frag->fr_literal) + ~align_mask) & align_mask; + } + + abort (); +} + +/* Set an absolute address (may result in a relocation entry). */ + +static void +out_set_addr (seg, frag, ofs) + segT seg; + fragS *frag; + addressT ofs; +{ + expressionS expr; + symbolS *sym; + + sym = symbol_new (fake_label_name, seg, ofs, frag); + + out_opcode (DW_LNS_extended_op); + out_uleb128 (sizeof_address + 1); + + out_opcode (DW_LNE_set_address); + expr.X_op = O_symbol; + expr.X_add_symbol = sym; + expr.X_add_number = 0; + emit_expr (&expr, sizeof_address); +} + +#if DWARF2_LINE_MIN_INSN_LENGTH > 1 +static void scale_addr_delta PARAMS ((addressT *)); + +static void +scale_addr_delta (addr_delta) + addressT *addr_delta; +{ + static int printed_this = 0; + if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0) + { + if (!printed_this) + as_bad("unaligned opcodes detected in executable segment"); + printed_this = 1; + } + *addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH; +} +#else +#define scale_addr_delta(A) +#endif + +/* Encode a pair of line and address skips as efficiently as possible. + Note that the line skip is signed, whereas the address skip is unsigned. + + The following two routines *must* be kept in sync. This is + enforced by making emit_inc_line_addr abort if we do not emit + exactly the expected number of bytes. */ + +static int +size_inc_line_addr (line_delta, addr_delta) + int line_delta; + addressT addr_delta; +{ + unsigned int tmp, opcode; + int len = 0; + + /* Scale the address delta by the minimum instruction length. */ + scale_addr_delta (&addr_delta); + + /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence. + We cannot use special opcodes here, since we want the end_sequence + to emit the matrix entry. */ + if (line_delta == INT_MAX) + { + if (addr_delta == MAX_SPECIAL_ADDR_DELTA) + len = 1; + else + len = 1 + sizeof_leb128 (addr_delta, 0); + return len + 3; + } + + /* Bias the line delta by the base. */ + tmp = line_delta - DWARF2_LINE_BASE; + + /* If the line increment is out of range of a special opcode, we + must encode it with DW_LNS_advance_line. */ + if (tmp >= DWARF2_LINE_RANGE) + { + len = 1 + sizeof_leb128 (line_delta, 1); + line_delta = 0; + tmp = 0 - DWARF2_LINE_BASE; + } + + /* Bias the opcode by the special opcode base. */ + tmp += DWARF2_LINE_OPCODE_BASE; + + /* Avoid overflow when addr_delta is large. */ + if (addr_delta < 256 + MAX_SPECIAL_ADDR_DELTA) + { + /* Try using a special opcode. */ + opcode = tmp + addr_delta * DWARF2_LINE_RANGE; + if (opcode <= 255) + return len + 1; + + /* Try using DW_LNS_const_add_pc followed by special op. */ + opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; + if (opcode <= 255) + return len + 2; + } + + /* Otherwise use DW_LNS_advance_pc. */ + len += 1 + sizeof_leb128 (addr_delta, 0); + + /* DW_LNS_copy or special opcode. */ + len += 1; + + return len; +} + +static void +emit_inc_line_addr (line_delta, addr_delta, p, len) + int line_delta; + addressT addr_delta; + char *p; + int len; +{ + unsigned int tmp, opcode; + int need_copy = 0; + char *end = p + len; + + /* Scale the address delta by the minimum instruction length. */ + scale_addr_delta (&addr_delta); + + /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence. + We cannot use special opcodes here, since we want the end_sequence + to emit the matrix entry. */ + if (line_delta == INT_MAX) + { + if (addr_delta == MAX_SPECIAL_ADDR_DELTA) + *p++ = DW_LNS_const_add_pc; + else + { + *p++ = DW_LNS_advance_pc; + p += output_leb128 (p, addr_delta, 0); + } + + *p++ = DW_LNS_extended_op; + *p++ = 1; + *p++ = DW_LNE_end_sequence; + goto done; + } + + /* Bias the line delta by the base. */ + tmp = line_delta - DWARF2_LINE_BASE; + + /* If the line increment is out of range of a special opcode, we + must encode it with DW_LNS_advance_line. */ + if (tmp >= DWARF2_LINE_RANGE) + { + *p++ = DW_LNS_advance_line; + p += output_leb128 (p, line_delta, 1); + + /* Prettier, I think, to use DW_LNS_copy instead of a + "line +0, addr +0" special opcode. */ + if (addr_delta == 0) + { + *p++ = DW_LNS_copy; + goto done; + } + + line_delta = 0; + tmp = 0 - DWARF2_LINE_BASE; + need_copy = 1; + } + + /* Bias the opcode by the special opcode base. */ + tmp += DWARF2_LINE_OPCODE_BASE; + + /* Avoid overflow when addr_delta is large. */ + if (addr_delta < 256 + MAX_SPECIAL_ADDR_DELTA) + { + /* Try using a special opcode. */ + opcode = tmp + addr_delta * DWARF2_LINE_RANGE; + if (opcode <= 255) + { + *p++ = opcode; + goto done; + } + + /* Try using DW_LNS_const_add_pc followed by special op. */ + opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; + if (opcode <= 255) + { + *p++ = DW_LNS_const_add_pc; + *p++ = opcode; + goto done; + } + } + + /* Otherwise use DW_LNS_advance_pc. */ + *p++ = DW_LNS_advance_pc; + p += output_leb128 (p, addr_delta, 0); + + if (need_copy) + *p++ = DW_LNS_copy; + else + *p++ = tmp; + + done: + assert (p == end); +} + +/* Handy routine to combine calls to the above two routines. */ + +static void +out_inc_line_addr (line_delta, addr_delta) + int line_delta; + addressT addr_delta; +{ + int len = size_inc_line_addr (line_delta, addr_delta); + emit_inc_line_addr (line_delta, addr_delta, frag_more (len), len); +} + +/* Generate a variant frag that we can use to relax address/line + increments between fragments of the target segment. */ + +static void +relax_inc_line_addr (line_delta, seg, to_frag, to_ofs, from_frag, from_ofs) + int line_delta; + segT seg; + fragS *to_frag, *from_frag; + addressT to_ofs, from_ofs; +{ + symbolS *to_sym, *from_sym; + expressionS expr; + int max_chars; + + to_sym = symbol_new (fake_label_name, seg, to_ofs, to_frag); + from_sym = symbol_new (fake_label_name, seg, from_ofs, from_frag); + + expr.X_op = O_subtract; + expr.X_add_symbol = to_sym; + expr.X_op_symbol = from_sym; + expr.X_add_number = 0; + + /* The maximum size of the frag is the line delta with a maximum + sized address delta. */ + max_chars = size_inc_line_addr (line_delta, -DWARF2_LINE_MIN_INSN_LENGTH); + + frag_var (rs_dwarf2dbg, max_chars, max_chars, 1, + make_expr_symbol (&expr), line_delta, NULL); +} + +/* The function estimates the size of a rs_dwarf2dbg variant frag + based on the current values of the symbols. It is called before + the relaxation loop. We set fr_subtype to the expected length. */ + +int +dwarf2dbg_estimate_size_before_relax (frag) + fragS *frag; +{ + offsetT addr_delta; + int size; + + addr_delta = resolve_symbol_value (frag->fr_symbol); + size = size_inc_line_addr (frag->fr_offset, addr_delta); + + frag->fr_subtype = size; + + return size; +} + +/* This function relaxes a rs_dwarf2dbg variant frag based on the + current values of the symbols. fr_subtype is the current length + of the frag. This returns the change in frag length. */ + +int +dwarf2dbg_relax_frag (frag) + fragS *frag; +{ + int old_size, new_size; + + old_size = frag->fr_subtype; + new_size = dwarf2dbg_estimate_size_before_relax (frag); + + return new_size - old_size; +} + +/* This function converts a rs_dwarf2dbg variant frag into a normal + fill frag. This is called after all relaxation has been done. + fr_subtype will be the desired length of the frag. */ + +void +dwarf2dbg_convert_frag (frag) + fragS *frag; +{ + offsetT addr_diff; + + addr_diff = resolve_symbol_value (frag->fr_symbol); + + /* fr_var carries the max_chars that we created the fragment with. + fr_subtype carries the current expected length. We must, of + course, have allocated enough memory earlier. */ + assert (frag->fr_var >= (int) frag->fr_subtype); + + emit_inc_line_addr (frag->fr_offset, addr_diff, + frag->fr_literal + frag->fr_fix, frag->fr_subtype); + + frag->fr_fix += frag->fr_subtype; + frag->fr_type = rs_fill; + frag->fr_var = 0; + frag->fr_offset = 0; +} + +/* Generate .debug_line content for the chain of line number entries + beginning at E, for segment SEG. */ + +static void +process_entries (seg, e) + segT seg; + struct line_entry *e; +{ + unsigned filenum = 1; + unsigned line = 1; + unsigned column = 0; + unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_BEGIN_STMT : 0; + fragS *frag = NULL; + fragS *last_frag; + addressT frag_ofs = 0; + addressT last_frag_ofs; + struct line_entry *next; + + while (e) + { + int changed = 0; + + if (filenum != e->loc.filenum) + { + filenum = e->loc.filenum; + out_opcode (DW_LNS_set_file); + out_uleb128 (filenum); + changed = 1; + } + + if (column != e->loc.column) + { + column = e->loc.column; + out_opcode (DW_LNS_set_column); + out_uleb128 (column); + changed = 1; + } + + if ((e->loc.flags ^ flags) & DWARF2_FLAG_BEGIN_STMT) + { + flags = e->loc.flags; + out_opcode (DW_LNS_negate_stmt); + changed = 1; + } + + if (e->loc.flags & DWARF2_FLAG_BEGIN_BLOCK) + { + out_opcode (DW_LNS_set_basic_block); + changed = 1; + } + + /* Don't try to optimize away redundant entries; gdb wants two + entries for a function where the code starts on the same line as + the {, and there's no way to identify that case here. Trust gcc + to optimize appropriately. */ + if (1 /* line != e->loc.line || changed */) + { + int line_delta = e->loc.line - line; + if (frag == NULL) + { + out_set_addr (seg, e->frag, e->frag_ofs); + out_inc_line_addr (line_delta, 0); + } + else if (frag == e->frag) + out_inc_line_addr (line_delta, e->frag_ofs - frag_ofs); + else + relax_inc_line_addr (line_delta, seg, e->frag, e->frag_ofs, + frag, frag_ofs); + + frag = e->frag; + frag_ofs = e->frag_ofs; + line = e->loc.line; + } + else if (frag == NULL) + { + out_set_addr (seg, e->frag, e->frag_ofs); + frag = e->frag; + frag_ofs = e->frag_ofs; + } + + next = e->next; + free (e); + e = next; + } + + /* Emit a DW_LNE_end_sequence for the end of the section. */ + last_frag = last_frag_for_seg (seg); + last_frag_ofs = get_frag_fix (last_frag); + if (frag == last_frag) + out_inc_line_addr (INT_MAX, last_frag_ofs - frag_ofs); + else + relax_inc_line_addr (INT_MAX, seg, last_frag, last_frag_ofs, + frag, frag_ofs); +} + +/* Emit the directory and file tables for .debug_line. */ + +static void +out_file_list () +{ + size_t size; + char *cp; + unsigned int i; + + /* Emit directory list. */ + for (i = 1; i < dirs_in_use; ++i) + { + size = strlen (dirs[i]) + 1; + cp = frag_more (size); + memcpy (cp, dirs[i], size); + } + /* Terminate it. */ + out_byte ('\0'); + + for (i = 1; i < files_in_use; ++i) + { + if (files[i].filename == NULL) + { + as_bad (_("unassigned file number %ld"), (long) i); + /* Prevent a crash later, particularly for file 1. */ + files[i].filename = ""; + continue; + } + + size = strlen (files[i].filename) + 1; + cp = frag_more (size); + memcpy (cp, files[i].filename, size); + + out_uleb128 (files[i].dir); /* directory number */ + out_uleb128 (0); /* last modification timestamp */ + out_uleb128 (0); /* filesize */ + } + + /* Terminate filename list. */ + out_byte (0); +} + +/* Emit the collected .debug_line data. */ + +static void +out_debug_line (line_seg) + segT line_seg; +{ + expressionS expr; + symbolS *line_start; + symbolS *prologue_end; + symbolS *line_end; + struct line_seg *s; + enum dwarf2_format d2f; + int sizeof_offset; + + subseg_set (line_seg, 0); + + line_start = symbol_new_now (); + prologue_end = symbol_make (fake_label_name); + line_end = symbol_make (fake_label_name); + + /* Total length of the information for this compilation unit. */ + expr.X_op = O_subtract; + expr.X_add_symbol = line_end; + expr.X_op_symbol = line_start; + + d2f = DWARF2_FORMAT (); + if (d2f == dwarf2_format_32bit) + { + expr.X_add_number = -4; + emit_expr (&expr, 4); + sizeof_offset = 4; + } + else if (d2f == dwarf2_format_64bit) + { + expr.X_add_number = -12; + out_four (-1); + emit_expr (&expr, 8); + sizeof_offset = 8; + } + else if (d2f == dwarf2_format_64bit_irix) + { + expr.X_add_number = -8; + emit_expr (&expr, 8); + sizeof_offset = 8; + } + else + { + as_fatal (_("internal error: unknown dwarf2 format")); + } + + /* Version. */ + out_two (2); + + /* Length of the prologue following this length. */ + expr.X_op = O_subtract; + expr.X_add_symbol = prologue_end; + expr.X_op_symbol = line_start; + expr.X_add_number = - (4 + 2 + 4); + emit_expr (&expr, sizeof_offset); + + /* Parameters of the state machine. */ + out_byte (DWARF2_LINE_MIN_INSN_LENGTH); + out_byte (DWARF2_LINE_DEFAULT_IS_STMT); + out_byte (DWARF2_LINE_BASE); + out_byte (DWARF2_LINE_RANGE); + out_byte (DWARF2_LINE_OPCODE_BASE); + + /* Standard opcode lengths. */ + out_byte (0); /* DW_LNS_copy */ + out_byte (1); /* DW_LNS_advance_pc */ + out_byte (1); /* DW_LNS_advance_line */ + out_byte (1); /* DW_LNS_set_file */ + out_byte (1); /* DW_LNS_set_column */ + out_byte (0); /* DW_LNS_negate_stmt */ + out_byte (0); /* DW_LNS_set_basic_block */ + out_byte (0); /* DW_LNS_const_add_pc */ + out_byte (1); /* DW_LNS_fixed_advance_pc */ + + out_file_list (); + + set_symbol_value_now (prologue_end); + + /* For each section, emit a statement program. */ + for (s = all_segs; s; s = s->next) + process_entries (s->seg, s->head->head); + + set_symbol_value_now (line_end); +} + +/* Emit data for .debug_aranges. */ + +static void +out_debug_aranges (aranges_seg, info_seg) + segT aranges_seg; + segT info_seg; +{ + unsigned int addr_size = sizeof_address; + addressT size, skip; + struct line_seg *s; + expressionS expr; + char *p; + + size = 4 + 2 + 4 + 1 + 1; + + skip = 2 * addr_size - (size & (2 * addr_size - 1)); + if (skip == 2 * addr_size) + skip = 0; + size += skip; + + for (s = all_segs; s; s = s->next) + size += 2 * addr_size; + + size += 2 * addr_size; + + subseg_set (aranges_seg, 0); + + /* Length of the compilation unit. */ + out_four (size - 4); + + /* Version. */ + out_two (2); + + /* Offset to .debug_info. */ + /* ??? sizeof_offset */ + TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), 4); + + /* Size of an address (offset portion). */ + out_byte (addr_size); + + /* Size of a segment descriptor. */ + out_byte (0); + + /* Align the header. */ + if (skip) + frag_align (ffs (2 * addr_size) - 1, 0, 0); + + for (s = all_segs; s; s = s->next) + { + fragS *frag; + symbolS *beg, *end; + + frag = first_frag_for_seg (s->seg); + beg = symbol_new (fake_label_name, s->seg, 0, frag); + s->text_start = beg; + + frag = last_frag_for_seg (s->seg); + end = symbol_new (fake_label_name, s->seg, get_frag_fix (frag), frag); + s->text_end = end; + + expr.X_op = O_symbol; + expr.X_add_symbol = beg; + expr.X_add_number = 0; + emit_expr (&expr, addr_size); + + expr.X_op = O_subtract; + expr.X_add_symbol = end; + expr.X_op_symbol = beg; + expr.X_add_number = 0; + emit_expr (&expr, addr_size); + } + + p = frag_more (2 * addr_size); + md_number_to_chars (p, 0, addr_size); + md_number_to_chars (p + addr_size, 0, addr_size); +} + +/* Emit data for .debug_abbrev. Note that this must be kept in + sync with out_debug_info below. */ + +static void +out_debug_abbrev (abbrev_seg) + segT abbrev_seg; +{ + subseg_set (abbrev_seg, 0); + + out_uleb128 (1); + out_uleb128 (DW_TAG_compile_unit); + out_byte (DW_CHILDREN_no); + out_abbrev (DW_AT_stmt_list, DW_FORM_data4); + if (all_segs->next == NULL) + { + out_abbrev (DW_AT_low_pc, DW_FORM_addr); + out_abbrev (DW_AT_high_pc, DW_FORM_addr); + } + out_abbrev (DW_AT_name, DW_FORM_string); + out_abbrev (DW_AT_comp_dir, DW_FORM_string); + out_abbrev (DW_AT_producer, DW_FORM_string); + out_abbrev (DW_AT_language, DW_FORM_data2); + out_abbrev (0, 0); + + /* Terminate the abbreviations for this compilation unit. */ + out_byte (0); +} + +/* Emit a description of this compilation unit for .debug_info. */ + +static void +out_debug_info (info_seg, abbrev_seg, line_seg) + segT info_seg; + segT abbrev_seg; + segT line_seg; +{ + char producer[128]; + char *comp_dir; + expressionS expr; + symbolS *info_start; + symbolS *info_end; + char *p; + int len; + enum dwarf2_format d2f; + int sizeof_offset; + + subseg_set (info_seg, 0); + + info_start = symbol_new_now (); + info_end = symbol_make (fake_label_name); + + /* Compilation Unit length. */ + expr.X_op = O_subtract; + expr.X_add_symbol = info_end; + expr.X_op_symbol = info_start; + + d2f = DWARF2_FORMAT (); + if (d2f == dwarf2_format_32bit) + { + expr.X_add_number = -4; + emit_expr (&expr, 4); + sizeof_offset = 4; + } + else if (d2f == dwarf2_format_64bit) + { + expr.X_add_number = -12; + out_four (-1); + emit_expr (&expr, 8); + sizeof_offset = 8; + } + else if (d2f == dwarf2_format_64bit_irix) + { + expr.X_add_number = -8; + emit_expr (&expr, 8); + sizeof_offset = 8; + } + else + { + as_fatal (_("internal error: unknown dwarf2 format")); + } + + /* DWARF version. */ + out_two (2); + + /* .debug_abbrev offset */ + TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset); + + /* Target address size. */ + out_byte (sizeof_address); + + /* DW_TAG_compile_unit DIE abbrev */ + out_uleb128 (1); + + /* DW_AT_stmt_list */ + /* ??? sizeof_offset */ + TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), 4); + + /* These two attributes may only be emitted if all of the code is + contiguous. Multiple sections are not that. */ + if (all_segs->next == NULL) + { + /* DW_AT_low_pc */ + expr.X_op = O_symbol; + expr.X_add_symbol = all_segs->text_start; + expr.X_add_number = 0; + emit_expr (&expr, sizeof_address); + + /* DW_AT_high_pc */ + expr.X_op = O_symbol; + expr.X_add_symbol = all_segs->text_end; + expr.X_add_number = 0; + emit_expr (&expr, sizeof_address); + } + + /* DW_AT_name. We don't have the actual file name that was present + on the command line, so assume files[1] is the main input file. + We're not supposed to get called unless at least one line number + entry was emitted, so this should always be defined. */ + if (!files || files_in_use < 1) + abort (); + if (files[1].dir) + { + len = strlen (dirs[files[1].dir]); + p = frag_more (len + 1); + memcpy (p, dirs[files[1].dir], len); + p[len] = '/'; + } + len = strlen (files[1].filename) + 1; + p = frag_more (len); + memcpy (p, files[1].filename, len); + + /* DW_AT_comp_dir */ + comp_dir = getpwd (); + len = strlen (comp_dir) + 1; + p = frag_more (len); + memcpy (p, comp_dir, len); + + /* DW_AT_producer */ + sprintf (producer, "GNU AS %s", VERSION); + len = strlen (producer) + 1; + p = frag_more (len); + memcpy (p, producer, len); + + /* DW_AT_language. Yes, this is probably not really MIPS, but the + dwarf2 draft has no standard code for assembler. */ + out_two (DW_LANG_Mips_Assembler); + + set_symbol_value_now (info_end); +} + +void +dwarf2_finish () +{ + segT line_seg; + struct line_seg *s; + + /* We don't need to do anything unless: + - Some debug information was recorded via .file/.loc + - or, we are generating DWARF2 information ourself (--gdwarf2) + - or, there is a user-provided .debug_info section which could + reference the file table in the .debug_line section we generate + below. */ + if (all_segs == NULL + && debug_type != DEBUG_DWARF2 + && bfd_get_section_by_name (stdoutput, ".debug_info") == NULL) + return; + + /* Calculate the size of an address for the target machine. */ + sizeof_address = DWARF2_ADDR_SIZE (stdoutput); + + /* Create and switch to the line number section. */ + line_seg = subseg_new (".debug_line", 0); + bfd_set_section_flags (stdoutput, line_seg, SEC_READONLY); + + /* For each subsection, chain the debug entries together. */ + for (s = all_segs; s; s = s->next) + { + struct line_subseg *ss = s->head; + struct line_entry **ptail = ss->ptail; + + while ((ss = ss->next) != NULL) + { + *ptail = ss->head; + ptail = ss->ptail; + } + } + + out_debug_line (line_seg); + + /* If this is assembler generated line info, we need .debug_info + and .debug_abbrev sections as well. */ + if (all_segs != NULL && debug_type == DEBUG_DWARF2) + { + segT abbrev_seg; + segT info_seg; + segT aranges_seg; + + info_seg = subseg_new (".debug_info", 0); + abbrev_seg = subseg_new (".debug_abbrev", 0); + aranges_seg = subseg_new (".debug_aranges", 0); + + bfd_set_section_flags (stdoutput, info_seg, SEC_READONLY); + bfd_set_section_flags (stdoutput, abbrev_seg, SEC_READONLY); + bfd_set_section_flags (stdoutput, aranges_seg, SEC_READONLY); + + record_alignment (aranges_seg, ffs (2 * sizeof_address) - 1); + + out_debug_aranges (aranges_seg, info_seg); + out_debug_abbrev (abbrev_seg); + out_debug_info (info_seg, abbrev_seg, line_seg); + } +} + +#else +void +dwarf2_finish () +{ +} + +int +dwarf2dbg_estimate_size_before_relax (frag) + fragS *frag ATTRIBUTE_UNUSED; +{ + as_fatal (_("dwarf2 is not supported for this object file format")); + return 0; +} + +int +dwarf2dbg_relax_frag (frag) + fragS *frag ATTRIBUTE_UNUSED; +{ + as_fatal (_("dwarf2 is not supported for this object file format")); + return 0; +} + +void +dwarf2dbg_convert_frag (frag) + fragS *frag ATTRIBUTE_UNUSED; +{ + as_fatal (_("dwarf2 is not supported for this object file format")); +} + +void +dwarf2_emit_insn (size) + int size ATTRIBUTE_UNUSED; +{ +} + +char * +dwarf2_directive_file (dummy) + int dummy ATTRIBUTE_UNUSED; +{ + s_app_file (0); + return NULL; +} + +void +dwarf2_directive_loc (dummy) + int dummy ATTRIBUTE_UNUSED; +{ + as_fatal (_("dwarf2 is not supported for this object file format")); +} +#endif /* BFD_ASSEMBLER */ diff --git a/contrib/binutils-2.14/gas/dwarf2dbg.h b/contrib/binutils-2.14/gas/dwarf2dbg.h new file mode 100644 index 0000000000..d60d0874bf --- /dev/null +++ b/contrib/binutils-2.14/gas/dwarf2dbg.h @@ -0,0 +1,85 @@ +/* dwarf2dbg.h - DWARF2 debug support + Copyright 1999, 2000 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef AS_DWARF2DBG_H +#define AS_DWARF2DBG_H + +#include "as.h" + +#define DWARF2_FLAG_BEGIN_STMT (1 << 0) /* beginning of statement */ +#define DWARF2_FLAG_BEGIN_BLOCK (1 << 1) /* beginning of basic block */ + +struct dwarf2_line_info { + unsigned int filenum; + unsigned int line; + unsigned int column; + unsigned int flags; +}; + +/* Implements the .file FILENO "FILENAME" directive. FILENO can be 0 + to indicate that no file number has been assigned. All real file + number must be >0. */ +extern char *dwarf2_directive_file PARAMS ((int dummy)); + +/* Implements the .loc FILENO LINENO [COLUMN] directive. FILENO is + the file number, LINENO the line number and the (optional) COLUMN + the column of the source code that the following instruction + corresponds to. FILENO can be 0 to indicate that the filename + specified by the textually most recent .file directive should be + used. */ +extern void dwarf2_directive_loc PARAMS ((int dummy)); + +/* Returns the current source information. If .file directives have + been encountered, the info for the corresponding source file is + returned. Otherwise, the info for the assembly source file is + returned. */ +extern void dwarf2_where PARAMS ((struct dwarf2_line_info *l)); + +/* This function generates .debug_line info based on the address and + source information passed in the arguments. ADDR should be the + frag-relative offset of the instruction the information is for and + L is the source information that should be associated with that + address. */ +extern void dwarf2_gen_line_info PARAMS ((addressT addr, + struct dwarf2_line_info *l)); + +/* Must be called for each generated instruction. */ +extern void dwarf2_emit_insn PARAMS ((int)); + +extern void dwarf2_finish PARAMS ((void)); + +extern int dwarf2dbg_estimate_size_before_relax PARAMS ((fragS *)); +extern int dwarf2dbg_relax_frag PARAMS ((fragS *)); +extern void dwarf2dbg_convert_frag PARAMS ((fragS *)); + +/* An enumeration which describes the sizes of offsets (to DWARF sections) + and the mechanism by which the size is indicated. */ +enum dwarf2_format { + /* 32-bit format: the initial length field is 4 bytes long. */ + dwarf2_format_32bit, + /* DWARF3 64-bit format: the representation of the initial length + (of a DWARF section) is 0xffffffff (4 bytes) followed by eight + bytes indicating the actual length. */ + dwarf2_format_64bit, + /* SGI extension to DWARF2: The initial length is eight bytes. */ + dwarf2_format_64bit_irix +}; + +#endif /* AS_DWARF2DBG_H */ diff --git a/contrib/binutils-2.14/gas/ecoff.c b/contrib/binutils-2.14/gas/ecoff.c new file mode 100644 index 0000000000..40b129b877 --- /dev/null +++ b/contrib/binutils-2.14/gas/ecoff.c @@ -0,0 +1,5292 @@ +/* ECOFF debugging support. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + Contributed by Cygnus Support. + This file was put together by Ian Lance Taylor . A + good deal of it comes directly from mips-tfile.c, by Michael + Meissner . + + This file is part of GAS. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" + +/* This file is compiled conditionally for those targets which use + ECOFF debugging information (e.g., MIPS ECOFF, MIPS ELF, Alpha + ECOFF). */ + +#include "ecoff.h" + +#ifdef ECOFF_DEBUGGING + +#include "coff/internal.h" +#include "coff/symconst.h" +#include "aout/stab_gnu.h" + +#include "safe-ctype.h" + +/* Why isn't this in coff/sym.h? */ +#define ST_RFDESCAPE 0xfff + +/* This file constructs the information used by the ECOFF debugging + format. It just builds a large block of data. + + We support both ECOFF style debugging and stabs debugging (the + stabs symbols are encapsulated in ECOFF symbols). This should let + us handle anything the compiler might throw at us. */ + +/* Here is a brief description of the MIPS ECOFF symbol table, by + Michael Meissner. The MIPS symbol table has the following pieces: + + Symbolic Header + | + +-- Auxiliary Symbols + | + +-- Dense number table + | + +-- Optimizer Symbols + | + +-- External Strings + | + +-- External Symbols + | + +-- Relative file descriptors + | + +-- File table + | + +-- Procedure table + | + +-- Line number table + | + +-- Local Strings + | + +-- Local Symbols + + The symbolic header points to each of the other tables, and also + contains the number of entries. It also contains a magic number + and MIPS compiler version number, such as 2.0. + + The auxiliary table is a series of 32 bit integers, that are + referenced as needed from the local symbol table. Unlike standard + COFF, the aux. information does not follow the symbol that uses + it, but rather is a separate table. In theory, this would allow + the MIPS compilers to collapse duplicate aux. entries, but I've not + noticed this happening with the 1.31 compiler suite. The different + types of aux. entries are: + + 1) dnLow: Low bound on array dimension. + + 2) dnHigh: High bound on array dimension. + + 3) isym: Index to the local symbol which is the start of the + function for the end of function first aux. entry. + + 4) width: Width of structures and bitfields. + + 5) count: Count of ranges for variant part. + + 6) rndx: A relative index into the symbol table. The relative + index field has two parts: rfd which is a pointer into the + relative file index table or ST_RFDESCAPE which says the next + aux. entry is the file number, and index: which is the pointer + into the local symbol within a given file table. This is for + things like references to types defined in another file. + + 7) Type information: This is like the COFF type bits, except it + is 32 bits instead of 16; they still have room to add new + basic types; and they can handle more than 6 levels of array, + pointer, function, etc. Each type information field contains + the following structure members: + + a) fBitfield: a bit that says this is a bitfield, and the + size in bits follows as the next aux. entry. + + b) continued: a bit that says the next aux. entry is a + continuation of the current type information (in case + there are more than 6 levels of array/ptr/function). + + c) bt: an integer containing the base type before adding + array, pointer, function, etc. qualifiers. The + current base types that I have documentation for are: + + btNil -- undefined + btAdr -- address - integer same size as ptr + btChar -- character + btUChar -- unsigned character + btShort -- short + btUShort -- unsigned short + btInt -- int + btUInt -- unsigned int + btLong -- long + btULong -- unsigned long + btFloat -- float (real) + btDouble -- Double (real) + btStruct -- Structure (Record) + btUnion -- Union (variant) + btEnum -- Enumerated + btTypedef -- defined via a typedef isymRef + btRange -- subrange of int + btSet -- pascal sets + btComplex -- fortran complex + btDComplex -- fortran double complex + btIndirect -- forward or unnamed typedef + btFixedDec -- Fixed Decimal + btFloatDec -- Float Decimal + btString -- Varying Length Character String + btBit -- Aligned Bit String + btPicture -- Picture + btVoid -- Void (MIPS cc revision >= 2.00) + + d) tq0 - tq5: type qualifier fields as needed. The + current type qualifier fields I have documentation for + are: + + tqNil -- no more qualifiers + tqPtr -- pointer + tqProc -- procedure + tqArray -- array + tqFar -- 8086 far pointers + tqVol -- volatile + + The dense number table is used in the front ends, and disappears by + the time the .o is created. + + With the 1.31 compiler suite, the optimization symbols don't seem + to be used as far as I can tell. + + The linker is the first entity that creates the relative file + descriptor table, and I believe it is used so that the individual + file table pointers don't have to be rewritten when the objects are + merged together into the program file. + + Unlike COFF, the basic symbol & string tables are split into + external and local symbols/strings. The relocation information + only goes off of the external symbol table, and the debug + information only goes off of the internal symbol table. The + external symbols can have links to an appropriate file index and + symbol within the file to give it the appropriate type information. + Because of this, the external symbols are actually larger than the + internal symbols (to contain the link information), and contain the + local symbol structure as a member, though this member is not the + first member of the external symbol structure (!). I suspect this + split is to make strip easier to deal with. + + Each file table has offsets for where the line numbers, local + strings, local symbols, and procedure table starts from within the + global tables, and the indexs are reset to 0 for each of those + tables for the file. + + The procedure table contains the binary equivalents of the .ent + (start of the function address), .frame (what register is the + virtual frame pointer, constant offset from the register to obtain + the VFP, and what register holds the return address), .mask/.fmask + (bitmask of saved registers, and where the first register is stored + relative to the VFP) assembler directives. It also contains the + low and high bounds of the line numbers if debugging is turned on. + + The line number table is a compressed form of the normal COFF line + table. Each line number entry is either 1 or 3 bytes long, and + contains a signed delta from the previous line, and an unsigned + count of the number of instructions this statement takes. + + The local symbol table contains the following fields: + + 1) iss: index to the local string table giving the name of the + symbol. + + 2) value: value of the symbol (address, register number, etc.). + + 3) st: symbol type. The current symbol types are: + + stNil -- Nuthin' special + stGlobal -- external symbol + stStatic -- static + stParam -- procedure argument + stLocal -- local variable + stLabel -- label + stProc -- External Procedure + stBlock -- beginning of block + stEnd -- end (of anything) + stMember -- member (of anything) + stTypedef -- type definition + stFile -- file name + stRegReloc -- register relocation + stForward -- forwarding address + stStaticProc -- Static procedure + stConstant -- const + + 4) sc: storage class. The current storage classes are: + + scText -- text symbol + scData -- initialized data symbol + scBss -- un-initialized data symbol + scRegister -- value of symbol is register number + scAbs -- value of symbol is absolute + scUndefined -- who knows? + scCdbLocal -- variable's value is IN se->va.?? + scBits -- this is a bit field + scCdbSystem -- value is IN debugger's address space + scRegImage -- register value saved on stack + scInfo -- symbol contains debugger information + scUserStruct -- addr in struct user for current process + scSData -- load time only small data + scSBss -- load time only small common + scRData -- load time only read only data + scVar -- Var parameter (fortranpascal) + scCommon -- common variable + scSCommon -- small common + scVarRegister -- Var parameter in a register + scVariant -- Variant record + scSUndefined -- small undefined(external) data + scInit -- .init section symbol + + 5) index: pointer to a local symbol or aux. entry. + + For the following program: + + #include + + main(){ + printf("Hello World!\n"); + return 0; + } + + Mips-tdump produces the following information: + + Global file header: + magic number 0x162 + # sections 2 + timestamp 645311799, Wed Jun 13 17:16:39 1990 + symbolic header offset 284 + symbolic header size 96 + optional header 56 + flags 0x0 + + Symbolic header, magic number = 0x7009, vstamp = 1.31: + + Info Offset Number Bytes + ==== ====== ====== ===== + + Line numbers 380 4 4 [13] + Dense numbers 0 0 0 + Procedures Tables 384 1 52 + Local Symbols 436 16 192 + Optimization Symbols 0 0 0 + Auxiliary Symbols 628 39 156 + Local Strings 784 80 80 + External Strings 864 144 144 + File Tables 1008 2 144 + Relative Files 0 0 0 + External Symbols 1152 20 320 + + File #0, "hello2.c" + + Name index = 1 Readin = No + Merge = No Endian = LITTLE + Debug level = G2 Language = C + Adr = 0x00000000 + + Info Start Number Size Offset + ==== ===== ====== ==== ====== + Local strings 0 15 15 784 + Local symbols 0 6 72 436 + Line numbers 0 13 13 380 + Optimization symbols 0 0 0 0 + Procedures 0 1 52 384 + Auxiliary symbols 0 14 56 628 + Relative Files 0 0 0 0 + + There are 6 local symbols, starting at 436 + + Symbol# 0: "hello2.c" + End+1 symbol = 6 + String index = 1 + Storage class = Text Index = 6 + Symbol type = File Value = 0 + + Symbol# 1: "main" + End+1 symbol = 5 + Type = int + String index = 10 + Storage class = Text Index = 12 + Symbol type = Proc Value = 0 + + Symbol# 2: "" + End+1 symbol = 4 + String index = 0 + Storage class = Text Index = 4 + Symbol type = Block Value = 8 + + Symbol# 3: "" + First symbol = 2 + String index = 0 + Storage class = Text Index = 2 + Symbol type = End Value = 28 + + Symbol# 4: "main" + First symbol = 1 + String index = 10 + Storage class = Text Index = 1 + Symbol type = End Value = 52 + + Symbol# 5: "hello2.c" + First symbol = 0 + String index = 1 + Storage class = Text Index = 0 + Symbol type = End Value = 0 + + There are 14 auxiliary table entries, starting at 628. + + * #0 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #1 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + * #2 8, [ 8/ 0], [ 2 0:0 0:0:0:0:0:0] + * #3 16, [ 16/ 0], [ 4 0:0 0:0:0:0:0:0] + * #4 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + * #5 32, [ 32/ 0], [ 8 0:0 0:0:0:0:0:0] + * #6 40, [ 40/ 0], [10 0:0 0:0:0:0:0:0] + * #7 44, [ 44/ 0], [11 0:0 0:0:0:0:0:0] + * #8 12, [ 12/ 0], [ 3 0:0 0:0:0:0:0:0] + * #9 20, [ 20/ 0], [ 5 0:0 0:0:0:0:0:0] + * #10 28, [ 28/ 0], [ 7 0:0 0:0:0:0:0:0] + * #11 36, [ 36/ 0], [ 9 0:0 0:0:0:0:0:0] + #12 5, [ 5/ 0], [ 1 1:0 0:0:0:0:0:0] + #13 24, [ 24/ 0], [ 6 0:0 0:0:0:0:0:0] + + There are 1 procedure descriptor entries, starting at 0. + + Procedure descriptor 0: + Name index = 10 Name = "main" + .mask 0x80000000,-4 .fmask 0x00000000,0 + .frame $29,24,$31 + Opt. start = -1 Symbols start = 1 + First line # = 3 Last line # = 6 + Line Offset = 0 Address = 0x00000000 + + There are 4 bytes holding line numbers, starting at 380. + Line 3, delta 0, count 2 + Line 4, delta 1, count 3 + Line 5, delta 1, count 2 + Line 6, delta 1, count 6 + + File #1, "/usr/include/stdio.h" + + Name index = 1 Readin = No + Merge = Yes Endian = LITTLE + Debug level = G2 Language = C + Adr = 0x00000000 + + Info Start Number Size Offset + ==== ===== ====== ==== ====== + Local strings 15 65 65 799 + Local symbols 6 10 120 508 + Line numbers 0 0 0 380 + Optimization symbols 0 0 0 0 + Procedures 1 0 0 436 + Auxiliary symbols 14 25 100 684 + Relative Files 0 0 0 0 + + There are 10 local symbols, starting at 442 + + Symbol# 0: "/usr/include/stdio.h" + End+1 symbol = 10 + String index = 1 + Storage class = Text Index = 10 + Symbol type = File Value = 0 + + Symbol# 1: "_iobuf" + End+1 symbol = 9 + String index = 22 + Storage class = Info Index = 9 + Symbol type = Block Value = 20 + + Symbol# 2: "_cnt" + Type = int + String index = 29 + Storage class = Info Index = 4 + Symbol type = Member Value = 0 + + Symbol# 3: "_ptr" + Type = ptr to char + String index = 34 + Storage class = Info Index = 15 + Symbol type = Member Value = 32 + + Symbol# 4: "_base" + Type = ptr to char + String index = 39 + Storage class = Info Index = 16 + Symbol type = Member Value = 64 + + Symbol# 5: "_bufsiz" + Type = int + String index = 45 + Storage class = Info Index = 4 + Symbol type = Member Value = 96 + + Symbol# 6: "_flag" + Type = short + String index = 53 + Storage class = Info Index = 3 + Symbol type = Member Value = 128 + + Symbol# 7: "_file" + Type = char + String index = 59 + Storage class = Info Index = 2 + Symbol type = Member Value = 144 + + Symbol# 8: "" + First symbol = 1 + String index = 0 + Storage class = Info Index = 1 + Symbol type = End Value = 0 + + Symbol# 9: "/usr/include/stdio.h" + First symbol = 0 + String index = 1 + Storage class = Text Index = 0 + Symbol type = End Value = 0 + + There are 25 auxiliary table entries, starting at 642. + + * #14 -1, [4095/1048575], [63 1:1 f:f:f:f:f:f] + #15 65544, [ 8/ 16], [ 2 0:0 1:0:0:0:0:0] + #16 65544, [ 8/ 16], [ 2 0:0 1:0:0:0:0:0] + * #17 196656, [ 48/ 48], [12 0:0 3:0:0:0:0:0] + * #18 8191, [4095/ 1], [63 1:1 0:0:0:0:f:1] + * #19 1, [ 1/ 0], [ 0 1:0 0:0:0:0:0:0] + * #20 20479, [4095/ 4], [63 1:1 0:0:0:0:f:4] + * #21 1, [ 1/ 0], [ 0 1:0 0:0:0:0:0:0] + * #22 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #23 2, [ 2/ 0], [ 0 0:1 0:0:0:0:0:0] + * #24 160, [ 160/ 0], [40 0:0 0:0:0:0:0:0] + * #25 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #26 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #27 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #28 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #29 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #30 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #31 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #32 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #33 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #34 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #35 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #36 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #37 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + * #38 0, [ 0/ 0], [ 0 0:0 0:0:0:0:0:0] + + There are 0 procedure descriptor entries, starting at 1. + + There are 20 external symbols, starting at 1152 + + Symbol# 0: "_iob" + Type = array [3 {160}] of struct _iobuf { ifd = 1, index = 1 } + String index = 0 Ifd = 1 + Storage class = Nil Index = 17 + Symbol type = Global Value = 60 + + Symbol# 1: "fopen" + String index = 5 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 2: "fdopen" + String index = 11 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 3: "freopen" + String index = 18 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 4: "popen" + String index = 26 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 5: "tmpfile" + String index = 32 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 6: "ftell" + String index = 40 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 7: "rewind" + String index = 46 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 8: "setbuf" + String index = 53 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 9: "setbuffer" + String index = 60 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 10: "setlinebuf" + String index = 70 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 11: "fgets" + String index = 81 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 12: "gets" + String index = 87 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 13: "ctermid" + String index = 92 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 14: "cuserid" + String index = 100 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 15: "tempnam" + String index = 108 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 16: "tmpnam" + String index = 116 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 17: "sprintf" + String index = 123 Ifd = 1 + Storage class = Nil Index = 1048575 + Symbol type = Proc Value = 0 + + Symbol# 18: "main" + Type = int + String index = 131 Ifd = 0 + Storage class = Text Index = 1 + Symbol type = Proc Value = 0 + + Symbol# 19: "printf" + String index = 136 Ifd = 0 + Storage class = Undefined Index = 1048575 + Symbol type = Proc Value = 0 + + The following auxiliary table entries were unused: + + #0 0 0x00000000 void + #2 8 0x00000008 char + #3 16 0x00000010 short + #4 24 0x00000018 int + #5 32 0x00000020 long + #6 40 0x00000028 float + #7 44 0x0000002c double + #8 12 0x0000000c unsigned char + #9 20 0x00000014 unsigned short + #10 28 0x0000001c unsigned int + #11 36 0x00000024 unsigned long + #14 0 0x00000000 void + #15 24 0x00000018 int + #19 32 0x00000020 long + #20 40 0x00000028 float + #21 44 0x0000002c double + #22 12 0x0000000c unsigned char + #23 20 0x00000014 unsigned short + #24 28 0x0000001c unsigned int + #25 36 0x00000024 unsigned long + #26 48 0x00000030 struct no name { ifd = -1, index = 1048575 } +*/ + +/* Redefinition of of storage classes as an enumeration for better + debugging. */ + +typedef enum sc { + sc_Nil = scNil, /* no storage class */ + sc_Text = scText, /* text symbol */ + sc_Data = scData, /* initialized data symbol */ + sc_Bss = scBss, /* un-initialized data symbol */ + sc_Register = scRegister, /* value of symbol is register number */ + sc_Abs = scAbs, /* value of symbol is absolute */ + sc_Undefined = scUndefined, /* who knows? */ + sc_CdbLocal = scCdbLocal, /* variable's value is IN se->va.?? */ + sc_Bits = scBits, /* this is a bit field */ + sc_CdbSystem = scCdbSystem, /* value is IN CDB's address space */ + sc_RegImage = scRegImage, /* register value saved on stack */ + sc_Info = scInfo, /* symbol contains debugger information */ + sc_UserStruct = scUserStruct, /* addr in struct user for current process */ + sc_SData = scSData, /* load time only small data */ + sc_SBss = scSBss, /* load time only small common */ + sc_RData = scRData, /* load time only read only data */ + sc_Var = scVar, /* Var parameter (fortran,pascal) */ + sc_Common = scCommon, /* common variable */ + sc_SCommon = scSCommon, /* small common */ + sc_VarRegister = scVarRegister, /* Var parameter in a register */ + sc_Variant = scVariant, /* Variant record */ + sc_SUndefined = scSUndefined, /* small undefined(external) data */ + sc_Init = scInit, /* .init section symbol */ + sc_Max = scMax /* Max storage class+1 */ +} sc_t; + +/* Redefinition of symbol type. */ + +typedef enum st { + st_Nil = stNil, /* Nuthin' special */ + st_Global = stGlobal, /* external symbol */ + st_Static = stStatic, /* static */ + st_Param = stParam, /* procedure argument */ + st_Local = stLocal, /* local variable */ + st_Label = stLabel, /* label */ + st_Proc = stProc, /* " " Procedure */ + st_Block = stBlock, /* beginning of block */ + st_End = stEnd, /* end (of anything) */ + st_Member = stMember, /* member (of anything - struct/union/enum */ + st_Typedef = stTypedef, /* type definition */ + st_File = stFile, /* file name */ + st_RegReloc = stRegReloc, /* register relocation */ + st_Forward = stForward, /* forwarding address */ + st_StaticProc = stStaticProc, /* load time only static procs */ + st_Constant = stConstant, /* const */ + st_Str = stStr, /* string */ + st_Number = stNumber, /* pure number (ie. 4 NOR 2+2) */ + st_Expr = stExpr, /* 2+2 vs. 4 */ + st_Type = stType, /* post-coercion SER */ + st_Max = stMax /* max type+1 */ +} st_t; + +/* Redefinition of type qualifiers. */ + +typedef enum tq { + tq_Nil = tqNil, /* bt is what you see */ + tq_Ptr = tqPtr, /* pointer */ + tq_Proc = tqProc, /* procedure */ + tq_Array = tqArray, /* duh */ + tq_Far = tqFar, /* longer addressing - 8086/8 land */ + tq_Vol = tqVol, /* volatile */ + tq_Max = tqMax /* Max type qualifier+1 */ +} tq_t; + +/* Redefinition of basic types. */ + +typedef enum bt { + bt_Nil = btNil, /* undefined */ + bt_Adr = btAdr, /* address - integer same size as pointer */ + bt_Char = btChar, /* character */ + bt_UChar = btUChar, /* unsigned character */ + bt_Short = btShort, /* short */ + bt_UShort = btUShort, /* unsigned short */ + bt_Int = btInt, /* int */ + bt_UInt = btUInt, /* unsigned int */ + bt_Long = btLong, /* long */ + bt_ULong = btULong, /* unsigned long */ + bt_Float = btFloat, /* float (real) */ + bt_Double = btDouble, /* Double (real) */ + bt_Struct = btStruct, /* Structure (Record) */ + bt_Union = btUnion, /* Union (variant) */ + bt_Enum = btEnum, /* Enumerated */ + bt_Typedef = btTypedef, /* defined via a typedef, isymRef points */ + bt_Range = btRange, /* subrange of int */ + bt_Set = btSet, /* pascal sets */ + bt_Complex = btComplex, /* fortran complex */ + bt_DComplex = btDComplex, /* fortran double complex */ + bt_Indirect = btIndirect, /* forward or unnamed typedef */ + bt_FixedDec = btFixedDec, /* Fixed Decimal */ + bt_FloatDec = btFloatDec, /* Float Decimal */ + bt_String = btString, /* Varying Length Character String */ + bt_Bit = btBit, /* Aligned Bit String */ + bt_Picture = btPicture, /* Picture */ + bt_Void = btVoid, /* Void */ + bt_Max = btMax /* Max basic type+1 */ +} bt_t; + +#define N_TQ itqMax + +/* States for whether to hash type or not. */ +typedef enum hash_state { + hash_no = 0, /* Don't hash type */ + hash_yes = 1, /* OK to hash type, or use previous hash */ + hash_record = 2 /* OK to record hash, but don't use prev. */ +} hash_state_t; + +/* Types of different sized allocation requests. */ +enum alloc_type { + alloc_type_none, /* dummy value */ + alloc_type_scope, /* nested scopes linked list */ + alloc_type_vlinks, /* glue linking pages in varray */ + alloc_type_shash, /* string hash element */ + alloc_type_thash, /* type hash element */ + alloc_type_tag, /* struct/union/tag element */ + alloc_type_forward, /* element to hold unknown tag */ + alloc_type_thead, /* head of type hash list */ + alloc_type_varray, /* general varray allocation */ + alloc_type_lineno, /* line number list */ + alloc_type_last /* last+1 element for array bounds */ +}; + +/* Types of auxiliary type information. */ +enum aux_type { + aux_tir, /* TIR type information */ + aux_rndx, /* relative index into symbol table */ + aux_dnLow, /* low dimension */ + aux_dnHigh, /* high dimension */ + aux_isym, /* symbol table index (end of proc) */ + aux_iss, /* index into string space (not used) */ + aux_width, /* width for non-default sized struc fields */ + aux_count /* count of ranges for variant arm */ +}; + +/* Structures to provide n-number of virtual arrays, each of which can + grow linearly, and which are written in the object file as + sequential pages. On systems with a BSD malloc, the + MAX_CLUSTER_PAGES should be 1 less than a power of two, since + malloc adds it's overhead, and rounds up to the next power of 2. + Pages are linked together via a linked list. + + If PAGE_SIZE is > 4096, the string length in the shash_t structure + can't be represented (assuming there are strings > 4096 bytes). */ + +/* FIXME: Yes, there can be such strings while emitting C++ class debug + info. Templates are the offender here, the test case in question + having a mangled class name of + + t7rb_tree4Z4xkeyZt4pair2ZC4xkeyZt7xsocket1Z4UserZt9select1st2Zt4pair\ + 2ZC4xkeyZt7xsocket1Z4UserZ4xkeyZt4less1Z4xkey + + Repeat that a couple dozen times while listing the class members and + you've got strings over 4k. Hack around this for now by increasing + the page size. A proper solution would abandon this structure scheme + certainly for very large strings, and possibly entirely. */ + +#ifndef PAGE_SIZE +#define PAGE_SIZE (8*1024) /* size of varray pages */ +#endif + +#define PAGE_USIZE ((unsigned long) PAGE_SIZE) + +#ifndef MAX_CLUSTER_PAGES /* # pages to get from system */ +#define MAX_CLUSTER_PAGES 63 +#endif + +/* Linked list connecting separate page allocations. */ +typedef struct vlinks { + struct vlinks *prev; /* previous set of pages */ + struct vlinks *next; /* next set of pages */ + union page *datum; /* start of page */ + unsigned long start_index; /* starting index # of page */ +} vlinks_t; + +/* Virtual array header. */ +typedef struct varray { + vlinks_t *first; /* first page link */ + vlinks_t *last; /* last page link */ + unsigned long num_allocated; /* # objects allocated */ + unsigned short object_size; /* size in bytes of each object */ + unsigned short objects_per_page; /* # objects that can fit on a page */ + unsigned short objects_last_page; /* # objects allocated on last page */ +} varray_t; + +#ifndef MALLOC_CHECK +#define OBJECTS_PER_PAGE(type) (PAGE_SIZE / sizeof (type)) +#else +#define OBJECTS_PER_PAGE(type) ((sizeof (type) > 1) ? 1 : PAGE_SIZE) +#endif + +#define INIT_VARRAY(type) { /* macro to initialize a varray */ \ + (vlinks_t *)0, /* first */ \ + (vlinks_t *)0, /* last */ \ + 0, /* num_allocated */ \ + sizeof (type), /* object_size */ \ + OBJECTS_PER_PAGE (type), /* objects_per_page */ \ + OBJECTS_PER_PAGE (type), /* objects_last_page */ \ +} + +/* Master type for indexes within the symbol table. */ +typedef unsigned long symint_t; + +/* Linked list support for nested scopes (file, block, structure, etc.). */ +typedef struct scope { + struct scope *prev; /* previous scope level */ + struct scope *free; /* free list pointer */ + struct localsym *lsym; /* pointer to local symbol node */ + st_t type; /* type of the node */ +} scope_t; + +/* For a local symbol we store a gas symbol as well as the debugging + information we generate. The gas symbol will be NULL if this is + only a debugging symbol. */ +typedef struct localsym { + const char *name; /* symbol name */ + symbolS *as_sym; /* symbol as seen by gas */ + bfd_vma addend; /* addend to as_sym value */ + struct efdr *file_ptr; /* file pointer */ + struct ecoff_proc *proc_ptr; /* proc pointer */ + struct localsym *begin_ptr; /* symbol at start of block */ + struct ecoff_aux *index_ptr; /* index value to be filled in */ + struct forward *forward_ref; /* forward references to this symbol */ + long sym_index; /* final symbol index */ + EXTR ecoff_sym; /* ECOFF debugging symbol */ +} localsym_t; + +/* For aux information we keep the type and the data. */ +typedef struct ecoff_aux { + enum aux_type type; /* aux type */ + AUXU data; /* aux data */ +} aux_t; + +/* For a procedure we store the gas symbol as well as the PDR + debugging information. */ +typedef struct ecoff_proc { + localsym_t *sym; /* associated symbol */ + PDR pdr; /* ECOFF debugging info */ +} proc_t; + +/* Number of proc_t structures allocated. */ +static unsigned long proc_cnt; + +/* Forward reference list for tags referenced, but not yet defined. */ +typedef struct forward { + struct forward *next; /* next forward reference */ + struct forward *free; /* free list pointer */ + aux_t *ifd_ptr; /* pointer to store file index */ + aux_t *index_ptr; /* pointer to store symbol index */ +} forward_t; + +/* Linked list support for tags. The first tag in the list is always + the current tag for that block. */ +typedef struct tag { + struct tag *free; /* free list pointer */ + struct shash *hash_ptr; /* pointer to the hash table head */ + struct tag *same_name; /* tag with same name in outer scope */ + struct tag *same_block; /* next tag defined in the same block. */ + struct forward *forward_ref; /* list of forward references */ + bt_t basic_type; /* bt_Struct, bt_Union, or bt_Enum */ + symint_t ifd; /* file # tag defined in */ + localsym_t *sym; /* file's local symbols */ +} tag_t; + +/* Head of a block's linked list of tags. */ +typedef struct thead { + struct thead *prev; /* previous block */ + struct thead *free; /* free list pointer */ + struct tag *first_tag; /* first tag in block defined */ +} thead_t; + +/* Union containing pointers to each the small structures which are freed up. */ +typedef union small_free { + scope_t *f_scope; /* scope structure */ + thead_t *f_thead; /* tag head structure */ + tag_t *f_tag; /* tag element structure */ + forward_t *f_forward; /* forward tag reference */ +} small_free_t; + +/* String hash table entry. */ + +typedef struct shash { + char *string; /* string we are hashing */ + symint_t indx; /* index within string table */ + EXTR *esym_ptr; /* global symbol pointer */ + localsym_t *sym_ptr; /* local symbol pointer */ + localsym_t *end_ptr; /* symbol pointer to end block */ + tag_t *tag_ptr; /* tag pointer */ + proc_t *proc_ptr; /* procedure descriptor pointer */ +} shash_t; + +/* Type hash table support. The size of the hash table must fit + within a page with the other extended file descriptor information. + Because unique types which are hashed are fewer in number than + strings, we use a smaller hash value. */ + +#define HASHBITS 30 + +#ifndef THASH_SIZE +#define THASH_SIZE 113 +#endif + +typedef struct thash { + struct thash *next; /* next hash value */ + AUXU type; /* type we are hashing */ + symint_t indx; /* index within string table */ +} thash_t; + +/* Extended file descriptor that contains all of the support necessary + to add things to each file separately. */ +typedef struct efdr { + FDR fdr; /* File header to be written out */ + FDR *orig_fdr; /* original file header */ + char *name; /* filename */ + int fake; /* whether this is faked .file */ + symint_t void_type; /* aux. pointer to 'void' type */ + symint_t int_type; /* aux. pointer to 'int' type */ + scope_t *cur_scope; /* current nested scopes */ + symint_t file_index; /* current file number */ + int nested_scopes; /* # nested scopes */ + varray_t strings; /* local strings */ + varray_t symbols; /* local symbols */ + varray_t procs; /* procedures */ + varray_t aux_syms; /* auxiliary symbols */ + struct efdr *next_file; /* next file descriptor */ + /* string/type hash tables */ + struct hash_control *str_hash; /* string hash table */ + thash_t *thash_head[THASH_SIZE]; +} efdr_t; + +/* Pre-initialized extended file structure. */ +static const efdr_t init_file = { + { /* FDR structure */ + 0, /* adr: memory address of beginning of file */ + 0, /* rss: file name (of source, if known) */ + 0, /* issBase: file's string space */ + 0, /* cbSs: number of bytes in the ss */ + 0, /* isymBase: beginning of symbols */ + 0, /* csym: count file's of symbols */ + 0, /* ilineBase: file's line symbols */ + 0, /* cline: count of file's line symbols */ + 0, /* ioptBase: file's optimization entries */ + 0, /* copt: count of file's optimization entries */ + 0, /* ipdFirst: start of procedures for this file */ + 0, /* cpd: count of procedures for this file */ + 0, /* iauxBase: file's auxiliary entries */ + 0, /* caux: count of file's auxiliary entries */ + 0, /* rfdBase: index into the file indirect table */ + 0, /* crfd: count file indirect entries */ + langC, /* lang: language for this file */ + 1, /* fMerge: whether this file can be merged */ + 0, /* fReadin: true if read in (not just created) */ + TARGET_BYTES_BIG_ENDIAN, /* fBigendian: if 1, compiled on big endian machine */ + GLEVEL_2, /* glevel: level this file was compiled with */ + 0, /* reserved: reserved for future use */ + 0, /* cbLineOffset: byte offset from header for this file ln's */ + 0, /* cbLine: size of lines for this file */ + }, + + (FDR *)0, /* orig_fdr: original file header pointer */ + (char *)0, /* name: pointer to filename */ + 0, /* fake: whether this is a faked .file */ + 0, /* void_type: ptr to aux node for void type */ + 0, /* int_type: ptr to aux node for int type */ + (scope_t *)0, /* cur_scope: current scope being processed */ + 0, /* file_index: current file # */ + 0, /* nested_scopes: # nested scopes */ + INIT_VARRAY (char), /* strings: local string varray */ + INIT_VARRAY (localsym_t), /* symbols: local symbols varray */ + INIT_VARRAY (proc_t), /* procs: procedure varray */ + INIT_VARRAY (aux_t), /* aux_syms: auxiliary symbols varray */ + + (struct efdr *)0, /* next_file: next file structure */ + + (struct hash_control *)0, /* str_hash: string hash table */ + { 0 }, /* thash_head: type hash table */ +}; + +static efdr_t *first_file; /* first file descriptor */ +static efdr_t **last_file_ptr = &first_file; /* file descriptor tail */ + +/* Line number information is kept in a list until the assembly is + finished. */ +typedef struct lineno_list { + struct lineno_list *next; /* next element in list */ + efdr_t *file; /* file this line is in */ + proc_t *proc; /* procedure this line is in */ + fragS *frag; /* fragment this line number is in */ + unsigned long paddr; /* offset within fragment */ + long lineno; /* actual line number */ +} lineno_list_t; + +static lineno_list_t *first_lineno; +static lineno_list_t *last_lineno; +static lineno_list_t **last_lineno_ptr = &first_lineno; + +/* Sometimes there will be some .loc statements before a .ent. We + keep them in this list so that we can fill in the procedure pointer + after we see the .ent. */ +static lineno_list_t *noproc_lineno; + +/* Union of various things that are held in pages. */ +typedef union page { + char byte [ PAGE_SIZE ]; + unsigned char ubyte [ PAGE_SIZE ]; + efdr_t file [ PAGE_SIZE / sizeof (efdr_t) ]; + FDR ofile [ PAGE_SIZE / sizeof (FDR) ]; + proc_t proc [ PAGE_SIZE / sizeof (proc_t) ]; + localsym_t sym [ PAGE_SIZE / sizeof (localsym_t) ]; + aux_t aux [ PAGE_SIZE / sizeof (aux_t) ]; + DNR dense [ PAGE_SIZE / sizeof (DNR) ]; + scope_t scope [ PAGE_SIZE / sizeof (scope_t) ]; + vlinks_t vlinks [ PAGE_SIZE / sizeof (vlinks_t) ]; + shash_t shash [ PAGE_SIZE / sizeof (shash_t) ]; + thash_t thash [ PAGE_SIZE / sizeof (thash_t) ]; + tag_t tag [ PAGE_SIZE / sizeof (tag_t) ]; + forward_t forward [ PAGE_SIZE / sizeof (forward_t) ]; + thead_t thead [ PAGE_SIZE / sizeof (thead_t) ]; + lineno_list_t lineno [ PAGE_SIZE / sizeof (lineno_list_t) ]; +} page_type; + +/* Structure holding allocation information for small sized structures. */ +typedef struct alloc_info { + char *alloc_name; /* name of this allocation type (must be first) */ + page_type *cur_page; /* current page being allocated from */ + small_free_t free_list; /* current free list if any */ + int unallocated; /* number of elements unallocated on page */ + int total_alloc; /* total number of allocations */ + int total_free; /* total number of frees */ + int total_pages; /* total number of pages allocated */ +} alloc_info_t; + +/* Type information collected together. */ +typedef struct type_info { + bt_t basic_type; /* basic type */ + int orig_type; /* original COFF-based type */ + int num_tq; /* # type qualifiers */ + int num_dims; /* # dimensions */ + int num_sizes; /* # sizes */ + int extra_sizes; /* # extra sizes not tied with dims */ + tag_t * tag_ptr; /* tag pointer */ + int bitfield; /* symbol is a bitfield */ + tq_t type_qualifiers[N_TQ]; /* type qualifiers (ptr, func, array)*/ + symint_t dimensions [N_TQ]; /* dimensions for each array */ + symint_t sizes [N_TQ+2]; /* sizes of each array slice + size of + struct/union/enum + bitfield size */ +} type_info_t; + +/* Pre-initialized type_info struct. */ +static const type_info_t type_info_init = { + bt_Nil, /* basic type */ + T_NULL, /* original COFF-based type */ + 0, /* # type qualifiers */ + 0, /* # dimensions */ + 0, /* # sizes */ + 0, /* sizes not tied with dims */ + NULL, /* ptr to tag */ + 0, /* bitfield */ + { /* type qualifiers */ + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + tq_Nil, + }, + { /* dimensions */ + 0, + 0, + 0, + 0, + 0, + 0 + }, + { /* sizes */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + }, +}; + +/* Global hash table for the tags table and global table for file + descriptors. */ + +static varray_t file_desc = INIT_VARRAY (efdr_t); + +static struct hash_control *tag_hash; + +/* Static types for int and void. Also, remember the last function's + type (which is set up when we encounter the declaration for the + function, and used when the end block for the function is emitted. */ + +static type_info_t int_type_info; +static type_info_t void_type_info; +static type_info_t last_func_type_info; +static symbolS *last_func_sym_value; + +/* Convert COFF basic type to ECOFF basic type. The T_NULL type + really should use bt_Void, but this causes the current ecoff GDB to + issue unsupported type messages, and the Ultrix 4.00 dbx (aka MIPS + 2.0) doesn't understand it, even though the compiler generates it. + Maybe this will be fixed in 2.10 or 2.20 of the MIPS compiler + suite, but for now go with what works. + + It would make sense for the .type and .scl directives to use the + ECOFF numbers directly, rather than using the COFF numbers and + mapping them. Unfortunately, this is historically what mips-tfile + expects, and changing gcc now would be a considerable pain (the + native compiler generates debugging information internally, rather + than via the assembler, so it will never use .type or .scl). */ + +static const bt_t map_coff_types[] = { + bt_Nil, /* T_NULL */ + bt_Nil, /* T_ARG */ + bt_Char, /* T_CHAR */ + bt_Short, /* T_SHORT */ + bt_Int, /* T_INT */ + bt_Long, /* T_LONG */ + bt_Float, /* T_FLOAT */ + bt_Double, /* T_DOUBLE */ + bt_Struct, /* T_STRUCT */ + bt_Union, /* T_UNION */ + bt_Enum, /* T_ENUM */ + bt_Enum, /* T_MOE */ + bt_UChar, /* T_UCHAR */ + bt_UShort, /* T_USHORT */ + bt_UInt, /* T_UINT */ + bt_ULong /* T_ULONG */ +}; + +/* Convert COFF storage class to ECOFF storage class. */ +static const sc_t map_coff_storage[] = { + sc_Nil, /* 0: C_NULL */ + sc_Abs, /* 1: C_AUTO auto var */ + sc_Undefined, /* 2: C_EXT external */ + sc_Data, /* 3: C_STAT static */ + sc_Register, /* 4: C_REG register */ + sc_Undefined, /* 5: C_EXTDEF ??? */ + sc_Text, /* 6: C_LABEL label */ + sc_Text, /* 7: C_ULABEL user label */ + sc_Info, /* 8: C_MOS member of struct */ + sc_Abs, /* 9: C_ARG argument */ + sc_Info, /* 10: C_STRTAG struct tag */ + sc_Info, /* 11: C_MOU member of union */ + sc_Info, /* 12: C_UNTAG union tag */ + sc_Info, /* 13: C_TPDEF typedef */ + sc_Data, /* 14: C_USTATIC ??? */ + sc_Info, /* 15: C_ENTAG enum tag */ + sc_Info, /* 16: C_MOE member of enum */ + sc_Register, /* 17: C_REGPARM register parameter */ + sc_Bits, /* 18; C_FIELD bitfield */ + sc_Nil, /* 19 */ + sc_Nil, /* 20 */ + sc_Nil, /* 21 */ + sc_Nil, /* 22 */ + sc_Nil, /* 23 */ + sc_Nil, /* 24 */ + sc_Nil, /* 25 */ + sc_Nil, /* 26 */ + sc_Nil, /* 27 */ + sc_Nil, /* 28 */ + sc_Nil, /* 29 */ + sc_Nil, /* 30 */ + sc_Nil, /* 31 */ + sc_Nil, /* 32 */ + sc_Nil, /* 33 */ + sc_Nil, /* 34 */ + sc_Nil, /* 35 */ + sc_Nil, /* 36 */ + sc_Nil, /* 37 */ + sc_Nil, /* 38 */ + sc_Nil, /* 39 */ + sc_Nil, /* 40 */ + sc_Nil, /* 41 */ + sc_Nil, /* 42 */ + sc_Nil, /* 43 */ + sc_Nil, /* 44 */ + sc_Nil, /* 45 */ + sc_Nil, /* 46 */ + sc_Nil, /* 47 */ + sc_Nil, /* 48 */ + sc_Nil, /* 49 */ + sc_Nil, /* 50 */ + sc_Nil, /* 51 */ + sc_Nil, /* 52 */ + sc_Nil, /* 53 */ + sc_Nil, /* 54 */ + sc_Nil, /* 55 */ + sc_Nil, /* 56 */ + sc_Nil, /* 57 */ + sc_Nil, /* 58 */ + sc_Nil, /* 59 */ + sc_Nil, /* 60 */ + sc_Nil, /* 61 */ + sc_Nil, /* 62 */ + sc_Nil, /* 63 */ + sc_Nil, /* 64 */ + sc_Nil, /* 65 */ + sc_Nil, /* 66 */ + sc_Nil, /* 67 */ + sc_Nil, /* 68 */ + sc_Nil, /* 69 */ + sc_Nil, /* 70 */ + sc_Nil, /* 71 */ + sc_Nil, /* 72 */ + sc_Nil, /* 73 */ + sc_Nil, /* 74 */ + sc_Nil, /* 75 */ + sc_Nil, /* 76 */ + sc_Nil, /* 77 */ + sc_Nil, /* 78 */ + sc_Nil, /* 79 */ + sc_Nil, /* 80 */ + sc_Nil, /* 81 */ + sc_Nil, /* 82 */ + sc_Nil, /* 83 */ + sc_Nil, /* 84 */ + sc_Nil, /* 85 */ + sc_Nil, /* 86 */ + sc_Nil, /* 87 */ + sc_Nil, /* 88 */ + sc_Nil, /* 89 */ + sc_Nil, /* 90 */ + sc_Nil, /* 91 */ + sc_Nil, /* 92 */ + sc_Nil, /* 93 */ + sc_Nil, /* 94 */ + sc_Nil, /* 95 */ + sc_Nil, /* 96 */ + sc_Nil, /* 97 */ + sc_Nil, /* 98 */ + sc_Nil, /* 99 */ + sc_Text, /* 100: C_BLOCK block start/end */ + sc_Text, /* 101: C_FCN function start/end */ + sc_Info, /* 102: C_EOS end of struct/union/enum */ + sc_Nil, /* 103: C_FILE file start */ + sc_Nil, /* 104: C_LINE line number */ + sc_Nil, /* 105: C_ALIAS combined type info */ + sc_Nil, /* 106: C_HIDDEN ??? */ +}; + +/* Convert COFF storage class to ECOFF symbol type. */ +static const st_t map_coff_sym_type[] = { + st_Nil, /* 0: C_NULL */ + st_Local, /* 1: C_AUTO auto var */ + st_Global, /* 2: C_EXT external */ + st_Static, /* 3: C_STAT static */ + st_Local, /* 4: C_REG register */ + st_Global, /* 5: C_EXTDEF ??? */ + st_Label, /* 6: C_LABEL label */ + st_Label, /* 7: C_ULABEL user label */ + st_Member, /* 8: C_MOS member of struct */ + st_Param, /* 9: C_ARG argument */ + st_Block, /* 10: C_STRTAG struct tag */ + st_Member, /* 11: C_MOU member of union */ + st_Block, /* 12: C_UNTAG union tag */ + st_Typedef, /* 13: C_TPDEF typedef */ + st_Static, /* 14: C_USTATIC ??? */ + st_Block, /* 15: C_ENTAG enum tag */ + st_Member, /* 16: C_MOE member of enum */ + st_Param, /* 17: C_REGPARM register parameter */ + st_Member, /* 18; C_FIELD bitfield */ + st_Nil, /* 19 */ + st_Nil, /* 20 */ + st_Nil, /* 21 */ + st_Nil, /* 22 */ + st_Nil, /* 23 */ + st_Nil, /* 24 */ + st_Nil, /* 25 */ + st_Nil, /* 26 */ + st_Nil, /* 27 */ + st_Nil, /* 28 */ + st_Nil, /* 29 */ + st_Nil, /* 30 */ + st_Nil, /* 31 */ + st_Nil, /* 32 */ + st_Nil, /* 33 */ + st_Nil, /* 34 */ + st_Nil, /* 35 */ + st_Nil, /* 36 */ + st_Nil, /* 37 */ + st_Nil, /* 38 */ + st_Nil, /* 39 */ + st_Nil, /* 40 */ + st_Nil, /* 41 */ + st_Nil, /* 42 */ + st_Nil, /* 43 */ + st_Nil, /* 44 */ + st_Nil, /* 45 */ + st_Nil, /* 46 */ + st_Nil, /* 47 */ + st_Nil, /* 48 */ + st_Nil, /* 49 */ + st_Nil, /* 50 */ + st_Nil, /* 51 */ + st_Nil, /* 52 */ + st_Nil, /* 53 */ + st_Nil, /* 54 */ + st_Nil, /* 55 */ + st_Nil, /* 56 */ + st_Nil, /* 57 */ + st_Nil, /* 58 */ + st_Nil, /* 59 */ + st_Nil, /* 60 */ + st_Nil, /* 61 */ + st_Nil, /* 62 */ + st_Nil, /* 63 */ + st_Nil, /* 64 */ + st_Nil, /* 65 */ + st_Nil, /* 66 */ + st_Nil, /* 67 */ + st_Nil, /* 68 */ + st_Nil, /* 69 */ + st_Nil, /* 70 */ + st_Nil, /* 71 */ + st_Nil, /* 72 */ + st_Nil, /* 73 */ + st_Nil, /* 74 */ + st_Nil, /* 75 */ + st_Nil, /* 76 */ + st_Nil, /* 77 */ + st_Nil, /* 78 */ + st_Nil, /* 79 */ + st_Nil, /* 80 */ + st_Nil, /* 81 */ + st_Nil, /* 82 */ + st_Nil, /* 83 */ + st_Nil, /* 84 */ + st_Nil, /* 85 */ + st_Nil, /* 86 */ + st_Nil, /* 87 */ + st_Nil, /* 88 */ + st_Nil, /* 89 */ + st_Nil, /* 90 */ + st_Nil, /* 91 */ + st_Nil, /* 92 */ + st_Nil, /* 93 */ + st_Nil, /* 94 */ + st_Nil, /* 95 */ + st_Nil, /* 96 */ + st_Nil, /* 97 */ + st_Nil, /* 98 */ + st_Nil, /* 99 */ + st_Block, /* 100: C_BLOCK block start/end */ + st_Proc, /* 101: C_FCN function start/end */ + st_End, /* 102: C_EOS end of struct/union/enum */ + st_File, /* 103: C_FILE file start */ + st_Nil, /* 104: C_LINE line number */ + st_Nil, /* 105: C_ALIAS combined type info */ + st_Nil, /* 106: C_HIDDEN ??? */ +}; + +/* Keep track of different sized allocation requests. */ +static alloc_info_t alloc_counts[(int) alloc_type_last]; + +/* Record whether we have seen any debugging information. */ +int ecoff_debugging_seen = 0; + +/* Various statics. */ +static efdr_t *cur_file_ptr = (efdr_t *) 0; /* current file desc. header */ +static proc_t *cur_proc_ptr = (proc_t *) 0; /* current procedure header */ +static proc_t *first_proc_ptr = (proc_t *) 0; /* first procedure header */ +static thead_t *top_tag_head = (thead_t *) 0; /* top level tag head */ +static thead_t *cur_tag_head = (thead_t *) 0; /* current tag head */ +#ifdef ECOFF_DEBUG +static int debug = 0; /* trace functions */ +#endif +static int stabs_seen = 0; /* != 0 if stabs have been seen */ + +static int current_file_idx; +static const char *current_stabs_filename; + +/* Pseudo symbol to use when putting stabs into the symbol table. */ +#ifndef STABS_SYMBOL +#define STABS_SYMBOL "@stabs" +#endif + +static char stabs_symbol[] = STABS_SYMBOL; + +/* Prototypes for functions defined in this file. */ + +static void add_varray_page PARAMS ((varray_t *vp)); +static symint_t add_string PARAMS ((varray_t *vp, + struct hash_control *hash_tbl, + const char *str, + shash_t **ret_hash)); +static localsym_t *add_ecoff_symbol PARAMS ((const char *str, st_t type, + sc_t storage, symbolS *sym, + bfd_vma addend, symint_t value, + symint_t indx)); +static symint_t add_aux_sym_symint PARAMS ((symint_t aux_word)); +static symint_t add_aux_sym_rndx PARAMS ((int file_index, + symint_t sym_index)); +static symint_t add_aux_sym_tir PARAMS ((type_info_t *t, + hash_state_t state, + thash_t **hash_tbl)); +static tag_t *get_tag PARAMS ((const char *tag, localsym_t *sym, + bt_t basic_type)); +static void add_unknown_tag PARAMS ((tag_t *ptag)); +static void add_procedure PARAMS ((char *func)); +static void add_file PARAMS ((const char *file_name, int indx, int fake)); +#ifdef ECOFF_DEBUG +static char *sc_to_string PARAMS ((sc_t storage_class)); +static char *st_to_string PARAMS ((st_t symbol_type)); +#endif +static void mark_stabs PARAMS ((int)); +static char *ecoff_add_bytes PARAMS ((char **buf, char **bufend, + char *bufptr, unsigned long need)); +static unsigned long ecoff_padding_adjust + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset, char **bufptrptr)); +static unsigned long ecoff_build_lineno + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset, long *linecntptr)); +static unsigned long ecoff_build_symbols + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static unsigned long ecoff_build_procs + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static unsigned long ecoff_build_aux + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static unsigned long ecoff_build_strings PARAMS ((char **buf, char **bufend, + unsigned long offset, + varray_t *vp)); +static unsigned long ecoff_build_ss + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static unsigned long ecoff_build_fdr + PARAMS ((const struct ecoff_debug_swap *backend, char **buf, char **bufend, + unsigned long offset)); +static void ecoff_setup_ext PARAMS ((void)); +static page_type *allocate_cluster PARAMS ((unsigned long npages)); +static page_type *allocate_page PARAMS ((void)); +static scope_t *allocate_scope PARAMS ((void)); +static void free_scope PARAMS ((scope_t *ptr)); +static vlinks_t *allocate_vlinks PARAMS ((void)); +static shash_t *allocate_shash PARAMS ((void)); +static thash_t *allocate_thash PARAMS ((void)); +static tag_t *allocate_tag PARAMS ((void)); +static void free_tag PARAMS ((tag_t *ptr)); +static forward_t *allocate_forward PARAMS ((void)); +static thead_t *allocate_thead PARAMS ((void)); +static void free_thead PARAMS ((thead_t *ptr)); +static lineno_list_t *allocate_lineno_list PARAMS ((void)); + +/* This function should be called when the assembler starts up. */ + +void +ecoff_read_begin_hook () +{ + tag_hash = hash_new (); + top_tag_head = allocate_thead (); + top_tag_head->first_tag = (tag_t *) NULL; + top_tag_head->free = (thead_t *) NULL; + top_tag_head->prev = cur_tag_head; + cur_tag_head = top_tag_head; +} + +/* This function should be called when a symbol is created. */ + +void +ecoff_symbol_new_hook (symbolP) + symbolS *symbolP; +{ + OBJ_SYMFIELD_TYPE *obj; + + /* Make sure that we have a file pointer, but only if we have seen a + file. If we haven't seen a file, then this is a probably special + symbol created by md_begin which may required special handling at + some point. Creating a dummy file with a dummy name is certainly + wrong. */ + if (cur_file_ptr == (efdr_t *) NULL + && seen_at_least_1_file ()) + add_file ((const char *) NULL, 0, 1); + obj = symbol_get_obj (symbolP); + obj->ecoff_file = cur_file_ptr; + obj->ecoff_symbol = NULL; + obj->ecoff_extern_size = 0; +} + +/* Add a page to a varray object. */ + +static void +add_varray_page (vp) + varray_t *vp; /* varray to add page to */ +{ + vlinks_t *new_links = allocate_vlinks (); + +#ifdef MALLOC_CHECK + if (vp->object_size > 1) + new_links->datum = (page_type *) xcalloc (1, vp->object_size); + else +#endif + new_links->datum = allocate_page (); + + alloc_counts[(int) alloc_type_varray].total_alloc++; + alloc_counts[(int) alloc_type_varray].total_pages++; + + new_links->start_index = vp->num_allocated; + vp->objects_last_page = 0; + + if (vp->first == (vlinks_t *) NULL) /* first allocation? */ + vp->first = vp->last = new_links; + else + { /* 2nd or greater allocation */ + new_links->prev = vp->last; + vp->last->next = new_links; + vp->last = new_links; + } +} + +/* Add a string (and null pad) to one of the string tables. */ + +static symint_t +add_string (vp, hash_tbl, str, ret_hash) + varray_t *vp; /* string obstack */ + struct hash_control *hash_tbl; /* ptr to hash table */ + const char *str; /* string */ + shash_t **ret_hash; /* return hash pointer */ +{ + register unsigned long len = strlen (str); + register shash_t *hash_ptr; + + if (len >= PAGE_USIZE) + as_fatal (_("string too big (%lu bytes)"), len); + + hash_ptr = (shash_t *) hash_find (hash_tbl, str); + if (hash_ptr == (shash_t *) NULL) + { + register const char *err; + + if (vp->objects_last_page + len >= PAGE_USIZE) + { + vp->num_allocated = + ((vp->num_allocated + PAGE_USIZE - 1) / PAGE_USIZE) * PAGE_USIZE; + add_varray_page (vp); + } + + hash_ptr = allocate_shash (); + hash_ptr->indx = vp->num_allocated; + + hash_ptr->string = &vp->last->datum->byte[vp->objects_last_page]; + + vp->objects_last_page += len + 1; + vp->num_allocated += len + 1; + + strcpy (hash_ptr->string, str); + + err = hash_insert (hash_tbl, str, (char *) hash_ptr); + if (err) + as_fatal (_("inserting \"%s\" into string hash table: %s"), + str, err); + } + + if (ret_hash != (shash_t **) NULL) + *ret_hash = hash_ptr; + + return hash_ptr->indx; +} + +/* Add debugging information for a symbol. */ + +static localsym_t * +add_ecoff_symbol (str, type, storage, sym_value, addend, value, indx) + const char *str; /* symbol name */ + st_t type; /* symbol type */ + sc_t storage; /* storage class */ + symbolS *sym_value; /* associated symbol. */ + bfd_vma addend; /* addend to sym_value. */ + symint_t value; /* value of symbol */ + symint_t indx; /* index to local/aux. syms */ +{ + localsym_t *psym; + register scope_t *pscope; + register thead_t *ptag_head; + register tag_t *ptag; + register tag_t *ptag_next; + register varray_t *vp; + register int scope_delta = 0; + shash_t *hash_ptr = (shash_t *) NULL; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal (_("no current file pointer")); + + vp = &cur_file_ptr->symbols; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + psym = &vp->last->datum->sym[vp->objects_last_page++]; + + if (str == (const char *) NULL && sym_value != (symbolS *) NULL) + psym->name = S_GET_NAME (sym_value); + else + psym->name = str; + psym->as_sym = sym_value; + if (sym_value != (symbolS *) NULL) + symbol_get_obj (sym_value)->ecoff_symbol = psym; + psym->addend = addend; + psym->file_ptr = cur_file_ptr; + psym->proc_ptr = cur_proc_ptr; + psym->begin_ptr = (localsym_t *) NULL; + psym->index_ptr = (aux_t *) NULL; + psym->forward_ref = (forward_t *) NULL; + psym->sym_index = -1; + memset (&psym->ecoff_sym, 0, sizeof (EXTR)); + psym->ecoff_sym.asym.value = value; + psym->ecoff_sym.asym.st = (unsigned) type; + psym->ecoff_sym.asym.sc = (unsigned) storage; + psym->ecoff_sym.asym.index = indx; + + /* If there is an associated symbol, we wait until the end of the + assembly before deciding where to put the name (it may be just an + external symbol). Otherwise, this is just a debugging symbol and + the name should go with the current file. */ + if (sym_value == (symbolS *) NULL) + psym->ecoff_sym.asym.iss = ((str == (const char *) NULL) + ? 0 + : add_string (&cur_file_ptr->strings, + cur_file_ptr->str_hash, + str, + &hash_ptr)); + + ++vp->num_allocated; + + if (ECOFF_IS_STAB (&psym->ecoff_sym.asym)) + return psym; + + /* Save the symbol within the hash table if this is a static + item, and it has a name. */ + if (hash_ptr != (shash_t *) NULL + && (type == st_Global || type == st_Static || type == st_Label + || type == st_Proc || type == st_StaticProc)) + hash_ptr->sym_ptr = psym; + + /* push or pop a scope if appropriate. */ + switch (type) + { + default: + break; + + case st_File: /* beginning of file */ + case st_Proc: /* procedure */ + case st_StaticProc: /* static procedure */ + case st_Block: /* begin scope */ + pscope = allocate_scope (); + pscope->prev = cur_file_ptr->cur_scope; + pscope->lsym = psym; + pscope->type = type; + cur_file_ptr->cur_scope = pscope; + + if (type != st_File) + scope_delta = 1; + + /* For every block type except file, struct, union, or + enumeration blocks, push a level on the tag stack. We omit + file types, so that tags can span file boundaries. */ + if (type != st_File && storage != sc_Info) + { + ptag_head = allocate_thead (); + ptag_head->first_tag = 0; + ptag_head->prev = cur_tag_head; + cur_tag_head = ptag_head; + } + break; + + case st_End: + pscope = cur_file_ptr->cur_scope; + if (pscope == (scope_t *) NULL) + as_fatal (_("too many st_End's")); + else + { + st_t begin_type = (st_t) pscope->lsym->ecoff_sym.asym.st; + + psym->begin_ptr = pscope->lsym; + + if (begin_type != st_File) + scope_delta = -1; + + /* Except for file, structure, union, or enumeration end + blocks remove all tags created within this scope. */ + if (begin_type != st_File && storage != sc_Info) + { + ptag_head = cur_tag_head; + cur_tag_head = ptag_head->prev; + + for (ptag = ptag_head->first_tag; + ptag != (tag_t *) NULL; + ptag = ptag_next) + { + if (ptag->forward_ref != (forward_t *) NULL) + add_unknown_tag (ptag); + + ptag_next = ptag->same_block; + ptag->hash_ptr->tag_ptr = ptag->same_name; + free_tag (ptag); + } + + free_thead (ptag_head); + } + + cur_file_ptr->cur_scope = pscope->prev; + + /* block begin gets next sym #. This is set when we know + the symbol index value. */ + + /* Functions push two or more aux words as follows: + 1st word: index+1 of the end symbol (filled in later). + 2nd word: type of the function (plus any aux words needed). + Also, tie the external pointer back to the function begin symbol. */ + if (begin_type != st_File && begin_type != st_Block) + { + symint_t ty; + varray_t *svp = &cur_file_ptr->aux_syms; + + pscope->lsym->ecoff_sym.asym.index = add_aux_sym_symint (0); + pscope->lsym->index_ptr = + &svp->last->datum->aux[svp->objects_last_page - 1]; + ty = add_aux_sym_tir (&last_func_type_info, + hash_no, + &cur_file_ptr->thash_head[0]); + +/* This seems to be unnecessary. I'm not even sure what it is + * intended to do. It's from mips-tfile. + * if (last_func_sym_value != (symbolS *) NULL) + * { + * last_func_sym_value->ifd = cur_file_ptr->file_index; + * last_func_sym_value->index = ty; + * } + */ + } + + free_scope (pscope); + } + } + + cur_file_ptr->nested_scopes += scope_delta; + +#ifdef ECOFF_DEBUG + if (debug && type != st_File + && (debug > 2 || type == st_Block || type == st_End + || type == st_Proc || type == st_StaticProc)) + { + char *sc_str = sc_to_string (storage); + char *st_str = st_to_string (type); + int depth = cur_file_ptr->nested_scopes + (scope_delta < 0); + + fprintf (stderr, + "\tlsym\tv= %10ld, depth= %2d, sc= %-12s", + value, depth, sc_str); + + if (str_start && str_end_p1 - str_start > 0) + fprintf (stderr, " st= %-11s name= %.*s\n", + st_str, str_end_p1 - str_start, str_start); + else + { + unsigned long len = strlen (st_str); + fprintf (stderr, " st= %.*s\n", len - 1, st_str); + } + } +#endif + + return psym; +} + +/* Add an auxiliary symbol (passing a symint). This is actually used + for integral aux types, not just symints. */ + +static symint_t +add_aux_sym_symint (aux_word) + symint_t aux_word; /* auxiliary information word */ +{ + register varray_t *vp; + register aux_t *aux_ptr; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal (_("no current file pointer")); + + vp = &cur_file_ptr->aux_syms; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[vp->objects_last_page++]; + aux_ptr->type = aux_isym; + aux_ptr->data.isym = aux_word; + + return vp->num_allocated++; +} + +/* Add an auxiliary symbol (passing a file/symbol index combo). */ + +static symint_t +add_aux_sym_rndx (file_index, sym_index) + int file_index; + symint_t sym_index; +{ + register varray_t *vp; + register aux_t *aux_ptr; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal (_("no current file pointer")); + + vp = &cur_file_ptr->aux_syms; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[vp->objects_last_page++]; + aux_ptr->type = aux_rndx; + aux_ptr->data.rndx.rfd = file_index; + aux_ptr->data.rndx.index = sym_index; + + return vp->num_allocated++; +} + +/* Add an auxiliary symbol (passing the basic type and possibly + type qualifiers). */ + +static symint_t +add_aux_sym_tir (t, state, hash_tbl) + type_info_t *t; /* current type information */ + hash_state_t state; /* whether to hash type or not */ + thash_t **hash_tbl; /* pointer to hash table to use */ +{ + register varray_t *vp; + register aux_t *aux_ptr; + static AUXU init_aux; + symint_t ret; + int i; + AUXU aux; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal (_("no current file pointer")); + + vp = &cur_file_ptr->aux_syms; + + aux = init_aux; + aux.ti.bt = (int) t->basic_type; + aux.ti.continued = 0; + aux.ti.fBitfield = t->bitfield; + + aux.ti.tq0 = (int) t->type_qualifiers[0]; + aux.ti.tq1 = (int) t->type_qualifiers[1]; + aux.ti.tq2 = (int) t->type_qualifiers[2]; + aux.ti.tq3 = (int) t->type_qualifiers[3]; + aux.ti.tq4 = (int) t->type_qualifiers[4]; + aux.ti.tq5 = (int) t->type_qualifiers[5]; + + /* For anything that adds additional information, we must not hash, + so check here, and reset our state. */ + + if (state != hash_no + && (t->type_qualifiers[0] == tq_Array + || t->type_qualifiers[1] == tq_Array + || t->type_qualifiers[2] == tq_Array + || t->type_qualifiers[3] == tq_Array + || t->type_qualifiers[4] == tq_Array + || t->type_qualifiers[5] == tq_Array + || t->basic_type == bt_Struct + || t->basic_type == bt_Union + || t->basic_type == bt_Enum + || t->bitfield + || t->num_dims > 0)) + state = hash_no; + + /* See if we can hash this type, and save some space, but some types + can't be hashed (because they contain arrays or continuations), + and others can be put into the hash list, but cannot use existing + types because other aux entries precede this one. */ + + if (state != hash_no) + { + register thash_t *hash_ptr; + register symint_t hi; + + hi = aux.isym & ((1 << HASHBITS) - 1); + hi %= THASH_SIZE; + + for (hash_ptr = hash_tbl[hi]; + hash_ptr != (thash_t *)0; + hash_ptr = hash_ptr->next) + { + if (aux.isym == hash_ptr->type.isym) + break; + } + + if (hash_ptr != (thash_t *) NULL && state == hash_yes) + return hash_ptr->indx; + + if (hash_ptr == (thash_t *) NULL) + { + hash_ptr = allocate_thash (); + hash_ptr->next = hash_tbl[hi]; + hash_ptr->type = aux; + hash_ptr->indx = vp->num_allocated; + hash_tbl[hi] = hash_ptr; + } + } + + /* Everything is set up, add the aux symbol. */ + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + aux_ptr = &vp->last->datum->aux[vp->objects_last_page++]; + aux_ptr->type = aux_tir; + aux_ptr->data = aux; + + ret = vp->num_allocated++; + + /* Add bitfield length if it exists. + + NOTE: Mips documentation claims bitfield goes at the end of the + AUX record, but the DECstation compiler emits it here. + (This would only make a difference for enum bitfields.) + + Also note: We use the last size given since gcc may emit 2 + for an enum bitfield. */ + + if (t->bitfield) + (void) add_aux_sym_symint ((symint_t) t->sizes[t->num_sizes - 1]); + + /* Add tag information if needed. Structure, union, and enum + references add 2 aux symbols: a [file index, symbol index] + pointer to the structure type, and the current file index. */ + + if (t->basic_type == bt_Struct + || t->basic_type == bt_Union + || t->basic_type == bt_Enum) + { + register symint_t file_index = t->tag_ptr->ifd; + register localsym_t *sym = t->tag_ptr->sym; + register forward_t *forward_ref = allocate_forward (); + + if (sym != (localsym_t *) NULL) + { + forward_ref->next = sym->forward_ref; + sym->forward_ref = forward_ref; + } + else + { + forward_ref->next = t->tag_ptr->forward_ref; + t->tag_ptr->forward_ref = forward_ref; + } + + (void) add_aux_sym_rndx (ST_RFDESCAPE, indexNil); + forward_ref->index_ptr + = &vp->last->datum->aux[vp->objects_last_page - 1]; + + (void) add_aux_sym_symint (file_index); + forward_ref->ifd_ptr + = &vp->last->datum->aux[vp->objects_last_page - 1]; + } + + /* Add information about array bounds if they exist. */ + for (i = 0; i < t->num_dims; i++) + { + (void) add_aux_sym_rndx (ST_RFDESCAPE, + cur_file_ptr->int_type); + + (void) add_aux_sym_symint (cur_file_ptr->file_index); /* file index*/ + (void) add_aux_sym_symint ((symint_t) 0); /* low bound */ + (void) add_aux_sym_symint (t->dimensions[i] - 1); /* high bound*/ + (void) add_aux_sym_symint ((t->dimensions[i] == 0) /* stride */ + ? 0 + : (t->sizes[i] * 8) / t->dimensions[i]); + }; + + /* NOTE: Mips documentation claims that the bitfield width goes here. + But it needs to be emitted earlier. */ + + return ret; +} + +/* Add a tag to the tag table (unless it already exists). */ + +static tag_t * +get_tag (tag, sym, basic_type) + const char *tag; /* tag name */ + localsym_t *sym; /* tag start block */ + bt_t basic_type; /* bt_Struct, bt_Union, or bt_Enum */ +{ + shash_t *hash_ptr; + const char *err; + tag_t *tag_ptr; + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal (_("no current file pointer")); + + hash_ptr = (shash_t *) hash_find (tag_hash, tag); + + if (hash_ptr != (shash_t *) NULL + && hash_ptr->tag_ptr != (tag_t *) NULL) + { + tag_ptr = hash_ptr->tag_ptr; + if (sym != (localsym_t *) NULL) + { + tag_ptr->basic_type = basic_type; + tag_ptr->ifd = cur_file_ptr->file_index; + tag_ptr->sym = sym; + } + return tag_ptr; + } + + if (hash_ptr == (shash_t *) NULL) + { + char *perm; + + perm = xstrdup (tag); + hash_ptr = allocate_shash (); + err = hash_insert (tag_hash, perm, (char *) hash_ptr); + if (err) + as_fatal (_("inserting \"%s\" into tag hash table: %s"), + tag, err); + hash_ptr->string = perm; + } + + tag_ptr = allocate_tag (); + tag_ptr->forward_ref = (forward_t *) NULL; + tag_ptr->hash_ptr = hash_ptr; + tag_ptr->same_name = hash_ptr->tag_ptr; + tag_ptr->basic_type = basic_type; + tag_ptr->sym = sym; + tag_ptr->ifd = ((sym == (localsym_t *) NULL) + ? (symint_t) -1 + : cur_file_ptr->file_index); + tag_ptr->same_block = cur_tag_head->first_tag; + + cur_tag_head->first_tag = tag_ptr; + hash_ptr->tag_ptr = tag_ptr; + + return tag_ptr; +} + +/* Add an unknown {struct, union, enum} tag. */ + +static void +add_unknown_tag (ptag) + tag_t *ptag; /* pointer to tag information */ +{ + shash_t *hash_ptr = ptag->hash_ptr; + char *name = hash_ptr->string; + localsym_t *sym; + forward_t **pf; + +#ifdef ECOFF_DEBUG + if (debug > 1) + { + char *agg_type = "{unknown aggregate type}"; + switch (ptag->basic_type) + { + case bt_Struct: agg_type = "struct"; break; + case bt_Union: agg_type = "union"; break; + case bt_Enum: agg_type = "enum"; break; + default: break; + } + + fprintf (stderr, "unknown %s %.*s found\n", agg_type, + hash_ptr->len, name_start); + } +#endif + + sym = add_ecoff_symbol (name, + st_Block, + sc_Info, + (symbolS *) NULL, + (bfd_vma) 0, + (symint_t) 0, + (symint_t) 0); + + (void) add_ecoff_symbol (name, + st_End, + sc_Info, + (symbolS *) NULL, + (bfd_vma) 0, + (symint_t) 0, + (symint_t) 0); + + for (pf = &sym->forward_ref; *pf != (forward_t *) NULL; pf = &(*pf)->next) + ; + *pf = ptag->forward_ref; +} + +/* Add a procedure to the current file's list of procedures, and record + this is the current procedure. */ + +static void +add_procedure (func) + char *func; /* func name */ +{ + register varray_t *vp; + register proc_t *new_proc_ptr; + symbolS *sym; + +#ifdef ECOFF_DEBUG + if (debug) + fputc ('\n', stderr); +#endif + + if (cur_file_ptr == (efdr_t *) NULL) + as_fatal (_("no current file pointer")); + + vp = &cur_file_ptr->procs; + + if (vp->objects_last_page == vp->objects_per_page) + add_varray_page (vp); + + cur_proc_ptr = new_proc_ptr = &vp->last->datum->proc[vp->objects_last_page++]; + + if (first_proc_ptr == (proc_t *) NULL) + first_proc_ptr = new_proc_ptr; + + vp->num_allocated++; + + new_proc_ptr->pdr.isym = -1; + new_proc_ptr->pdr.iline = -1; + new_proc_ptr->pdr.lnLow = -1; + new_proc_ptr->pdr.lnHigh = -1; + + /* Set the BSF_FUNCTION flag for the symbol. */ + sym = symbol_find_or_make (func); + symbol_get_bfdsym (sym)->flags |= BSF_FUNCTION; + + /* Push the start of the function. */ + new_proc_ptr->sym = add_ecoff_symbol ((const char *) NULL, st_Proc, sc_Text, + sym, (bfd_vma) 0, (symint_t) 0, + (symint_t) 0); + + ++proc_cnt; + + /* Fill in the linenos preceding the .ent, if any. */ + if (noproc_lineno != (lineno_list_t *) NULL) + { + lineno_list_t *l; + + for (l = noproc_lineno; l != (lineno_list_t *) NULL; l = l->next) + l->proc = new_proc_ptr; + *last_lineno_ptr = noproc_lineno; + while (*last_lineno_ptr != NULL) + { + last_lineno = *last_lineno_ptr; + last_lineno_ptr = &last_lineno->next; + } + noproc_lineno = (lineno_list_t *) NULL; + } +} + +symbolS * +ecoff_get_cur_proc_sym () +{ + return (cur_proc_ptr ? cur_proc_ptr->sym->as_sym : NULL); +} + +/* Add a new filename, and set up all of the file relative + virtual arrays (strings, symbols, aux syms, etc.). Record + where the current file structure lives. */ + +static void +add_file (file_name, indx, fake) + const char *file_name; /* file name */ + int indx ATTRIBUTE_UNUSED; + int fake; +{ + register int first_ch; + register efdr_t *fil_ptr; + +#ifdef ECOFF_DEBUG + if (debug) + fprintf (stderr, "\tfile\t%.*s\n", len, file_start); +#endif + + /* If the file name is NULL, then no .file symbol appeared, and we + want to use the actual file name. */ + if (file_name == (const char *) NULL) + { + char *file; + + if (first_file != (efdr_t *) NULL) + as_fatal (_("fake .file after real one")); + as_where (&file, (unsigned int *) NULL); + file_name = (const char *) file; + + /* Automatically generate ECOFF debugging information, since I + think that's what other ECOFF assemblers do. We don't do + this if we see a .file directive with a string, since that + implies that some sort of debugging information is being + provided. */ + if (! symbol_table_frozen && debug_type == DEBUG_UNSPECIFIED) + debug_type = DEBUG_ECOFF; + } + else if (debug_type == DEBUG_UNSPECIFIED) + debug_type = DEBUG_NONE; + +#ifndef NO_LISTING + if (listing) + listing_source_file (file_name); +#endif + + current_stabs_filename = file_name; + + /* If we're creating stabs, then we don't actually make a new FDR. + Instead, we just create a stabs symbol. */ + if (stabs_seen) + { + (void) add_ecoff_symbol (file_name, st_Nil, sc_Nil, + symbol_new ("L0\001", now_seg, + (valueT) frag_now_fix (), + frag_now), + (bfd_vma) 0, 0, ECOFF_MARK_STAB (N_SOL)); + return; + } + + first_ch = *file_name; + + /* FIXME: We can't safely merge files which have line number + information (fMerge will be zero in this case). Otherwise, we + get incorrect line number debugging info. See for instance + ecoff_build_lineno, which will end up setting all file->fdr.* + fields multiple times, resulting in incorrect debug info. In + order to make this work right, all line number and symbol info + for the same source file has to be adjacent in the object file, + so that a single file descriptor can be used to point to them. + This would require maintaining file specific lists of line + numbers and symbols for each file, so that they can be merged + together (or output together) when two .file pseudo-ops are + merged into one file descriptor. */ + + /* See if the file has already been created. */ + for (fil_ptr = first_file; + fil_ptr != (efdr_t *) NULL; + fil_ptr = fil_ptr->next_file) + { + if (first_ch == fil_ptr->name[0] + && strcmp (file_name, fil_ptr->name) == 0 + && fil_ptr->fdr.fMerge) + { + cur_file_ptr = fil_ptr; + if (! fake) + cur_file_ptr->fake = 0; + break; + } + } + + /* If this is a new file, create it. */ + if (fil_ptr == (efdr_t *) NULL) + { + if (file_desc.objects_last_page == file_desc.objects_per_page) + add_varray_page (&file_desc); + + fil_ptr = cur_file_ptr = + &file_desc.last->datum->file[file_desc.objects_last_page++]; + *fil_ptr = init_file; + + fil_ptr->file_index = current_file_idx++; + ++file_desc.num_allocated; + + fil_ptr->fake = fake; + + /* Allocate the string hash table. */ + fil_ptr->str_hash = hash_new (); + + /* Make sure 0 byte in string table is null */ + add_string (&fil_ptr->strings, + fil_ptr->str_hash, + "", + (shash_t **)0); + + if (strlen (file_name) > PAGE_USIZE - 2) + as_fatal (_("filename goes over one page boundary")); + + /* Push the start of the filename. We assume that the filename + will be stored at string offset 1. */ + (void) add_ecoff_symbol (file_name, st_File, sc_Text, + (symbolS *) NULL, (bfd_vma) 0, + (symint_t) 0, (symint_t) 0); + fil_ptr->fdr.rss = 1; + fil_ptr->name = &fil_ptr->strings.last->datum->byte[1]; + + /* Update the linked list of file descriptors. */ + *last_file_ptr = fil_ptr; + last_file_ptr = &fil_ptr->next_file; + + /* Add void & int types to the file (void should be first to catch + errant 0's within the index fields). */ + fil_ptr->void_type = add_aux_sym_tir (&void_type_info, + hash_yes, + &cur_file_ptr->thash_head[0]); + + fil_ptr->int_type = add_aux_sym_tir (&int_type_info, + hash_yes, + &cur_file_ptr->thash_head[0]); + } +} + +/* This function is called when the assembler notices a preprocessor + directive switching to a new file. This will not happen in + compiler output, only in hand coded assembler. */ + +void +ecoff_new_file (name) + const char *name; +{ + if (cur_file_ptr != NULL && strcmp (cur_file_ptr->name, name) == 0) + return; + add_file (name, 0, 0); + + /* This is a hand coded assembler file, so automatically turn on + debugging information. */ + if (debug_type == DEBUG_UNSPECIFIED) + debug_type = DEBUG_ECOFF; +} + +#ifdef ECOFF_DEBUG + +/* Convert storage class to string. */ + +static char * +sc_to_string (storage_class) + sc_t storage_class; +{ + switch (storage_class) + { + case sc_Nil: return "Nil,"; + case sc_Text: return "Text,"; + case sc_Data: return "Data,"; + case sc_Bss: return "Bss,"; + case sc_Register: return "Register,"; + case sc_Abs: return "Abs,"; + case sc_Undefined: return "Undefined,"; + case sc_CdbLocal: return "CdbLocal,"; + case sc_Bits: return "Bits,"; + case sc_CdbSystem: return "CdbSystem,"; + case sc_RegImage: return "RegImage,"; + case sc_Info: return "Info,"; + case sc_UserStruct: return "UserStruct,"; + case sc_SData: return "SData,"; + case sc_SBss: return "SBss,"; + case sc_RData: return "RData,"; + case sc_Var: return "Var,"; + case sc_Common: return "Common,"; + case sc_SCommon: return "SCommon,"; + case sc_VarRegister: return "VarRegister,"; + case sc_Variant: return "Variant,"; + case sc_SUndefined: return "SUndefined,"; + case sc_Init: return "Init,"; + case sc_Max: return "Max,"; + } + + return "???,"; +} + +#endif /* DEBUG */ + +#ifdef ECOFF_DEBUG + +/* Convert symbol type to string. */ + +static char * +st_to_string (symbol_type) + st_t symbol_type; +{ + switch (symbol_type) + { + case st_Nil: return "Nil,"; + case st_Global: return "Global,"; + case st_Static: return "Static,"; + case st_Param: return "Param,"; + case st_Local: return "Local,"; + case st_Label: return "Label,"; + case st_Proc: return "Proc,"; + case st_Block: return "Block,"; + case st_End: return "End,"; + case st_Member: return "Member,"; + case st_Typedef: return "Typedef,"; + case st_File: return "File,"; + case st_RegReloc: return "RegReloc,"; + case st_Forward: return "Forward,"; + case st_StaticProc: return "StaticProc,"; + case st_Constant: return "Constant,"; + case st_Str: return "String,"; + case st_Number: return "Number,"; + case st_Expr: return "Expr,"; + case st_Type: return "Type,"; + case st_Max: return "Max,"; + } + + return "???,"; +} + +#endif /* DEBUG */ + +/* Parse .begin directives which have a label as the first argument + which gives the location of the start of the block. */ + +void +ecoff_directive_begin (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char name_end; + + if (cur_file_ptr == (efdr_t *) NULL) + { + as_warn (_(".begin directive without a preceding .file directive")); + demand_empty_rest_of_line (); + return; + } + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (_(".begin directive without a preceding .ent directive")); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + (void) add_ecoff_symbol ((const char *) NULL, st_Block, sc_Text, + symbol_find_or_make (name), + (bfd_vma) 0, (symint_t) 0, (symint_t) 0); + + *input_line_pointer = name_end; + + /* The line number follows, but we don't use it. */ + (void) get_absolute_expression (); + demand_empty_rest_of_line (); +} + +/* Parse .bend directives which have a label as the first argument + which gives the location of the end of the block. */ + +void +ecoff_directive_bend (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char name_end; + symbolS *endsym; + + if (cur_file_ptr == (efdr_t *) NULL) + { + as_warn (_(".bend directive without a preceding .file directive")); + demand_empty_rest_of_line (); + return; + } + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (_(".bend directive without a preceding .ent directive")); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + /* The value is the distance between the .bend directive and the + corresponding symbol. We fill in the offset when we write out + the symbol. */ + endsym = symbol_find (name); + if (endsym == (symbolS *) NULL) + as_warn (_(".bend directive names unknown symbol")); + else + (void) add_ecoff_symbol ((const char *) NULL, st_End, sc_Text, endsym, + (bfd_vma) 0, (symint_t) 0, (symint_t) 0); + + *input_line_pointer = name_end; + + /* The line number follows, but we don't use it. */ + (void) get_absolute_expression (); + demand_empty_rest_of_line (); +} + +/* COFF debugging information is provided as a series of directives + (.def, .scl, etc.). We build up information as we read the + directives in the following static variables, and file it away when + we reach the .endef directive. */ +static char *coff_sym_name; +static type_info_t coff_type; +static sc_t coff_storage_class; +static st_t coff_symbol_typ; +static int coff_is_function; +static char *coff_tag; +static valueT coff_value; +static symbolS *coff_sym_value; +static bfd_vma coff_sym_addend; +static int coff_inside_enumeration; + +/* Handle a .def directive: start defining a symbol. */ + +void +ecoff_directive_def (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char name_end; + + ecoff_debugging_seen = 1; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + name_end = get_symbol_end (); + + if (coff_sym_name != (char *) NULL) + as_warn (_(".def pseudo-op used inside of .def/.endef; ignored")); + else if (*name == '\0') + as_warn (_("empty symbol name in .def; ignored")); + else + { + if (coff_sym_name != (char *) NULL) + free (coff_sym_name); + if (coff_tag != (char *) NULL) + free (coff_tag); + + coff_sym_name = xstrdup (name); + coff_type = type_info_init; + coff_storage_class = sc_Nil; + coff_symbol_typ = st_Nil; + coff_is_function = 0; + coff_tag = (char *) NULL; + coff_value = 0; + coff_sym_value = (symbolS *) NULL; + coff_sym_addend = 0; + } + + *input_line_pointer = name_end; + + demand_empty_rest_of_line (); +} + +/* Handle a .dim directive, used to give dimensions for an array. The + arguments are comma separated numbers. mips-tfile assumes that + there will not be more than 6 dimensions, and gdb won't read any + more than that anyhow, so I will also make that assumption. */ + +void +ecoff_directive_dim (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + int dimens[N_TQ]; + int i; + + if (coff_sym_name == (char *) NULL) + { + as_warn (_(".dim pseudo-op used outside of .def/.endef; ignored")); + demand_empty_rest_of_line (); + return; + } + + for (i = 0; i < N_TQ; i++) + { + SKIP_WHITESPACE (); + dimens[i] = get_absolute_expression (); + if (*input_line_pointer == ',') + ++input_line_pointer; + else + { + if (*input_line_pointer != '\n' + && *input_line_pointer != ';') + as_warn (_("badly formed .dim directive")); + break; + } + } + + if (i == N_TQ) + --i; + + /* The dimensions are stored away in reverse order. */ + for (; i >= 0; i--) + { + if (coff_type.num_dims >= N_TQ) + { + as_warn (_("too many .dim entries")); + break; + } + coff_type.dimensions[coff_type.num_dims] = dimens[i]; + ++coff_type.num_dims; + } + + demand_empty_rest_of_line (); +} + +/* Handle a .scl directive, which sets the COFF storage class of the + symbol. */ + +void +ecoff_directive_scl (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + long val; + + if (coff_sym_name == (char *) NULL) + { + as_warn (_(".scl pseudo-op used outside of .def/.endef; ignored")); + demand_empty_rest_of_line (); + return; + } + + val = get_absolute_expression (); + + coff_symbol_typ = map_coff_sym_type[val]; + coff_storage_class = map_coff_storage[val]; + + demand_empty_rest_of_line (); +} + +/* Handle a .size directive. For some reason mips-tfile.c thinks that + .size can have multiple arguments. We humor it, although gcc will + never generate more than one argument. */ + +void +ecoff_directive_size (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + int sizes[N_TQ]; + int i; + + if (coff_sym_name == (char *) NULL) + { + as_warn (_(".size pseudo-op used outside of .def/.endef; ignored")); + demand_empty_rest_of_line (); + return; + } + + for (i = 0; i < N_TQ; i++) + { + SKIP_WHITESPACE (); + sizes[i] = get_absolute_expression (); + if (*input_line_pointer == ',') + ++input_line_pointer; + else + { + if (*input_line_pointer != '\n' + && *input_line_pointer != ';') + as_warn (_("badly formed .size directive")); + break; + } + } + + if (i == N_TQ) + --i; + + /* The sizes are stored away in reverse order. */ + for (; i >= 0; i--) + { + if (coff_type.num_sizes >= N_TQ) + { + as_warn (_("too many .size entries")); + break; + } + coff_type.sizes[coff_type.num_sizes] = sizes[i]; + ++coff_type.num_sizes; + } + + demand_empty_rest_of_line (); +} + +/* Handle the .type directive, which gives the COFF type of the + symbol. */ + +void +ecoff_directive_type (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + long val; + tq_t *tq_ptr; + tq_t *tq_shft; + + if (coff_sym_name == (char *) NULL) + { + as_warn (_(".type pseudo-op used outside of .def/.endef; ignored")); + demand_empty_rest_of_line (); + return; + } + + val = get_absolute_expression (); + + coff_type.orig_type = BTYPE (val); + coff_type.basic_type = map_coff_types[coff_type.orig_type]; + + tq_ptr = &coff_type.type_qualifiers[N_TQ]; + while (val & ~N_BTMASK) + { + if (tq_ptr == &coff_type.type_qualifiers[0]) + { + /* FIXME: We could handle this by setting the continued bit. + There would still be a limit: the .type argument can not + be infinite. */ + as_warn (_("the type of %s is too complex; it will be simplified"), + coff_sym_name); + break; + } + if (ISPTR (val)) + *--tq_ptr = tq_Ptr; + else if (ISFCN (val)) + *--tq_ptr = tq_Proc; + else if (ISARY (val)) + *--tq_ptr = tq_Array; + else + as_fatal (_("Unrecognized .type argument")); + + val = DECREF (val); + } + + tq_shft = &coff_type.type_qualifiers[0]; + while (tq_ptr != &coff_type.type_qualifiers[N_TQ]) + *tq_shft++ = *tq_ptr++; + + if (tq_shft != &coff_type.type_qualifiers[0] && tq_shft[-1] == tq_Proc) + { + /* If this is a function, ignore it, so that we don't get two + entries (one from the .ent, and one for the .def that + precedes it). Save the type information so that the end + block can properly add it after the begin block index. For + MIPS knows what reason, we must strip off the function type + at this point. */ + coff_is_function = 1; + tq_shft[-1] = tq_Nil; + } + + while (tq_shft != &coff_type.type_qualifiers[N_TQ]) + *tq_shft++ = tq_Nil; + + demand_empty_rest_of_line (); +} + +/* Handle the .tag directive, which gives the name of a structure, + union or enum. */ + +void +ecoff_directive_tag (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char name_end; + + if (coff_sym_name == (char *) NULL) + { + as_warn (_(".tag pseudo-op used outside of .def/.endef; ignored")); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + coff_tag = xstrdup (name); + + *input_line_pointer = name_end; + + demand_empty_rest_of_line (); +} + +/* Handle the .val directive, which gives the value of the symbol. It + may be the name of a static or global symbol. */ + +void +ecoff_directive_val (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + expressionS exp; + + if (coff_sym_name == (char *) NULL) + { + as_warn (_(".val pseudo-op used outside of .def/.endef; ignored")); + demand_empty_rest_of_line (); + return; + } + + expression (&exp); + if (exp.X_op != O_constant && exp.X_op != O_symbol) + { + as_bad (_(".val expression is too copmlex")); + demand_empty_rest_of_line (); + return; + } + + if (exp.X_op == O_constant) + coff_value = exp.X_add_number; + else + { + coff_sym_value = exp.X_add_symbol; + coff_sym_addend = exp.X_add_number; + } + + demand_empty_rest_of_line (); +} + +/* Handle the .endef directive, which terminates processing of COFF + debugging information for a symbol. */ + +void +ecoff_directive_endef (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + symint_t indx; + localsym_t *sym; + + demand_empty_rest_of_line (); + + if (coff_sym_name == (char *) NULL) + { + as_warn (_(".endef pseudo-op used before .def; ignored")); + return; + } + + name = coff_sym_name; + coff_sym_name = (char *) NULL; + + /* If the symbol is a static or external, we have already gotten the + appropriate type and class, so make sure we don't override those + values. This is needed because there are some type and classes + that are not in COFF, such as short data, etc. */ + if (coff_sym_value != (symbolS *) NULL) + { + coff_symbol_typ = st_Nil; + coff_storage_class = sc_Nil; + } + + coff_type.extra_sizes = coff_tag != (char *) NULL; + if (coff_type.num_dims > 0) + { + int diff = coff_type.num_dims - coff_type.num_sizes; + int i = coff_type.num_dims - 1; + int j; + + if (coff_type.num_sizes != 1 || diff < 0) + { + as_warn (_("bad COFF debugging information")); + return; + } + + /* If this is an array, make sure the same number of dimensions + and sizes were passed, creating extra sizes for multiply + dimensioned arrays if not passed. */ + coff_type.extra_sizes = 0; + if (diff) + { + j = (sizeof (coff_type.sizes) / sizeof (coff_type.sizes[0])) - 1; + while (j >= 0) + { + coff_type.sizes[j] = (((j - diff) >= 0) + ? coff_type.sizes[j - diff] + : 0); + j--; + } + + coff_type.num_sizes = i + 1; + for (i--; i >= 0; i--) + coff_type.sizes[i] = (coff_type.dimensions[i + 1] == 0 + ? 0 + : (coff_type.sizes[i + 1] + / coff_type.dimensions[i + 1])); + } + } + else if (coff_symbol_typ == st_Member + && coff_type.num_sizes - coff_type.extra_sizes == 1) + { + /* Is this a bitfield? This is indicated by a structure memeber + having a size field that isn't an array. */ + coff_type.bitfield = 1; + } + + /* Except for enumeration members & begin/ending of scopes, put the + type word in the aux. symbol table. */ + if (coff_symbol_typ == st_Block || coff_symbol_typ == st_End) + indx = 0; + else if (coff_inside_enumeration) + indx = cur_file_ptr->void_type; + else + { + if (coff_type.basic_type == bt_Struct + || coff_type.basic_type == bt_Union + || coff_type.basic_type == bt_Enum) + { + if (coff_tag == (char *) NULL) + { + as_warn (_("no tag specified for %s"), name); + return; + } + + coff_type.tag_ptr = get_tag (coff_tag, (localsym_t *) NULL, + coff_type.basic_type); + } + + if (coff_is_function) + { + last_func_type_info = coff_type; + last_func_sym_value = coff_sym_value; + return; + } + + indx = add_aux_sym_tir (&coff_type, + hash_yes, + &cur_file_ptr->thash_head[0]); + } + + /* Do any last minute adjustments that are necessary. */ + switch (coff_symbol_typ) + { + default: + break; + + /* For the beginning of structs, unions, and enumerations, the + size info needs to be passed in the value field. */ + case st_Block: + if (coff_type.num_sizes - coff_type.num_dims - coff_type.extra_sizes + != 1) + { + as_warn (_("bad COFF debugging information")); + return; + } + else + coff_value = coff_type.sizes[0]; + + coff_inside_enumeration = (coff_type.orig_type == T_ENUM); + break; + + /* For the end of structs, unions, and enumerations, omit the + name which is always ".eos". This needs to be done last, so + that any error reporting above gives the correct name. */ + case st_End: + free (name); + name = (char *) NULL; + coff_value = 0; + coff_inside_enumeration = 0; + break; + + /* Members of structures and unions that aren't bitfields, need + to adjust the value from a byte offset to a bit offset. + Members of enumerations do not have the value adjusted, and + can be distinguished by indx == indexNil. For enumerations, + update the maximum enumeration value. */ + case st_Member: + if (! coff_type.bitfield && ! coff_inside_enumeration) + coff_value *= 8; + + break; + } + + /* Add the symbol. */ + sym = add_ecoff_symbol (name, + coff_symbol_typ, + coff_storage_class, + coff_sym_value, + coff_sym_addend, + (symint_t) coff_value, + indx); + + /* deal with struct, union, and enum tags. */ + if (coff_symbol_typ == st_Block) + { + /* Create or update the tag information. */ + tag_t *tag_ptr = get_tag (name, + sym, + coff_type.basic_type); + forward_t **pf; + + /* Remember any forward references. */ + for (pf = &sym->forward_ref; + *pf != (forward_t *) NULL; + pf = &(*pf)->next) + ; + *pf = tag_ptr->forward_ref; + tag_ptr->forward_ref = (forward_t *) NULL; + } +} + +/* Parse .end directives. */ + +void +ecoff_directive_end (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char name_end; + symbolS *ent; + + if (cur_file_ptr == (efdr_t *) NULL) + { + as_warn (_(".end directive without a preceding .file directive")); + demand_empty_rest_of_line (); + return; + } + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (_(".end directive without a preceding .ent directive")); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + if (name == input_line_pointer) + { + as_warn (_(".end directive has no name")); + *input_line_pointer = name_end; + demand_empty_rest_of_line (); + return; + } + + /* The value is the distance between the .end directive and the + corresponding symbol. We create a fake symbol to hold the + current location, and put in the offset when we write out the + symbol. */ + ent = symbol_find (name); + if (ent == (symbolS *) NULL) + as_warn (_(".end directive names unknown symbol")); + else + (void) add_ecoff_symbol ((const char *) NULL, st_End, sc_Text, + symbol_new ("L0\001", now_seg, + (valueT) frag_now_fix (), + frag_now), + (bfd_vma) 0, (symint_t) 0, (symint_t) 0); + + cur_proc_ptr = (proc_t *) NULL; + + *input_line_pointer = name_end; + demand_empty_rest_of_line (); +} + +/* Parse .ent directives. */ + +void +ecoff_directive_ent (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char name_end; + + if (cur_file_ptr == (efdr_t *) NULL) + add_file ((const char *) NULL, 0, 1); + + if (cur_proc_ptr != (proc_t *) NULL) + { + as_warn (_("second .ent directive found before .end directive")); + demand_empty_rest_of_line (); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + if (name == input_line_pointer) + { + as_warn (_(".ent directive has no name")); + *input_line_pointer = name_end; + demand_empty_rest_of_line (); + return; + } + + add_procedure (name); + + *input_line_pointer = name_end; + + /* The .ent directive is sometimes followed by a number. I'm not + really sure what the number means. I don't see any way to store + the information in the PDR. The Irix 4 assembler seems to ignore + the information. */ + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + } + if (ISDIGIT (*input_line_pointer) + || *input_line_pointer == '-') + (void) get_absolute_expression (); + + demand_empty_rest_of_line (); +} + +/* Parse .extern directives. */ + +void +ecoff_directive_extern (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + int c; + symbolS *symbolp; + valueT size; + + name = input_line_pointer; + c = get_symbol_end (); + symbolp = symbol_find_or_make (name); + *input_line_pointer = c; + + S_SET_EXTERNAL (symbolp); + + if (*input_line_pointer == ',') + ++input_line_pointer; + size = get_absolute_expression (); + + symbol_get_obj (symbolp)->ecoff_extern_size = size; +} + +/* Parse .file directives. */ + +void +ecoff_directive_file (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + int indx; + char *name; + int len; + + if (cur_proc_ptr != (proc_t *) NULL) + { + as_warn (_("no way to handle .file within .ent/.end section")); + demand_empty_rest_of_line (); + return; + } + + indx = (int) get_absolute_expression (); + + /* FIXME: we don't have to save the name here. */ + name = demand_copy_C_string (&len); + + add_file (name, indx - 1, 0); + + demand_empty_rest_of_line (); +} + +/* Parse .fmask directives. */ + +void +ecoff_directive_fmask (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + long val; + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (_(".fmask outside of .ent")); + demand_empty_rest_of_line (); + return; + } + + if (get_absolute_expression_and_terminator (&val) != ',') + { + as_warn (_("bad .fmask directive")); + --input_line_pointer; + demand_empty_rest_of_line (); + return; + } + + cur_proc_ptr->pdr.fregmask = val; + cur_proc_ptr->pdr.fregoffset = get_absolute_expression (); + + demand_empty_rest_of_line (); +} + +/* Parse .frame directives. */ + +void +ecoff_directive_frame (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + long val; + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (_(".frame outside of .ent")); + demand_empty_rest_of_line (); + return; + } + + cur_proc_ptr->pdr.framereg = tc_get_register (1); + + SKIP_WHITESPACE (); + if (*input_line_pointer++ != ',' + || get_absolute_expression_and_terminator (&val) != ',') + { + as_warn (_("bad .frame directive")); + --input_line_pointer; + demand_empty_rest_of_line (); + return; + } + + cur_proc_ptr->pdr.frameoffset = val; + + cur_proc_ptr->pdr.pcreg = tc_get_register (0); + +#if 0 + /* Alpha-OSF1 adds "the offset of saved $a0 from $sp", according to + Sandro. I don't yet know where this value should be stored, if + anywhere. */ + demand_empty_rest_of_line (); +#else + s_ignore (42); +#endif +} + +/* Parse .mask directives. */ + +void +ecoff_directive_mask (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + long val; + + if (cur_proc_ptr == (proc_t *) NULL) + { + as_warn (_(".mask outside of .ent")); + demand_empty_rest_of_line (); + return; + } + + if (get_absolute_expression_and_terminator (&val) != ',') + { + as_warn (_("bad .mask directive")); + --input_line_pointer; + demand_empty_rest_of_line (); + return; + } + + cur_proc_ptr->pdr.regmask = val; + cur_proc_ptr->pdr.regoffset = get_absolute_expression (); + + demand_empty_rest_of_line (); +} + +/* Parse .loc directives. */ + +void +ecoff_directive_loc (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + lineno_list_t *list; + symint_t lineno; + + if (cur_file_ptr == (efdr_t *) NULL) + { + as_warn (_(".loc before .file")); + demand_empty_rest_of_line (); + return; + } + + if (now_seg != text_section) + { + as_warn (_(".loc outside of .text")); + demand_empty_rest_of_line (); + return; + } + + /* Skip the file number. */ + SKIP_WHITESPACE (); + get_absolute_expression (); + SKIP_WHITESPACE (); + + lineno = get_absolute_expression (); + +#ifndef NO_LISTING + if (listing) + listing_source_line (lineno); +#endif + + /* If we're building stabs, then output a special label rather than + ECOFF line number info. */ + if (stabs_seen) + { + (void) add_ecoff_symbol ((char *) NULL, st_Label, sc_Text, + symbol_new ("L0\001", now_seg, + (valueT) frag_now_fix (), + frag_now), + (bfd_vma) 0, 0, lineno); + return; + } + + list = allocate_lineno_list (); + + list->next = (lineno_list_t *) NULL; + list->file = cur_file_ptr; + list->proc = cur_proc_ptr; + list->frag = frag_now; + list->paddr = frag_now_fix (); + list->lineno = lineno; + + /* We don't want to merge files which have line numbers. */ + cur_file_ptr->fdr.fMerge = 0; + + /* A .loc directive will sometimes appear before a .ent directive, + which means that cur_proc_ptr will be NULL here. Arrange to + patch this up. */ + if (cur_proc_ptr == (proc_t *) NULL) + { + lineno_list_t **pl; + + pl = &noproc_lineno; + while (*pl != (lineno_list_t *) NULL) + pl = &(*pl)->next; + *pl = list; + } + else + { + last_lineno = list; + *last_lineno_ptr = list; + last_lineno_ptr = &list->next; + } +} + +/* The MIPS assembler sometimes inserts nop instructions in the + instruction stream. When this happens, we must patch up the .loc + information so that it points to the instruction after the nop. */ + +void +ecoff_fix_loc (old_frag, old_frag_offset) + fragS *old_frag; + unsigned long old_frag_offset; +{ + if (last_lineno != NULL + && last_lineno->frag == old_frag + && last_lineno->paddr == old_frag_offset) + { + last_lineno->frag = frag_now; + last_lineno->paddr = frag_now_fix (); + } +} + +/* Make sure the @stabs symbol is emitted. */ + +static void +mark_stabs (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + if (! stabs_seen) + { + /* Add a dummy @stabs dymbol. */ + stabs_seen = 1; + (void) add_ecoff_symbol (stabs_symbol, stNil, scInfo, + (symbolS *) NULL, + (bfd_vma) 0, (symint_t) -1, + ECOFF_MARK_STAB (0)); + } +} + +/* Parse .weakext directives. */ +#ifndef TC_MIPS +/* For TC_MIPS use the version in tc-mips.c. */ +void +ecoff_directive_weakext (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + int c; + symbolS *symbolP; + expressionS exp; + + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + *input_line_pointer = c; + + SKIP_WHITESPACE (); + + if (*input_line_pointer == ',') + { + if (S_IS_DEFINED (symbolP)) + { + as_bad (_("symbol `%s' is already defined"), + S_GET_NAME (symbolP)); + ignore_rest_of_line (); + return; + } + + ++input_line_pointer; + SKIP_WHITESPACE (); + if (! is_end_of_line[(unsigned char) *input_line_pointer]) + { + expression (&exp); + if (exp.X_op != O_symbol) + { + as_bad (_("bad .weakext directive")); + ignore_rest_of_line (); + return; + } + symbol_set_value_expression (symbolP, &exp); + } + } + + S_SET_WEAK (symbolP); + + demand_empty_rest_of_line (); +} +#endif /* not TC_MIPS */ + +/* Handle .stabs directives. The actual parsing routine is done by a + generic routine. This routine is called via OBJ_PROCESS_STAB. + When this is called, input_line_pointer will be pointing at the + value field of the stab. + + .stabs directives have five fields: + "string" a string, encoding the type information. + code a numeric code, defined in + 0 a zero + desc a zero or line number + value a numeric value or an address. + + If the value is relocatable, we transform this into: + iss points as an index into string space + value value from lookup of the name + st st from lookup of the name + sc sc from lookup of the name + index code|CODE_MASK + + If the value is not relocatable, we transform this into: + iss points as an index into string space + value value + st st_Nil + sc sc_Nil + index code|CODE_MASK + + .stabn directives have four fields (string is null): + code a numeric code, defined in + 0 a zero + desc a zero or a line number + value a numeric value or an address. */ + +void +ecoff_stab (sec, what, string, type, other, desc) + segT sec ATTRIBUTE_UNUSED; + int what; + const char *string; + int type; + int other; + int desc; +{ + efdr_t *save_file_ptr = cur_file_ptr; + symbolS *sym; + symint_t value; + bfd_vma addend; + st_t st; + sc_t sc; + symint_t indx; + localsym_t *hold = NULL; + + ecoff_debugging_seen = 1; + + /* We don't handle .stabd. */ + if (what != 's' && what != 'n') + { + as_bad (_(".stab%c is not supported"), what); + return; + } + + /* A .stabn uses a null name, not an empty string. */ + if (what == 'n') + string = NULL; + + /* We ignore the other field. */ + if (other != 0) + as_warn (_(".stab%c: ignoring non-zero other field"), what); + + /* Make sure we have a current file. */ + if (cur_file_ptr == (efdr_t *) NULL) + { + add_file ((const char *) NULL, 0, 1); + save_file_ptr = cur_file_ptr; + } + + /* For stabs in ECOFF, the first symbol must be @stabs. This is a + signal to gdb. */ + if (stabs_seen == 0) + mark_stabs (0); + + /* Line number stabs are handled differently, since they have two + values, the line number and the address of the label. We use the + index field (aka desc) to hold the line number, and the value + field to hold the address. The symbol type is st_Label, which + should be different from the other stabs, so that gdb can + recognize it. */ + if (type == N_SLINE) + { + SYMR dummy_symr; + char *name; + char name_end; + +#ifndef NO_LISTING + if (listing) + listing_source_line ((unsigned int) desc); +#endif + + dummy_symr.index = desc; + if (dummy_symr.index != desc) + { + as_warn (_("line number (%d) for .stab%c directive cannot fit in index field (20 bits)"), + desc, what); + return; + } + + name = input_line_pointer; + name_end = get_symbol_end (); + + sym = symbol_find_or_make (name); + *input_line_pointer = name_end; + + value = 0; + addend = 0; + st = st_Label; + sc = sc_Text; + indx = desc; + } + else + { +#ifndef NO_LISTING + if (listing && (type == N_SO || type == N_SOL)) + listing_source_file (string); +#endif + + if (ISDIGIT (*input_line_pointer) + || *input_line_pointer == '-' + || *input_line_pointer == '+') + { + st = st_Nil; + sc = sc_Nil; + sym = (symbolS *) NULL; + value = get_absolute_expression (); + addend = 0; + } + else if (! is_name_beginner ((unsigned char) *input_line_pointer)) + { + as_warn (_("illegal .stab%c directive, bad character"), what); + return; + } + else + { + expressionS exp; + + sc = sc_Nil; + st = st_Nil; + + expression (&exp); + if (exp.X_op == O_constant) + { + sym = NULL; + value = exp.X_add_number; + addend = 0; + } + else if (exp.X_op == O_symbol) + { + sym = exp.X_add_symbol; + value = 0; + addend = exp.X_add_number; + } + else + { + sym = make_expr_symbol (&exp); + value = 0; + addend = 0; + } + } + + indx = ECOFF_MARK_STAB (type); + } + + /* Don't store the stabs symbol we are creating as the type of the + ECOFF symbol. We want to compute the type of the ECOFF symbol + independently. */ + if (sym != (symbolS *) NULL) + hold = symbol_get_obj (sym)->ecoff_symbol; + + (void) add_ecoff_symbol (string, st, sc, sym, addend, value, indx); + + if (sym != (symbolS *) NULL) + symbol_get_obj (sym)->ecoff_symbol = hold; + + /* Restore normal file type. */ + cur_file_ptr = save_file_ptr; +} + +/* Frob an ECOFF symbol. Small common symbols go into a special + .scommon section rather than bfd_com_section. */ + +void +ecoff_frob_symbol (sym) + symbolS *sym; +{ + if (S_IS_COMMON (sym) + && S_GET_VALUE (sym) > 0 + && S_GET_VALUE (sym) <= bfd_get_gp_size (stdoutput)) + { + static asection scom_section; + static asymbol scom_symbol; + + /* We must construct a fake section similar to bfd_com_section + but with the name .scommon. */ + if (scom_section.name == NULL) + { + scom_section = bfd_com_section; + scom_section.name = ".scommon"; + scom_section.output_section = &scom_section; + scom_section.symbol = &scom_symbol; + scom_section.symbol_ptr_ptr = &scom_section.symbol; + scom_symbol = *bfd_com_section.symbol; + scom_symbol.name = ".scommon"; + scom_symbol.section = &scom_section; + } + S_SET_SEGMENT (sym, &scom_section); + } + + /* Double check weak symbols. */ + if (S_IS_WEAK (sym)) + { + if (S_IS_COMMON (sym)) + as_bad (_("symbol `%s' can not be both weak and common"), + S_GET_NAME (sym)); + } +} + +/* Add bytes to the symbolic information buffer. */ + +static char * +ecoff_add_bytes (buf, bufend, bufptr, need) + char **buf; + char **bufend; + char *bufptr; + unsigned long need; +{ + unsigned long at; + unsigned long want; + + at = bufptr - *buf; + need -= *bufend - bufptr; + if (need < PAGE_SIZE) + need = PAGE_SIZE; + want = (*bufend - *buf) + need; + *buf = xrealloc (*buf, want); + *bufend = *buf + want; + return *buf + at; +} + +/* Adjust the symbolic information buffer to the alignment required + for the ECOFF target debugging information. */ + +static unsigned long +ecoff_padding_adjust (backend, buf, bufend, offset, bufptrptr) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; + char **bufptrptr; +{ + bfd_size_type align; + + align = backend->debug_align; + if ((offset & (align - 1)) != 0) + { + unsigned long add; + + add = align - (offset & (align - 1)); + if ((unsigned long) (*bufend - (*buf + offset)) < add) + (void) ecoff_add_bytes (buf, bufend, *buf + offset, add); + memset (*buf + offset, 0, add); + offset += add; + if (bufptrptr != (char **) NULL) + *bufptrptr = *buf + offset; + } + + return offset; +} + +/* Build the line number information. */ + +static unsigned long +ecoff_build_lineno (backend, buf, bufend, offset, linecntptr) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; + long *linecntptr; +{ + char *bufptr; + register lineno_list_t *l; + lineno_list_t *last; + efdr_t *file; + proc_t *proc; + unsigned long c; + long iline; + long totcount; + lineno_list_t first; + lineno_list_t *local_first_lineno = first_lineno; + + if (linecntptr != (long *) NULL) + *linecntptr = 0; + + bufptr = *buf + offset; + + file = (efdr_t *) NULL; + proc = (proc_t *) NULL; + last = (lineno_list_t *) NULL; + c = offset; + iline = 0; + totcount = 0; + + /* For some reason the address of the first procedure is ignored + when reading line numbers. This doesn't matter if the address of + the first procedure is 0, but when gcc is generating MIPS + embedded PIC code, it will put strings in the .text section + before the first procedure. We cope by inserting a dummy line if + the address of the first procedure is not 0. Hopefully this + won't screw things up too badly. + + Don't do this for ECOFF assembly source line numbers. They work + without this extra attention. */ + if (debug_type != DEBUG_ECOFF + && first_proc_ptr != (proc_t *) NULL + && local_first_lineno != (lineno_list_t *) NULL + && ((S_GET_VALUE (first_proc_ptr->sym->as_sym) + + bfd_get_section_vma (stdoutput, + S_GET_SEGMENT (first_proc_ptr->sym->as_sym))) + != 0)) + { + first.file = local_first_lineno->file; + first.proc = local_first_lineno->proc; + first.frag = &zero_address_frag; + first.paddr = 0; + first.lineno = 0; + + first.next = local_first_lineno; + local_first_lineno = &first; + } + + for (l = local_first_lineno; l != (lineno_list_t *) NULL; l = l->next) + { + long count; + long delta; + + /* Get the offset to the memory address of the next line number + (in words). Do this first, so that we can skip ahead to the + next useful line number entry. */ + if (l->next == (lineno_list_t *) NULL) + { + /* We want a count of zero, but it will be decremented + before it is used. */ + count = 1; + } + else if (l->next->frag->fr_address + l->next->paddr + > l->frag->fr_address + l->paddr) + { + count = ((l->next->frag->fr_address + l->next->paddr + - (l->frag->fr_address + l->paddr)) + >> 2); + } + else + { + /* Don't change last, so we still get the right delta. */ + continue; + } + + if (l->file != file || l->proc != proc) + { + if (l->proc != proc && proc != (proc_t *) NULL) + proc->pdr.lnHigh = last->lineno; + if (l->file != file && file != (efdr_t *) NULL) + { + file->fdr.cbLine = c - file->fdr.cbLineOffset; + file->fdr.cline = totcount + count; + if (linecntptr != (long *) NULL) + *linecntptr += totcount + count; + totcount = 0; + } + + if (l->file != file) + { + efdr_t *last_file = file; + + file = l->file; + if (last_file != (efdr_t *) NULL) + file->fdr.ilineBase + = last_file->fdr.ilineBase + last_file->fdr.cline; + else + file->fdr.ilineBase = 0; + file->fdr.cbLineOffset = c; + } + if (l->proc != proc) + { + proc = l->proc; + if (proc != (proc_t *) NULL) + { + proc->pdr.lnLow = l->lineno; + proc->pdr.cbLineOffset = c - file->fdr.cbLineOffset; + proc->pdr.iline = totcount; + } + } + + last = (lineno_list_t *) NULL; + } + + totcount += count; + + /* Get the offset to this line number. */ + if (last == (lineno_list_t *) NULL) + delta = 0; + else + delta = l->lineno - last->lineno; + + /* Put in the offset to this line number. */ + while (delta != 0) + { + int setcount; + + /* 1 is added to each count read. */ + --count; + /* We can only adjust the word count by up to 15 words at a + time. */ + if (count <= 0x0f) + { + setcount = count; + count = 0; + } + else + { + setcount = 0x0f; + count -= 0x0f; + } + if (delta >= -7 && delta <= 7) + { + if (bufptr >= *bufend) + bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1); + *bufptr++ = setcount + (delta << 4); + delta = 0; + ++c; + } + else + { + int set; + + if (*bufend - bufptr < 3) + bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 3); + *bufptr++ = setcount + (8 << 4); + if (delta < -0x8000) + { + set = -0x8000; + delta += 0x8000; + } + else if (delta > 0x7fff) + { + set = 0x7fff; + delta -= 0x7fff; + } + else + { + set = delta; + delta = 0; + } + *bufptr++ = set >> 8; + *bufptr++ = set & 0xffff; + c += 3; + } + } + + /* Finish adjusting the count. */ + while (count > 0) + { + if (bufptr >= *bufend) + bufptr = ecoff_add_bytes (buf, bufend, bufptr, (long) 1); + /* 1 is added to each count read. */ + --count; + if (count > 0x0f) + { + *bufptr++ = 0x0f; + count -= 0x0f; + } + else + { + *bufptr++ = count; + count = 0; + } + ++c; + } + + ++iline; + last = l; + } + + if (proc != (proc_t *) NULL) + proc->pdr.lnHigh = last->lineno; + if (file != (efdr_t *) NULL) + { + file->fdr.cbLine = c - file->fdr.cbLineOffset; + file->fdr.cline = totcount; + } + + if (linecntptr != (long *) NULL) + *linecntptr += totcount; + + c = ecoff_padding_adjust (backend, buf, bufend, c, &bufptr); + + return c; +} + +/* Build and swap out the symbols. */ + +static unsigned long +ecoff_build_symbols (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + const bfd_size_type external_sym_size = backend->external_sym_size; + void (* const swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)) + = backend->swap_sym_out; + char *sym_out; + long isym; + vlinks_t *file_link; + + sym_out = *buf + offset; + + isym = 0; + + /* The symbols are stored by file. */ + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int ifilesym; + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + vlinks_t *sym_link; + + fil_ptr->fdr.isymBase = isym; + ifilesym = isym; + for (sym_link = fil_ptr->symbols.first; + sym_link != (vlinks_t *) NULL; + sym_link = sym_link->next) + { + int sym_cnt; + localsym_t *sym_ptr; + localsym_t *sym_end; + + if (sym_link->next == (vlinks_t *) NULL) + sym_cnt = fil_ptr->symbols.objects_last_page; + else + sym_cnt = fil_ptr->symbols.objects_per_page; + sym_ptr = sym_link->datum->sym; + sym_end = sym_ptr + sym_cnt; + for (; sym_ptr < sym_end; sym_ptr++) + { + int local; + symbolS *as_sym; + forward_t *f; + + know (sym_ptr->file_ptr == fil_ptr); + + /* If there is no associated gas symbol, then this + is a pure debugging symbol. We have already + added the name (if any) to fil_ptr->strings. + Otherwise we must decide whether this is an + external or a local symbol (actually, it may be + both if the local provides additional debugging + information for the external). */ + local = 1; + as_sym = sym_ptr->as_sym; + if (as_sym != (symbolS *) NULL) + { + symint_t indx; + + /* The value of a block start symbol is the + offset from the start of the procedure. For + other symbols we just use the gas value (but + we must offset it by the vma of the section, + just as BFD does, because BFD will not see + this value). */ + if (sym_ptr->ecoff_sym.asym.st == (int) st_Block + && sym_ptr->ecoff_sym.asym.sc == (int) sc_Text) + { + symbolS *begin_sym; + + know (sym_ptr->proc_ptr != (proc_t *) NULL); + begin_sym = sym_ptr->proc_ptr->sym->as_sym; + if (S_GET_SEGMENT (as_sym) + != S_GET_SEGMENT (begin_sym)) + as_warn (_(".begin/.bend in different segments")); + sym_ptr->ecoff_sym.asym.value = + S_GET_VALUE (as_sym) - S_GET_VALUE (begin_sym); + } + else + sym_ptr->ecoff_sym.asym.value = + (S_GET_VALUE (as_sym) + + bfd_get_section_vma (stdoutput, + S_GET_SEGMENT (as_sym)) + + sym_ptr->addend); + + sym_ptr->ecoff_sym.weakext = S_IS_WEAK (as_sym); + + /* Set st_Proc to st_StaticProc for local + functions. */ + if (sym_ptr->ecoff_sym.asym.st == st_Proc + && S_IS_DEFINED (as_sym) + && ! S_IS_EXTERNAL (as_sym) + && ! S_IS_WEAK (as_sym)) + sym_ptr->ecoff_sym.asym.st = st_StaticProc; + + /* Get the type and storage class based on where + the symbol actually wound up. Traditionally, + N_LBRAC and N_RBRAC are *not* relocated. */ + indx = sym_ptr->ecoff_sym.asym.index; + if (sym_ptr->ecoff_sym.asym.st == st_Nil + && sym_ptr->ecoff_sym.asym.sc == sc_Nil + && (! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym) + || ((ECOFF_UNMARK_STAB (indx) != N_LBRAC) + && (ECOFF_UNMARK_STAB (indx) != N_RBRAC)))) + { + segT seg; + const char *segname; + st_t st; + sc_t sc; + + seg = S_GET_SEGMENT (as_sym); + segname = segment_name (seg); + + if (! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym) + && (S_IS_EXTERNAL (as_sym) + || S_IS_WEAK (as_sym) + || ! S_IS_DEFINED (as_sym))) + { + if ((symbol_get_bfdsym (as_sym)->flags + & BSF_FUNCTION) != 0) + st = st_Proc; + else + st = st_Global; + } + else if (seg == text_section) + st = st_Label; + else + st = st_Static; + + if (! S_IS_DEFINED (as_sym)) + { + valueT s; + + s = symbol_get_obj (as_sym)->ecoff_extern_size; + if (s == 0 + || s > bfd_get_gp_size (stdoutput)) + sc = sc_Undefined; + else + { + sc = sc_SUndefined; + sym_ptr->ecoff_sym.asym.value = s; + } +#ifdef S_SET_SIZE + S_SET_SIZE (as_sym, s); +#endif + } + else if (S_IS_COMMON (as_sym)) + { + if (S_GET_VALUE (as_sym) > 0 + && (S_GET_VALUE (as_sym) + <= bfd_get_gp_size (stdoutput))) + sc = sc_SCommon; + else + sc = sc_Common; + } + else if (seg == text_section) + sc = sc_Text; + else if (seg == data_section) + sc = sc_Data; + else if (strcmp (segname, ".rdata") == 0 + || strcmp (segname, ".rodata") == 0) + sc = sc_RData; + else if (strcmp (segname, ".sdata") == 0) + sc = sc_SData; + else if (seg == bss_section) + sc = sc_Bss; + else if (strcmp (segname, ".sbss") == 0) + sc = sc_SBss; + else if (seg == &bfd_abs_section) + sc = sc_Abs; + else + { + /* This must be a user named section. + This is not possible in ECOFF, but it + is in ELF. */ + sc = sc_Data; + } + + sym_ptr->ecoff_sym.asym.st = (int) st; + sym_ptr->ecoff_sym.asym.sc = (int) sc; + } + + /* This is just an external symbol if it is + outside a procedure and it has a type. + FIXME: g++ will generate symbols which have + different names in the debugging information + than the actual symbol. Should we handle + them here? */ + if ((S_IS_EXTERNAL (as_sym) + || S_IS_WEAK (as_sym) + || ! S_IS_DEFINED (as_sym)) + && sym_ptr->proc_ptr == (proc_t *) NULL + && sym_ptr->ecoff_sym.asym.st != (int) st_Nil + && ! ECOFF_IS_STAB (&sym_ptr->ecoff_sym.asym)) + local = 0; + + /* This is just an external symbol if it is a + common symbol. */ + if (S_IS_COMMON (as_sym)) + local = 0; + + /* If an st_end symbol has an associated gas + symbol, then it is a local label created for + a .bend or .end directive. Stabs line + numbers will have \001 in the names. */ + if (local + && sym_ptr->ecoff_sym.asym.st != st_End + && strchr (sym_ptr->name, '\001') == 0) + sym_ptr->ecoff_sym.asym.iss = + add_string (&fil_ptr->strings, + fil_ptr->str_hash, + sym_ptr->name, + (shash_t **) NULL); + } + + /* We now know the index of this symbol; fill in + locations that have been waiting for that + information. */ + if (sym_ptr->begin_ptr != (localsym_t *) NULL) + { + localsym_t *begin_ptr; + st_t begin_type; + + know (local); + begin_ptr = sym_ptr->begin_ptr; + know (begin_ptr->sym_index != -1); + sym_ptr->ecoff_sym.asym.index = begin_ptr->sym_index; + if (sym_ptr->ecoff_sym.asym.sc != (int) sc_Info) + sym_ptr->ecoff_sym.asym.iss = + begin_ptr->ecoff_sym.asym.iss; + + begin_type = begin_ptr->ecoff_sym.asym.st; + if (begin_type == st_File + || begin_type == st_Block) + { + begin_ptr->ecoff_sym.asym.index = + isym - ifilesym + 1; + (*swap_sym_out) (stdoutput, + &begin_ptr->ecoff_sym.asym, + (*buf + + offset + + (begin_ptr->sym_index + * external_sym_size))); + } + else + { + know (begin_ptr->index_ptr != (aux_t *) NULL); + begin_ptr->index_ptr->data.isym = + isym - ifilesym + 1; + } + + /* The value of the symbol marking the end of a + procedure is the size of the procedure. The + value of the symbol marking the end of a + block is the offset from the start of the + procedure to the block. */ + if (begin_type == st_Proc + || begin_type == st_StaticProc) + { + know (as_sym != (symbolS *) NULL); + know (begin_ptr->as_sym != (symbolS *) NULL); + if (S_GET_SEGMENT (as_sym) + != S_GET_SEGMENT (begin_ptr->as_sym)) + as_warn (_(".begin/.bend in different segments")); + sym_ptr->ecoff_sym.asym.value = + (S_GET_VALUE (as_sym) + - S_GET_VALUE (begin_ptr->as_sym)); + + /* If the size is odd, this is probably a + mips16 function; force it to be even. */ + if ((sym_ptr->ecoff_sym.asym.value & 1) != 0) + ++sym_ptr->ecoff_sym.asym.value; + +#ifdef S_SET_SIZE + S_SET_SIZE (begin_ptr->as_sym, + sym_ptr->ecoff_sym.asym.value); +#endif + } + else if (begin_type == st_Block + && sym_ptr->ecoff_sym.asym.sc != (int) sc_Info) + { + symbolS *begin_sym; + + know (as_sym != (symbolS *) NULL); + know (sym_ptr->proc_ptr != (proc_t *) NULL); + begin_sym = sym_ptr->proc_ptr->sym->as_sym; + if (S_GET_SEGMENT (as_sym) + != S_GET_SEGMENT (begin_sym)) + as_warn (_(".begin/.bend in different segments")); + sym_ptr->ecoff_sym.asym.value = + S_GET_VALUE (as_sym) - S_GET_VALUE (begin_sym); + } + } + + for (f = sym_ptr->forward_ref; + f != (forward_t *) NULL; + f = f->next) + { + know (local); + f->ifd_ptr->data.isym = fil_ptr->file_index; + f->index_ptr->data.rndx.index = isym - ifilesym; + } + + if (local) + { + if ((bfd_size_type)(*bufend - sym_out) < external_sym_size) + sym_out = ecoff_add_bytes (buf, bufend, + sym_out, + external_sym_size); + (*swap_sym_out) (stdoutput, &sym_ptr->ecoff_sym.asym, + sym_out); + sym_out += external_sym_size; + + sym_ptr->sym_index = isym; + + if (sym_ptr->proc_ptr != (proc_t *) NULL + && sym_ptr->proc_ptr->sym == sym_ptr) + sym_ptr->proc_ptr->pdr.isym = isym - ifilesym; + + ++isym; + } + + /* Record the local symbol index and file number in + case this is an external symbol. Note that this + destroys the asym.index field. */ + if (as_sym != (symbolS *) NULL + && symbol_get_obj (as_sym)->ecoff_symbol == sym_ptr) + { + if ((sym_ptr->ecoff_sym.asym.st == st_Proc + || sym_ptr->ecoff_sym.asym.st == st_StaticProc) + && local) + sym_ptr->ecoff_sym.asym.index = isym - ifilesym - 1; + sym_ptr->ecoff_sym.ifd = fil_ptr->file_index; + + /* Don't try to merge an FDR which has an + external symbol attached to it. */ + if (S_IS_EXTERNAL (as_sym) || S_IS_WEAK (as_sym)) + fil_ptr->fdr.fMerge = 0; + } + } + } + fil_ptr->fdr.csym = isym - fil_ptr->fdr.isymBase; + } + } + + return offset + isym * external_sym_size; +} + +/* Swap out the procedure information. */ + +static unsigned long +ecoff_build_procs (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + const bfd_size_type external_pdr_size = backend->external_pdr_size; + void (* const swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR)) + = backend->swap_pdr_out; + char *pdr_out; + long iproc; + vlinks_t *file_link; + + pdr_out = *buf + offset; + + iproc = 0; + + /* The procedures are stored by file. */ + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + vlinks_t *proc_link; + int first; + + fil_ptr->fdr.ipdFirst = iproc; + first = 1; + for (proc_link = fil_ptr->procs.first; + proc_link != (vlinks_t *) NULL; + proc_link = proc_link->next) + { + int prc_cnt; + proc_t *proc_ptr; + proc_t *proc_end; + + if (proc_link->next == (vlinks_t *) NULL) + prc_cnt = fil_ptr->procs.objects_last_page; + else + prc_cnt = fil_ptr->procs.objects_per_page; + proc_ptr = proc_link->datum->proc; + proc_end = proc_ptr + prc_cnt; + for (; proc_ptr < proc_end; proc_ptr++) + { + symbolS *adr_sym; + unsigned long adr; + + adr_sym = proc_ptr->sym->as_sym; + adr = (S_GET_VALUE (adr_sym) + + bfd_get_section_vma (stdoutput, + S_GET_SEGMENT (adr_sym))); + if (first) + { + /* This code used to force the adr of the very + first fdr to be 0. However, the native tools + don't do that, and I can't remember why it + used to work that way, so I took it out. */ + fil_ptr->fdr.adr = adr; + first = 0; + } + proc_ptr->pdr.adr = adr - fil_ptr->fdr.adr; + if ((bfd_size_type)(*bufend - pdr_out) < external_pdr_size) + pdr_out = ecoff_add_bytes (buf, bufend, + pdr_out, + external_pdr_size); + (*swap_pdr_out) (stdoutput, &proc_ptr->pdr, pdr_out); + pdr_out += external_pdr_size; + ++iproc; + } + } + fil_ptr->fdr.cpd = iproc - fil_ptr->fdr.ipdFirst; + } + } + + return offset + iproc * external_pdr_size; +} + +/* Swap out the aux information. */ + +static unsigned long +ecoff_build_aux (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + int bigendian; + union aux_ext *aux_out; + long iaux; + vlinks_t *file_link; + + bigendian = bfd_big_endian (stdoutput); + + aux_out = (union aux_ext *) (*buf + offset); + + iaux = 0; + + /* The aux entries are stored by file. */ + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + vlinks_t *aux_link; + + fil_ptr->fdr.fBigendian = bigendian; + fil_ptr->fdr.iauxBase = iaux; + for (aux_link = fil_ptr->aux_syms.first; + aux_link != (vlinks_t *) NULL; + aux_link = aux_link->next) + { + int aux_cnt; + aux_t *aux_ptr; + aux_t *aux_end; + + if (aux_link->next == (vlinks_t *) NULL) + aux_cnt = fil_ptr->aux_syms.objects_last_page; + else + aux_cnt = fil_ptr->aux_syms.objects_per_page; + aux_ptr = aux_link->datum->aux; + aux_end = aux_ptr + aux_cnt; + for (; aux_ptr < aux_end; aux_ptr++) + { + if ((unsigned long) (*bufend - (char *) aux_out) + < sizeof (union aux_ext)) + aux_out = ((union aux_ext *) + ecoff_add_bytes (buf, bufend, + (char *) aux_out, + sizeof (union aux_ext))); + switch (aux_ptr->type) + { + case aux_tir: + (*backend->swap_tir_out) (bigendian, + &aux_ptr->data.ti, + &aux_out->a_ti); + break; + case aux_rndx: + (*backend->swap_rndx_out) (bigendian, + &aux_ptr->data.rndx, + &aux_out->a_rndx); + break; + case aux_dnLow: + AUX_PUT_DNLOW (bigendian, aux_ptr->data.dnLow, + aux_out); + break; + case aux_dnHigh: + AUX_PUT_DNHIGH (bigendian, aux_ptr->data.dnHigh, + aux_out); + break; + case aux_isym: + AUX_PUT_ISYM (bigendian, aux_ptr->data.isym, + aux_out); + break; + case aux_iss: + AUX_PUT_ISS (bigendian, aux_ptr->data.iss, + aux_out); + break; + case aux_width: + AUX_PUT_WIDTH (bigendian, aux_ptr->data.width, + aux_out); + break; + case aux_count: + AUX_PUT_COUNT (bigendian, aux_ptr->data.count, + aux_out); + break; + } + + ++aux_out; + ++iaux; + } + } + fil_ptr->fdr.caux = iaux - fil_ptr->fdr.iauxBase; + } + } + + return ecoff_padding_adjust (backend, buf, bufend, + offset + iaux * sizeof (union aux_ext), + (char **) NULL); +} + +/* Copy out the strings from a varray_t. This returns the number of + bytes copied, rather than the new offset. */ + +static unsigned long +ecoff_build_strings (buf, bufend, offset, vp) + char **buf; + char **bufend; + unsigned long offset; + varray_t *vp; +{ + unsigned long istr; + char *str_out; + vlinks_t *str_link; + + str_out = *buf + offset; + + istr = 0; + + for (str_link = vp->first; + str_link != (vlinks_t *) NULL; + str_link = str_link->next) + { + unsigned long str_cnt; + + if (str_link->next == (vlinks_t *) NULL) + str_cnt = vp->objects_last_page; + else + str_cnt = vp->objects_per_page; + + if ((unsigned long)(*bufend - str_out) < str_cnt) + str_out = ecoff_add_bytes (buf, bufend, str_out, str_cnt); + + memcpy (str_out, str_link->datum->byte, str_cnt); + str_out += str_cnt; + istr += str_cnt; + } + + return istr; +} + +/* Dump out the local strings. */ + +static unsigned long +ecoff_build_ss (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + long iss; + vlinks_t *file_link; + + iss = 0; + + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + long ss_cnt; + + fil_ptr->fdr.issBase = iss; + ss_cnt = ecoff_build_strings (buf, bufend, offset + iss, + &fil_ptr->strings); + fil_ptr->fdr.cbSs = ss_cnt; + iss += ss_cnt; + } + } + + return ecoff_padding_adjust (backend, buf, bufend, offset + iss, + (char **) NULL); +} + +/* Swap out the file descriptors. */ + +static unsigned long +ecoff_build_fdr (backend, buf, bufend, offset) + const struct ecoff_debug_swap *backend; + char **buf; + char **bufend; + unsigned long offset; +{ + const bfd_size_type external_fdr_size = backend->external_fdr_size; + void (* const swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)) + = backend->swap_fdr_out; + long ifile; + char *fdr_out; + vlinks_t *file_link; + + ifile = 0; + + fdr_out = *buf + offset; + + for (file_link = file_desc.first; + file_link != (vlinks_t *) NULL; + file_link = file_link->next) + { + int fil_cnt; + efdr_t *fil_ptr; + efdr_t *fil_end; + + if (file_link->next == (vlinks_t *) NULL) + fil_cnt = file_desc.objects_last_page; + else + fil_cnt = file_desc.objects_per_page; + fil_ptr = file_link->datum->file; + fil_end = fil_ptr + fil_cnt; + for (; fil_ptr < fil_end; fil_ptr++) + { + if ((bfd_size_type)(*bufend - fdr_out) < external_fdr_size) + fdr_out = ecoff_add_bytes (buf, bufend, fdr_out, + external_fdr_size); + (*swap_fdr_out) (stdoutput, &fil_ptr->fdr, fdr_out); + fdr_out += external_fdr_size; + ++ifile; + } + } + + return offset + ifile * external_fdr_size; +} + +/* Set up the external symbols. These are supposed to be handled by + the backend. This routine just gets the right information and + calls a backend function to deal with it. */ + +static void +ecoff_setup_ext () +{ + register symbolS *sym; + + for (sym = symbol_rootP; sym != (symbolS *) NULL; sym = symbol_next (sym)) + { + if (symbol_get_obj (sym)->ecoff_symbol == NULL) + continue; + + /* If this is a local symbol, then force the fields to zero. */ + if (! S_IS_EXTERNAL (sym) + && ! S_IS_WEAK (sym) + && S_IS_DEFINED (sym)) + { + struct localsym *lsym; + + lsym = symbol_get_obj (sym)->ecoff_symbol; + lsym->ecoff_sym.asym.value = 0; + lsym->ecoff_sym.asym.st = (int) st_Nil; + lsym->ecoff_sym.asym.sc = (int) sc_Nil; + lsym->ecoff_sym.asym.index = indexNil; + } + + obj_ecoff_set_ext (sym, &symbol_get_obj (sym)->ecoff_symbol->ecoff_sym); + } +} + +/* Build the ECOFF debugging information. */ + +unsigned long +ecoff_build_debug (hdr, bufp, backend) + HDRR *hdr; + char **bufp; + const struct ecoff_debug_swap *backend; +{ + const bfd_size_type external_pdr_size = backend->external_pdr_size; + tag_t *ptag; + tag_t *ptag_next; + efdr_t *fil_ptr; + int end_warning; + efdr_t *hold_file_ptr; + proc_t *hold_proc_ptr; + symbolS *sym; + char *buf; + char *bufend; + unsigned long offset; + + /* Make sure we have a file. */ + if (first_file == (efdr_t *) NULL) + add_file ((const char *) NULL, 0, 1); + + /* Handle any top level tags. */ + for (ptag = top_tag_head->first_tag; + ptag != (tag_t *) NULL; + ptag = ptag_next) + { + if (ptag->forward_ref != (forward_t *) NULL) + add_unknown_tag (ptag); + + ptag_next = ptag->same_block; + ptag->hash_ptr->tag_ptr = ptag->same_name; + free_tag (ptag); + } + + free_thead (top_tag_head); + + /* Look through the symbols. Add debugging information for each + symbol that has not already received it. */ + hold_file_ptr = cur_file_ptr; + hold_proc_ptr = cur_proc_ptr; + cur_proc_ptr = (proc_t *) NULL; + for (sym = symbol_rootP; sym != (symbolS *) NULL; sym = symbol_next (sym)) + { + if (symbol_get_obj (sym)->ecoff_symbol != NULL + || symbol_get_obj (sym)->ecoff_file == (efdr_t *) NULL + || (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0) + continue; + + cur_file_ptr = symbol_get_obj (sym)->ecoff_file; + add_ecoff_symbol ((const char *) NULL, st_Nil, sc_Nil, sym, + (bfd_vma) 0, S_GET_VALUE (sym), indexNil); + } + cur_proc_ptr = hold_proc_ptr; + cur_file_ptr = hold_file_ptr; + + /* Output an ending symbol for all the files. We have to do this + here for the last file, so we may as well do it for all of the + files. */ + end_warning = 0; + for (fil_ptr = first_file; + fil_ptr != (efdr_t *) NULL; + fil_ptr = fil_ptr->next_file) + { + cur_file_ptr = fil_ptr; + while (cur_file_ptr->cur_scope != (scope_t *) NULL + && cur_file_ptr->cur_scope->prev != (scope_t *) NULL) + { + cur_file_ptr->cur_scope = cur_file_ptr->cur_scope->prev; + if (! end_warning && ! cur_file_ptr->fake) + { + as_warn (_("missing .end or .bend at end of file")); + end_warning = 1; + } + } + if (cur_file_ptr->cur_scope != (scope_t *) NULL) + (void) add_ecoff_symbol ((const char *) NULL, + st_End, sc_Text, + (symbolS *) NULL, + (bfd_vma) 0, + (symint_t) 0, + (symint_t) 0); + } + + /* Build the symbolic information. */ + offset = 0; + buf = xmalloc (PAGE_SIZE); + bufend = buf + PAGE_SIZE; + + /* Build the line number information. */ + hdr->cbLineOffset = offset; + offset = ecoff_build_lineno (backend, &buf, &bufend, offset, + &hdr->ilineMax); + hdr->cbLine = offset - hdr->cbLineOffset; + + /* We don't use dense numbers at all. */ + hdr->idnMax = 0; + hdr->cbDnOffset = 0; + + /* We can't build the PDR table until we have built the symbols, + because a PDR contains a symbol index. However, we set aside + space at this point. */ + hdr->ipdMax = proc_cnt; + hdr->cbPdOffset = offset; + if ((bfd_size_type)(bufend - (buf + offset)) < proc_cnt * external_pdr_size) + (void) ecoff_add_bytes (&buf, &bufend, buf + offset, + proc_cnt * external_pdr_size); + offset += proc_cnt * external_pdr_size; + + /* Build the local symbols. */ + hdr->cbSymOffset = offset; + offset = ecoff_build_symbols (backend, &buf, &bufend, offset); + hdr->isymMax = (offset - hdr->cbSymOffset) / backend->external_sym_size; + + /* Building the symbols initializes the symbol index in the PDR's. + Now we can swap out the PDR's. */ + (void) ecoff_build_procs (backend, &buf, &bufend, hdr->cbPdOffset); + + /* We don't use optimization symbols. */ + hdr->ioptMax = 0; + hdr->cbOptOffset = 0; + + /* Swap out the auxiliary type information. */ + hdr->cbAuxOffset = offset; + offset = ecoff_build_aux (backend, &buf, &bufend, offset); + hdr->iauxMax = (offset - hdr->cbAuxOffset) / sizeof (union aux_ext); + + /* Copy out the local strings. */ + hdr->cbSsOffset = offset; + offset = ecoff_build_ss (backend, &buf, &bufend, offset); + hdr->issMax = offset - hdr->cbSsOffset; + + /* We don't use relative file descriptors. */ + hdr->crfd = 0; + hdr->cbRfdOffset = 0; + + /* Swap out the file descriptors. */ + hdr->cbFdOffset = offset; + offset = ecoff_build_fdr (backend, &buf, &bufend, offset); + hdr->ifdMax = (offset - hdr->cbFdOffset) / backend->external_fdr_size; + + /* Set up the external symbols, which are handled by the BFD back + end. */ + hdr->issExtMax = 0; + hdr->cbSsExtOffset = 0; + hdr->iextMax = 0; + hdr->cbExtOffset = 0; + ecoff_setup_ext (); + + know ((offset & (backend->debug_align - 1)) == 0); + + /* FIXME: This value should be determined from the .verstamp directive, + with reasonable defaults in config files. */ +#ifdef TC_ALPHA + hdr->vstamp = 0x030b; +#else + hdr->vstamp = 0x020b; +#endif + + *bufp = buf; + return offset; +} + +/* Allocate a cluster of pages. */ + +#ifndef MALLOC_CHECK + +static page_type * +allocate_cluster (npages) + unsigned long npages; +{ + register page_type *value = (page_type *) xmalloc (npages * PAGE_USIZE); + +#ifdef ECOFF_DEBUG + if (debug > 3) + fprintf (stderr, "\talloc\tnpages = %d, value = 0x%.8x\n", npages, value); +#endif + + memset (value, 0, npages * PAGE_USIZE); + + return value; +} + +static page_type *cluster_ptr = NULL; +static unsigned long pages_left = 0; + +#endif /* MALLOC_CHECK */ + +/* Allocate one page (which is initialized to 0). */ + +static page_type * +allocate_page () +{ +#ifndef MALLOC_CHECK + + if (pages_left == 0) + { + pages_left = MAX_CLUSTER_PAGES; + cluster_ptr = allocate_cluster (pages_left); + } + + pages_left--; + return cluster_ptr++; + +#else /* MALLOC_CHECK */ + + page_type *ptr; + + ptr = xmalloc (PAGE_USIZE); + memset (ptr, 0, PAGE_USIZE); + return ptr; + +#endif /* MALLOC_CHECK */ +} + +/* Allocate scoping information. */ + +static scope_t * +allocate_scope () +{ + register scope_t *ptr; + static scope_t initial_scope; + +#ifndef MALLOC_CHECK + + ptr = alloc_counts[(int) alloc_type_scope].free_list.f_scope; + if (ptr != (scope_t *) NULL) + alloc_counts[(int) alloc_type_scope].free_list.f_scope = ptr->free; + else + { + register int unallocated = alloc_counts[(int) alloc_type_scope].unallocated; + register page_type *cur_page = alloc_counts[(int) alloc_type_scope].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (scope_t); + alloc_counts[(int) alloc_type_scope].cur_page = cur_page = allocate_page (); + alloc_counts[(int) alloc_type_scope].total_pages++; + } + + ptr = &cur_page->scope[--unallocated]; + alloc_counts[(int) alloc_type_scope].unallocated = unallocated; + } + +#else + + ptr = (scope_t *) xmalloc (sizeof (scope_t)); + +#endif + + alloc_counts[(int) alloc_type_scope].total_alloc++; + *ptr = initial_scope; + return ptr; +} + +/* Free scoping information. */ + +static void +free_scope (ptr) + scope_t *ptr; +{ + alloc_counts[(int) alloc_type_scope].total_free++; + +#ifndef MALLOC_CHECK + ptr->free = alloc_counts[(int) alloc_type_scope].free_list.f_scope; + alloc_counts[(int) alloc_type_scope].free_list.f_scope = ptr; +#else + free ((PTR) ptr); +#endif +} + +/* Allocate links for pages in a virtual array. */ + +static vlinks_t * +allocate_vlinks () +{ + register vlinks_t *ptr; + static vlinks_t initial_vlinks; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int) alloc_type_vlinks].unallocated; + register page_type *cur_page = alloc_counts[(int) alloc_type_vlinks].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (vlinks_t); + alloc_counts[(int) alloc_type_vlinks].cur_page = cur_page = allocate_page (); + alloc_counts[(int) alloc_type_vlinks].total_pages++; + } + + ptr = &cur_page->vlinks[--unallocated]; + alloc_counts[(int) alloc_type_vlinks].unallocated = unallocated; + +#else + + ptr = (vlinks_t *) xmalloc (sizeof (vlinks_t)); + +#endif + + alloc_counts[(int) alloc_type_vlinks].total_alloc++; + *ptr = initial_vlinks; + return ptr; +} + +/* Allocate string hash buckets. */ + +static shash_t * +allocate_shash () +{ + register shash_t *ptr; + static shash_t initial_shash; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int) alloc_type_shash].unallocated; + register page_type *cur_page = alloc_counts[(int) alloc_type_shash].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (shash_t); + alloc_counts[(int) alloc_type_shash].cur_page = cur_page = allocate_page (); + alloc_counts[(int) alloc_type_shash].total_pages++; + } + + ptr = &cur_page->shash[--unallocated]; + alloc_counts[(int) alloc_type_shash].unallocated = unallocated; + +#else + + ptr = (shash_t *) xmalloc (sizeof (shash_t)); + +#endif + + alloc_counts[(int) alloc_type_shash].total_alloc++; + *ptr = initial_shash; + return ptr; +} + +/* Allocate type hash buckets. */ + +static thash_t * +allocate_thash () +{ + register thash_t *ptr; + static thash_t initial_thash; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int) alloc_type_thash].unallocated; + register page_type *cur_page = alloc_counts[(int) alloc_type_thash].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (thash_t); + alloc_counts[(int) alloc_type_thash].cur_page = cur_page = allocate_page (); + alloc_counts[(int) alloc_type_thash].total_pages++; + } + + ptr = &cur_page->thash[--unallocated]; + alloc_counts[(int) alloc_type_thash].unallocated = unallocated; + +#else + + ptr = (thash_t *) xmalloc (sizeof (thash_t)); + +#endif + + alloc_counts[(int) alloc_type_thash].total_alloc++; + *ptr = initial_thash; + return ptr; +} + +/* Allocate structure, union, or enum tag information. */ + +static tag_t * +allocate_tag () +{ + register tag_t *ptr; + static tag_t initial_tag; + +#ifndef MALLOC_CHECK + + ptr = alloc_counts[(int) alloc_type_tag].free_list.f_tag; + if (ptr != (tag_t *) NULL) + alloc_counts[(int) alloc_type_tag].free_list.f_tag = ptr->free; + else + { + register int unallocated = alloc_counts[(int) alloc_type_tag].unallocated; + register page_type *cur_page = alloc_counts[(int) alloc_type_tag].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (tag_t); + alloc_counts[(int) alloc_type_tag].cur_page = cur_page = allocate_page (); + alloc_counts[(int) alloc_type_tag].total_pages++; + } + + ptr = &cur_page->tag[--unallocated]; + alloc_counts[(int) alloc_type_tag].unallocated = unallocated; + } + +#else + + ptr = (tag_t *) xmalloc (sizeof (tag_t)); + +#endif + + alloc_counts[(int) alloc_type_tag].total_alloc++; + *ptr = initial_tag; + return ptr; +} + +/* Free scoping information. */ + +static void +free_tag (ptr) + tag_t *ptr; +{ + alloc_counts[(int) alloc_type_tag].total_free++; + +#ifndef MALLOC_CHECK + ptr->free = alloc_counts[(int) alloc_type_tag].free_list.f_tag; + alloc_counts[(int) alloc_type_tag].free_list.f_tag = ptr; +#else + free ((PTR_T) ptr); +#endif +} + +/* Allocate forward reference to a yet unknown tag. */ + +static forward_t * +allocate_forward () +{ + register forward_t *ptr; + static forward_t initial_forward; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int) alloc_type_forward].unallocated; + register page_type *cur_page = alloc_counts[(int) alloc_type_forward].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (forward_t); + alloc_counts[(int) alloc_type_forward].cur_page = cur_page = allocate_page (); + alloc_counts[(int) alloc_type_forward].total_pages++; + } + + ptr = &cur_page->forward[--unallocated]; + alloc_counts[(int) alloc_type_forward].unallocated = unallocated; + +#else + + ptr = (forward_t *) xmalloc (sizeof (forward_t)); + +#endif + + alloc_counts[(int) alloc_type_forward].total_alloc++; + *ptr = initial_forward; + return ptr; +} + +/* Allocate head of type hash list. */ + +static thead_t * +allocate_thead () +{ + register thead_t *ptr; + static thead_t initial_thead; + +#ifndef MALLOC_CHECK + + ptr = alloc_counts[(int) alloc_type_thead].free_list.f_thead; + if (ptr != (thead_t *) NULL) + alloc_counts[(int) alloc_type_thead].free_list.f_thead = ptr->free; + else + { + register int unallocated = alloc_counts[(int) alloc_type_thead].unallocated; + register page_type *cur_page = alloc_counts[(int) alloc_type_thead].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (thead_t); + alloc_counts[(int) alloc_type_thead].cur_page = cur_page = allocate_page (); + alloc_counts[(int) alloc_type_thead].total_pages++; + } + + ptr = &cur_page->thead[--unallocated]; + alloc_counts[(int) alloc_type_thead].unallocated = unallocated; + } + +#else + + ptr = (thead_t *) xmalloc (sizeof (thead_t)); + +#endif + + alloc_counts[(int) alloc_type_thead].total_alloc++; + *ptr = initial_thead; + return ptr; +} + +/* Free scoping information. */ + +static void +free_thead (ptr) + thead_t *ptr; +{ + alloc_counts[(int) alloc_type_thead].total_free++; + +#ifndef MALLOC_CHECK + ptr->free = (thead_t *) alloc_counts[(int) alloc_type_thead].free_list.f_thead; + alloc_counts[(int) alloc_type_thead].free_list.f_thead = ptr; +#else + free ((PTR_T) ptr); +#endif +} + +static lineno_list_t * +allocate_lineno_list () +{ + register lineno_list_t *ptr; + static lineno_list_t initial_lineno_list; + +#ifndef MALLOC_CHECK + + register int unallocated = alloc_counts[(int) alloc_type_lineno].unallocated; + register page_type *cur_page = alloc_counts[(int) alloc_type_lineno].cur_page; + + if (unallocated == 0) + { + unallocated = PAGE_SIZE / sizeof (lineno_list_t); + alloc_counts[(int) alloc_type_lineno].cur_page = cur_page = allocate_page (); + alloc_counts[(int) alloc_type_lineno].total_pages++; + } + + ptr = &cur_page->lineno[--unallocated]; + alloc_counts[(int) alloc_type_lineno].unallocated = unallocated; + +#else + + ptr = (lineno_list_t *) xmalloc (sizeof (lineno_list_t)); + +#endif + + alloc_counts[(int) alloc_type_lineno].total_alloc++; + *ptr = initial_lineno_list; + return ptr; +} + +void +ecoff_set_gp_prolog_size (sz) + int sz; +{ + if (cur_proc_ptr == 0) + return; + + cur_proc_ptr->pdr.gp_prologue = sz; + if (cur_proc_ptr->pdr.gp_prologue != sz) + { + as_warn (_("GP prologue size exceeds field size, using 0 instead")); + cur_proc_ptr->pdr.gp_prologue = 0; + } + + cur_proc_ptr->pdr.gp_used = 1; +} + +int +ecoff_no_current_file () +{ + return cur_file_ptr == (efdr_t *) NULL; +} + +void +ecoff_generate_asm_lineno () +{ + unsigned int lineno; + char *filename; + lineno_list_t *list; + + as_where (&filename, &lineno); + + if (current_stabs_filename == (char *) NULL + || strcmp (current_stabs_filename, filename)) + add_file (filename, 0, 1); + + list = allocate_lineno_list (); + + list->next = (lineno_list_t *) NULL; + list->file = cur_file_ptr; + list->proc = cur_proc_ptr; + list->frag = frag_now; + list->paddr = frag_now_fix (); + list->lineno = lineno; + + /* We don't want to merge files which have line numbers. */ + cur_file_ptr->fdr.fMerge = 0; + + /* A .loc directive will sometimes appear before a .ent directive, + which means that cur_proc_ptr will be NULL here. Arrange to + patch this up. */ + if (cur_proc_ptr == (proc_t *) NULL) + { + lineno_list_t **pl; + + pl = &noproc_lineno; + while (*pl != (lineno_list_t *) NULL) + pl = &(*pl)->next; + *pl = list; + } + else + { + last_lineno = list; + *last_lineno_ptr = list; + last_lineno_ptr = &list->next; + } +} + +#else + +void +ecoff_generate_asm_lineno () +{ +} + +#endif /* ECOFF_DEBUGGING */ diff --git a/contrib/binutils-2.14/gas/ecoff.h b/contrib/binutils-2.14/gas/ecoff.h new file mode 100644 index 0000000000..f6b96c61a2 --- /dev/null +++ b/contrib/binutils-2.14/gas/ecoff.h @@ -0,0 +1,111 @@ +/* ecoff.h -- header file for ECOFF debugging support + Copyright 1993, 1994, 1995, 1996, 1997, 1998 + Free Software Foundation, Inc. + Contributed by Cygnus Support. + Put together by Ian Lance Taylor . + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef GAS_ECOFF_H +#define GAS_ECOFF_H + +#ifdef ECOFF_DEBUGGING + +#include "coff/sym.h" +#include "coff/ecoff.h" + +/* Whether we have seen any ECOFF debugging information. */ +extern int ecoff_debugging_seen; + +/* This function should be called at the start of assembly, by + obj_read_begin_hook. */ +extern void ecoff_read_begin_hook PARAMS ((void)); + +/* This function should be called when the assembler switches to a new + file. */ +extern void ecoff_new_file PARAMS ((const char *)); + +/* This function should be called when a new symbol is created, by + obj_symbol_new_hook. */ +extern void ecoff_symbol_new_hook PARAMS ((symbolS *)); + +/* This function should be called by the obj_frob_symbol hook. */ +extern void ecoff_frob_symbol PARAMS ((symbolS *)); + +/* Build the ECOFF debugging information. This should be called by + obj_frob_file. This fills in the counts in *HDR; the offsets are + filled in relative to the start of the *BUFP. It sets *BUFP to a + block of memory holding the debugging information. It returns the + length of *BUFP. */ +extern unsigned long ecoff_build_debug + PARAMS ((HDRR *hdr, char **bufp, const struct ecoff_debug_swap *)); + +/* Functions to handle the ECOFF debugging directives. */ +extern void ecoff_directive_begin PARAMS ((int)); +extern void ecoff_directive_bend PARAMS ((int)); +extern void ecoff_directive_end PARAMS ((int)); +extern void ecoff_directive_ent PARAMS ((int)); +extern void ecoff_directive_fmask PARAMS ((int)); +extern void ecoff_directive_frame PARAMS ((int)); +extern void ecoff_directive_loc PARAMS ((int)); +extern void ecoff_directive_mask PARAMS ((int)); + +/* Other ECOFF directives. */ +extern void ecoff_directive_extern PARAMS ((int)); +extern void ecoff_directive_weakext PARAMS ((int)); + +/* Functions to handle the COFF debugging directives. */ +extern void ecoff_directive_def PARAMS ((int)); +extern void ecoff_directive_dim PARAMS ((int)); +extern void ecoff_directive_endef PARAMS ((int)); +extern void ecoff_directive_file PARAMS ((int)); +extern void ecoff_directive_scl PARAMS ((int)); +extern void ecoff_directive_size PARAMS ((int)); +extern void ecoff_directive_tag PARAMS ((int)); +extern void ecoff_directive_type PARAMS ((int)); +extern void ecoff_directive_val PARAMS ((int)); + +/* Handle stabs. */ +extern void ecoff_stab PARAMS ((segT sec, int what, const char *string, + int type, int other, int desc)); + +/* Set the GP prologue size. */ +extern void ecoff_set_gp_prolog_size PARAMS ((int sz)); + +/* This routine is called from the ECOFF code to set the external + information for a symbol. */ +#ifndef obj_ecoff_set_ext +extern void obj_ecoff_set_ext PARAMS ((symbolS *, EXTR *)); +#endif + +/* This routine is used to patch up a line number directive when + instructions are moved around. */ +extern void ecoff_fix_loc PARAMS ((fragS *, unsigned long)); + +/* This function is called from read.c to peek at cur_file_ptr. */ +extern int ecoff_no_current_file PARAMS ((void)); + +/* This function returns the symbol associated with the current proc. */ +extern symbolS *ecoff_get_cur_proc_sym PARAMS ((void)); + +#endif /* ECOFF_DEBUGGING */ + +/* This routine is called from read.c to generate line number for .s file. */ +extern void ecoff_generate_asm_lineno PARAMS ((void)); + +#endif /* ! GAS_ECOFF_H */ diff --git a/contrib/binutils-2.14/gas/ehopt.c b/contrib/binutils-2.14/gas/ehopt.c new file mode 100644 index 0000000000..6e19ae69bf --- /dev/null +++ b/contrib/binutils-2.14/gas/ehopt.c @@ -0,0 +1,546 @@ +/* ehopt.c--optimize gcc exception frame information. + Copyright 1998, 2000, 2001, 2003 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "as.h" +#include "subsegs.h" + +/* We include this ELF file, even though we may not be assembling for + ELF, since the exception frame information is always in a format + derived from DWARF. */ + +#include "elf/dwarf2.h" + +/* Try to optimize gcc 2.8 exception frame information. + + Exception frame information is emitted for every function in the + .eh_frame or .debug_frame sections. Simple information for a function + with no exceptions looks like this: + +__FRAME_BEGIN__: + .4byte .LLCIE1 / Length of Common Information Entry +.LSCIE1: +#if .eh_frame + .4byte 0x0 / CIE Identifier Tag +#elif .debug_frame + .4byte 0xffffffff / CIE Identifier Tag +#endif + .byte 0x1 / CIE Version + .byte 0x0 / CIE Augmentation (none) + .byte 0x1 / ULEB128 0x1 (CIE Code Alignment Factor) + .byte 0x7c / SLEB128 -4 (CIE Data Alignment Factor) + .byte 0x8 / CIE RA Column + .byte 0xc / DW_CFA_def_cfa + .byte 0x4 / ULEB128 0x4 + .byte 0x4 / ULEB128 0x4 + .byte 0x88 / DW_CFA_offset, column 0x8 + .byte 0x1 / ULEB128 0x1 + .align 4 +.LECIE1: + .set .LLCIE1,.LECIE1-.LSCIE1 / CIE Length Symbol + .4byte .LLFDE1 / FDE Length +.LSFDE1: + .4byte .LSFDE1-__FRAME_BEGIN__ / FDE CIE offset + .4byte .LFB1 / FDE initial location + .4byte .LFE1-.LFB1 / FDE address range + .byte 0x4 / DW_CFA_advance_loc4 + .4byte .LCFI0-.LFB1 + .byte 0xe / DW_CFA_def_cfa_offset + .byte 0x8 / ULEB128 0x8 + .byte 0x85 / DW_CFA_offset, column 0x5 + .byte 0x2 / ULEB128 0x2 + .byte 0x4 / DW_CFA_advance_loc4 + .4byte .LCFI1-.LCFI0 + .byte 0xd / DW_CFA_def_cfa_register + .byte 0x5 / ULEB128 0x5 + .byte 0x4 / DW_CFA_advance_loc4 + .4byte .LCFI2-.LCFI1 + .byte 0x2e / DW_CFA_GNU_args_size + .byte 0x4 / ULEB128 0x4 + .byte 0x4 / DW_CFA_advance_loc4 + .4byte .LCFI3-.LCFI2 + .byte 0x2e / DW_CFA_GNU_args_size + .byte 0x0 / ULEB128 0x0 + .align 4 +.LEFDE1: + .set .LLFDE1,.LEFDE1-.LSFDE1 / FDE Length Symbol + + The immediate issue we can address in the assembler is the + DW_CFA_advance_loc4 followed by a four byte value. The value is + the difference of two addresses in the function. Since gcc does + not know this value, it always uses four bytes. We will know the + value at the end of assembly, so we can do better. */ + +struct cie_info +{ + unsigned code_alignment; + int z_augmentation; +}; + +static int get_cie_info PARAMS ((struct cie_info *)); + +/* Extract information from the CIE. */ + +static int +get_cie_info (info) + struct cie_info *info; +{ + fragS *f; + fixS *fix; + int offset; + char CIE_id; + char augmentation[10]; + int iaug; + int code_alignment = 0; + + /* We should find the CIE at the start of the section. */ + +#if defined (BFD_ASSEMBLER) || defined (MANY_SEGMENTS) + f = seg_info (now_seg)->frchainP->frch_root; +#else + f = frchain_now->frch_root; +#endif +#ifdef BFD_ASSEMBLER + fix = seg_info (now_seg)->frchainP->fix_root; +#else + fix = *seg_fix_rootP; +#endif + + /* Look through the frags of the section to find the code alignment. */ + + /* First make sure that the CIE Identifier Tag is 0/-1. */ + + if (strcmp (segment_name (now_seg), ".debug_frame") == 0) + CIE_id = (char)0xff; + else + CIE_id = 0; + + offset = 4; + while (f != NULL && offset >= f->fr_fix) + { + offset -= f->fr_fix; + f = f->fr_next; + } + if (f == NULL + || f->fr_fix - offset < 4 + || f->fr_literal[offset] != CIE_id + || f->fr_literal[offset + 1] != CIE_id + || f->fr_literal[offset + 2] != CIE_id + || f->fr_literal[offset + 3] != CIE_id) + return 0; + + /* Next make sure the CIE version number is 1. */ + + offset += 4; + while (f != NULL && offset >= f->fr_fix) + { + offset -= f->fr_fix; + f = f->fr_next; + } + if (f == NULL + || f->fr_fix - offset < 1 + || f->fr_literal[offset] != 1) + return 0; + + /* Skip the augmentation (a null terminated string). */ + + iaug = 0; + ++offset; + while (1) + { + while (f != NULL && offset >= f->fr_fix) + { + offset -= f->fr_fix; + f = f->fr_next; + } + if (f == NULL) + return 0; + + while (offset < f->fr_fix && f->fr_literal[offset] != '\0') + { + if ((size_t) iaug < (sizeof augmentation) - 1) + { + augmentation[iaug] = f->fr_literal[offset]; + ++iaug; + } + ++offset; + } + if (offset < f->fr_fix) + break; + } + ++offset; + while (f != NULL && offset >= f->fr_fix) + { + offset -= f->fr_fix; + f = f->fr_next; + } + if (f == NULL) + return 0; + + augmentation[iaug] = '\0'; + if (augmentation[0] == '\0') + { + /* No augmentation. */ + } + else if (strcmp (augmentation, "eh") == 0) + { + /* We have to skip a pointer. Unfortunately, we don't know how + large it is. We find out by looking for a matching fixup. */ + while (fix != NULL + && (fix->fx_frag != f || fix->fx_where != offset)) + fix = fix->fx_next; + if (fix == NULL) + offset += 4; + else + offset += fix->fx_size; + while (f != NULL && offset >= f->fr_fix) + { + offset -= f->fr_fix; + f = f->fr_next; + } + if (f == NULL) + return 0; + } + else if (augmentation[0] != 'z') + return 0; + + /* We're now at the code alignment factor, which is a ULEB128. If + it isn't a single byte, forget it. */ + + code_alignment = f->fr_literal[offset] & 0xff; + if ((code_alignment & 0x80) != 0) + code_alignment = 0; + + info->code_alignment = code_alignment; + info->z_augmentation = (augmentation[0] == 'z'); + + return 1; +} + +/* This function is called from emit_expr. It looks for cases which + we can optimize. + + Rather than try to parse all this information as we read it, we + look for a single byte DW_CFA_advance_loc4 followed by a 4 byte + difference. We turn that into a rs_cfa_advance frag, and handle + those frags at the end of the assembly. If the gcc output changes + somewhat, this optimization may stop working. + + This function returns non-zero if it handled the expression and + emit_expr should not do anything, or zero otherwise. It can also + change *EXP and *PNBYTES. */ + +int +check_eh_frame (exp, pnbytes) + expressionS *exp; + unsigned int *pnbytes; +{ + struct frame_data + { + enum frame_state + { + state_idle, + state_saw_size, + state_saw_cie_offset, + state_saw_pc_begin, + state_seeing_aug_size, + state_skipping_aug, + state_wait_loc4, + state_saw_loc4, + state_error, + } state; + + int cie_info_ok; + struct cie_info cie_info; + + symbolS *size_end_sym; + fragS *loc4_frag; + int loc4_fix; + + int aug_size; + int aug_shift; + }; + + static struct frame_data eh_frame_data; + static struct frame_data debug_frame_data; + struct frame_data *d; + + /* Don't optimize. */ + if (flag_traditional_format) + return 0; + + /* Select the proper section data. */ + if (strcmp (segment_name (now_seg), ".eh_frame") == 0) + d = &eh_frame_data; + else if (strcmp (segment_name (now_seg), ".debug_frame") == 0) + d = &debug_frame_data; + else + return 0; + + if (d->state >= state_saw_size && S_IS_DEFINED (d->size_end_sym)) + { + /* We have come to the end of the CIE or FDE. See below where + we set saw_size. We must check this first because we may now + be looking at the next size. */ + d->state = state_idle; + } + + switch (d->state) + { + case state_idle: + if (*pnbytes == 4) + { + /* This might be the size of the CIE or FDE. We want to know + the size so that we don't accidentally optimize across an FDE + boundary. We recognize the size in one of two forms: a + symbol which will later be defined as a difference, or a + subtraction of two symbols. Either way, we can tell when we + are at the end of the FDE because the symbol becomes defined + (in the case of a subtraction, the end symbol, from which the + start symbol is being subtracted). Other ways of describing + the size will not be optimized. */ + if ((exp->X_op == O_symbol || exp->X_op == O_subtract) + && ! S_IS_DEFINED (exp->X_add_symbol)) + { + d->state = state_saw_size; + d->size_end_sym = exp->X_add_symbol; + } + } + break; + + case state_saw_size: + case state_saw_cie_offset: + /* Assume whatever form it appears in, it appears atomically. */ + d->state += 1; + break; + + case state_saw_pc_begin: + /* Decide whether we should see an augmentation. */ + if (! d->cie_info_ok + && ! (d->cie_info_ok = get_cie_info (&d->cie_info))) + d->state = state_error; + else if (d->cie_info.z_augmentation) + { + d->state = state_seeing_aug_size; + d->aug_size = 0; + d->aug_shift = 0; + } + else + d->state = state_wait_loc4; + break; + + case state_seeing_aug_size: + /* Bytes == -1 means this comes from an leb128 directive. */ + if ((int)*pnbytes == -1 && exp->X_op == O_constant) + { + d->aug_size = exp->X_add_number; + d->state = state_skipping_aug; + } + else if (*pnbytes == 1 && exp->X_op == O_constant) + { + unsigned char byte = exp->X_add_number; + d->aug_size |= (byte & 0x7f) << d->aug_shift; + d->aug_shift += 7; + if ((byte & 0x80) == 0) + d->state = state_skipping_aug; + } + else + d->state = state_error; + if (d->state == state_skipping_aug && d->aug_size == 0) + d->state = state_wait_loc4; + break; + + case state_skipping_aug: + if ((int)*pnbytes < 0) + d->state = state_error; + else + { + int left = (d->aug_size -= *pnbytes); + if (left == 0) + d->state = state_wait_loc4; + else if (left < 0) + d->state = state_error; + } + break; + + case state_wait_loc4: + if (*pnbytes == 1 + && exp->X_op == O_constant + && exp->X_add_number == DW_CFA_advance_loc4) + { + /* This might be a DW_CFA_advance_loc4. Record the frag and the + position within the frag, so that we can change it later. */ + frag_grow (1); + d->state = state_saw_loc4; + d->loc4_frag = frag_now; + d->loc4_fix = frag_now_fix (); + } + break; + + case state_saw_loc4: + d->state = state_wait_loc4; + if (*pnbytes != 4) + break; + if (exp->X_op == O_constant) + { + /* This is a case which we can optimize. The two symbols being + subtracted were in the same frag and the expression was + reduced to a constant. We can do the optimization entirely + in this function. */ + if (d->cie_info.code_alignment > 0 + && exp->X_add_number % d->cie_info.code_alignment == 0 + && exp->X_add_number / d->cie_info.code_alignment < 0x40) + { + d->loc4_frag->fr_literal[d->loc4_fix] + = DW_CFA_advance_loc + | (exp->X_add_number / d->cie_info.code_alignment); + /* No more bytes needed. */ + return 1; + } + else if (exp->X_add_number < 0x100) + { + d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc1; + *pnbytes = 1; + } + else if (exp->X_add_number < 0x10000) + { + d->loc4_frag->fr_literal[d->loc4_fix] = DW_CFA_advance_loc2; + *pnbytes = 2; + } + } + else if (exp->X_op == O_subtract) + { + /* This is a case we can optimize. The expression was not + reduced, so we can not finish the optimization until the end + of the assembly. We set up a variant frag which we handle + later. */ + int fr_subtype; + + if (d->cie_info.code_alignment > 0) + fr_subtype = d->cie_info.code_alignment << 3; + else + fr_subtype = 0; + + frag_var (rs_cfa, 4, 0, fr_subtype, make_expr_symbol (exp), + d->loc4_fix, (char *) d->loc4_frag); + return 1; + } + break; + + case state_error: + /* Just skipping everything. */ + break; + } + + return 0; +} + +/* The function estimates the size of a rs_cfa variant frag based on + the current values of the symbols. It is called before the + relaxation loop. We set fr_subtype{0:2} to the expected length. */ + +int +eh_frame_estimate_size_before_relax (frag) + fragS *frag; +{ + offsetT diff; + int ca = frag->fr_subtype >> 3; + int ret; + + diff = resolve_symbol_value (frag->fr_symbol); + + if (ca > 0 && diff % ca == 0 && diff / ca < 0x40) + ret = 0; + else if (diff < 0x100) + ret = 1; + else if (diff < 0x10000) + ret = 2; + else + ret = 4; + + frag->fr_subtype = (frag->fr_subtype & ~7) | ret; + + return ret; +} + +/* This function relaxes a rs_cfa variant frag based on the current + values of the symbols. fr_subtype{0:2} is the current length of + the frag. This returns the change in frag length. */ + +int +eh_frame_relax_frag (frag) + fragS *frag; +{ + int oldsize, newsize; + + oldsize = frag->fr_subtype & 7; + newsize = eh_frame_estimate_size_before_relax (frag); + return newsize - oldsize; +} + +/* This function converts a rs_cfa variant frag into a normal fill + frag. This is called after all relaxation has been done. + fr_subtype{0:2} will be the desired length of the frag. */ + +void +eh_frame_convert_frag (frag) + fragS *frag; +{ + offsetT diff; + fragS *loc4_frag; + int loc4_fix; + + loc4_frag = (fragS *) frag->fr_opcode; + loc4_fix = (int) frag->fr_offset; + + diff = resolve_symbol_value (frag->fr_symbol); + + switch (frag->fr_subtype & 7) + { + case 0: + { + int ca = frag->fr_subtype >> 3; + assert (ca > 0 && diff % ca == 0 && diff / ca < 0x40); + loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | (diff / ca); + } + break; + + case 1: + assert (diff < 0x100); + loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1; + frag->fr_literal[frag->fr_fix] = diff; + break; + + case 2: + assert (diff < 0x10000); + loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2; + md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2); + break; + + default: + md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4); + break; + } + + frag->fr_fix += frag->fr_subtype & 7; + frag->fr_type = rs_fill; + frag->fr_subtype = 0; + frag->fr_offset = 0; +} diff --git a/contrib/binutils-2.14/gas/expr.c b/contrib/binutils-2.14/gas/expr.c new file mode 100644 index 0000000000..6478887c9c --- /dev/null +++ b/contrib/binutils-2.14/gas/expr.c @@ -0,0 +1,1926 @@ +/* expr.c -operands, expressions- + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This is really a branch office of as-read.c. I split it out to clearly + distinguish the world of expressions from the world of statements. + (It also gives smaller files to re-compile.) + Here, "operand"s are of expressions, not instructions. */ + +#include +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#include "as.h" +#include "safe-ctype.h" +#include "obstack.h" + +static void floating_constant PARAMS ((expressionS * expressionP)); +static valueT generic_bignum_to_int32 PARAMS ((void)); +#ifdef BFD64 +static valueT generic_bignum_to_int64 PARAMS ((void)); +#endif +static void integer_constant PARAMS ((int radix, expressionS * expressionP)); +static void mri_char_constant PARAMS ((expressionS *)); +static void current_location PARAMS ((expressionS *)); +static void clean_up_expression PARAMS ((expressionS * expressionP)); +static segT operand PARAMS ((expressionS *)); +static operatorT operator PARAMS ((int *)); + +extern const char EXP_CHARS[], FLT_CHARS[]; + +/* We keep a mapping of expression symbols to file positions, so that + we can provide better error messages. */ + +struct expr_symbol_line { + struct expr_symbol_line *next; + symbolS *sym; + char *file; + unsigned int line; +}; + +static struct expr_symbol_line *expr_symbol_lines; + +/* Build a dummy symbol to hold a complex expression. This is how we + build expressions up out of other expressions. The symbol is put + into the fake section expr_section. */ + +symbolS * +make_expr_symbol (expressionP) + expressionS *expressionP; +{ + expressionS zero; + const char *fake; + symbolS *symbolP; + struct expr_symbol_line *n; + + if (expressionP->X_op == O_symbol + && expressionP->X_add_number == 0) + return expressionP->X_add_symbol; + + if (expressionP->X_op == O_big) + { + /* This won't work, because the actual value is stored in + generic_floating_point_number or generic_bignum, and we are + going to lose it if we haven't already. */ + if (expressionP->X_add_number > 0) + as_bad (_("bignum invalid")); + else + as_bad (_("floating point number invalid")); + zero.X_op = O_constant; + zero.X_add_number = 0; + zero.X_unsigned = 0; + clean_up_expression (&zero); + expressionP = &zero; + } + + fake = FAKE_LABEL_NAME; + + /* Putting constant symbols in absolute_section rather than + expr_section is convenient for the old a.out code, for which + S_GET_SEGMENT does not always retrieve the value put in by + S_SET_SEGMENT. */ + symbolP = symbol_create (fake, + (expressionP->X_op == O_constant + ? absolute_section + : expr_section), + 0, &zero_address_frag); + symbol_set_value_expression (symbolP, expressionP); + + if (expressionP->X_op == O_constant) + resolve_symbol_value (symbolP); + + n = (struct expr_symbol_line *) xmalloc (sizeof *n); + n->sym = symbolP; + as_where (&n->file, &n->line); + n->next = expr_symbol_lines; + expr_symbol_lines = n; + + return symbolP; +} + +/* Return the file and line number for an expr symbol. Return + non-zero if something was found, 0 if no information is known for + the symbol. */ + +int +expr_symbol_where (sym, pfile, pline) + symbolS *sym; + char **pfile; + unsigned int *pline; +{ + register struct expr_symbol_line *l; + + for (l = expr_symbol_lines; l != NULL; l = l->next) + { + if (l->sym == sym) + { + *pfile = l->file; + *pline = l->line; + return 1; + } + } + + return 0; +} + +/* Utilities for building expressions. + Since complex expressions are recorded as symbols for use in other + expressions these return a symbolS * and not an expressionS *. + These explicitly do not take an "add_number" argument. */ +/* ??? For completeness' sake one might want expr_build_symbol. + It would just return its argument. */ + +/* Build an expression for an unsigned constant. + The corresponding one for signed constants is missing because + there's currently no need for it. One could add an unsigned_p flag + but that seems more clumsy. */ + +symbolS * +expr_build_uconstant (value) + offsetT value; +{ + expressionS e; + + e.X_op = O_constant; + e.X_add_number = value; + e.X_unsigned = 1; + return make_expr_symbol (&e); +} + +/* Build an expression for OP s1. */ + +symbolS * +expr_build_unary (op, s1) + operatorT op; + symbolS *s1; +{ + expressionS e; + + e.X_op = op; + e.X_add_symbol = s1; + e.X_add_number = 0; + return make_expr_symbol (&e); +} + +/* Build an expression for s1 OP s2. */ + +symbolS * +expr_build_binary (op, s1, s2) + operatorT op; + symbolS *s1; + symbolS *s2; +{ + expressionS e; + + e.X_op = op; + e.X_add_symbol = s1; + e.X_op_symbol = s2; + e.X_add_number = 0; + return make_expr_symbol (&e); +} + +/* Build an expression for the current location ('.'). */ + +symbolS * +expr_build_dot () +{ + expressionS e; + + current_location (&e); + return make_expr_symbol (&e); +} + +/* Build any floating-point literal here. + Also build any bignum literal here. */ + +/* Seems atof_machine can backscan through generic_bignum and hit whatever + happens to be loaded before it in memory. And its way too complicated + for me to fix right. Thus a hack. JF: Just make generic_bignum bigger, + and never write into the early words, thus they'll always be zero. + I hate Dean's floating-point code. Bleh. */ +LITTLENUM_TYPE generic_bignum[SIZE_OF_LARGE_NUMBER + 6]; + +FLONUM_TYPE generic_floating_point_number = { + &generic_bignum[6], /* low. (JF: Was 0) */ + &generic_bignum[SIZE_OF_LARGE_NUMBER + 6 - 1], /* high. JF: (added +6) */ + 0, /* leader. */ + 0, /* exponent. */ + 0 /* sign. */ +}; + +/* If nonzero, we've been asked to assemble nan, +inf or -inf. */ +int generic_floating_point_magic; + +static void +floating_constant (expressionP) + expressionS *expressionP; +{ + /* input_line_pointer -> floating-point constant. */ + int error_code; + + error_code = atof_generic (&input_line_pointer, ".", EXP_CHARS, + &generic_floating_point_number); + + if (error_code) + { + if (error_code == ERROR_EXPONENT_OVERFLOW) + { + as_bad (_("bad floating-point constant: exponent overflow")); + } + else + { + as_bad (_("bad floating-point constant: unknown error code=%d"), + error_code); + } + } + expressionP->X_op = O_big; + /* input_line_pointer -> just after constant, which may point to + whitespace. */ + expressionP->X_add_number = -1; +} + +static valueT +generic_bignum_to_int32 () +{ + valueT number = + ((generic_bignum[1] & LITTLENUM_MASK) << LITTLENUM_NUMBER_OF_BITS) + | (generic_bignum[0] & LITTLENUM_MASK); + number &= 0xffffffff; + return number; +} + +#ifdef BFD64 +static valueT +generic_bignum_to_int64 () +{ + valueT number = + ((((((((valueT) generic_bignum[3] & LITTLENUM_MASK) + << LITTLENUM_NUMBER_OF_BITS) + | ((valueT) generic_bignum[2] & LITTLENUM_MASK)) + << LITTLENUM_NUMBER_OF_BITS) + | ((valueT) generic_bignum[1] & LITTLENUM_MASK)) + << LITTLENUM_NUMBER_OF_BITS) + | ((valueT) generic_bignum[0] & LITTLENUM_MASK)); + return number; +} +#endif + +static void +integer_constant (radix, expressionP) + int radix; + expressionS *expressionP; +{ + char *start; /* Start of number. */ + char *suffix = NULL; + char c; + valueT number; /* Offset or (absolute) value. */ + short int digit; /* Value of next digit in current radix. */ + short int maxdig = 0; /* Highest permitted digit value. */ + int too_many_digits = 0; /* If we see >= this number of. */ + char *name; /* Points to name of symbol. */ + symbolS *symbolP; /* Points to symbol. */ + + int small; /* True if fits in 32 bits. */ + + /* May be bignum, or may fit in 32 bits. */ + /* Most numbers fit into 32 bits, and we want this case to be fast. + so we pretend it will fit into 32 bits. If, after making up a 32 + bit number, we realise that we have scanned more digits than + comfortably fit into 32 bits, we re-scan the digits coding them + into a bignum. For decimal and octal numbers we are + conservative: Some numbers may be assumed bignums when in fact + they do fit into 32 bits. Numbers of any radix can have excess + leading zeros: We strive to recognise this and cast them back + into 32 bits. We must check that the bignum really is more than + 32 bits, and change it back to a 32-bit number if it fits. The + number we are looking for is expected to be positive, but if it + fits into 32 bits as an unsigned number, we let it be a 32-bit + number. The cavalier approach is for speed in ordinary cases. */ + /* This has been extended for 64 bits. We blindly assume that if + you're compiling in 64-bit mode, the target is a 64-bit machine. + This should be cleaned up. */ + +#ifdef BFD64 +#define valuesize 64 +#else /* includes non-bfd case, mostly */ +#define valuesize 32 +#endif + + if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) && radix == 0) + { + int flt = 0; + + /* In MRI mode, the number may have a suffix indicating the + radix. For that matter, it might actually be a floating + point constant. */ + for (suffix = input_line_pointer; ISALNUM (*suffix); suffix++) + { + if (*suffix == 'e' || *suffix == 'E') + flt = 1; + } + + if (suffix == input_line_pointer) + { + radix = 10; + suffix = NULL; + } + else + { + c = *--suffix; + c = TOUPPER (c); + if (c == 'B') + radix = 2; + else if (c == 'D') + radix = 10; + else if (c == 'O' || c == 'Q') + radix = 8; + else if (c == 'H') + radix = 16; + else if (suffix[1] == '.' || c == 'E' || flt) + { + floating_constant (expressionP); + return; + } + else + { + radix = 10; + suffix = NULL; + } + } + } + + switch (radix) + { + case 2: + maxdig = 2; + too_many_digits = valuesize + 1; + break; + case 8: + maxdig = radix = 8; + too_many_digits = (valuesize + 2) / 3 + 1; + break; + case 16: + maxdig = radix = 16; + too_many_digits = (valuesize + 3) / 4 + 1; + break; + case 10: + maxdig = radix = 10; + too_many_digits = (valuesize + 11) / 4; /* Very rough. */ + } +#undef valuesize + start = input_line_pointer; + c = *input_line_pointer++; + for (number = 0; + (digit = hex_value (c)) < maxdig; + c = *input_line_pointer++) + { + number = number * radix + digit; + } + /* c contains character after number. */ + /* input_line_pointer->char after c. */ + small = (input_line_pointer - start - 1) < too_many_digits; + + if (radix == 16 && c == '_') + { + /* This is literal of the form 0x333_0_12345678_1. + This example is equivalent to 0x00000333000000001234567800000001. */ + + int num_little_digits = 0; + int i; + input_line_pointer = start; /* -> 1st digit. */ + + know (LITTLENUM_NUMBER_OF_BITS == 16); + + for (c = '_'; c == '_'; num_little_digits += 2) + { + + /* Convert one 64-bit word. */ + int ndigit = 0; + number = 0; + for (c = *input_line_pointer++; + (digit = hex_value (c)) < maxdig; + c = *(input_line_pointer++)) + { + number = number * radix + digit; + ndigit++; + } + + /* Check for 8 digit per word max. */ + if (ndigit > 8) + as_bad (_("a bignum with underscores may not have more than 8 hex digits in any word")); + + /* Add this chunk to the bignum. + Shift things down 2 little digits. */ + know (LITTLENUM_NUMBER_OF_BITS == 16); + for (i = min (num_little_digits + 1, SIZE_OF_LARGE_NUMBER - 1); + i >= 2; + i--) + generic_bignum[i] = generic_bignum[i - 2]; + + /* Add the new digits as the least significant new ones. */ + generic_bignum[0] = number & 0xffffffff; + generic_bignum[1] = number >> 16; + } + + /* Again, c is char after number, input_line_pointer->after c. */ + + if (num_little_digits > SIZE_OF_LARGE_NUMBER - 1) + num_little_digits = SIZE_OF_LARGE_NUMBER - 1; + + assert (num_little_digits >= 4); + + if (num_little_digits != 8) + as_bad (_("a bignum with underscores must have exactly 4 words")); + + /* We might have some leading zeros. These can be trimmed to give + us a change to fit this constant into a small number. */ + while (generic_bignum[num_little_digits - 1] == 0 + && num_little_digits > 1) + num_little_digits--; + + if (num_little_digits <= 2) + { + /* will fit into 32 bits. */ + number = generic_bignum_to_int32 (); + small = 1; + } +#ifdef BFD64 + else if (num_little_digits <= 4) + { + /* Will fit into 64 bits. */ + number = generic_bignum_to_int64 (); + small = 1; + } +#endif + else + { + small = 0; + + /* Number of littlenums in the bignum. */ + number = num_little_digits; + } + } + else if (!small) + { + /* We saw a lot of digits. manufacture a bignum the hard way. */ + LITTLENUM_TYPE *leader; /* -> high order littlenum of the bignum. */ + LITTLENUM_TYPE *pointer; /* -> littlenum we are frobbing now. */ + long carry; + + leader = generic_bignum; + generic_bignum[0] = 0; + generic_bignum[1] = 0; + generic_bignum[2] = 0; + generic_bignum[3] = 0; + input_line_pointer = start; /* -> 1st digit. */ + c = *input_line_pointer++; + for (; (carry = hex_value (c)) < maxdig; c = *input_line_pointer++) + { + for (pointer = generic_bignum; pointer <= leader; pointer++) + { + long work; + + work = carry + radix * *pointer; + *pointer = work & LITTLENUM_MASK; + carry = work >> LITTLENUM_NUMBER_OF_BITS; + } + if (carry) + { + if (leader < generic_bignum + SIZE_OF_LARGE_NUMBER - 1) + { + /* Room to grow a longer bignum. */ + *++leader = carry; + } + } + } + /* Again, c is char after number. */ + /* input_line_pointer -> after c. */ + know (LITTLENUM_NUMBER_OF_BITS == 16); + if (leader < generic_bignum + 2) + { + /* Will fit into 32 bits. */ + number = generic_bignum_to_int32 (); + small = 1; + } +#ifdef BFD64 + else if (leader < generic_bignum + 4) + { + /* Will fit into 64 bits. */ + number = generic_bignum_to_int64 (); + small = 1; + } +#endif + else + { + /* Number of littlenums in the bignum. */ + number = leader - generic_bignum + 1; + } + } + + if ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) + && suffix != NULL + && input_line_pointer - 1 == suffix) + c = *input_line_pointer++; + + if (small) + { + /* Here with number, in correct radix. c is the next char. + Note that unlike un*x, we allow "011f" "0x9f" to both mean + the same as the (conventional) "9f". + This is simply easier than checking for strict canonical + form. Syntax sux! */ + + if (LOCAL_LABELS_FB && c == 'b') + { + /* Backward ref to local label. + Because it is backward, expect it to be defined. */ + /* Construct a local label. */ + name = fb_label_name ((int) number, 0); + + /* Seen before, or symbol is defined: OK. */ + symbolP = symbol_find (name); + if ((symbolP != NULL) && (S_IS_DEFINED (symbolP))) + { + /* Local labels are never absolute. Don't waste time + checking absoluteness. */ + know (SEG_NORMAL (S_GET_SEGMENT (symbolP))); + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + } + else + { + /* Either not seen or not defined. */ + /* @@ Should print out the original string instead of + the parsed number. */ + as_bad (_("backward ref to unknown label \"%d:\""), + (int) number); + expressionP->X_op = O_constant; + } + + expressionP->X_add_number = 0; + } /* case 'b' */ + else if (LOCAL_LABELS_FB && c == 'f') + { + /* Forward reference. Expect symbol to be undefined or + unknown. undefined: seen it before. unknown: never seen + it before. + + Construct a local label name, then an undefined symbol. + Don't create a xseg frag for it: caller may do that. + Just return it as never seen before. */ + name = fb_label_name ((int) number, 1); + symbolP = symbol_find_or_make (name); + /* We have no need to check symbol properties. */ +#ifndef many_segments + /* Since "know" puts its arg into a "string", we + can't have newlines in the argument. */ + know (S_GET_SEGMENT (symbolP) == undefined_section || S_GET_SEGMENT (symbolP) == text_section || S_GET_SEGMENT (symbolP) == data_section); +#endif + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + } /* case 'f' */ + else if (LOCAL_LABELS_DOLLAR && c == '$') + { + /* If the dollar label is *currently* defined, then this is just + another reference to it. If it is not *currently* defined, + then this is a fresh instantiation of that number, so create + it. */ + + if (dollar_label_defined ((long) number)) + { + name = dollar_label_name ((long) number, 0); + symbolP = symbol_find (name); + know (symbolP != NULL); + } + else + { + name = dollar_label_name ((long) number, 1); + symbolP = symbol_find_or_make (name); + } + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + } /* case '$' */ + else + { + expressionP->X_op = O_constant; +#ifdef TARGET_WORD_SIZE + /* Sign extend NUMBER. */ + number |= (-(number >> (TARGET_WORD_SIZE - 1))) << (TARGET_WORD_SIZE - 1); +#endif + expressionP->X_add_number = number; + input_line_pointer--; /* Restore following character. */ + } /* Really just a number. */ + } + else + { + /* Not a small number. */ + expressionP->X_op = O_big; + expressionP->X_add_number = number; /* Number of littlenums. */ + input_line_pointer--; /* -> char following number. */ + } +} + +/* Parse an MRI multi character constant. */ + +static void +mri_char_constant (expressionP) + expressionS *expressionP; +{ + int i; + + if (*input_line_pointer == '\'' + && input_line_pointer[1] != '\'') + { + expressionP->X_op = O_constant; + expressionP->X_add_number = 0; + return; + } + + /* In order to get the correct byte ordering, we must build the + number in reverse. */ + for (i = SIZE_OF_LARGE_NUMBER - 1; i >= 0; i--) + { + int j; + + generic_bignum[i] = 0; + for (j = 0; j < CHARS_PER_LITTLENUM; j++) + { + if (*input_line_pointer == '\'') + { + if (input_line_pointer[1] != '\'') + break; + ++input_line_pointer; + } + generic_bignum[i] <<= 8; + generic_bignum[i] += *input_line_pointer; + ++input_line_pointer; + } + + if (i < SIZE_OF_LARGE_NUMBER - 1) + { + /* If there is more than one littlenum, left justify the + last one to make it match the earlier ones. If there is + only one, we can just use the value directly. */ + for (; j < CHARS_PER_LITTLENUM; j++) + generic_bignum[i] <<= 8; + } + + if (*input_line_pointer == '\'' + && input_line_pointer[1] != '\'') + break; + } + + if (i < 0) + { + as_bad (_("character constant too large")); + i = 0; + } + + if (i > 0) + { + int c; + int j; + + c = SIZE_OF_LARGE_NUMBER - i; + for (j = 0; j < c; j++) + generic_bignum[j] = generic_bignum[i + j]; + i = c; + } + + know (LITTLENUM_NUMBER_OF_BITS == 16); + if (i > 2) + { + expressionP->X_op = O_big; + expressionP->X_add_number = i; + } + else + { + expressionP->X_op = O_constant; + if (i < 2) + expressionP->X_add_number = generic_bignum[0] & LITTLENUM_MASK; + else + expressionP->X_add_number = + (((generic_bignum[1] & LITTLENUM_MASK) + << LITTLENUM_NUMBER_OF_BITS) + | (generic_bignum[0] & LITTLENUM_MASK)); + } + + /* Skip the final closing quote. */ + ++input_line_pointer; +} + +/* Return an expression representing the current location. This + handles the magic symbol `.'. */ + +static void +current_location (expressionp) + expressionS *expressionp; +{ + if (now_seg == absolute_section) + { + expressionp->X_op = O_constant; + expressionp->X_add_number = abs_section_offset; + } + else + { + symbolS *symbolp; + + symbolp = symbol_new (FAKE_LABEL_NAME, now_seg, + (valueT) frag_now_fix (), + frag_now); + expressionp->X_op = O_symbol; + expressionp->X_add_symbol = symbolp; + expressionp->X_add_number = 0; + } +} + +/* In: Input_line_pointer points to 1st char of operand, which may + be a space. + + Out: An expressionS. + The operand may have been empty: in this case X_op == O_absent. + Input_line_pointer->(next non-blank) char after operand. */ + +static segT +operand (expressionP) + expressionS *expressionP; +{ + char c; + symbolS *symbolP; /* Points to symbol. */ + char *name; /* Points to name of symbol. */ + segT segment; + + /* All integers are regarded as unsigned unless they are negated. + This is because the only thing which cares whether a number is + unsigned is the code in emit_expr which extends constants into + bignums. It should only sign extend negative numbers, so that + something like ``.quad 0x80000000'' is not sign extended even + though it appears negative if valueT is 32 bits. */ + expressionP->X_unsigned = 1; + + /* Digits, assume it is a bignum. */ + + SKIP_WHITESPACE (); /* Leading whitespace is part of operand. */ + c = *input_line_pointer++; /* input_line_pointer -> past char in c. */ + + if (is_end_of_line[(unsigned char) c]) + goto eol; + + switch (c) + { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + input_line_pointer--; + + integer_constant ((NUMBERS_WITH_SUFFIX || flag_m68k_mri) + ? 0 : 10, + expressionP); + break; + +#ifdef LITERAL_PREFIXDOLLAR_HEX + case '$': + /* $L is the start of a local label, not a hex constant. */ + if (* input_line_pointer == 'L') + goto isname; + integer_constant (16, expressionP); + break; +#endif + +#ifdef LITERAL_PREFIXPERCENT_BIN + case '%': + integer_constant (2, expressionP); + break; +#endif + + case '0': + /* Non-decimal radix. */ + + if (NUMBERS_WITH_SUFFIX || flag_m68k_mri) + { + char *s; + + /* Check for a hex or float constant. */ + for (s = input_line_pointer; hex_p (*s); s++) + ; + if (*s == 'h' || *s == 'H' || *input_line_pointer == '.') + { + --input_line_pointer; + integer_constant (0, expressionP); + break; + } + } + c = *input_line_pointer; + switch (c) + { + case 'o': + case 'O': + case 'q': + case 'Q': + case '8': + case '9': + if (NUMBERS_WITH_SUFFIX || flag_m68k_mri) + { + integer_constant (0, expressionP); + break; + } + /* Fall through. */ + default: + default_case: + if (c && strchr (FLT_CHARS, c)) + { + input_line_pointer++; + floating_constant (expressionP); + expressionP->X_add_number = - TOLOWER (c); + } + else + { + /* The string was only zero. */ + expressionP->X_op = O_constant; + expressionP->X_add_number = 0; + } + + break; + + case 'x': + case 'X': + if (flag_m68k_mri) + goto default_case; + input_line_pointer++; + integer_constant (16, expressionP); + break; + + case 'b': + if (LOCAL_LABELS_FB && ! (flag_m68k_mri || NUMBERS_WITH_SUFFIX)) + { + /* This code used to check for '+' and '-' here, and, in + some conditions, fall through to call + integer_constant. However, that didn't make sense, + as integer_constant only accepts digits. */ + /* Some of our code elsewhere does permit digits greater + than the expected base; for consistency, do the same + here. */ + if (input_line_pointer[1] < '0' + || input_line_pointer[1] > '9') + { + /* Parse this as a back reference to label 0. */ + input_line_pointer--; + integer_constant (10, expressionP); + break; + } + /* Otherwise, parse this as a binary number. */ + } + /* Fall through. */ + case 'B': + input_line_pointer++; + if (flag_m68k_mri || NUMBERS_WITH_SUFFIX) + goto default_case; + integer_constant (2, expressionP); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + integer_constant ((flag_m68k_mri || NUMBERS_WITH_SUFFIX) + ? 0 : 8, + expressionP); + break; + + case 'f': + if (LOCAL_LABELS_FB) + { + /* If it says "0f" and it could possibly be a floating point + number, make it one. Otherwise, make it a local label, + and try to deal with parsing the rest later. */ + if (!input_line_pointer[1] + || (is_end_of_line[0xff & input_line_pointer[1]]) + || strchr (FLT_CHARS, 'f') == NULL) + goto is_0f_label; + { + char *cp = input_line_pointer + 1; + int r = atof_generic (&cp, ".", EXP_CHARS, + &generic_floating_point_number); + switch (r) + { + case 0: + case ERROR_EXPONENT_OVERFLOW: + if (*cp == 'f' || *cp == 'b') + /* Looks like a difference expression. */ + goto is_0f_label; + else if (cp == input_line_pointer + 1) + /* No characters has been accepted -- looks like + end of operand. */ + goto is_0f_label; + else + goto is_0f_float; + default: + as_fatal (_("expr.c(operand): bad atof_generic return val %d"), + r); + } + } + + /* Okay, now we've sorted it out. We resume at one of these + two labels, depending on what we've decided we're probably + looking at. */ + is_0f_label: + input_line_pointer--; + integer_constant (10, expressionP); + break; + + is_0f_float: + /* Fall through. */ + ; + } + + case 'd': + case 'D': + if (flag_m68k_mri || NUMBERS_WITH_SUFFIX) + { + integer_constant (0, expressionP); + break; + } + /* Fall through. */ + case 'F': + case 'r': + case 'e': + case 'E': + case 'g': + case 'G': + input_line_pointer++; + floating_constant (expressionP); + expressionP->X_add_number = - TOLOWER (c); + break; + + case '$': + if (LOCAL_LABELS_DOLLAR) + { + integer_constant (10, expressionP); + break; + } + else + goto default_case; + } + + break; + + case '(': +#ifndef NEED_INDEX_OPERATOR + case '[': +#endif + /* Didn't begin with digit & not a name. */ + segment = expression (expressionP); + /* expression () will pass trailing whitespace. */ + if ((c == '(' && *input_line_pointer != ')') + || (c == '[' && *input_line_pointer != ']')) + { +#ifdef RELAX_PAREN_GROUPING + if (c != '(') +#endif + as_bad (_("missing '%c'"), c == '(' ? ')' : ']'); + } + else + input_line_pointer++; + SKIP_WHITESPACE (); + /* Here with input_line_pointer -> char after "(...)". */ + return segment; + +#ifdef TC_M68K + case 'E': + if (! flag_m68k_mri || *input_line_pointer != '\'') + goto de_fault; + as_bad (_("EBCDIC constants are not supported")); + /* Fall through. */ + case 'A': + if (! flag_m68k_mri || *input_line_pointer != '\'') + goto de_fault; + ++input_line_pointer; + /* Fall through. */ +#endif + case '\'': + if (! flag_m68k_mri) + { + /* Warning: to conform to other people's assemblers NO + ESCAPEMENT is permitted for a single quote. The next + character, parity errors and all, is taken as the value + of the operand. VERY KINKY. */ + expressionP->X_op = O_constant; + expressionP->X_add_number = *input_line_pointer++; + break; + } + + mri_char_constant (expressionP); + break; + + case '+': + (void) operand (expressionP); + break; + +#ifdef TC_M68K + case '"': + /* Double quote is the bitwise not operator in MRI mode. */ + if (! flag_m68k_mri) + goto de_fault; + /* Fall through. */ +#endif + case '~': + /* '~' is permitted to start a label on the Delta. */ + if (is_name_beginner (c)) + goto isname; + case '!': + case '-': + { + operand (expressionP); + if (expressionP->X_op == O_constant) + { + /* input_line_pointer -> char after operand. */ + if (c == '-') + { + expressionP->X_add_number = - expressionP->X_add_number; + /* Notice: '-' may overflow: no warning is given. + This is compatible with other people's + assemblers. Sigh. */ + expressionP->X_unsigned = 0; + } + else if (c == '~' || c == '"') + expressionP->X_add_number = ~ expressionP->X_add_number; + else + expressionP->X_add_number = ! expressionP->X_add_number; + } + else if (expressionP->X_op == O_big + && expressionP->X_add_number <= 0 + && c == '-' + && (generic_floating_point_number.sign == '+' + || generic_floating_point_number.sign == 'P')) + { + /* Negative flonum (eg, -1.000e0). */ + if (generic_floating_point_number.sign == '+') + generic_floating_point_number.sign = '-'; + else + generic_floating_point_number.sign = 'N'; + } + else if (expressionP->X_op != O_illegal + && expressionP->X_op != O_absent) + { + expressionP->X_add_symbol = make_expr_symbol (expressionP); + if (c == '-') + expressionP->X_op = O_uminus; + else if (c == '~' || c == '"') + expressionP->X_op = O_bit_not; + else + expressionP->X_op = O_logical_not; + expressionP->X_add_number = 0; + } + else + as_warn (_("Unary operator %c ignored because bad operand follows"), + c); + } + break; + +#if defined (DOLLAR_DOT) || defined (TC_M68K) + case '$': + /* '$' is the program counter when in MRI mode, or when + DOLLAR_DOT is defined. */ +#ifndef DOLLAR_DOT + if (! flag_m68k_mri) + goto de_fault; +#endif + if (flag_m68k_mri && hex_p (*input_line_pointer)) + { + /* In MRI mode, '$' is also used as the prefix for a + hexadecimal constant. */ + integer_constant (16, expressionP); + break; + } + + if (is_part_of_name (*input_line_pointer)) + goto isname; + + current_location (expressionP); + break; +#endif + + case '.': + if (!is_part_of_name (*input_line_pointer)) + { + current_location (expressionP); + break; + } + else if ((strncasecmp (input_line_pointer, "startof.", 8) == 0 + && ! is_part_of_name (input_line_pointer[8])) + || (strncasecmp (input_line_pointer, "sizeof.", 7) == 0 + && ! is_part_of_name (input_line_pointer[7]))) + { + int start; + + start = (input_line_pointer[1] == 't' + || input_line_pointer[1] == 'T'); + input_line_pointer += start ? 8 : 7; + SKIP_WHITESPACE (); + if (*input_line_pointer != '(') + as_bad (_("syntax error in .startof. or .sizeof.")); + else + { + char *buf; + + ++input_line_pointer; + SKIP_WHITESPACE (); + name = input_line_pointer; + c = get_symbol_end (); + + buf = (char *) xmalloc (strlen (name) + 10); + if (start) + sprintf (buf, ".startof.%s", name); + else + sprintf (buf, ".sizeof.%s", name); + symbolP = symbol_make (buf); + free (buf); + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + + *input_line_pointer = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ')') + as_bad (_("syntax error in .startof. or .sizeof.")); + else + ++input_line_pointer; + } + break; + } + else + { + goto isname; + } + + case ',': + eol: + /* Can't imagine any other kind of operand. */ + expressionP->X_op = O_absent; + input_line_pointer--; + break; + +#ifdef TC_M68K + case '%': + if (! flag_m68k_mri) + goto de_fault; + integer_constant (2, expressionP); + break; + + case '@': + if (! flag_m68k_mri) + goto de_fault; + integer_constant (8, expressionP); + break; + + case ':': + if (! flag_m68k_mri) + goto de_fault; + + /* In MRI mode, this is a floating point constant represented + using hexadecimal digits. */ + + ++input_line_pointer; + integer_constant (16, expressionP); + break; + + case '*': + if (! flag_m68k_mri || is_part_of_name (*input_line_pointer)) + goto de_fault; + + current_location (expressionP); + break; +#endif + + default: +#ifdef TC_M68K + de_fault: +#endif + if (is_name_beginner (c)) /* Here if did not begin with a digit. */ + { + /* Identifier begins here. + This is kludged for speed, so code is repeated. */ + isname: + name = --input_line_pointer; + c = get_symbol_end (); + +#ifdef md_parse_name + /* This is a hook for the backend to parse certain names + specially in certain contexts. If a name always has a + specific value, it can often be handled by simply + entering it in the symbol table. */ + if (md_parse_name (name, expressionP, &c)) + { + *input_line_pointer = c; + break; + } +#endif + +#ifdef TC_I960 + /* The MRI i960 assembler permits + lda sizeof code,g13 + FIXME: This should use md_parse_name. */ + if (flag_mri + && (strcasecmp (name, "sizeof") == 0 + || strcasecmp (name, "startof") == 0)) + { + int start; + char *buf; + + start = (name[1] == 't' + || name[1] == 'T'); + + *input_line_pointer = c; + SKIP_WHITESPACE (); + + name = input_line_pointer; + c = get_symbol_end (); + + buf = (char *) xmalloc (strlen (name) + 10); + if (start) + sprintf (buf, ".startof.%s", name); + else + sprintf (buf, ".sizeof.%s", name); + symbolP = symbol_make (buf); + free (buf); + + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + + *input_line_pointer = c; + SKIP_WHITESPACE (); + + break; + } +#endif + + symbolP = symbol_find_or_make (name); + + /* If we have an absolute symbol or a reg, then we know its + value now. */ + segment = S_GET_SEGMENT (symbolP); + if (segment == absolute_section) + { + expressionP->X_op = O_constant; + expressionP->X_add_number = S_GET_VALUE (symbolP); + } + else if (segment == reg_section) + { + expressionP->X_op = O_register; + expressionP->X_add_number = S_GET_VALUE (symbolP); + } + else + { + expressionP->X_op = O_symbol; + expressionP->X_add_symbol = symbolP; + expressionP->X_add_number = 0; + } + *input_line_pointer = c; + } + else + { + /* Let the target try to parse it. Success is indicated by changing + the X_op field to something other than O_absent and pointing + input_line_pointer past the expression. If it can't parse the + expression, X_op and input_line_pointer should be unchanged. */ + expressionP->X_op = O_absent; + --input_line_pointer; + md_operand (expressionP); + if (expressionP->X_op == O_absent) + { + ++input_line_pointer; + as_bad (_("bad expression")); + expressionP->X_op = O_constant; + expressionP->X_add_number = 0; + } + } + break; + } + + /* It is more 'efficient' to clean up the expressionS when they are + created. Doing it here saves lines of code. */ + clean_up_expression (expressionP); + SKIP_WHITESPACE (); /* -> 1st char after operand. */ + know (*input_line_pointer != ' '); + + /* The PA port needs this information. */ + if (expressionP->X_add_symbol) + symbol_mark_used (expressionP->X_add_symbol); + + switch (expressionP->X_op) + { + default: + return absolute_section; + case O_symbol: + return S_GET_SEGMENT (expressionP->X_add_symbol); + case O_register: + return reg_section; + } +} + +/* Internal. Simplify a struct expression for use by expr (). */ + +/* In: address of an expressionS. + The X_op field of the expressionS may only take certain values. + Elsewise we waste time special-case testing. Sigh. Ditto SEG_ABSENT. + + Out: expressionS may have been modified: + Unused fields zeroed to help expr (). */ + +static void +clean_up_expression (expressionP) + expressionS *expressionP; +{ + switch (expressionP->X_op) + { + case O_illegal: + case O_absent: + expressionP->X_add_number = 0; + /* Fall through. */ + case O_big: + case O_constant: + case O_register: + expressionP->X_add_symbol = NULL; + /* Fall through. */ + case O_symbol: + case O_uminus: + case O_bit_not: + expressionP->X_op_symbol = NULL; + break; + default: + break; + } +} + +/* Expression parser. */ + +/* We allow an empty expression, and just assume (absolute,0) silently. + Unary operators and parenthetical expressions are treated as operands. + As usual, Q==quantity==operand, O==operator, X==expression mnemonics. + + We used to do an aho/ullman shift-reduce parser, but the logic got so + warped that I flushed it and wrote a recursive-descent parser instead. + Now things are stable, would anybody like to write a fast parser? + Most expressions are either register (which does not even reach here) + or 1 symbol. Then "symbol+constant" and "symbol-symbol" are common. + So I guess it doesn't really matter how inefficient more complex expressions + are parsed. + + After expr(RANK,resultP) input_line_pointer->operator of rank <= RANK. + Also, we have consumed any leading or trailing spaces (operand does that) + and done all intervening operators. + + This returns the segment of the result, which will be + absolute_section or the segment of a symbol. */ + +#undef __ +#define __ O_illegal + +/* Maps ASCII -> operators. */ +static const operatorT op_encoding[256] = { + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + + __, O_bit_or_not, __, __, __, O_modulus, O_bit_and, __, + __, __, O_multiply, O_add, __, O_subtract, __, O_divide, + __, __, __, __, __, __, __, __, + __, __, __, __, O_lt, __, O_gt, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, +#ifdef NEED_INDEX_OPERATOR + O_index, +#else + __, +#endif + __, __, O_bit_exclusive_or, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, + __, __, __, __, O_bit_inclusive_or, __, __, __, + + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, + __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __ +}; + +/* Rank Examples + 0 operand, (expression) + 1 || + 2 && + 3 == <> < <= >= > + 4 + - + 5 used for * / % in MRI mode + 6 & ^ ! | + 7 * / % << >> + 8 unary - unary ~ +*/ +static operator_rankT op_rank[] = { + 0, /* O_illegal */ + 0, /* O_absent */ + 0, /* O_constant */ + 0, /* O_symbol */ + 0, /* O_symbol_rva */ + 0, /* O_register */ + 0, /* O_big */ + 9, /* O_uminus */ + 9, /* O_bit_not */ + 9, /* O_logical_not */ + 8, /* O_multiply */ + 8, /* O_divide */ + 8, /* O_modulus */ + 8, /* O_left_shift */ + 8, /* O_right_shift */ + 7, /* O_bit_inclusive_or */ + 7, /* O_bit_or_not */ + 7, /* O_bit_exclusive_or */ + 7, /* O_bit_and */ + 5, /* O_add */ + 5, /* O_subtract */ + 4, /* O_eq */ + 4, /* O_ne */ + 4, /* O_lt */ + 4, /* O_le */ + 4, /* O_ge */ + 4, /* O_gt */ + 3, /* O_logical_and */ + 2, /* O_logical_or */ + 1, /* O_index */ + 0, /* O_md1 */ + 0, /* O_md2 */ + 0, /* O_md3 */ + 0, /* O_md4 */ + 0, /* O_md5 */ + 0, /* O_md6 */ + 0, /* O_md7 */ + 0, /* O_md8 */ + 0, /* O_md9 */ + 0, /* O_md10 */ + 0, /* O_md11 */ + 0, /* O_md12 */ + 0, /* O_md13 */ + 0, /* O_md14 */ + 0, /* O_md15 */ + 0, /* O_md16 */ +}; + +/* Unfortunately, in MRI mode for the m68k, multiplication and + division have lower precedence than the bit wise operators. This + function sets the operator precedences correctly for the current + mode. Also, MRI uses a different bit_not operator, and this fixes + that as well. */ + +#define STANDARD_MUL_PRECEDENCE 8 +#define MRI_MUL_PRECEDENCE 6 + +void +expr_set_precedence () +{ + if (flag_m68k_mri) + { + op_rank[O_multiply] = MRI_MUL_PRECEDENCE; + op_rank[O_divide] = MRI_MUL_PRECEDENCE; + op_rank[O_modulus] = MRI_MUL_PRECEDENCE; + } + else + { + op_rank[O_multiply] = STANDARD_MUL_PRECEDENCE; + op_rank[O_divide] = STANDARD_MUL_PRECEDENCE; + op_rank[O_modulus] = STANDARD_MUL_PRECEDENCE; + } +} + +/* Initialize the expression parser. */ + +void +expr_begin () +{ + expr_set_precedence (); + + /* Verify that X_op field is wide enough. */ + { + expressionS e; + e.X_op = O_max; + assert (e.X_op == O_max); + } +} + +/* Return the encoding for the operator at INPUT_LINE_POINTER, and + sets NUM_CHARS to the number of characters in the operator. + Does not advance INPUT_LINE_POINTER. */ + +static inline operatorT +operator (num_chars) + int *num_chars; +{ + int c; + operatorT ret; + + c = *input_line_pointer & 0xff; + *num_chars = 1; + + if (is_end_of_line[c]) + return O_illegal; + + switch (c) + { + default: + return op_encoding[c]; + + case '<': + switch (input_line_pointer[1]) + { + default: + return op_encoding[c]; + case '<': + ret = O_left_shift; + break; + case '>': + ret = O_ne; + break; + case '=': + ret = O_le; + break; + } + *num_chars = 2; + return ret; + + case '=': + if (input_line_pointer[1] != '=') + return op_encoding[c]; + + *num_chars = 2; + return O_eq; + + case '>': + switch (input_line_pointer[1]) + { + default: + return op_encoding[c]; + case '>': + ret = O_right_shift; + break; + case '=': + ret = O_ge; + break; + } + *num_chars = 2; + return ret; + + case '!': + /* We accept !! as equivalent to ^ for MRI compatibility. */ + if (input_line_pointer[1] != '!') + { + if (flag_m68k_mri) + return O_bit_inclusive_or; + return op_encoding[c]; + } + *num_chars = 2; + return O_bit_exclusive_or; + + case '|': + if (input_line_pointer[1] != '|') + return op_encoding[c]; + + *num_chars = 2; + return O_logical_or; + + case '&': + if (input_line_pointer[1] != '&') + return op_encoding[c]; + + *num_chars = 2; + return O_logical_and; + } + + /* NOTREACHED */ +} + +/* Parse an expression. */ + +segT +expr (rankarg, resultP) + int rankarg; /* Larger # is higher rank. */ + expressionS *resultP; /* Deliver result here. */ +{ + operator_rankT rank = (operator_rankT) rankarg; + segT retval; + expressionS right; + operatorT op_left; + operatorT op_right; + int op_chars; + + know (rank >= 0); + + /* Save the value of dot for the fixup code. */ + if (rank == 0) + dot_value = frag_now_fix (); + + retval = operand (resultP); + + /* operand () gobbles spaces. */ + know (*input_line_pointer != ' '); + + op_left = operator (&op_chars); + while (op_left != O_illegal && op_rank[(int) op_left] > rank) + { + segT rightseg; + + input_line_pointer += op_chars; /* -> after operator. */ + + rightseg = expr (op_rank[(int) op_left], &right); + if (right.X_op == O_absent) + { + as_warn (_("missing operand; zero assumed")); + right.X_op = O_constant; + right.X_add_number = 0; + right.X_add_symbol = NULL; + right.X_op_symbol = NULL; + } + + know (*input_line_pointer != ' '); + + if (op_left == O_index) + { + if (*input_line_pointer != ']') + as_bad ("missing right bracket"); + else + { + ++input_line_pointer; + SKIP_WHITESPACE (); + } + } + + op_right = operator (&op_chars); + + know (op_right == O_illegal + || op_rank[(int) op_right] <= op_rank[(int) op_left]); + know ((int) op_left >= (int) O_multiply + && (int) op_left <= (int) O_logical_or); + + /* input_line_pointer->after right-hand quantity. */ + /* left-hand quantity in resultP. */ + /* right-hand quantity in right. */ + /* operator in op_left. */ + + if (resultP->X_op == O_big) + { + if (resultP->X_add_number > 0) + as_warn (_("left operand is a bignum; integer 0 assumed")); + else + as_warn (_("left operand is a float; integer 0 assumed")); + resultP->X_op = O_constant; + resultP->X_add_number = 0; + resultP->X_add_symbol = NULL; + resultP->X_op_symbol = NULL; + } + if (right.X_op == O_big) + { + if (right.X_add_number > 0) + as_warn (_("right operand is a bignum; integer 0 assumed")); + else + as_warn (_("right operand is a float; integer 0 assumed")); + right.X_op = O_constant; + right.X_add_number = 0; + right.X_add_symbol = NULL; + right.X_op_symbol = NULL; + } + + /* Optimize common cases. */ +#ifdef md_optimize_expr + if (md_optimize_expr (resultP, op_left, &right)) + { + /* Skip. */ + ; + } + else +#endif + if (op_left == O_add && right.X_op == O_constant) + { + /* X + constant. */ + resultP->X_add_number += right.X_add_number; + } + /* This case comes up in PIC code. */ + else if (op_left == O_subtract + && right.X_op == O_symbol + && resultP->X_op == O_symbol + && (symbol_get_frag (right.X_add_symbol) + == symbol_get_frag (resultP->X_add_symbol)) + && (SEG_NORMAL (rightseg) + || right.X_add_symbol == resultP->X_add_symbol)) + { + resultP->X_add_number -= right.X_add_number; + resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol) + - S_GET_VALUE (right.X_add_symbol)); + resultP->X_op = O_constant; + resultP->X_add_symbol = 0; + } + else if (op_left == O_subtract && right.X_op == O_constant) + { + /* X - constant. */ + resultP->X_add_number -= right.X_add_number; + } + else if (op_left == O_add && resultP->X_op == O_constant) + { + /* Constant + X. */ + resultP->X_op = right.X_op; + resultP->X_add_symbol = right.X_add_symbol; + resultP->X_op_symbol = right.X_op_symbol; + resultP->X_add_number += right.X_add_number; + retval = rightseg; + } + else if (resultP->X_op == O_constant && right.X_op == O_constant) + { + /* Constant OP constant. */ + offsetT v = right.X_add_number; + if (v == 0 && (op_left == O_divide || op_left == O_modulus)) + { + as_warn (_("division by zero")); + v = 1; + } + switch (op_left) + { + default: abort (); + case O_multiply: resultP->X_add_number *= v; break; + case O_divide: resultP->X_add_number /= v; break; + case O_modulus: resultP->X_add_number %= v; break; + case O_left_shift: resultP->X_add_number <<= v; break; + case O_right_shift: + /* We always use unsigned shifts, to avoid relying on + characteristics of the compiler used to compile gas. */ + resultP->X_add_number = + (offsetT) ((valueT) resultP->X_add_number >> (valueT) v); + break; + case O_bit_inclusive_or: resultP->X_add_number |= v; break; + case O_bit_or_not: resultP->X_add_number |= ~v; break; + case O_bit_exclusive_or: resultP->X_add_number ^= v; break; + case O_bit_and: resultP->X_add_number &= v; break; + case O_add: resultP->X_add_number += v; break; + case O_subtract: resultP->X_add_number -= v; break; + case O_eq: + resultP->X_add_number = + resultP->X_add_number == v ? ~ (offsetT) 0 : 0; + break; + case O_ne: + resultP->X_add_number = + resultP->X_add_number != v ? ~ (offsetT) 0 : 0; + break; + case O_lt: + resultP->X_add_number = + resultP->X_add_number < v ? ~ (offsetT) 0 : 0; + break; + case O_le: + resultP->X_add_number = + resultP->X_add_number <= v ? ~ (offsetT) 0 : 0; + break; + case O_ge: + resultP->X_add_number = + resultP->X_add_number >= v ? ~ (offsetT) 0 : 0; + break; + case O_gt: + resultP->X_add_number = + resultP->X_add_number > v ? ~ (offsetT) 0 : 0; + break; + case O_logical_and: + resultP->X_add_number = resultP->X_add_number && v; + break; + case O_logical_or: + resultP->X_add_number = resultP->X_add_number || v; + break; + } + } + else if (resultP->X_op == O_symbol + && right.X_op == O_symbol + && (op_left == O_add + || op_left == O_subtract + || (resultP->X_add_number == 0 + && right.X_add_number == 0))) + { + /* Symbol OP symbol. */ + resultP->X_op = op_left; + resultP->X_op_symbol = right.X_add_symbol; + if (op_left == O_add) + resultP->X_add_number += right.X_add_number; + else if (op_left == O_subtract) + { + resultP->X_add_number -= right.X_add_number; + if (retval == rightseg && SEG_NORMAL (retval)) + { + retval = absolute_section; + rightseg = absolute_section; + } + } + } + else + { + /* The general case. */ + resultP->X_add_symbol = make_expr_symbol (resultP); + resultP->X_op_symbol = make_expr_symbol (&right); + resultP->X_op = op_left; + resultP->X_add_number = 0; + resultP->X_unsigned = 1; + } + + if (retval != rightseg) + { + if (! SEG_NORMAL (retval)) + { + if (retval != undefined_section || SEG_NORMAL (rightseg)) + retval = rightseg; + } + else if (SEG_NORMAL (rightseg) +#ifdef DIFF_EXPR_OK + && op_left != O_subtract +#endif + ) + as_bad (_("operation combines symbols in different segments")); + } + + op_left = op_right; + } /* While next operator is >= this rank. */ + + /* The PA port needs this information. */ + if (resultP->X_add_symbol) + symbol_mark_used (resultP->X_add_symbol); + + return resultP->X_op == O_constant ? absolute_section : retval; +} + +/* This lives here because it belongs equally in expr.c & read.c. + expr.c is just a branch office read.c anyway, and putting it + here lessens the crowd at read.c. + + Assume input_line_pointer is at start of symbol name. + Advance input_line_pointer past symbol name. + Turn that character into a '\0', returning its former value. + This allows a string compare (RMS wants symbol names to be strings) + of the symbol name. + There will always be a char following symbol name, because all good + lines end in end-of-line. */ + +char +get_symbol_end () +{ + char c; + + /* We accept \001 in a name in case this is being called with a + constructed string. */ + if (is_name_beginner (c = *input_line_pointer++) || c == '\001') + { + while (is_part_of_name (c = *input_line_pointer++) + || c == '\001') + ; + if (is_name_ender (c)) + c = *input_line_pointer++; + } + *--input_line_pointer = 0; + return (c); +} + +unsigned int +get_single_number () +{ + expressionS exp; + operand (&exp); + return exp.X_add_number; +} diff --git a/contrib/binutils-2.14/gas/expr.h b/contrib/binutils-2.14/gas/expr.h new file mode 100644 index 0000000000..bb08ddd027 --- /dev/null +++ b/contrib/binutils-2.14/gas/expr.h @@ -0,0 +1,172 @@ +/* expr.h -> header file for expr.c + Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + * By popular demand, we define a struct to represent an expression. + * This will no doubt mutate as expressions become baroque. + * + * Currently, we support expressions like "foo OP bar + 42". In other + * words we permit a (possibly undefined) symbol, a (possibly + * undefined) symbol and the operation used to combine the symbols, + * and an (absolute) augend. RMS says this is so we can have 1-pass + * assembly for any compiler emissions, and a 'case' statement might + * emit 'undefined1 - undefined2'. + * + * The type of an expression used to be stored as a segment. That got + * confusing because it overloaded the concept of a segment. I added + * an operator field, instead. + */ + +/* This is the type of an expression. The operator types are also + used while parsing an expression. + + NOTE: This enumeration must match the op_rank array in expr.c. */ + +typedef enum { + /* An illegal expression. */ + O_illegal, + /* A nonexistent expression. */ + O_absent, + /* X_add_number (a constant expression). */ + O_constant, + /* X_add_symbol + X_add_number. */ + O_symbol, + /* X_add_symbol + X_add_number - the base address of the image. */ + O_symbol_rva, + /* A register (X_add_number is register number). */ + O_register, + /* A big value. If X_add_number is negative or 0, the value is in + generic_floating_point_number. Otherwise the value is in + generic_bignum, and X_add_number is the number of LITTLENUMs in + the value. */ + O_big, + /* (- X_add_symbol) + X_add_number. */ + O_uminus, + /* (~ X_add_symbol) + X_add_number. */ + O_bit_not, + /* (! X_add_symbol) + X_add_number. */ + O_logical_not, + /* (X_add_symbol * X_op_symbol) + X_add_number. */ + O_multiply, + /* (X_add_symbol / X_op_symbol) + X_add_number. */ + O_divide, + /* (X_add_symbol % X_op_symbol) + X_add_number. */ + O_modulus, + /* (X_add_symbol << X_op_symbol) + X_add_number. */ + O_left_shift, + /* (X_add_symbol >> X_op_symbol) + X_add_number. */ + O_right_shift, + /* (X_add_symbol | X_op_symbol) + X_add_number. */ + O_bit_inclusive_or, + /* (X_add_symbol |~ X_op_symbol) + X_add_number. */ + O_bit_or_not, + /* (X_add_symbol ^ X_op_symbol) + X_add_number. */ + O_bit_exclusive_or, + /* (X_add_symbol & X_op_symbol) + X_add_number. */ + O_bit_and, + /* (X_add_symbol + X_op_symbol) + X_add_number. */ + O_add, + /* (X_add_symbol - X_op_symbol) + X_add_number. */ + O_subtract, + /* (X_add_symbol == X_op_symbol) + X_add_number. */ + O_eq, + /* (X_add_symbol != X_op_symbol) + X_add_number. */ + O_ne, + /* (X_add_symbol < X_op_symbol) + X_add_number. */ + O_lt, + /* (X_add_symbol <= X_op_symbol) + X_add_number. */ + O_le, + /* (X_add_symbol >= X_op_symbol) + X_add_number. */ + O_ge, + /* (X_add_symbol > X_op_symbol) + X_add_number. */ + O_gt, + /* (X_add_symbol && X_op_symbol) + X_add_number. */ + O_logical_and, + /* (X_add_symbol || X_op_symbol) + X_add_number. */ + O_logical_or, + /* X_op_symbol [ X_add_symbol ] */ + O_index, + /* machine dependent operators */ + O_md1, O_md2, O_md3, O_md4, O_md5, O_md6, O_md7, O_md8, + O_md9, O_md10, O_md11, O_md12, O_md13, O_md14, O_md15, O_md16, + O_md17, O_md18, O_md19, O_md20, O_md21, O_md22, O_md23, O_md24, + O_md25, O_md26, O_md27, O_md28, O_md29, O_md30, O_md31, O_md32, + /* this must be the largest value */ + O_max +} operatorT; + +typedef struct expressionS { + /* The main symbol. */ + symbolS *X_add_symbol; + /* The second symbol, if needed. */ + symbolS *X_op_symbol; + /* A number to add. */ + offsetT X_add_number; + + /* The type of the expression. We can't assume that an arbitrary + compiler can handle a bitfield of enum type. FIXME: We could + check this using autoconf. */ +#ifdef __GNUC__ + operatorT X_op : 8; +#else + unsigned char X_op; +#endif + + /* Non-zero if X_add_number should be regarded as unsigned. This is + only valid for O_constant expressions. It is only used when an + O_constant must be extended into a bignum (i.e., it is not used + when performing arithmetic on these values). + FIXME: This field is not set very reliably. */ + unsigned int X_unsigned : 1; + + /* 7 additional bits can be defined if needed. */ + + /* Machine dependent field */ + unsigned short X_md; +} expressionS; + +/* "result" should be type (expressionS *). */ +#define expression(result) expr (0, result) + +/* If an expression is O_big, look here for its value. These common + data may be clobbered whenever expr() is called. */ +/* Flonums returned here. Big enough to hold most precise flonum. */ +extern FLONUM_TYPE generic_floating_point_number; +/* Bignums returned here. */ +extern LITTLENUM_TYPE generic_bignum[]; +/* Number of littlenums in above. */ +#define SIZE_OF_LARGE_NUMBER (20) + +typedef char operator_rankT; + +extern char get_symbol_end PARAMS ((void)); +extern void expr_begin PARAMS ((void)); +extern void expr_set_precedence PARAMS ((void)); +extern segT expr PARAMS ((int rank, expressionS * resultP)); +extern unsigned int get_single_number PARAMS ((void)); +extern symbolS *make_expr_symbol PARAMS ((expressionS * expressionP)); +extern int expr_symbol_where + PARAMS ((symbolS *, char **, unsigned int *)); + +extern symbolS *expr_build_uconstant PARAMS ((offsetT)); +extern symbolS *expr_build_unary PARAMS ((operatorT, symbolS *)); +extern symbolS *expr_build_binary PARAMS ((operatorT, symbolS *, symbolS *)); +extern symbolS *expr_build_dot PARAMS ((void)); diff --git a/contrib/binutils-2.14/gas/flonum-copy.c b/contrib/binutils-2.14/gas/flonum-copy.c new file mode 100644 index 0000000000..1e6b40ba70 --- /dev/null +++ b/contrib/binutils-2.14/gas/flonum-copy.c @@ -0,0 +1,73 @@ +/* flonum_copy.c - copy a flonum + Copyright 1987, 1990, 1991, 1992, 1993, 2000 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" + +void +flonum_copy (in, out) + FLONUM_TYPE *in; + FLONUM_TYPE *out; +{ + unsigned int in_length; /* 0 origin */ + unsigned int out_length; /* 0 origin */ + + out->sign = in->sign; + in_length = in->leader - in->low; + + if (in->leader < in->low) + { + out->leader = out->low - 1; /* 0.0 case */ + } + else + { + out_length = out->high - out->low; + /* Assume no GAPS in packing of littlenums. + I.e. sizeof(array) == sizeof(element) * number_of_elements. */ + if (in_length <= out_length) + { + { + /* For defensive programming, zero any high-order + littlenums we don't need. This is destroying evidence + and wasting time, so why bother??? */ + if (in_length < out_length) + { + memset ((char *) (out->low + in_length + 1), '\0', + out_length - in_length); + } + } + memcpy ((void *) (out->low), (void *) (in->low), + ((in_length + 1) * sizeof (LITTLENUM_TYPE))); + out->exponent = in->exponent; + out->leader = in->leader - in->low + out->low; + } + else + { + int shorten; /* 1-origin. Number of littlenums we drop. */ + + shorten = in_length - out_length; + /* Assume out_length >= 0 ! */ + memcpy ((void *) (out->low), (void *) (in->low + shorten), + ((out_length + 1) * sizeof (LITTLENUM_TYPE))); + out->leader = out->high; + out->exponent = in->exponent + shorten; + } + } /* if any significant bits */ +} diff --git a/contrib/binutils-2.14/gas/flonum-konst.c b/contrib/binutils-2.14/gas/flonum-konst.c new file mode 100644 index 0000000000..3e606fbfd7 --- /dev/null +++ b/contrib/binutils-2.14/gas/flonum-konst.c @@ -0,0 +1,228 @@ +/* flonum_const.c - Useful Flonum constants + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 2000, 2002 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "ansidecl.h" +#include "flonum.h" +/* JF: I added the last entry to this table, and I'm not + sure if its right or not. Could go either way. I wish + I really understood this stuff. */ + +const int table_size_of_flonum_powers_of_ten = 13; + +static const LITTLENUM_TYPE zero[] = { + 1 +}; + +/***********************************************************************\ + * * + * Warning: the low order bits may be WRONG here. * + * I took this from a suspect bc(1) script. * + * "minus_X"[] is supposed to be 10^(2^-X) expressed in base 2^16. * + * The radix point is just AFTER the highest element of the [] * + * * + * Because bc rounds DOWN for printing (I think), the lowest * + * significance littlenums should probably have 1 added to them. * + * * + \***********************************************************************/ + +/* JF: If this equals 6553/(2^16)+39321/(2^32)+... it approaches .1 */ +static const LITTLENUM_TYPE minus_1[] = { + 39322, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, + 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 39321, 6553 +}; + +static const LITTLENUM_TYPE plus_1[] = { + 10 +}; + +/* JF: If this equals 655/(2^16) + 23592/(2^32) + ... it approaches .01 */ +static const LITTLENUM_TYPE minus_2[] = { + 10486, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 49807, + 10485, 36700, 62914, 23592, 49807, 10485, 36700, 62914, 23592, 655 +}; + +static const LITTLENUM_TYPE plus_2[] = { + 100 +}; + +/* This approaches .0001 */ +static const LITTLENUM_TYPE minus_3[] = { + 52534, 20027, 37329, 65116, 64067, 60397, 14784, 18979, 33659, 19503, + 2726, 9542, 629, 2202, 40475, 10590, 4299, 47815, 36280, 6 +}; + +static const LITTLENUM_TYPE plus_3[] = { + 10000 +}; + +/* JF: this approaches 1e-8 */ +static const LITTLENUM_TYPE minus_4[] = { + 22517, 49501, 54293, 19424, 60699, 6716, 24348, 22618, 23904, 21327, + 3919, 44703, 19149, 28803, 48959, 6259, 50273, 62237, 42 +}; + +/* This equals 1525 * 2^16 + 57600 */ +static const LITTLENUM_TYPE plus_4[] = { + 57600, 1525 +}; + +/* This approaches 1e-16 */ +static const LITTLENUM_TYPE minus_5[] = { + 22199, 45957, 17005, 26266, 10526, 16260, 55017, 35680, 40443, 19789, + 17356, 30195, 55905, 28426, 63010, 44197, 1844 +}; + +static const LITTLENUM_TYPE plus_5[] = { + 28609, 34546, 35 +}; + +static const LITTLENUM_TYPE minus_6[] = { + 30926, 26518, 13110, 43018, 54982, 48258, 24658, 15209, 63366, 11929, + 20069, 43857, 60487, 51 +}; + +static const LITTLENUM_TYPE plus_6[] = { + 61313, 34220, 16731, 11629, 1262 +}; + +static const LITTLENUM_TYPE minus_7[] = { + 29819, 14733, 21490, 40602, 31315, 65186, 2695 +}; + +static const LITTLENUM_TYPE plus_7[] = { + 7937, 49002, 60772, 28216, 38893, 55975, 63988, 59711, 20227, 24 +}; + +static const LITTLENUM_TYPE minus_8[] = { + 27579, 64807, 12543, 794, 13907, 61297, 12013, 64360, 15961, 20566, + 24178, 15922, 59427, 110 +}; + +static const LITTLENUM_TYPE plus_8[] = { + 15873, 11925, 39177, 991, 14589, 3861, 58415, 9076, 62956, 54223, + 56328, 50180, 45274, 48333, 32537, 42547, 9731, 59679, 590 +}; + +static const LITTLENUM_TYPE minus_9[] = { + 11042, 8464, 58971, 63429, 6022, 63485, 5500, 53464, 47545, 50068, + 56988, 22819, 49708, 54493, 9920, 47667, 40409, 35764, 10383, 54466, + 32702, 17493, 32420, 34382, 22750, 20681, 12300 +}; + +static const LITTLENUM_TYPE plus_9[] = { + 20678, 27614, 28272, 53066, 55311, 54677, 29038, 9906, 26288, 44486, + 13860, 7445, 54106, 15426, 21518, 25599, 29632, 52309, 61207, 26105, + 10482, 21948, 51191, 32988, 60892, 62574, 61390, 24540, 21495, 5 +}; + +static const LITTLENUM_TYPE minus_10[] = { + 6214, 48771, 23471, 30163, 31763, 38013, 57001, 11770, 18263, 36366, + 20742, 45086, 56969, 53231, 37856, 55814, 38057, 15692, 46761, 8713, + 6102, 20083, 8269, 11839, 11571, 50963, 15649, 11698, 40675, 2308 +}; + +static const LITTLENUM_TYPE plus_10[] = { + 63839, 36576, 45712, 44516, 37803, 29482, 4966, 30556, 37961, 23310, + 27070, 44972, 29507, 48257, 45209, 7494, 17831, 38728, 41577, 29443, + 36016, 7955, 35339, 35479, 36011, 14553, 49618, 5588, 25396, 28 +}; + +static const LITTLENUM_TYPE minus_11[] = { + 16663, 56882, 61983, 7804, 36555, 32060, 34502, 1000, 14356, 21681, + 6605, 34767, 51411, 59048, 53614, 39850, 30079, 6496, 6846, 26841, + 40778, 19578, 59899, 44085, 54016, 24259, 11232, 21229, 21313, 81 +}; + +static const LITTLENUM_TYPE plus_11[] = { + 92, 9054, 62707, 17993, 7821, 56838, 13992, 21321, 29637, 48426, + 42982, 38668, 49574, 28820, 18200, 18927, 53979, 16219, 37484, 2516, + 44642, 14665, 11587, 41926, 13556, 23956, 54320, 6661, 55766, 805 +}; + +static const LITTLENUM_TYPE minus_12[] = { + 33202, 45969, 58804, 56734, 16482, 26007, 44984, 49334, 31007, 32944, + 44517, 63329, 47131, 15291, 59465, 2264, 23218, 11829, 59771, 38798, + 31051, 28748, 23129, 40541, 41562, 35108, 50620, 59014, 51817, 6613 +}; + +static const LITTLENUM_TYPE plus_12[] = { + 10098, 37922, 58070, 7432, 10470, 63465, 23718, 62190, 47420, 7009, + 38443, 4587, 45596, 38472, 52129, 52779, 29012, 13559, 48688, 31678, + 41753, 58662, 10668, 36067, 29906, 56906, 21461, 46556, 59571, 9 +}; + +static const LITTLENUM_TYPE minus_13[] = { + 45309, 27592, 37144, 34637, 34328, 41671, 34620, 24135, 53401, 22112, + 21576, 45147, 39310, 44051, 48572, 3676, 46544, 59768, 33350, 2323, + 49524, 61568, 3903, 36487, 36356, 30903, 14975, 9035, 29715, 667 +}; + +static const LITTLENUM_TYPE plus_13[] = { + 18788, 16960, 6318, 45685, 55400, 46230, 35794, 25588, 7253, 55541, + 49716, 59760, 63592, 8191, 63765, 58530, 44667, 13294, 10001, 55586, + 47887, 18738, 9509, 40896, 42506, 52580, 4171, 325, 12329, 98 +}; + +/* Shut up complaints about differing pointer types. They only differ + in the const attribute, but there isn't any easy way to do this + */ +#define X (LITTLENUM_TYPE *) + +const FLONUM_TYPE flonum_negative_powers_of_ten[] = { + {X zero, X zero, X zero, 0, '+'}, + {X minus_1, X minus_1 + 19, X minus_1 + 19, -20, '+'}, + {X minus_2, X minus_2 + 19, X minus_2 + 19, -20, '+'}, + {X minus_3, X minus_3 + 19, X minus_3 + 19, -20, '+'}, + {X minus_4, X minus_4 + 18, X minus_4 + 18, -20, '+'}, + {X minus_5, X minus_5 + 16, X minus_5 + 16, -20, '+'}, + {X minus_6, X minus_6 + 13, X minus_6 + 13, -20, '+'}, + {X minus_7, X minus_7 + 6, X minus_7 + 6, -20, '+'}, + {X minus_8, X minus_8 + 13, X minus_8 + 13, -40, '+'}, + {X minus_9, X minus_9 + 26, X minus_9 + 26, -80, '+'}, + {X minus_10, X minus_10 + 29, X minus_10 + 29, -136, '+'}, + {X minus_11, X minus_11 + 29, X minus_11 + 29, -242, '+'}, + {X minus_12, X minus_12 + 29, X minus_12 + 29, -455, '+'}, + {X minus_13, X minus_13 + 29, X minus_13 + 29, -880, '+'}, +}; + +const FLONUM_TYPE flonum_positive_powers_of_ten[] = { + {X zero, X zero, X zero, 0, '+'}, + {X plus_1, X plus_1 + 0, X plus_1 + 0, 0, '+'}, + {X plus_2, X plus_2 + 0, X plus_2 + 0, 0, '+'}, + {X plus_3, X plus_3 + 0, X plus_3 + 0, 0, '+'}, + {X plus_4, X plus_4 + 1, X plus_4 + 1, 0, '+'}, + {X plus_5, X plus_5 + 2, X plus_5 + 2, 1, '+'}, + {X plus_6, X plus_6 + 4, X plus_6 + 4, 2, '+'}, + {X plus_7, X plus_7 + 9, X plus_7 + 9, 4, '+'}, + {X plus_8, X plus_8 + 18, X plus_8 + 18, 8, '+'}, + {X plus_9, X plus_9 + 29, X plus_9 + 29, 24, '+'}, + {X plus_10, X plus_10 + 29, X plus_10 + 29, 77, '+'}, + {X plus_11, X plus_11 + 29, X plus_11 + 29, 183, '+'}, + {X plus_12, X plus_12 + 29, X plus_12 + 29, 396, '+'}, + {X plus_13, X plus_13 + 29, X plus_13 + 29, 821, '+'}, +}; + +#ifdef VMS +void +dummy1 () +{ +} +#endif diff --git a/contrib/binutils-2.14/gas/flonum-mult.c b/contrib/binutils-2.14/gas/flonum-mult.c new file mode 100644 index 0000000000..e23579ace8 --- /dev/null +++ b/contrib/binutils-2.14/gas/flonum-mult.c @@ -0,0 +1,190 @@ +/* flonum_mult.c - multiply two flonums + Copyright 1987, 1990, 1991, 1992, 1995, 2000, 2002 + Free Software Foundation, Inc. + + This file is part of Gas, the GNU Assembler. + + The GNU assembler is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY. No author or distributor + accepts responsibility to anyone for the consequences of using it + or for whether it serves any particular purpose or works at all, + unless he says so in writing. Refer to the GNU Assembler General + Public License for full details. + + Everyone is granted permission to copy, modify and redistribute + the GNU Assembler, but only under the conditions described in the + GNU Assembler General Public License. A copy of this license is + supposed to have been given to you along with the GNU Assembler + so you can know your rights and responsibilities. It should be + in a file named COPYING. Among other things, the copyright + notice and this notice must be preserved on all copies. */ + +#include "ansidecl.h" +#include "flonum.h" + +/* plan for a . b => p(roduct) + + +-------+-------+-/ /-+-------+-------+ + | a | a | ... | a | a | + | A | A-1 | | 1 | 0 | + +-------+-------+-/ /-+-------+-------+ + + +-------+-------+-/ /-+-------+-------+ + | b | b | ... | b | b | + | B | B-1 | | 1 | 0 | + +-------+-------+-/ /-+-------+-------+ + + +-------+-------+-/ /-+-------+-/ /-+-------+-------+ + | p | p | ... | p | ... | p | p | + | A+B+1| A+B | | N | | 1 | 0 | + +-------+-------+-/ /-+-------+-/ /-+-------+-------+ + + /^\ + (carry) a .b ... | ... a .b a .b + A B | 0 1 0 0 + | + ... | ... a .b + | 1 0 + | + | ... + | + | + | + | ___ + | \ + +----- P = > a .b + N /__ i j + + N = 0 ... A+B + + for all i,j where i+j=N + [i,j integers > 0] + + a[], b[], p[] may not intersect. + Zero length factors signify 0 significant bits: treat as 0.0. + 0.0 factors do the right thing. + Zero length product OK. + + I chose the ForTran accent "foo[bar]" instead of the C accent "*garply" + because I felt the ForTran way was more intuitive. The C way would + probably yield better code on most C compilers. Dean Elsner. + (C style also gives deeper insight [to me] ... oh well ...) */ + +void +flonum_multip (a, b, product) + const FLONUM_TYPE *a; + const FLONUM_TYPE *b; + FLONUM_TYPE *product; +{ + int size_of_a; /* 0 origin */ + int size_of_b; /* 0 origin */ + int size_of_product; /* 0 origin */ + int size_of_sum; /* 0 origin */ + int extra_product_positions; /* 1 origin */ + unsigned long work; + unsigned long carry; + long exponent; + LITTLENUM_TYPE *q; + long significant; /* TRUE when we emit a non-0 littlenum */ + /* ForTran accent follows. */ + int P; /* Scan product low-order -> high. */ + int N; /* As in sum above. */ + int A; /* Which [] of a? */ + int B; /* Which [] of b? */ + + if ((a->sign != '-' && a->sign != '+') + || (b->sign != '-' && b->sign != '+')) + { + /* Got to fail somehow. Any suggestions? */ + product->sign = 0; + return; + } + product->sign = (a->sign == b->sign) ? '+' : '-'; + size_of_a = a->leader - a->low; + size_of_b = b->leader - b->low; + exponent = a->exponent + b->exponent; + size_of_product = product->high - product->low; + size_of_sum = size_of_a + size_of_b; + extra_product_positions = size_of_product - size_of_sum; + if (extra_product_positions < 0) + { + P = extra_product_positions; /* P < 0 */ + exponent -= extra_product_positions; /* Increases exponent. */ + } + else + { + P = 0; + } + carry = 0; + significant = 0; + for (N = 0; N <= size_of_sum; N++) + { + work = carry; + carry = 0; + for (A = 0; A <= N; A++) + { + B = N - A; + if (A <= size_of_a && B <= size_of_b && B >= 0) + { +#ifdef TRACE + printf ("a:low[%d.]=%04x b:low[%d.]=%04x work_before=%08x\n", + A, a->low[A], B, b->low[B], work); +#endif + /* Watch out for sign extension! Without the casts, on + the DEC Alpha, the multiplication result is *signed* + int, which gets sign-extended to convert to the + unsigned long! */ + work += (unsigned long) a->low[A] * (unsigned long) b->low[B]; + carry += work >> LITTLENUM_NUMBER_OF_BITS; + work &= LITTLENUM_MASK; +#ifdef TRACE + printf ("work=%08x carry=%04x\n", work, carry); +#endif + } + } + significant |= work; + if (significant || P < 0) + { + if (P >= 0) + { + product->low[P] = work; +#ifdef TRACE + printf ("P=%d. work[p]:=%04x\n", P, work); +#endif + } + P++; + } + else + { + extra_product_positions++; + exponent++; + } + } + /* [P]-> position # size_of_sum + 1. + This is where 'carry' should go. */ +#ifdef TRACE + printf ("final carry =%04x\n", carry); +#endif + if (carry) + { + if (extra_product_positions > 0) + product->low[P] = carry; + else + { + /* No room at high order for carry littlenum. */ + /* Shift right 1 to make room for most significant littlenum. */ + exponent++; + P--; + for (q = product->low + P; q >= product->low; q--) + { + work = *q; + *q = carry; + carry = work; + } + } + } + else + P--; + product->leader = product->low + P; + product->exponent = exponent; +} diff --git a/contrib/binutils-2.14/gas/flonum.h b/contrib/binutils-2.14/gas/flonum.h new file mode 100644 index 0000000000..e50d9bf90f --- /dev/null +++ b/contrib/binutils-2.14/gas/flonum.h @@ -0,0 +1,102 @@ +/* flonum.h - Floating point package + Copyright 1987, 1990, 1991, 1992, 1994, 1996, 2000 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/***********************************************************************\ + * * + * Arbitrary-precision floating point arithmetic. * + * * + * * + * Notation: a floating point number is expressed as * + * MANTISSA * (2 ** EXPONENT). * + * * + * If this offends more traditional mathematicians, then * + * please tell me your nomenclature for flonums! * + * * + \***********************************************************************/ + +#include "bignum.h" + +/***********************************************************************\ + * * + * Variable precision floating point numbers. * + * * + * Exponent is the place value of the low littlenum. E.g.: * + * If 0: low points to the units littlenum. * + * If 1: low points to the LITTLENUM_RADIX littlenum. * + * If -1: low points to the 1/LITTLENUM_RADIX littlenum. * + * * + \***********************************************************************/ + +/* JF: A sign value of 0 means we have been asked to assemble NaN + A sign value of 'P' means we've been asked to assemble +Inf + A sign value of 'N' means we've been asked to assemble -Inf + */ +struct FLONUM_STRUCT { + LITTLENUM_TYPE *low; /* low order littlenum of a bignum */ + LITTLENUM_TYPE *high; /* high order littlenum of a bignum */ + LITTLENUM_TYPE *leader; /* -> 1st non-zero littlenum */ + /* If flonum is 0.0, leader==low-1 */ + long exponent; /* base LITTLENUM_RADIX */ + char sign; /* '+' or '-' */ +}; + +typedef struct FLONUM_STRUCT FLONUM_TYPE; + +/***********************************************************************\ + * * + * Since we can (& do) meet with exponents like 10^5000, it * + * is silly to make a table of ~ 10,000 entries, one for each * + * power of 10. We keep a table where item [n] is a struct * + * FLONUM_FLOATING_POINT representing 10^(2^n). We then * + * multiply appropriate entries from this table to get any * + * particular power of 10. For the example of 10^5000, a table * + * of just 25 entries suffices: 10^(2^-12)...10^(2^+12). * + * * + \***********************************************************************/ + +extern const FLONUM_TYPE flonum_positive_powers_of_ten[]; +extern const FLONUM_TYPE flonum_negative_powers_of_ten[]; +extern const int table_size_of_flonum_powers_of_ten; +/* Flonum_XXX_powers_of_ten[] table has legal indices from 0 to + + this number inclusive. */ + +/***********************************************************************\ + * * + * Declare worker functions. * + * * + \***********************************************************************/ + +int atof_generic PARAMS ((char **address_of_string_pointer, + const char *string_of_decimal_marks, + const char *string_of_decimal_exponent_marks, + FLONUM_TYPE * address_of_generic_floating_point_number)); + +void flonum_copy PARAMS ((FLONUM_TYPE * in, FLONUM_TYPE * out)); +void flonum_multip PARAMS ((const FLONUM_TYPE * a, const FLONUM_TYPE * b, + FLONUM_TYPE * product)); + +/***********************************************************************\ + * * + * Declare error codes. * + * * + \***********************************************************************/ + +#define ERROR_EXPONENT_OVERFLOW (2) diff --git a/contrib/binutils-2.14/gas/frags.c b/contrib/binutils-2.14/gas/frags.c new file mode 100644 index 0000000000..8d7ed2f58a --- /dev/null +++ b/contrib/binutils-2.14/gas/frags.c @@ -0,0 +1,385 @@ +/* frags.c - manage frags - + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" + +extern fragS zero_address_frag; +extern fragS bss_address_frag; + +/* Initialization for frag routines. */ + +void +frag_init () +{ + zero_address_frag.fr_type = rs_fill; + bss_address_frag.fr_type = rs_fill; +} + +/* Allocate a frag on the specified obstack. + Call this routine from everywhere else, so that all the weird alignment + hackery can be done in just one place. */ + +fragS * +frag_alloc (ob) + struct obstack *ob; +{ + fragS *ptr; + int oalign; + + (void) obstack_alloc (ob, 0); + oalign = obstack_alignment_mask (ob); + obstack_alignment_mask (ob) = 0; + ptr = (fragS *) obstack_alloc (ob, SIZEOF_STRUCT_FRAG); + obstack_alignment_mask (ob) = oalign; + memset (ptr, 0, SIZEOF_STRUCT_FRAG); + return ptr; +} + +/* Try to augment current frag by nchars chars. + If there is no room, close of the current frag with a ".fill 0" + and begin a new frag. Unless the new frag has nchars chars available + do not return. Do not set up any fields of *now_frag. */ + +void +frag_grow (nchars) + unsigned int nchars; +{ + if (obstack_room (&frchain_now->frch_obstack) < nchars) + { + unsigned int n; + long oldc; + + frag_wane (frag_now); + frag_new (0); + oldc = frchain_now->frch_obstack.chunk_size; + frchain_now->frch_obstack.chunk_size = 2 * nchars + SIZEOF_STRUCT_FRAG; + if (frchain_now->frch_obstack.chunk_size > 0) + while ((n = obstack_room (&frchain_now->frch_obstack)) < nchars + && (unsigned long) frchain_now->frch_obstack.chunk_size > nchars) + { + frag_wane (frag_now); + frag_new (0); + } + frchain_now->frch_obstack.chunk_size = oldc; + } + if (obstack_room (&frchain_now->frch_obstack) < nchars) + as_fatal (_("can't extend frag %u chars"), nchars); +} + +/* Call this to close off a completed frag, and start up a new (empty) + frag, in the same subsegment as the old frag. + [frchain_now remains the same but frag_now is updated.] + Because this calculates the correct value of fr_fix by + looking at the obstack 'frags', it needs to know how many + characters at the end of the old frag belong to the maximal + variable part; The rest must belong to fr_fix. + It doesn't actually set up the old frag's fr_var. You may have + set fr_var == 1, but allocated 10 chars to the end of the frag; + In this case you pass old_frags_var_max_size == 10. + In fact, you may use fr_var for something totally unrelated to the + size of the variable part of the frag; None of the generic frag + handling code makes use of fr_var. + + Make a new frag, initialising some components. Link new frag at end + of frchain_now. */ + +void +frag_new (old_frags_var_max_size) + /* Number of chars (already allocated on obstack frags) in + variable_length part of frag. */ + int old_frags_var_max_size; +{ + fragS *former_last_fragP; + frchainS *frchP; + + assert (frchain_now->frch_last == frag_now); + + /* Fix up old frag's fr_fix. */ + frag_now->fr_fix = frag_now_fix_octets () - old_frags_var_max_size; + /* Make sure its type is valid. */ + assert (frag_now->fr_type != 0); + + /* This will align the obstack so the next struct we allocate on it + will begin at a correct boundary. */ + obstack_finish (&frchain_now->frch_obstack); + frchP = frchain_now; + know (frchP); + former_last_fragP = frchP->frch_last; + assert (former_last_fragP != 0); + assert (former_last_fragP == frag_now); + frag_now = frag_alloc (&frchP->frch_obstack); + + as_where (&frag_now->fr_file, &frag_now->fr_line); + + /* Generally, frag_now->points to an address rounded up to next + alignment. However, characters will add to obstack frags + IMMEDIATELY after the struct frag, even if they are not starting + at an alignment address. */ + former_last_fragP->fr_next = frag_now; + frchP->frch_last = frag_now; + +#ifndef NO_LISTING + { + extern struct list_info_struct *listing_tail; + frag_now->line = listing_tail; + } +#endif + + assert (frchain_now->frch_last == frag_now); + + frag_now->fr_next = NULL; +} + +/* Start a new frag unless we have n more chars of room in the current frag. + Close off the old frag with a .fill 0. + + Return the address of the 1st char to write into. Advance + frag_now_growth past the new chars. */ + +char * +frag_more (nchars) + int nchars; +{ + register char *retval; + + if (now_seg == absolute_section) + { + as_bad (_("attempt to allocate data in absolute section")); + subseg_set (text_section, 0); + } + + if (mri_common_symbol != NULL) + { + as_bad (_("attempt to allocate data in common section")); + mri_common_symbol = NULL; + } + + frag_grow (nchars); + retval = obstack_next_free (&frchain_now->frch_obstack); + obstack_blank_fast (&frchain_now->frch_obstack, nchars); + return (retval); +} + +/* Start a new frag unless we have max_chars more chars of room in the + current frag. Close off the old frag with a .fill 0. + + Set up a machine_dependent relaxable frag, then start a new frag. + Return the address of the 1st char of the var part of the old frag + to write into. */ + +char * +frag_var (type, max_chars, var, subtype, symbol, offset, opcode) + relax_stateT type; + int max_chars; + int var; + relax_substateT subtype; + symbolS *symbol; + offsetT offset; + char *opcode; +{ + register char *retval; + + frag_grow (max_chars); + retval = obstack_next_free (&frchain_now->frch_obstack); + obstack_blank_fast (&frchain_now->frch_obstack, max_chars); + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; +#ifdef USING_CGEN + frag_now->fr_cgen.insn = 0; + frag_now->fr_cgen.opindex = 0; + frag_now->fr_cgen.opinfo = 0; +#endif +#ifdef TC_FRAG_INIT + TC_FRAG_INIT (frag_now); +#endif + as_where (&frag_now->fr_file, &frag_now->fr_line); + frag_new (max_chars); + return (retval); +} + +/* OVE: This variant of frag_var assumes that space for the tail has been + allocated by caller. + No call to frag_grow is done. */ + +char * +frag_variant (type, max_chars, var, subtype, symbol, offset, opcode) + relax_stateT type; + int max_chars; + int var; + relax_substateT subtype; + symbolS *symbol; + offsetT offset; + char *opcode; +{ + register char *retval; + + retval = obstack_next_free (&frchain_now->frch_obstack); + frag_now->fr_var = var; + frag_now->fr_type = type; + frag_now->fr_subtype = subtype; + frag_now->fr_symbol = symbol; + frag_now->fr_offset = offset; + frag_now->fr_opcode = opcode; +#ifdef USING_CGEN + frag_now->fr_cgen.insn = 0; + frag_now->fr_cgen.opindex = 0; + frag_now->fr_cgen.opinfo = 0; +#endif +#ifdef TC_FRAG_INIT + TC_FRAG_INIT (frag_now); +#endif + as_where (&frag_now->fr_file, &frag_now->fr_line); + frag_new (max_chars); + return (retval); +} + +/* Reduce the variable end of a frag to a harmless state. */ + +void +frag_wane (fragP) + register fragS *fragP; +{ + fragP->fr_type = rs_fill; + fragP->fr_offset = 0; + fragP->fr_var = 0; +} + +/* Make an alignment frag. The size of this frag will be adjusted to + force the next frag to have the appropriate alignment. ALIGNMENT + is the power of two to which to align. FILL_CHARACTER is the + character to use to fill in any bytes which are skipped. MAX is + the maximum number of characters to skip when doing the alignment, + or 0 if there is no maximum. */ + +void +frag_align (alignment, fill_character, max) + int alignment; + int fill_character; + int max; +{ + if (now_seg == absolute_section) + { + addressT new_off; + addressT mask; + + mask = (~(addressT) 0) << alignment; + new_off = (abs_section_offset + ~mask) & mask; + if (max == 0 || new_off - abs_section_offset <= (addressT) max) + abs_section_offset = new_off; + } + else + { + char *p; + + p = frag_var (rs_align, 1, 1, (relax_substateT) max, + (symbolS *) 0, (offsetT) alignment, (char *) 0); + *p = fill_character; + } +} + +/* Make an alignment frag like frag_align, but fill with a repeating + pattern rather than a single byte. ALIGNMENT is the power of two + to which to align. FILL_PATTERN is the fill pattern to repeat in + the bytes which are skipped. N_FILL is the number of bytes in + FILL_PATTERN. MAX is the maximum number of characters to skip when + doing the alignment, or 0 if there is no maximum. */ + +void +frag_align_pattern (alignment, fill_pattern, n_fill, max) + int alignment; + const char *fill_pattern; + int n_fill; + int max; +{ + char *p; + + p = frag_var (rs_align, n_fill, n_fill, (relax_substateT) max, + (symbolS *) 0, (offsetT) alignment, (char *) 0); + memcpy (p, fill_pattern, n_fill); +} + +/* The NOP_OPCODE is for the alignment fill value. Fill it with a nop + instruction so that the disassembler does not choke on it. */ +#ifndef NOP_OPCODE +#define NOP_OPCODE 0x00 +#endif + +/* Use this to restrict the amount of memory allocated for representing + the alignment code. Needs to be large enough to hold any fixed sized + prologue plus the replicating portion. */ +#ifndef MAX_MEM_FOR_RS_ALIGN_CODE + /* Assume that if HANDLE_ALIGN is not defined then no special action + is required to code fill, which means that we get just repeat the + one NOP_OPCODE byte. */ +# ifndef HANDLE_ALIGN +# define MAX_MEM_FOR_RS_ALIGN_CODE 1 +# else +# define MAX_MEM_FOR_RS_ALIGN_CODE ((1 << alignment) - 1) +# endif +#endif + +void +frag_align_code (alignment, max) + int alignment; + int max; +{ + char *p; + + p = frag_var (rs_align_code, MAX_MEM_FOR_RS_ALIGN_CODE, 1, + (relax_substateT) max, (symbolS *) 0, + (offsetT) alignment, (char *) 0); + *p = NOP_OPCODE; +} + +addressT +frag_now_fix_octets () +{ + if (now_seg == absolute_section) + return abs_section_offset; + + return ((char *) obstack_next_free (&frchain_now->frch_obstack) + - frag_now->fr_literal); +} + +addressT +frag_now_fix () +{ + return frag_now_fix_octets () / OCTETS_PER_BYTE; +} + +void +frag_append_1_char (datum) + int datum; +{ + if (obstack_room (&frchain_now->frch_obstack) <= 1) + { + frag_wane (frag_now); + frag_new (0); + } + obstack_1grow (&frchain_now->frch_obstack, datum); +} diff --git a/contrib/binutils-2.14/gas/frags.h b/contrib/binutils-2.14/gas/frags.h new file mode 100644 index 0000000000..9d52ae8357 --- /dev/null +++ b/contrib/binutils-2.14/gas/frags.h @@ -0,0 +1,163 @@ +/* frags.h - Header file for the frag concept. + Copyright 1987, 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef FRAGS_H +#define FRAGS_H + +#ifdef ANSI_PROTOTYPES +struct obstack; +#endif + +/* A code fragment (frag) is some known number of chars, followed by some + unknown number of chars. Typically the unknown number of chars is an + instruction address whose size is yet unknown. We always know the greatest + possible size the unknown number of chars may become, and reserve that + much room at the end of the frag. + Once created, frags do not change address during assembly. + We chain the frags in (a) forward-linked list(s). The object-file address + of the 1st char of a frag is generally not known until after relax(). + Many things at assembly time describe an address by {object-file-address + of a particular frag}+offset. + + BUG: it may be smarter to have a single pointer off to various different + notes for different frag kinds. See how code pans. */ + +struct frag { + /* Object file address (as an octet offset). */ + addressT fr_address; + /* When relaxing multiple times, remember the address the frag had + in the last relax pass. */ + addressT last_fr_address; + + /* (Fixed) number of octets we know we have. May be 0. */ + offsetT fr_fix; + /* May be used for (Variable) number of octets after above. + The generic frag handling code no longer makes any use of fr_var. */ + offsetT fr_var; + /* For variable-length tail. */ + offsetT fr_offset; + /* For variable-length tail. */ + symbolS *fr_symbol; + /* Points to opcode low addr byte, for relaxation. */ + char *fr_opcode; + + /* Chain forward; ascending address order. Rooted in frch_root. */ + struct frag *fr_next; + + /* Where the frag was created, or where it became a variant frag. */ + char *fr_file; + unsigned int fr_line; + +#ifndef NO_LISTING + struct list_info_struct *line; +#endif + + /* Flipped each relax pass so we can easily determine whether + fr_address has been adjusted. */ + unsigned int relax_marker:1; + + /* What state is my tail in? */ + relax_stateT fr_type; + relax_substateT fr_subtype; + +#ifdef USING_CGEN + /* Don't include this unless using CGEN to keep frag size down. */ + struct { + /* CGEN_INSN entry for this instruction. */ + const struct cgen_insn *insn; + /* Index into operand table. */ + int opindex; + /* Target specific data, usually reloc number. */ + int opinfo; + } fr_cgen; +#endif + +#ifdef TC_FRAG_TYPE + TC_FRAG_TYPE tc_frag_data; +#endif + + /* Data begins here. */ + char fr_literal[1]; +}; + +#define SIZEOF_STRUCT_FRAG \ +((char *) zero_address_frag.fr_literal - (char *) &zero_address_frag) +/* We want to say fr_literal[0] above. */ + +/* Current frag we are building. This frag is incomplete. It is, + however, included in frchain_now. The fr_fix field is bogus; + instead, use frag_now_fix (). */ +COMMON fragS *frag_now; +extern addressT frag_now_fix PARAMS ((void)); +extern addressT frag_now_fix_octets PARAMS ((void)); + +/* For foreign-segment symbol fixups. */ +COMMON fragS zero_address_frag; +/* For local common (N_BSS segment) fixups. */ +COMMON fragS bss_address_frag; + +#if 0 +/* A macro to speed up appending exactly 1 char to current frag. */ +/* JF changed < 1 to <= 1 to avoid a race conditon. */ +#define FRAG_APPEND_1_CHAR(datum) \ +{ \ + if (obstack_room (&frags) <= 1) \ + { \ + frag_wane (frag_now); \ + frag_new (0); \ + } \ + obstack_1grow (&frags, datum); \ +} +#else +extern void frag_append_1_char PARAMS ((int)); +#define FRAG_APPEND_1_CHAR(X) frag_append_1_char (X) +#endif + +void frag_init PARAMS ((void)); +fragS *frag_alloc PARAMS ((struct obstack *)); +void frag_grow PARAMS ((unsigned int nchars)); +char *frag_more PARAMS ((int nchars)); +void frag_align PARAMS ((int alignment, int fill_character, int max)); +void frag_align_pattern PARAMS ((int alignment, + const char *fill_pattern, + int n_fill, + int max)); +void frag_align_code PARAMS ((int alignment, int max)); +void frag_new PARAMS ((int old_frags_var_max_size)); +void frag_wane PARAMS ((fragS * fragP)); + +char *frag_variant PARAMS ((relax_stateT type, + int max_chars, + int var, + relax_substateT subtype, + symbolS * symbol, + offsetT offset, + char *opcode)); + +char *frag_var PARAMS ((relax_stateT type, + int max_chars, + int var, + relax_substateT subtype, + symbolS * symbol, + offsetT offset, + char *opcode)); + +#endif /* FRAGS_H */ diff --git a/contrib/binutils-2.14/gas/hash.c b/contrib/binutils-2.14/gas/hash.c new file mode 100644 index 0000000000..df9101db6b --- /dev/null +++ b/contrib/binutils-2.14/gas/hash.c @@ -0,0 +1,598 @@ +/* hash.c -- gas hash table code + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, + 2000, 2001, 2002 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This version of the hash table code is a wholescale replacement of + the old hash table code, which was fairly bad. This is based on + the hash table code in BFD, but optimized slightly for the + asssembler. The assembler does not need to derive structures that + are stored in the hash table. Instead, it always stores a pointer. + The assembler uses the hash table mostly to store symbols, and we + don't need to confuse the symbol structure with a hash table + structure. */ + +#include "as.h" +#include "safe-ctype.h" +#include "obstack.h" + +/* The default number of entries to use when creating a hash table. */ + +#define DEFAULT_SIZE (4051) + +/* An entry in a hash table. */ + +struct hash_entry { + /* Next entry for this hash code. */ + struct hash_entry *next; + /* String being hashed. */ + const char *string; + /* Hash code. This is the full hash code, not the index into the + table. */ + unsigned long hash; + /* Pointer being stored in the hash table. */ + PTR data; +}; + +/* A hash table. */ + +struct hash_control { + /* The hash array. */ + struct hash_entry **table; + /* The number of slots in the hash table. */ + unsigned int size; + /* An obstack for this hash table. */ + struct obstack memory; + +#ifdef HASH_STATISTICS + /* Statistics. */ + unsigned long lookups; + unsigned long hash_compares; + unsigned long string_compares; + unsigned long insertions; + unsigned long replacements; + unsigned long deletions; +#endif /* HASH_STATISTICS */ +}; + +/* Create a hash table. This return a control block. */ + +struct hash_control * +hash_new () +{ + unsigned int size; + struct hash_control *ret; + unsigned int alloc; + + size = DEFAULT_SIZE; + + ret = (struct hash_control *) xmalloc (sizeof *ret); + obstack_begin (&ret->memory, chunksize); + alloc = size * sizeof (struct hash_entry *); + ret->table = (struct hash_entry **) obstack_alloc (&ret->memory, alloc); + memset (ret->table, 0, alloc); + ret->size = size; + +#ifdef HASH_STATISTICS + ret->lookups = 0; + ret->hash_compares = 0; + ret->string_compares = 0; + ret->insertions = 0; + ret->replacements = 0; + ret->deletions = 0; +#endif + + return ret; +} + +/* Delete a hash table, freeing all allocated memory. */ + +void +hash_die (table) + struct hash_control *table; +{ + obstack_free (&table->memory, 0); + free (table); +} + +/* Look up a string in a hash table. This returns a pointer to the + hash_entry, or NULL if the string is not in the table. If PLIST is + not NULL, this sets *PLIST to point to the start of the list which + would hold this hash entry. If PHASH is not NULL, this sets *PHASH + to the hash code for KEY. + + Each time we look up a string, we move it to the start of the list + for its hash code, to take advantage of referential locality. */ + +static struct hash_entry *hash_lookup PARAMS ((struct hash_control *, + const char *, + struct hash_entry ***, + unsigned long *)); + +static struct hash_entry * +hash_lookup (table, key, plist, phash) + struct hash_control *table; + const char *key; + struct hash_entry ***plist; + unsigned long *phash; +{ + register unsigned long hash; + unsigned int len; + register const unsigned char *s; + register unsigned int c; + unsigned int index; + struct hash_entry **list; + struct hash_entry *p; + struct hash_entry *prev; + +#ifdef HASH_STATISTICS + ++table->lookups; +#endif + + hash = 0; + len = 0; + s = (const unsigned char *) key; + while ((c = *s++) != '\0') + { + hash += c + (c << 17); + hash ^= hash >> 2; + ++len; + } + hash += len + (len << 17); + hash ^= hash >> 2; + + if (phash != NULL) + *phash = hash; + + index = hash % table->size; + list = table->table + index; + + if (plist != NULL) + *plist = list; + + prev = NULL; + for (p = *list; p != NULL; p = p->next) + { +#ifdef HASH_STATISTICS + ++table->hash_compares; +#endif + + if (p->hash == hash) + { +#ifdef HASH_STATISTICS + ++table->string_compares; +#endif + + if (strcmp (p->string, key) == 0) + { + if (prev != NULL) + { + prev->next = p->next; + p->next = *list; + *list = p; + } + + return p; + } + } + + prev = p; + } + + return NULL; +} + +/* Insert an entry into a hash table. This returns NULL on success. + On error, it returns a printable string indicating the error. It + is considered to be an error if the entry already exists in the + hash table. */ + +const char * +hash_insert (table, key, value) + struct hash_control *table; + const char *key; + PTR value; +{ + struct hash_entry *p; + struct hash_entry **list; + unsigned long hash; + + p = hash_lookup (table, key, &list, &hash); + if (p != NULL) + return "exists"; + +#ifdef HASH_STATISTICS + ++table->insertions; +#endif + + p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p)); + p->string = key; + p->hash = hash; + p->data = value; + + p->next = *list; + *list = p; + + return NULL; +} + +/* Insert or replace an entry in a hash table. This returns NULL on + success. On error, it returns a printable string indicating the + error. If an entry already exists, its value is replaced. */ + +const char * +hash_jam (table, key, value) + struct hash_control *table; + const char *key; + PTR value; +{ + struct hash_entry *p; + struct hash_entry **list; + unsigned long hash; + + p = hash_lookup (table, key, &list, &hash); + if (p != NULL) + { +#ifdef HASH_STATISTICS + ++table->replacements; +#endif + + p->data = value; + } + else + { +#ifdef HASH_STATISTICS + ++table->insertions; +#endif + + p = (struct hash_entry *) obstack_alloc (&table->memory, sizeof (*p)); + p->string = key; + p->hash = hash; + p->data = value; + + p->next = *list; + *list = p; + } + + return NULL; +} + +/* Replace an existing entry in a hash table. This returns the old + value stored for the entry. If the entry is not found in the hash + table, this does nothing and returns NULL. */ + +PTR +hash_replace (table, key, value) + struct hash_control *table; + const char *key; + PTR value; +{ + struct hash_entry *p; + PTR ret; + + p = hash_lookup (table, key, NULL, NULL); + if (p == NULL) + return NULL; + +#ifdef HASH_STATISTICS + ++table->replacements; +#endif + + ret = p->data; + + p->data = value; + + return ret; +} + +/* Find an entry in a hash table, returning its value. Returns NULL + if the entry is not found. */ + +PTR +hash_find (table, key) + struct hash_control *table; + const char *key; +{ + struct hash_entry *p; + + p = hash_lookup (table, key, NULL, NULL); + if (p == NULL) + return NULL; + + return p->data; +} + +/* Delete an entry from a hash table. This returns the value stored + for that entry, or NULL if there is no such entry. */ + +PTR +hash_delete (table, key) + struct hash_control *table; + const char *key; +{ + struct hash_entry *p; + struct hash_entry **list; + + p = hash_lookup (table, key, &list, NULL); + if (p == NULL) + return NULL; + + if (p != *list) + abort (); + +#ifdef HASH_STATISTICS + ++table->deletions; +#endif + + *list = p->next; + + /* Note that we never reclaim the memory for this entry. If gas + ever starts deleting hash table entries in a big way, this will + have to change. */ + + return p->data; +} + +/* Traverse a hash table. Call the function on every entry in the + hash table. */ + +void +hash_traverse (table, pfn) + struct hash_control *table; + void (*pfn) PARAMS ((const char *key, PTR value)); +{ + unsigned int i; + + for (i = 0; i < table->size; ++i) + { + struct hash_entry *p; + + for (p = table->table[i]; p != NULL; p = p->next) + (*pfn) (p->string, p->data); + } +} + +/* Print hash table statistics on the specified file. NAME is the + name of the hash table, used for printing a header. */ + +void +hash_print_statistics (f, name, table) + FILE *f ATTRIBUTE_UNUSED; + const char *name ATTRIBUTE_UNUSED; + struct hash_control *table ATTRIBUTE_UNUSED; +{ +#ifdef HASH_STATISTICS + unsigned int i; + unsigned long total; + unsigned long empty; + + fprintf (f, "%s hash statistics:\n", name); + fprintf (f, "\t%lu lookups\n", table->lookups); + fprintf (f, "\t%lu hash comparisons\n", table->hash_compares); + fprintf (f, "\t%lu string comparisons\n", table->string_compares); + fprintf (f, "\t%lu insertions\n", table->insertions); + fprintf (f, "\t%lu replacements\n", table->replacements); + fprintf (f, "\t%lu deletions\n", table->deletions); + + total = 0; + empty = 0; + for (i = 0; i < table->size; ++i) + { + struct hash_entry *p; + + if (table->table[i] == NULL) + ++empty; + else + { + for (p = table->table[i]; p != NULL; p = p->next) + ++total; + } + } + + fprintf (f, "\t%g average chain length\n", (double) total / table->size); + fprintf (f, "\t%lu empty slots\n", empty); +#endif +} + +#ifdef TEST + +/* This test program is left over from the old hash table code. */ + +/* Number of hash tables to maintain (at once) in any testing. */ +#define TABLES (6) + +/* We can have 12 statistics. */ +#define STATBUFSIZE (12) + +/* Display statistics here. */ +int statbuf[STATBUFSIZE]; + +/* Human farts here. */ +char answer[100]; + +/* We test many hash tables at once. */ +char *hashtable[TABLES]; + +/* Points to curent hash_control. */ +char *h; +char **pp; +char *p; +char *name; +char *value; +int size; +int used; +char command; + +/* Number 0:TABLES-1 of current hashed symbol table. */ +int number; + +int +main () +{ + void applicatee (); + void destroy (); + char *what (); + int *ip; + + number = 0; + h = 0; + printf ("type h for help\n"); + for (;;) + { + printf ("hash_test command: "); + gets (answer); + command = answer[0]; + command = TOLOWER (command); /* Ecch! */ + switch (command) + { + case '#': + printf ("old hash table #=%d.\n", number); + whattable (); + break; + case '?': + for (pp = hashtable; pp < hashtable + TABLES; pp++) + { + printf ("address of hash table #%d control block is %xx\n", + pp - hashtable, *pp); + } + break; + case 'a': + hash_traverse (h, applicatee); + break; + case 'd': + hash_traverse (h, destroy); + hash_die (h); + break; + case 'f': + p = hash_find (h, name = what ("symbol")); + printf ("value of \"%s\" is \"%s\"\n", name, p ? p : "NOT-PRESENT"); + break; + case 'h': + printf ("# show old, select new default hash table number\n"); + printf ("? display all hashtable control block addresses\n"); + printf ("a apply a simple display-er to each symbol in table\n"); + printf ("d die: destroy hashtable\n"); + printf ("f find value of nominated symbol\n"); + printf ("h this help\n"); + printf ("i insert value into symbol\n"); + printf ("j jam value into symbol\n"); + printf ("n new hashtable\n"); + printf ("r replace a value with another\n"); + printf ("s say what %% of table is used\n"); + printf ("q exit this program\n"); + printf ("x delete a symbol from table, report its value\n"); + break; + case 'i': + p = hash_insert (h, name = what ("symbol"), value = what ("value")); + if (p) + { + printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, + p); + } + break; + case 'j': + p = hash_jam (h, name = what ("symbol"), value = what ("value")); + if (p) + { + printf ("symbol=\"%s\" value=\"%s\" error=%s\n", name, value, p); + } + break; + case 'n': + h = hashtable[number] = (char *) hash_new (); + break; + case 'q': + exit (EXIT_SUCCESS); + case 'r': + p = hash_replace (h, name = what ("symbol"), value = what ("value")); + printf ("old value was \"%s\"\n", p ? p : "{}"); + break; + case 's': + hash_say (h, statbuf, STATBUFSIZE); + for (ip = statbuf; ip < statbuf + STATBUFSIZE; ip++) + { + printf ("%d ", *ip); + } + printf ("\n"); + break; + case 'x': + p = hash_delete (h, name = what ("symbol")); + printf ("old value was \"%s\"\n", p ? p : "{}"); + break; + default: + printf ("I can't understand command \"%c\"\n", command); + break; + } + } +} + +char * +what (description) + char *description; +{ + printf (" %s : ", description); + gets (answer); + return xstrdup (answer); +} + +void +destroy (string, value) + char *string; + char *value; +{ + free (string); + free (value); +} + +void +applicatee (string, value) + char *string; + char *value; +{ + printf ("%.20s-%.20s\n", string, value); +} + +/* Determine number: what hash table to use. + Also determine h: points to hash_control. */ + +void +whattable () +{ + for (;;) + { + printf (" what hash table (%d:%d) ? ", 0, TABLES - 1); + gets (answer); + sscanf (answer, "%d", &number); + if (number >= 0 && number < TABLES) + { + h = hashtable[number]; + if (!h) + { + printf ("warning: current hash-table-#%d. has no hash-control\n", number); + } + return; + } + else + { + printf ("invalid hash table number: %d\n", number); + } + } +} + +#endif /* TEST */ diff --git a/contrib/binutils-2.14/gas/hash.h b/contrib/binutils-2.14/gas/hash.h new file mode 100644 index 0000000000..ecab0fa13c --- /dev/null +++ b/contrib/binutils-2.14/gas/hash.h @@ -0,0 +1,78 @@ +/* hash.h -- header file for gas hash table routines + Copyright 1987, 1992, 1993, 1995, 1999 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef HASH_H +#define HASH_H + +struct hash_control; + +/* Create a hash table. This return a control block. */ + +extern struct hash_control *hash_new PARAMS ((void)); + +/* Delete a hash table, freeing all allocated memory. */ + +extern void hash_die PARAMS ((struct hash_control *)); + +/* Insert an entry into a hash table. This returns NULL on success. + On error, it returns a printable string indicating the error. It + is considered to be an error if the entry already exists in the + hash table. */ + +extern const char *hash_insert PARAMS ((struct hash_control *, + const char *key, PTR value)); + +/* Insert or replace an entry in a hash table. This returns NULL on + success. On error, it returns a printable string indicating the + error. If an entry already exists, its value is replaced. */ + +extern const char *hash_jam PARAMS ((struct hash_control *, + const char *key, PTR value)); + +/* Replace an existing entry in a hash table. This returns the old + value stored for the entry. If the entry is not found in the hash + table, this does nothing and returns NULL. */ + +extern PTR hash_replace PARAMS ((struct hash_control *, const char *key, + PTR value)); + +/* Find an entry in a hash table, returning its value. Returns NULL + if the entry is not found. */ + +extern PTR hash_find PARAMS ((struct hash_control *, const char *key)); + +/* Delete an entry from a hash table. This returns the value stored + for that entry, or NULL if there is no such entry. */ + +extern PTR hash_delete PARAMS ((struct hash_control *, const char *key)); + +/* Traverse a hash table. Call the function on every entry in the + hash table. */ + +extern void hash_traverse PARAMS ((struct hash_control *, + void (*pfn) (const char *key, PTR value))); + +/* Print hash table statistics on the specified file. NAME is the + name of the hash table, used for printing a header. */ + +extern void hash_print_statistics PARAMS ((FILE *, const char *name, + struct hash_control *)); + +#endif /* HASH_H */ diff --git a/contrib/binutils-2.14/gas/input-file.c b/contrib/binutils-2.14/gas/input-file.c new file mode 100644 index 0000000000..5c23f31eac --- /dev/null +++ b/contrib/binutils-2.14/gas/input-file.c @@ -0,0 +1,253 @@ +/* input_file.c - Deal with Input Files - + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1999, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Confines all details of reading source bytes to this module. + All O/S specific crocks should live here. + What we lose in "efficiency" we gain in modularity. + Note we don't need to #include the "as.h" file. No common coupling! */ + +#include +#include +#include "as.h" +#include "input-file.h" +#include "safe-ctype.h" + +static int input_file_get PARAMS ((char *, int)); + +/* This variable is non-zero if the file currently being read should be + preprocessed by app. It is zero if the file can be read straight in. */ +int preprocess = 0; + +/* This code opens a file, then delivers BUFFER_SIZE character + chunks of the file on demand. + BUFFER_SIZE is supposed to be a number chosen for speed. + The caller only asks once what BUFFER_SIZE is, and asks before + the nature of the input files (if any) is known. */ + +#define BUFFER_SIZE (32 * 1024) + +/* We use static data: the data area is not sharable. */ + +static FILE *f_in; +static char *file_name; + +/* Struct for saving the state of this module for file includes. */ +struct saved_file + { + FILE * f_in; + char * file_name; + int preprocess; + char * app_save; + }; + +/* These hooks accomodate most operating systems. */ + +void +input_file_begin () +{ + f_in = (FILE *) 0; +} + +void +input_file_end () +{ +} + +/* Return BUFFER_SIZE. */ +unsigned int +input_file_buffer_size () +{ + return (BUFFER_SIZE); +} + +int +input_file_is_open () +{ + return f_in != (FILE *) 0; +} + +/* Push the state of our input, returning a pointer to saved info that + can be restored with input_file_pop (). */ + +char * +input_file_push () +{ + register struct saved_file *saved; + + saved = (struct saved_file *) xmalloc (sizeof *saved); + + saved->f_in = f_in; + saved->file_name = file_name; + saved->preprocess = preprocess; + if (preprocess) + saved->app_save = app_push (); + + /* Initialize for new file. */ + input_file_begin (); + + return (char *) saved; +} + +void +input_file_pop (arg) + char *arg; +{ + register struct saved_file *saved = (struct saved_file *) arg; + + input_file_end (); /* Close out old file. */ + + f_in = saved->f_in; + file_name = saved->file_name; + preprocess = saved->preprocess; + if (preprocess) + app_pop (saved->app_save); + + free (arg); +} + +void +input_file_open (filename, pre) + char *filename; /* "" means use stdin. Must not be 0. */ + int pre; +{ + int c; + char buf[80]; + + preprocess = pre; + + assert (filename != 0); /* Filename may not be NULL. */ + if (filename[0]) + { /* We have a file name. Suck it and see. */ + f_in = fopen (filename, FOPEN_RT); + file_name = filename; + } + else + { /* use stdin for the input file. */ + f_in = stdin; + file_name = _("{standard input}"); /* For error messages. */ + } + if (f_in == (FILE *) 0) + { + as_bad (_("can't open %s for reading"), file_name); + as_perror ("%s", file_name); + return; + } + + c = getc (f_in); + if (c == '#') + { + /* Begins with comment, may not want to preprocess. */ + c = getc (f_in); + if (c == 'N') + { + fgets (buf, 80, f_in); + if (!strncmp (buf, "O_APP", 5) && ISSPACE (buf[5])) + preprocess = 0; + if (!strchr (buf, '\n')) + ungetc ('#', f_in); /* It was longer. */ + else + ungetc ('\n', f_in); + } + else if (c == 'A') + { + fgets (buf, 80, f_in); + if (!strncmp (buf, "PP", 2) && ISSPACE (buf[2])) + preprocess = 1; + if (!strchr (buf, '\n')) + ungetc ('#', f_in); + else + ungetc ('\n', f_in); + } + else if (c == '\n') + ungetc ('\n', f_in); + else + ungetc ('#', f_in); + } + else + ungetc (c, f_in); +} + +/* Close input file. */ + +void +input_file_close () +{ + /* Don't close a null file pointer. */ + if (f_in != NULL) + fclose (f_in); + + f_in = 0; +} + +/* This function is passed to do_scrub_chars. */ + +static int +input_file_get (buf, buflen) + char *buf; + int buflen; +{ + int size; + + size = fread (buf, sizeof (char), buflen, f_in); + if (size < 0) + { + as_perror (_("Can't read from %s"), file_name); + size = 0; + } + return size; +} + +/* Read a buffer from the input file. */ + +char * +input_file_give_next_buffer (where) + char *where; /* Where to place 1st character of new buffer. */ +{ + char *return_value; /* -> Last char of what we read, + 1. */ + register int size; + + if (f_in == (FILE *) 0) + return 0; + /* fflush (stdin); could be done here if you want to synchronise + stdin and stdout, for the case where our input file is stdin. + Since the assembler shouldn't do any output to stdout, we + don't bother to synch output and input. */ + if (preprocess) + size = do_scrub_chars (input_file_get, where, BUFFER_SIZE); + else + size = fread (where, sizeof (char), BUFFER_SIZE, f_in); + if (size < 0) + { + as_perror (_("Can't read from %s"), file_name); + size = 0; + } + if (size) + return_value = where + size; + else + { + if (fclose (f_in)) + as_perror (_("Can't close %s"), file_name); + f_in = (FILE *) 0; + return_value = 0; + } + + return return_value; +} diff --git a/contrib/binutils-2.14/gas/input-file.h b/contrib/binutils-2.14/gas/input-file.h new file mode 100644 index 0000000000..9934869464 --- /dev/null +++ b/contrib/binutils-2.14/gas/input-file.h @@ -0,0 +1,66 @@ +/* input_file.h header for input-file.c + Copyright 1987, 1992, 1993, 2000 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/*"input_file.c":Operating-system dependant functions to read source files.*/ + +/* + * No matter what the operating system, this module must provide the + * following services to its callers. + * + * input_file_begin() Call once before anything else. + * + * input_file_end() Call once after everything else. + * + * input_file_buffer_size() Call anytime. Returns largest possible + * delivery from + * input_file_give_next_buffer(). + * + * input_file_open(name) Call once for each input file. + * + * input_file_give_next_buffer(where) Call once to get each new buffer. + * Return 0: no more chars left in file, + * the file has already been closed. + * Otherwise: return a pointer to just + * after the last character we read + * into the buffer. + * If we can only read 0 characters, then + * end-of-file is faked. + * + * input_file_push() Push state, which can be restored + * later. Does implicit input_file_begin. + * Returns char * to saved state. + * + * input_file_pop (arg) Pops previously saved state. + * + * input_file_close () Closes opened file. + * + * All errors are reported (using as_perror) so caller doesn't have to think + * about I/O errors. No I/O errors are fatal: an end-of-file may be faked. + */ + +char *input_file_give_next_buffer PARAMS ((char *where)); +char *input_file_push PARAMS ((void)); +unsigned int input_file_buffer_size PARAMS ((void)); +int input_file_is_open PARAMS ((void)); +void input_file_begin PARAMS ((void)); +void input_file_close PARAMS ((void)); +void input_file_end PARAMS ((void)); +void input_file_open PARAMS ((char *filename, int pre)); +void input_file_pop PARAMS ((char *arg)); diff --git a/contrib/binutils-2.14/gas/input-scrub.c b/contrib/binutils-2.14/gas/input-scrub.c new file mode 100644 index 0000000000..d3437114aa --- /dev/null +++ b/contrib/binutils-2.14/gas/input-scrub.c @@ -0,0 +1,529 @@ +/* input_scrub.c - Break up input buffers into whole numbers of lines. + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 2000 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include /* Need this to make errno declaration right */ +#include "as.h" +#include "input-file.h" +#include "sb.h" +#include "listing.h" + +/* + * O/S independent module to supply buffers of sanitised source code + * to rest of assembler. We get sanitised input data of arbitrary length. + * We break these buffers on line boundaries, recombine pieces that + * were broken across buffers, and return a buffer of full lines to + * the caller. + * The last partial line begins the next buffer we build and return to caller. + * The buffer returned to caller is preceeded by BEFORE_STRING and followed + * by AFTER_STRING, as sentinels. The last character before AFTER_STRING + * is a newline. + * Also looks after line numbers, for e.g. error messages. + */ + +/* + * We don't care how filthy our buffers are, but our callers assume + * that the following sanitation has already been done. + * + * No comments, reduce a comment to a space. + * Reduce a tab to a space unless it is 1st char of line. + * All multiple tabs and spaces collapsed into 1 char. Tab only + * legal if 1st char of line. + * # line file statements converted to .line x;.file y; statements. + * Escaped newlines at end of line: remove them but add as many newlines + * to end of statement as you removed in the middle, to synch line numbers. + */ + +#define BEFORE_STRING ("\n") +#define AFTER_STRING ("\0") /* memcpy of 0 chars might choke. */ +#define BEFORE_SIZE (1) +#define AFTER_SIZE (1) + +static char *buffer_start; /*->1st char of full buffer area. */ +static char *partial_where; /*->after last full line in buffer. */ +static int partial_size; /* >=0. Number of chars in partial line in buffer. */ + +/* Because we need AFTER_STRING just after last full line, it clobbers + 1st part of partial line. So we preserve 1st part of partial line + here. */ +static char save_source[AFTER_SIZE]; + +/* What is the largest size buffer that input_file_give_next_buffer() + could return to us? */ +static unsigned int buffer_length; + +/* The index into an sb structure we are reading from. -1 if none. */ +static int sb_index = -1; + +/* If we are reading from an sb structure, this is it. */ +static sb from_sb; + +/* Should we do a conditional check on from_sb? */ +static int from_sb_is_expansion = 1; + +/* The number of nested sb structures we have included. */ +int macro_nest; + +/* We can have more than one source file open at once, though the info for all + but the latest one are saved off in a struct input_save. These files remain + open, so we are limited by the number of open files allowed by the + underlying OS. We may also sequentially read more than one source file in an + assembly. */ + +/* We must track the physical file and line number for error messages. We also + track a "logical" file and line number corresponding to (C?) compiler + source line numbers. Whenever we open a file we must fill in + physical_input_file. So if it is NULL we have not opened any files yet. */ + +static char *physical_input_file; +static char *logical_input_file; + +typedef unsigned int line_numberT; /* 1-origin line number in a source file. */ +/* A line ends in '\n' or eof. */ + +static line_numberT physical_input_line; +static int logical_input_line; + +/* Struct used to save the state of the input handler during include files */ +struct input_save { + char * buffer_start; + char * partial_where; + int partial_size; + char save_source[AFTER_SIZE]; + unsigned int buffer_length; + char * physical_input_file; + char * logical_input_file; + line_numberT physical_input_line; + int logical_input_line; + int sb_index; + sb from_sb; + int from_sb_is_expansion; /* Should we do a conditional check? */ + struct input_save * next_saved_file; /* Chain of input_saves. */ + char * input_file_save; /* Saved state of input routines. */ + char * saved_position; /* Caller's saved position in buf. */ +}; + +static struct input_save *input_scrub_push PARAMS ((char *saved_position)); +static char *input_scrub_pop PARAMS ((struct input_save *arg)); +static void as_1_char PARAMS ((unsigned int c, FILE * stream)); + +/* Saved information about the file that .include'd this one. When we hit EOF, + we automatically pop to that file. */ + +static struct input_save *next_saved_file; + +/* Push the state of input reading and scrubbing so that we can #include. + The return value is a 'void *' (fudged for old compilers) to a save + area, which can be restored by passing it to input_scrub_pop(). */ + +static struct input_save * +input_scrub_push (saved_position) + char *saved_position; +{ + register struct input_save *saved; + + saved = (struct input_save *) xmalloc (sizeof *saved); + + saved->saved_position = saved_position; + saved->buffer_start = buffer_start; + saved->partial_where = partial_where; + saved->partial_size = partial_size; + saved->buffer_length = buffer_length; + saved->physical_input_file = physical_input_file; + saved->logical_input_file = logical_input_file; + saved->physical_input_line = physical_input_line; + saved->logical_input_line = logical_input_line; + saved->sb_index = sb_index; + saved->from_sb = from_sb; + saved->from_sb_is_expansion = from_sb_is_expansion; + memcpy (saved->save_source, save_source, sizeof (save_source)); + saved->next_saved_file = next_saved_file; + saved->input_file_save = input_file_push (); + + input_file_begin (); /* Reinitialize! */ + logical_input_line = -1; + logical_input_file = (char *) NULL; + buffer_length = input_file_buffer_size (); + sb_index = -1; + + buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); + memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE); + + return saved; +} + +static char * +input_scrub_pop (saved) + struct input_save *saved; +{ + char *saved_position; + + input_scrub_end (); /* Finish off old buffer */ + + input_file_pop (saved->input_file_save); + saved_position = saved->saved_position; + buffer_start = saved->buffer_start; + buffer_length = saved->buffer_length; + physical_input_file = saved->physical_input_file; + logical_input_file = saved->logical_input_file; + physical_input_line = saved->physical_input_line; + logical_input_line = saved->logical_input_line; + sb_index = saved->sb_index; + from_sb = saved->from_sb; + from_sb_is_expansion = saved->from_sb_is_expansion; + partial_where = saved->partial_where; + partial_size = saved->partial_size; + next_saved_file = saved->next_saved_file; + memcpy (save_source, saved->save_source, sizeof (save_source)); + + free (saved); + return saved_position; +} + +void +input_scrub_begin () +{ + know (strlen (BEFORE_STRING) == BEFORE_SIZE); + know (strlen (AFTER_STRING) == AFTER_SIZE + || (AFTER_STRING[0] == '\0' && AFTER_SIZE == 1)); + + input_file_begin (); + + buffer_length = input_file_buffer_size (); + + buffer_start = xmalloc ((BEFORE_SIZE + buffer_length + buffer_length + AFTER_SIZE)); + memcpy (buffer_start, BEFORE_STRING, (int) BEFORE_SIZE); + + /* Line number things. */ + logical_input_line = -1; + logical_input_file = (char *) NULL; + physical_input_file = NULL; /* No file read yet. */ + next_saved_file = NULL; /* At EOF, don't pop to any other file */ + do_scrub_begin (flag_m68k_mri); +} + +void +input_scrub_end () +{ + if (buffer_start) + { + free (buffer_start); + buffer_start = 0; + input_file_end (); + } +} + +/* Start reading input from a new file. + Return start of caller's part of buffer. */ + +char * +input_scrub_new_file (filename) + char *filename; +{ + input_file_open (filename, !flag_no_comments); + physical_input_file = filename[0] ? filename : _("{standard input}"); + physical_input_line = 0; + + partial_size = 0; + return (buffer_start + BEFORE_SIZE); +} + +/* Include a file from the current file. Save our state, cause it to + be restored on EOF, and begin handling a new file. Same result as + input_scrub_new_file. */ + +char * +input_scrub_include_file (filename, position) + char *filename; + char *position; +{ + next_saved_file = input_scrub_push (position); + return input_scrub_new_file (filename); +} + +/* Start getting input from an sb structure. This is used when + expanding a macro. */ + +void +input_scrub_include_sb (from, position, is_expansion) + sb *from; + char *position; + int is_expansion; +{ + if (macro_nest > max_macro_nest) + as_fatal (_("macros nested too deeply")); + ++macro_nest; + +#ifdef md_macro_start + if (is_expansion) + { + md_macro_start (); + } +#endif + + next_saved_file = input_scrub_push (position); + + sb_new (&from_sb); + from_sb_is_expansion = is_expansion; + if (from->len >= 1 && from->ptr[0] != '\n') + { + /* Add the sentinel required by read.c. */ + sb_add_char (&from_sb, '\n'); + } + sb_add_sb (&from_sb, from); + sb_index = 1; + + /* These variables are reset by input_scrub_push. Restore them + since we are, after all, still at the same point in the file. */ + logical_input_line = next_saved_file->logical_input_line; + logical_input_file = next_saved_file->logical_input_file; +} + +void +input_scrub_close () +{ + input_file_close (); +} + +char * +input_scrub_next_buffer (bufp) + char **bufp; +{ + register char *limit; /*->just after last char of buffer. */ + + if (sb_index >= 0) + { + if (sb_index >= from_sb.len) + { + sb_kill (&from_sb); + if (from_sb_is_expansion + ) + { + cond_finish_check (macro_nest); +#ifdef md_macro_end + /* Allow the target to clean up per-macro expansion + data. */ + md_macro_end (); +#endif + } + --macro_nest; + partial_where = NULL; + if (next_saved_file != NULL) + *bufp = input_scrub_pop (next_saved_file); + return partial_where; + } + + partial_where = from_sb.ptr + from_sb.len; + partial_size = 0; + *bufp = from_sb.ptr + sb_index; + sb_index = from_sb.len; + return partial_where; + } + + *bufp = buffer_start + BEFORE_SIZE; + + if (partial_size) + { + memcpy (buffer_start + BEFORE_SIZE, partial_where, + (unsigned int) partial_size); + memcpy (buffer_start + BEFORE_SIZE, save_source, AFTER_SIZE); + } + limit = input_file_give_next_buffer (buffer_start + + BEFORE_SIZE + + partial_size); + if (limit) + { + register char *p; /* Find last newline. */ + + for (p = limit - 1; *p != '\n'; --p) + ; + ++p; + + while (p <= buffer_start + BEFORE_SIZE) + { + int limoff; + + limoff = limit - buffer_start; + buffer_length += input_file_buffer_size (); + buffer_start = xrealloc (buffer_start, + (BEFORE_SIZE + + 2 * buffer_length + + AFTER_SIZE)); + *bufp = buffer_start + BEFORE_SIZE; + limit = input_file_give_next_buffer (buffer_start + limoff); + + if (limit == NULL) + { + as_warn (_("partial line at end of file ignored")); + partial_where = NULL; + if (next_saved_file) + *bufp = input_scrub_pop (next_saved_file); + return NULL; + } + + for (p = limit - 1; *p != '\n'; --p) + ; + ++p; + } + + partial_where = p; + partial_size = limit - p; + memcpy (save_source, partial_where, (int) AFTER_SIZE); + memcpy (partial_where, AFTER_STRING, (int) AFTER_SIZE); + } + else + { + partial_where = 0; + if (partial_size > 0) + { + as_warn (_("partial line at end of file ignored")); + } + + /* Tell the listing we've finished the file. */ + LISTING_EOF (); + + /* If we should pop to another file at EOF, do it. */ + if (next_saved_file) + { + *bufp = input_scrub_pop (next_saved_file); /* Pop state */ + /* partial_where is now correct to return, since we popped it. */ + } + } + return (partial_where); +} + +/* The remaining part of this file deals with line numbers, error + messages and so on. Return TRUE if we opened any file. */ + +int +seen_at_least_1_file () +{ + return (physical_input_file != NULL); +} + +void +bump_line_counters () +{ + if (sb_index < 0) + { + ++physical_input_line; + if (logical_input_line >= 0) + ++logical_input_line; + } +} + +/* Tells us what the new logical line number and file are. + If the line_number is -1, we don't change the current logical line + number. If it is -2, we decrement the logical line number (this is + to support the .appfile pseudo-op inserted into the stream by + do_scrub_chars). + If the fname is NULL, we don't change the current logical file name. + Returns nonzero if the filename actually changes. */ + +int +new_logical_line (fname, line_number) + char *fname; /* DON'T destroy it! We point to it! */ + int line_number; +{ + if (line_number >= 0) + logical_input_line = line_number; + else if (line_number == -2 && logical_input_line > 0) + --logical_input_line; + + if (fname + && (logical_input_file == NULL + || strcmp (logical_input_file, fname))) + { + logical_input_file = fname; + return 1; + } + else + return 0; +} + +/* Return the current file name and line number. + namep should be char * const *, but there are compilers which screw + up declarations like that, and it's easier to avoid it. */ + +void +as_where (namep, linep) + char **namep; + unsigned int *linep; +{ + if (logical_input_file != NULL + && (linep == NULL || logical_input_line >= 0)) + { + *namep = logical_input_file; + if (linep != NULL) + *linep = logical_input_line; + } + else if (physical_input_file != NULL) + { + *namep = physical_input_file; + if (linep != NULL) + *linep = physical_input_line; + } + else + { + *namep = 0; + if (linep != NULL) + *linep = 0; + } +} + +/* Output to given stream how much of line we have scanned so far. + Assumes we have scanned up to and including input_line_pointer. + No free '\n' at end of line. */ + +void +as_howmuch (stream) + FILE *stream; /* Opened for write please. */ +{ + register char *p; /* Scan input line. */ + + for (p = input_line_pointer - 1; *p != '\n'; --p) + { + } + ++p; /* p->1st char of line. */ + for (; p <= input_line_pointer; p++) + { + /* Assume ASCII. EBCDIC & other micro-computer char sets ignored. */ + as_1_char ((unsigned char) *p, stream); + } +} + +static void +as_1_char (c, stream) + unsigned int c; + FILE *stream; +{ + if (c > 127) + { + (void) putc ('%', stream); + c -= 128; + } + if (c < 32) + { + (void) putc ('^', stream); + c += '@'; + } + (void) putc (c, stream); +} diff --git a/contrib/binutils-2.14/gas/listing.c b/contrib/binutils-2.14/gas/listing.c new file mode 100644 index 0000000000..7510d85895 --- /dev/null +++ b/contrib/binutils-2.14/gas/listing.c @@ -0,0 +1,1404 @@ +/* listing.c - mainting assembly listings + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002 + Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* + Contributed by Steve Chamberlain + + A listing page looks like: + + LISTING_HEADER sourcefilename pagenumber + TITLE LINE + SUBTITLE LINE + linenumber address data source + linenumber address data source + linenumber address data source + linenumber address data source + + If not overridden, the listing commands are: + + .title "stuff" + Put "stuff" onto the title line + .sbttl "stuff" + Put stuff onto the subtitle line + + If these commands come within 10 lines of the top of the page, they + will affect the page they are on, as well as any subsequent page + + .eject + Thow a page + .list + Increment the enable listing counter + .nolist + Decrement the enable listing counter + + .psize Y[,X] + Set the paper size to X wide and Y high. Setting a psize Y of + zero will suppress form feeds except where demanded by .eject + + If the counter goes below zero, listing is suppressed. + + Listings are a maintained by read calling various listing_ + functions. What happens most is that the macro NO_LISTING is not + defined (from the Makefile), then the macro LISTING_NEWLINE expands + into a call to listing_newline. The call is done from read.c, every + time it sees a newline, and -l is on the command line. + + The function listing_newline remembers the frag associated with the + newline, and creates a new frag - note that this is wasteful, but not + a big deal, since listing slows things down a lot anyway. The + function also rememebers when the filename changes. + + When all the input has finished, and gas has had a chance to settle + down, the listing is output. This is done by running down the list of + frag/source file records, and opening the files as needed and printing + out the bytes and chars associated with them. + + The only things which the architecture can change about the listing + are defined in these macros: + + LISTING_HEADER The name of the architecture + LISTING_WORD_SIZE The make of the number of bytes in a word, this determines + the clumping of the output data. eg a value of + 2 makes words look like 1234 5678, whilst 1 + would make the same value look like 12 34 56 + 78 + LISTING_LHS_WIDTH Number of words of above size for the lhs + + LISTING_LHS_WIDTH_SECOND Number of words for the data on the lhs + for the second line + + LISTING_LHS_CONT_LINES Max number of lines to use up for a continutation + LISTING_RHS_WIDTH Number of chars from the input file to print + on a line +*/ + +#include "as.h" +#include "obstack.h" +#include "safe-ctype.h" +#include "input-file.h" +#include "subsegs.h" + +#ifndef NO_LISTING + +#ifndef LISTING_HEADER +#define LISTING_HEADER "GAS LISTING" +#endif +#ifndef LISTING_WORD_SIZE +#define LISTING_WORD_SIZE 4 +#endif +#ifndef LISTING_LHS_WIDTH +#define LISTING_LHS_WIDTH ((LISTING_WORD_SIZE) > 4 ? 1 : 4 / (LISTING_WORD_SIZE)) +#endif +#ifndef LISTING_LHS_WIDTH_SECOND +#define LISTING_LHS_WIDTH_SECOND LISTING_LHS_WIDTH +#endif +#ifndef LISTING_RHS_WIDTH +#define LISTING_RHS_WIDTH 100 +#endif +#ifndef LISTING_LHS_CONT_LINES +#define LISTING_LHS_CONT_LINES 4 +#endif + +/* This structure remembers which .s were used. */ +typedef struct file_info_struct { + struct file_info_struct * next; + char * filename; + long pos; + unsigned int linenum; + int at_end; +} file_info_type; + +/* This structure rememebrs which line from which file goes into which + frag. */ +struct list_info_struct { + /* Frag which this line of source is nearest to. */ + fragS *frag; + + /* The actual line in the source file. */ + unsigned int line; + /* Pointer to the file info struct for the file which this line + belongs to. */ + file_info_type *file; + + /* The expanded text of any macro that may have been executing. */ + char *line_contents; + + /* Next in list. */ + struct list_info_struct *next; + + /* Pointer to the file info struct for the high level language + source line that belongs here. */ + file_info_type *hll_file; + /* High level language source line. */ + unsigned int hll_line; + + /* Pointer to any error message associated with this line. */ + char *message; + + enum { + EDICT_NONE, + EDICT_SBTTL, + EDICT_TITLE, + EDICT_NOLIST, + EDICT_LIST, + EDICT_NOLIST_NEXT, + EDICT_EJECT + } edict; + char *edict_arg; + + /* Nonzero if this line is to be omitted because it contains + debugging information. This can become a flags field if we come + up with more information to store here. */ + int debugging; +}; + +typedef struct list_info_struct list_info_type; + +int listing_lhs_width = LISTING_LHS_WIDTH; +int listing_lhs_width_second = LISTING_LHS_WIDTH_SECOND; +int listing_lhs_cont_lines = LISTING_LHS_CONT_LINES; +int listing_rhs_width = LISTING_RHS_WIDTH; + +struct list_info_struct * listing_tail; + +static file_info_type * file_info_head; +static file_info_type * last_open_file_info; +static FILE * last_open_file; +static struct list_info_struct * head; +static int paper_width = 200; +static int paper_height = 60; + +extern int listing; + +/* File to output listings to. */ +static FILE *list_file; + +/* This static array is used to keep the text of data to be printed + before the start of the line. */ + +#define MAX_BYTES \ + (((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width \ + + ((((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second) \ + * listing_lhs_cont_lines) \ + + 20) + +static char *data_buffer; + +/* Prototypes. */ +static void listing_message PARAMS ((const char *name, const char *message)); +static file_info_type *file_info PARAMS ((const char *file_name)); +static void new_frag PARAMS ((void)); +static char *buffer_line PARAMS ((file_info_type *file, + char *line, unsigned int size)); +static void listing_page PARAMS ((list_info_type *list)); +static unsigned int calc_hex PARAMS ((list_info_type *list)); +static void print_lines PARAMS ((list_info_type *, unsigned int, + char *, unsigned int)); +static void list_symbol_table PARAMS ((void)); +static void print_source PARAMS ((file_info_type *current_file, + list_info_type *list, + char *buffer, + unsigned int width)); +static int debugging_pseudo PARAMS ((list_info_type *, const char *)); +static void listing_listing PARAMS ((char *name)); + +static void +listing_message (name, message) + const char *name; + const char *message; +{ + if (listing_tail != (list_info_type *) NULL) + { + unsigned int l = strlen (name) + strlen (message) + 1; + char *n = (char *) xmalloc (l); + strcpy (n, name); + strcat (n, message); + listing_tail->message = n; + } +} + +void +listing_warning (message) + const char *message; +{ + listing_message (_("Warning:"), message); +} + +void +listing_error (message) + const char *message; +{ + listing_message (_("Error:"), message); +} + +static file_info_type * +file_info (file_name) + const char *file_name; +{ + /* Find an entry with this file name. */ + file_info_type *p = file_info_head; + + while (p != (file_info_type *) NULL) + { + if (strcmp (p->filename, file_name) == 0) + return p; + p = p->next; + } + + /* Make new entry. */ + + p = (file_info_type *) xmalloc (sizeof (file_info_type)); + p->next = file_info_head; + file_info_head = p; + p->filename = xstrdup (file_name); + p->pos = 0; + p->linenum = 0; + p->at_end = 0; + + return p; +} + +static void +new_frag () +{ + + frag_wane (frag_now); + frag_new (0); + +} + +void +listing_newline (ps) + char *ps; +{ + char *file; + unsigned int line; + static unsigned int last_line = 0xffff; + static char *last_file = NULL; + list_info_type *new = NULL; + + if (listing == 0) + return; + + if (now_seg == absolute_section) + return; + +#ifdef OBJ_ELF + /* In ELF, anything in a section beginning with .debug or .line is + considered to be debugging information. This includes the + statement which switches us into the debugging section, which we + can only set after we are already in the debugging section. */ + if ((listing & LISTING_NODEBUG) != 0 + && listing_tail != NULL + && ! listing_tail->debugging) + { + const char *segname; + + segname = segment_name (now_seg); + if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0 + || strncmp (segname, ".line", sizeof ".line" - 1) == 0) + listing_tail->debugging = 1; + } +#endif + + as_where (&file, &line); + if (ps == NULL) + { + if (line == last_line + && !(last_file && file && strcmp (file, last_file))) + return; + + new = (list_info_type *) xmalloc (sizeof (list_info_type)); + + /* Detect if we are reading from stdin by examining the file + name returned by as_where(). + + [FIXME: We rely upon the name in the strcmp below being the + same as the one used by input_scrub_new_file(), if that is + not true, then this code will fail]. + + If we are reading from stdin, then we need to save each input + line here (assuming of course that we actually have a line of + input to read), so that it can be displayed in the listing + that is produced at the end of the assembly. */ + if (strcmp (file, _("{standard input}")) == 0 + && input_line_pointer != NULL) + { + char *copy; + int len; + int seen_quote = 0; + + for (copy = input_line_pointer - 1; + *copy && (seen_quote + || (! is_end_of_line [(unsigned char) *copy])); + copy++) + if (*copy == '"' && copy[-1] != '\\') + seen_quote = ! seen_quote; + + len = (copy - input_line_pointer) + 2; + + copy = xmalloc (len); + + if (copy != NULL) + { + char *src = input_line_pointer - 1; + char *dest = copy; + + while (--len) + { + unsigned char c = *src++; + + /* Omit control characters in the listing. */ + if (!ISCNTRL (c)) + *dest++ = c; + } + + *dest = 0; + } + + new->line_contents = copy; + } + else + new->line_contents = NULL; + } + else + { + new = (list_info_type *) xmalloc (sizeof (list_info_type)); + new->line_contents = ps; + } + + last_line = line; + last_file = file; + + new_frag (); + + if (listing_tail) + listing_tail->next = new; + else + head = new; + + listing_tail = new; + + new->frag = frag_now; + new->line = line; + new->file = file_info (file); + new->next = (list_info_type *) NULL; + new->message = (char *) NULL; + new->edict = EDICT_NONE; + new->hll_file = (file_info_type *) NULL; + new->hll_line = 0; + new->debugging = 0; + + new_frag (); + +#ifdef OBJ_ELF + /* In ELF, anything in a section beginning with .debug or .line is + considered to be debugging information. */ + if ((listing & LISTING_NODEBUG) != 0) + { + const char *segname; + + segname = segment_name (now_seg); + if (strncmp (segname, ".debug", sizeof ".debug" - 1) == 0 + || strncmp (segname, ".line", sizeof ".line" - 1) == 0) + new->debugging = 1; + } +#endif +} + +/* Attach all current frags to the previous line instead of the + current line. This is called by the MIPS backend when it discovers + that it needs to add some NOP instructions; the added NOP + instructions should go with the instruction that has the delay, not + with the new instruction. */ + +void +listing_prev_line () +{ + list_info_type *l; + fragS *f; + + if (head == (list_info_type *) NULL + || head == listing_tail) + return; + + new_frag (); + + for (l = head; l->next != listing_tail; l = l->next) + ; + + for (f = frchain_now->frch_root; f != (fragS *) NULL; f = f->fr_next) + if (f->line == listing_tail) + f->line = l; + + listing_tail->frag = frag_now; + new_frag (); +} + +/* This function returns the next source line from the file supplied, + truncated to size. It appends a fake line to the end of each input + file to make. */ + +static char * +buffer_line (file, line, size) + file_info_type *file; + char *line; + unsigned int size; +{ + unsigned int count = 0; + int c; + + char *p = line; + + /* If we couldn't open the file, return an empty line. */ + if (file->at_end) + return ""; + + /* Check the cache and see if we last used this file. */ + if (!last_open_file_info || file != last_open_file_info) + { + if (last_open_file) + { + last_open_file_info->pos = ftell (last_open_file); + fclose (last_open_file); + } + + last_open_file_info = file; + last_open_file = fopen (file->filename, FOPEN_RT); + if (last_open_file == NULL) + { + file->at_end = 1; + return ""; + } + + /* Seek to where we were last time this file was open. */ + if (file->pos) + fseek (last_open_file, file->pos, SEEK_SET); + } + + c = fgetc (last_open_file); + + /* Leave room for null. */ + size -= 1; + + while (c != EOF && c != '\n') + { + if (count < size) + *p++ = c; + count++; + + c = fgetc (last_open_file); + + } + if (c == EOF) + { + file->at_end = 1; + if (count + 2 < size) + { + *p++ = '.'; + *p++ = '.'; + *p++ = '.'; + } + } + file->linenum++; + *p++ = 0; + return line; +} + +static const char *fn; + +static unsigned int eject; /* Eject pending */ +static unsigned int page; /* Current page number */ +static char *title; /* Current title */ +static char *subtitle; /* Current subtitle */ +static unsigned int on_page; /* Number of lines printed on current page */ + +static void +listing_page (list) + list_info_type *list; +{ + /* Grope around, see if we can see a title or subtitle edict coming up + soon. (we look down 10 lines of the page and see if it's there) */ + if ((eject || (on_page >= (unsigned int) paper_height)) + && paper_height != 0) + { + unsigned int c = 10; + int had_title = 0; + int had_subtitle = 0; + + page++; + + while (c != 0 && list) + { + if (list->edict == EDICT_SBTTL && !had_subtitle) + { + had_subtitle = 1; + subtitle = list->edict_arg; + } + if (list->edict == EDICT_TITLE && !had_title) + { + had_title = 1; + title = list->edict_arg; + } + list = list->next; + c--; + } + + if (page > 1) + { + fprintf (list_file, "\f"); + } + + fprintf (list_file, "%s %s \t\t\tpage %d\n", LISTING_HEADER, fn, page); + fprintf (list_file, "%s\n", title); + fprintf (list_file, "%s\n", subtitle); + on_page = 3; + eject = 0; + } +} + +static unsigned int +calc_hex (list) + list_info_type *list; +{ + int data_buffer_size; + list_info_type *first = list; + unsigned int address = ~(unsigned int) 0; + fragS *frag; + fragS *frag_ptr; + unsigned int octet_in_frag; + + /* Find first frag which says it belongs to this line. */ + frag = list->frag; + while (frag && frag->line != list) + frag = frag->fr_next; + + frag_ptr = frag; + + data_buffer_size = 0; + + /* Dump all the frags which belong to this line. */ + while (frag_ptr != (fragS *) NULL && frag_ptr->line == first) + { + /* Print as many bytes from the fixed part as is sensible. */ + octet_in_frag = 0; + while ((offsetT) octet_in_frag < frag_ptr->fr_fix + && data_buffer_size < MAX_BYTES - 3) + { + if (address == ~(unsigned int) 0) + { + address = frag_ptr->fr_address / OCTETS_PER_BYTE; + } + + sprintf (data_buffer + data_buffer_size, + "%02X", + (frag_ptr->fr_literal[octet_in_frag]) & 0xff); + data_buffer_size += 2; + octet_in_frag++; + } + if (frag_ptr->fr_type == rs_fill) + { + unsigned int var_rep_max = octet_in_frag; + unsigned int var_rep_idx = octet_in_frag; + + /* Print as many bytes from the variable part as is sensible. */ + while (((offsetT) octet_in_frag + < (frag_ptr->fr_fix + frag_ptr->fr_var * frag_ptr->fr_offset)) + && data_buffer_size < MAX_BYTES - 3) + { + if (address == ~(unsigned int) 0) + { + address = frag_ptr->fr_address / OCTETS_PER_BYTE; + } + sprintf (data_buffer + data_buffer_size, + "%02X", + (frag_ptr->fr_literal[var_rep_idx]) & 0xff); +#if 0 + data_buffer[data_buffer_size++] = '*'; + data_buffer[data_buffer_size++] = '*'; +#endif + data_buffer_size += 2; + + var_rep_idx++; + octet_in_frag++; + + if ((offsetT) var_rep_idx >= frag_ptr->fr_fix + frag_ptr->fr_var) + var_rep_idx = var_rep_max; + } + } + + frag_ptr = frag_ptr->fr_next; + } + data_buffer[data_buffer_size] = '\0'; + return address; +} + +static void +print_lines (list, lineno, string, address) + list_info_type *list; + unsigned int lineno; + char *string; + unsigned int address; +{ + unsigned int idx; + unsigned int nchars; + unsigned int lines; + unsigned int octet_in_word = 0; + char *src = data_buffer; + int cur; + + /* Print the stuff on the first line. */ + listing_page (list); + nchars = (LISTING_WORD_SIZE * 2 + 1) * listing_lhs_width; + + /* Print the hex for the first line. */ + if (address == ~(unsigned int) 0) + { + fprintf (list_file, "% 4d ", lineno); + for (idx = 0; idx < nchars; idx++) + fprintf (list_file, " "); + + fprintf (list_file, "\t%s\n", string ? string : ""); + + on_page++; + + listing_page (0); + + return; + } + + if (had_errors ()) + fprintf (list_file, "% 4d ???? ", lineno); + else + fprintf (list_file, "% 4d %04x ", lineno, address); + + /* And the data to go along with it. */ + idx = 0; + cur = 0; + while (src[cur] && idx < nchars) + { + int offset; + offset = cur; + fprintf (list_file, "%c%c", src[offset], src[offset + 1]); + cur += 2; + octet_in_word++; + + if (octet_in_word == LISTING_WORD_SIZE) + { + fprintf (list_file, " "); + idx++; + octet_in_word = 0; + } + + idx += 2; + } + + for (; idx < nchars; idx++) + fprintf (list_file, " "); + + fprintf (list_file, "\t%s\n", string ? string : ""); + on_page++; + listing_page (list); + + if (list->message) + { + fprintf (list_file, "**** %s\n", list->message); + listing_page (list); + on_page++; + } + + for (lines = 0; + lines < (unsigned int) listing_lhs_cont_lines + && src[cur]; + lines++) + { + nchars = ((LISTING_WORD_SIZE * 2) + 1) * listing_lhs_width_second - 1; + idx = 0; + + /* Print any more lines of data, but more compactly. */ + fprintf (list_file, "% 4d ", lineno); + + while (src[cur] && idx < nchars) + { + int offset; + offset = cur; + fprintf (list_file, "%c%c", src[offset], src[offset + 1]); + cur += 2; + idx += 2; + octet_in_word++; + + if (octet_in_word == LISTING_WORD_SIZE) + { + fprintf (list_file, " "); + idx++; + octet_in_word = 0; + } + } + + fprintf (list_file, "\n"); + on_page++; + listing_page (list); + } +} + +static void +list_symbol_table () +{ + extern symbolS *symbol_rootP; + int got_some = 0; + + symbolS *ptr; + eject = 1; + listing_page (0); + + for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr)) + { + if (SEG_NORMAL (S_GET_SEGMENT (ptr)) + || S_GET_SEGMENT (ptr) == absolute_section) + { +#ifdef BFD_ASSEMBLER + /* Don't report section symbols. They are not interesting. */ + if (symbol_section_p (ptr)) + continue; +#endif + if (S_GET_NAME (ptr)) + { + char buf[30], fmt[8]; + valueT val = S_GET_VALUE (ptr); + + /* @@ Note that this is dependent on the compilation options, + not solely on the target characteristics. */ + if (sizeof (val) == 4 && sizeof (int) == 4) + sprintf (buf, "%08lx", (unsigned long) val); + else if (sizeof (val) <= sizeof (unsigned long)) + { + sprintf (fmt, "%%0%lulx", + (unsigned long) (sizeof (val) * 2)); + sprintf (buf, fmt, (unsigned long) val); + } +#if defined (BFD64) + else if (sizeof (val) > 4) + sprintf_vma (buf, val); +#endif + else + abort (); + + if (!got_some) + { + fprintf (list_file, "DEFINED SYMBOLS\n"); + on_page++; + got_some = 1; + } + + if (symbol_get_frag (ptr) && symbol_get_frag (ptr)->line) + { + fprintf (list_file, "%20s:%-5d %s:%s %s\n", + symbol_get_frag (ptr)->line->file->filename, + symbol_get_frag (ptr)->line->line, + segment_name (S_GET_SEGMENT (ptr)), + buf, S_GET_NAME (ptr)); + } + else + { + fprintf (list_file, "%33s:%s %s\n", + segment_name (S_GET_SEGMENT (ptr)), + buf, S_GET_NAME (ptr)); + } + + on_page++; + listing_page (0); + } + } + + } + if (!got_some) + { + fprintf (list_file, "NO DEFINED SYMBOLS\n"); + on_page++; + } + fprintf (list_file, "\n"); + on_page++; + listing_page (0); + + got_some = 0; + + for (ptr = symbol_rootP; ptr != (symbolS *) NULL; ptr = symbol_next (ptr)) + { + if (S_GET_NAME (ptr) && strlen (S_GET_NAME (ptr)) != 0) + { + if (S_GET_SEGMENT (ptr) == undefined_section) + { + if (!got_some) + { + got_some = 1; + fprintf (list_file, "UNDEFINED SYMBOLS\n"); + on_page++; + listing_page (0); + } + fprintf (list_file, "%s\n", S_GET_NAME (ptr)); + on_page++; + listing_page (0); + } + } + } + if (!got_some) + { + fprintf (list_file, "NO UNDEFINED SYMBOLS\n"); + on_page++; + listing_page (0); + } +} + +static void +print_source (current_file, list, buffer, width) + file_info_type *current_file; + list_info_type *list; + char *buffer; + unsigned int width; +{ + if (!current_file->at_end) + { + while (current_file->linenum < list->hll_line + && !current_file->at_end) + { + char *p = buffer_line (current_file, buffer, width); + fprintf (list_file, "%4u:%-13s **** %s\n", current_file->linenum, + current_file->filename, p); + on_page++; + listing_page (list); + } + } +} + +/* Sometimes the user doesn't want to be bothered by the debugging + records inserted by the compiler, see if the line is suspicious. */ + +static int +debugging_pseudo (list, line) + list_info_type *list; + const char *line; +{ + static int in_debug; + int was_debug; + + if (list->debugging) + { + in_debug = 1; + return 1; + } + + was_debug = in_debug; + in_debug = 0; + + while (ISSPACE (*line)) + line++; + + if (*line != '.') + { +#ifdef OBJ_ELF + /* The ELF compiler sometimes emits blank lines after switching + out of a debugging section. If the next line drops us back + into debugging information, then don't print the blank line. + This is a hack for a particular compiler behaviour, not a + general case. */ + if (was_debug + && *line == '\0' + && list->next != NULL + && list->next->debugging) + { + in_debug = 1; + return 1; + } +#endif + + return 0; + } + + line++; + + if (strncmp (line, "def", 3) == 0) + return 1; + if (strncmp (line, "val", 3) == 0) + return 1; + if (strncmp (line, "scl", 3) == 0) + return 1; + if (strncmp (line, "line", 4) == 0) + return 1; + if (strncmp (line, "endef", 5) == 0) + return 1; + if (strncmp (line, "ln", 2) == 0) + return 1; + if (strncmp (line, "type", 4) == 0) + return 1; + if (strncmp (line, "size", 4) == 0) + return 1; + if (strncmp (line, "dim", 3) == 0) + return 1; + if (strncmp (line, "tag", 3) == 0) + return 1; + + if (strncmp (line, "stabs", 5) == 0) + return 1; + if (strncmp (line, "stabn", 5) == 0) + return 1; + + return 0; +} + +static void +listing_listing (name) + char *name ATTRIBUTE_UNUSED; +{ + list_info_type *list = head; + file_info_type *current_hll_file = (file_info_type *) NULL; + char *message; + char *buffer; + char *p; + int show_listing = 1; + unsigned int width; + + buffer = xmalloc (listing_rhs_width); + data_buffer = xmalloc (MAX_BYTES); + eject = 1; + list = head; + + while (list != (list_info_type *) NULL && 0) + { + if (list->next) + list->frag = list->next->frag; + list = list->next; + + } + + list = head->next; + + while (list) + { + unsigned int list_line; + + width = listing_rhs_width > paper_width ? paper_width : + listing_rhs_width; + + list_line = list->line; + switch (list->edict) + { + case EDICT_LIST: + /* Skip all lines up to the current. */ + list_line--; + break; + case EDICT_NOLIST: + show_listing--; + break; + case EDICT_NOLIST_NEXT: + if (show_listing == 0) + list_line--; + break; + case EDICT_EJECT: + break; + case EDICT_NONE: + break; + case EDICT_TITLE: + title = list->edict_arg; + break; + case EDICT_SBTTL: + subtitle = list->edict_arg; + break; + default: + abort (); + } + + if (show_listing <= 0) + { + while (list->file->linenum < list_line + && !list->file->at_end) + p = buffer_line (list->file, buffer, width); + } + + if (list->edict == EDICT_LIST + || (list->edict == EDICT_NOLIST_NEXT && show_listing == 0)) + { + /* Enable listing for the single line that caused the enable. */ + list_line++; + show_listing++; + } + + if (show_listing > 0) + { + /* Scan down the list and print all the stuff which can be done + with this line (or lines). */ + message = 0; + + if (list->hll_file) + { + current_hll_file = list->hll_file; + } + + if (current_hll_file && list->hll_line && (listing & LISTING_HLL)) + { + print_source (current_hll_file, list, buffer, width); + } + + if (list->line_contents) + { + if (!((listing & LISTING_NODEBUG) + && debugging_pseudo (list, list->line_contents))) + { + print_lines (list, + list->file->linenum == 0 ? list->line : list->file->linenum, + list->line_contents, calc_hex (list)); + } + free (list->line_contents); + list->line_contents = NULL; + } + else + { + while (list->file->linenum < list_line + && !list->file->at_end) + { + unsigned int address; + + p = buffer_line (list->file, buffer, width); + + if (list->file->linenum < list_line) + address = ~(unsigned int) 0; + else + address = calc_hex (list); + + if (!((listing & LISTING_NODEBUG) + && debugging_pseudo (list, p))) + print_lines (list, list->file->linenum, p, address); + } + } + + if (list->edict == EDICT_EJECT) + { + eject = 1; + } + } + + if (list->edict == EDICT_NOLIST_NEXT && show_listing == 1) + --show_listing; + + list = list->next; + } + + free (buffer); + free (data_buffer); + data_buffer = NULL; +} + +void +listing_print (name) + char *name; +{ + int using_stdout; + + title = ""; + subtitle = ""; + + if (name == NULL) + { + list_file = stdout; + using_stdout = 1; + } + else + { + list_file = fopen (name, FOPEN_WT); + if (list_file != NULL) + using_stdout = 0; + else + { + as_perror (_("can't open list file: %s"), name); + list_file = stdout; + using_stdout = 1; + } + } + + if (listing & LISTING_NOFORM) + { + paper_height = 0; + } + + if (listing & LISTING_LISTING) + { + listing_listing (name); + } + + if (listing & LISTING_SYMBOLS) + { + list_symbol_table (); + } + + if (! using_stdout) + { + if (fclose (list_file) == EOF) + as_perror (_("error closing list file: %s"), name); + } + + if (last_open_file) + { + fclose (last_open_file); + } +} + +void +listing_file (name) + const char *name; +{ + fn = name; +} + +void +listing_eject (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + if (listing) + listing_tail->edict = EDICT_EJECT; +} + +void +listing_flags (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + while ((*input_line_pointer++) && (*input_line_pointer != '\n')) + input_line_pointer++; + +} + +/* Turn listing on or off. An argument of 0 means to turn off + listing. An argument of 1 means to turn on listing. An argument + of 2 means to turn off listing, but as of the next line; that is, + the current line should be listed, but the next line should not. */ + +void +listing_list (on) + int on; +{ + if (listing) + { + switch (on) + { + case 0: + if (listing_tail->edict == EDICT_LIST) + listing_tail->edict = EDICT_NONE; + else + listing_tail->edict = EDICT_NOLIST; + break; + case 1: + if (listing_tail->edict == EDICT_NOLIST + || listing_tail->edict == EDICT_NOLIST_NEXT) + listing_tail->edict = EDICT_NONE; + else + listing_tail->edict = EDICT_LIST; + break; + case 2: + listing_tail->edict = EDICT_NOLIST_NEXT; + break; + default: + abort (); + } + } +} + +void +listing_psize (width_only) + int width_only; +{ + if (! width_only) + { + paper_height = get_absolute_expression (); + + if (paper_height < 0 || paper_height > 1000) + { + paper_height = 0; + as_warn (_("strange paper height, set to no form")); + } + + if (*input_line_pointer != ',') + { + demand_empty_rest_of_line (); + return; + } + + ++input_line_pointer; + } + + paper_width = get_absolute_expression (); + + demand_empty_rest_of_line (); +} + +void +listing_nopage (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + paper_height = 0; +} + +void +listing_title (depth) + int depth; +{ + int quoted; + char *start; + char *ttl; + unsigned int length; + + SKIP_WHITESPACE (); + if (*input_line_pointer != '\"') + quoted = 0; + else + { + quoted = 1; + ++input_line_pointer; + } + + start = input_line_pointer; + + while (*input_line_pointer) + { + if (quoted + ? *input_line_pointer == '\"' + : is_end_of_line[(unsigned char) *input_line_pointer]) + { + if (listing) + { + length = input_line_pointer - start; + ttl = xmalloc (length + 1); + memcpy (ttl, start, length); + ttl[length] = 0; + listing_tail->edict = depth ? EDICT_SBTTL : EDICT_TITLE; + listing_tail->edict_arg = ttl; + } + if (quoted) + input_line_pointer++; + demand_empty_rest_of_line (); + return; + } + else if (*input_line_pointer == '\n') + { + as_bad (_("new line in title")); + demand_empty_rest_of_line (); + return; + } + else + { + input_line_pointer++; + } + } +} + +void +listing_source_line (line) + unsigned int line; +{ + if (listing) + { + new_frag (); + listing_tail->hll_line = line; + new_frag (); + } +} + +void +listing_source_file (file) + const char *file; +{ + if (listing) + listing_tail->hll_file = file_info (file); +} + +#else + +/* Dummy functions for when compiled without listing enabled. */ + +void +listing_flags (ignore) + int ignore; +{ + s_ignore (0); +} + +void +listing_list (on) + int on; +{ + s_ignore (0); +} + +void +listing_eject (ignore) + int ignore; +{ + s_ignore (0); +} + +void +listing_psize (ignore) + int ignore; +{ + s_ignore (0); +} + +void +listing_nopage (ignore) + int ignore; +{ + s_ignore (0); +} + +void +listing_title (depth) + int depth; +{ + s_ignore (0); +} + +void +listing_file (name) + const char *name; +{ + +} + +void +listing_newline (name) + char *name; +{ + +} + +void +listing_source_line (n) + unsigned int n; +{ + +} + +void +listing_source_file (n) + const char *n; +{ + +} + +#endif diff --git a/contrib/binutils-2.14/gas/listing.h b/contrib/binutils-2.14/gas/listing.h new file mode 100644 index 0000000000..3301735eb0 --- /dev/null +++ b/contrib/binutils-2.14/gas/listing.h @@ -0,0 +1,67 @@ +/* This file is listing.h + Copyright 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1995, 1997, 1998 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef __listing_h__ +#define __listing_h__ + +#define LISTING_LISTING 1 +#define LISTING_SYMBOLS 2 +#define LISTING_NOFORM 4 +#define LISTING_HLL 8 +#define LISTING_NODEBUG 16 +#define LISTING_NOCOND 32 +#define LISTING_MACEXP 64 + +#define LISTING_DEFAULT (LISTING_LISTING | LISTING_HLL | LISTING_SYMBOLS) + +#ifndef NO_LISTING +#define LISTING_NEWLINE() { if (listing) listing_newline(NULL); } +#else +#define LISTING_NEWLINE() {;} +#endif +#define LISTING_EOF() LISTING_NEWLINE() + +#define LISTING_SKIP_COND() ((listing & LISTING_NOCOND) != 0) + +void listing_eject PARAMS ((int)); +void listing_error PARAMS ((const char *message)); +void listing_file PARAMS ((const char *name)); +void listing_flags PARAMS ((int)); +void listing_list PARAMS ((int on)); +void listing_newline PARAMS ((char *ps)); +void listing_prev_line PARAMS ((void)); +void listing_print PARAMS ((char *name)); +void listing_psize PARAMS ((int)); +void listing_nopage PARAMS ((int)); +void listing_source_file PARAMS ((const char *)); +void listing_source_line PARAMS ((unsigned int)); +void listing_title PARAMS ((int depth)); +void listing_warning PARAMS ((const char *message)); +void listing_width PARAMS ((unsigned int x)); + +extern int listing_lhs_width; +extern int listing_lhs_width_second; +extern int listing_lhs_cont_lines; +extern int listing_rhs_width; + +#endif /* __listing_h__ */ + +/* end of listing.h */ diff --git a/contrib/binutils-2.14/gas/literal.c b/contrib/binutils-2.14/gas/literal.c new file mode 100644 index 0000000000..7315f3eee0 --- /dev/null +++ b/contrib/binutils-2.14/gas/literal.c @@ -0,0 +1,95 @@ +/* as.c - GAS literal pool management. + Copyright 1994, 2000 Free Software Foundation, Inc. + Written by Ken Raeburn (raeburn@cygnus.com). + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This isn't quite a "constant" pool. Some of the values may get + adjusted at run time, e.g., for symbolic relocations when shared + libraries are in use. It's more of a "literal" pool. + + On the Alpha, this should be used for .lita and .lit8. (Is there + ever a .lit4?) On the MIPS, it could be used for .lit4 as well. + + The expressions passed here should contain either constants or symbols, + not a combination of both. Typically, the constant pool is accessed + with some sort of GP register, so the size of the pool must be kept down + if possible. The exception is section offsets -- if you're storing a + pointer to the start of .data, for example, and your machine provides + for 16-bit signed addends, you might want to store .data+32K, so that + you can access all of the first 64K of .data with the one pointer. + + This isn't a requirement, just a guideline that can help keep .o file + size down. */ + +#include "as.h" +#include "subsegs.h" + +#if defined (BFD_ASSEMBLER) && defined (NEED_LITERAL_POOL) + +valueT +add_to_literal_pool (sym, addend, sec, size) + symbolS *sym; + valueT addend; + segT sec; + int size; +{ + segT current_section = now_seg; + int current_subsec = now_subseg; + valueT offset; + bfd_reloc_code_real_type reloc_type; + char *p; + segment_info_type *seginfo = seg_info (sec); + fixS *fixp; + + offset = 0; + /* @@ This assumes all entries in a given section will be of the same + size... Probably correct, but unwise to rely on. */ + /* This must always be called with the same subsegment. */ + if (seginfo->frchainP) + for (fixp = seginfo->frchainP->fix_root; + fixp != (fixS *) NULL; + fixp = fixp->fx_next, offset += size) + { + if (fixp->fx_addsy == sym && fixp->fx_offset == addend) + return offset; + } + + subseg_set (sec, 0); + p = frag_more (size); + memset (p, 0, size); + + switch (size) + { + case 4: + reloc_type = BFD_RELOC_32; + break; + case 8: + reloc_type = BFD_RELOC_64; + break; + default: + abort (); + } + fix_new (frag_now, p - frag_now->fr_literal, size, sym, addend, 0, + reloc_type); + + subseg_set (current_section, current_subsec); + offset = seginfo->literal_pool_size; + seginfo->literal_pool_size += size; + return offset; +} +#endif /* BFD_ASSEMBLER */ diff --git a/contrib/binutils-2.14/gas/macro.c b/contrib/binutils-2.14/gas/macro.c new file mode 100644 index 0000000000..b0b7ec21e7 --- /dev/null +++ b/contrib/binutils-2.14/gas/macro.c @@ -0,0 +1,1230 @@ +/* macro.c - macro support for gas + Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "config.h" + +#ifndef __GNUC__ +# if HAVE_ALLOCA_H +# include +# else +# ifdef _AIX +/* Indented so that pre-ansi C compilers will ignore it, rather than + choke on it. Some versions of AIX require this to be the first + thing in the file. */ + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +# if !defined (__STDC__) && !defined (__hpux) +extern char *alloca (); +# else +extern void *alloca (); +# endif /* __STDC__, __hpux */ +# endif /* alloca */ +# endif /* _AIX */ +# endif /* HAVE_ALLOCA_H */ +#endif /* __GNUC__ */ + +#include +#ifdef HAVE_STRING_H +#include +#else +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#include "libiberty.h" +#include "safe-ctype.h" +#include "sb.h" +#include "hash.h" +#include "macro.h" + +#include "asintl.h" + +/* The routines in this file handle macro definition and expansion. + They are called by gas. */ + +/* Internal functions. */ + +static int get_token PARAMS ((int, sb *, sb *)); +static int getstring PARAMS ((int, sb *, sb *)); +static int get_any_string PARAMS ((int, sb *, sb *, int, int)); +static int do_formals PARAMS ((macro_entry *, int, sb *)); +static int get_apost_token PARAMS ((int, sb *, sb *, int)); +static int sub_actual + PARAMS ((int, sb *, sb *, struct hash_control *, int, sb *, int)); +static const char *macro_expand_body + PARAMS ((sb *, sb *, formal_entry *, struct hash_control *, int)); +static const char *macro_expand PARAMS ((int, sb *, macro_entry *, sb *)); + +#define ISWHITE(x) ((x) == ' ' || (x) == '\t') + +#define ISSEP(x) \ + ((x) == ' ' || (x) == '\t' || (x) == ',' || (x) == '"' || (x) == ';' \ + || (x) == ')' || (x) == '(' \ + || ((macro_alternate || macro_mri) && ((x) == '<' || (x) == '>'))) + +#define ISBASE(x) \ + ((x) == 'b' || (x) == 'B' \ + || (x) == 'q' || (x) == 'Q' \ + || (x) == 'h' || (x) == 'H' \ + || (x) == 'd' || (x) == 'D') + +/* The macro hash table. */ + +struct hash_control *macro_hash; + +/* Whether any macros have been defined. */ + +int macro_defined; + +/* Whether we are in alternate syntax mode. */ + +static int macro_alternate; + +/* Whether we are in MRI mode. */ + +static int macro_mri; + +/* Whether we should strip '@' characters. */ + +static int macro_strip_at; + +/* Function to use to parse an expression. */ + +static int (*macro_expr) PARAMS ((const char *, int, sb *, int *)); + +/* Number of macro expansions that have been done. */ + +static int macro_number; + +/* Initialize macro processing. */ + +void +macro_init (alternate, mri, strip_at, expr) + int alternate; + int mri; + int strip_at; + int (*expr) PARAMS ((const char *, int, sb *, int *)); +{ + macro_hash = hash_new (); + macro_defined = 0; + macro_alternate = alternate; + macro_mri = mri; + macro_strip_at = strip_at; + macro_expr = expr; +} + +/* Switch in and out of MRI mode on the fly. */ + +void +macro_mri_mode (mri) + int mri; +{ + macro_mri = mri; +} + +/* Read input lines till we get to a TO string. + Increase nesting depth if we get a FROM string. + Put the results into sb at PTR. + Add a new input line to an sb using GET_LINE. + Return 1 on success, 0 on unexpected EOF. */ + +int +buffer_and_nest (from, to, ptr, get_line) + const char *from; + const char *to; + sb *ptr; + int (*get_line) PARAMS ((sb *)); +{ + int from_len = strlen (from); + int to_len = strlen (to); + int depth = 1; + int line_start = ptr->len; + + int more = get_line (ptr); + + while (more) + { + /* Try and find the first pseudo op on the line. */ + int i = line_start; + + if (! macro_alternate && ! macro_mri) + { + /* With normal syntax we can suck what we want till we get + to the dot. With the alternate, labels have to start in + the first column, since we cant tell what's a label and + whats a pseudoop. */ + + /* Skip leading whitespace. */ + while (i < ptr->len && ISWHITE (ptr->ptr[i])) + i++; + + /* Skip over a label. */ + while (i < ptr->len + && (ISALNUM (ptr->ptr[i]) + || ptr->ptr[i] == '_' + || ptr->ptr[i] == '$')) + i++; + + /* And a colon. */ + if (i < ptr->len + && ptr->ptr[i] == ':') + i++; + + } + /* Skip trailing whitespace. */ + while (i < ptr->len && ISWHITE (ptr->ptr[i])) + i++; + + if (i < ptr->len && (ptr->ptr[i] == '.' + || macro_alternate + || macro_mri)) + { + if (ptr->ptr[i] == '.') + i++; + if (strncasecmp (ptr->ptr + i, from, from_len) == 0 + && (ptr->len == (i + from_len) + || ! ISALNUM (ptr->ptr[i + from_len]))) + depth++; + if (strncasecmp (ptr->ptr + i, to, to_len) == 0 + && (ptr->len == (i + to_len) + || ! ISALNUM (ptr->ptr[i + to_len]))) + { + depth--; + if (depth == 0) + { + /* Reset the string to not include the ending rune. */ + ptr->len = line_start; + break; + } + } + } + + /* Add the original end-of-line char to the end and keep running. */ + sb_add_char (ptr, more); + line_start = ptr->len; + more = get_line (ptr); + } + + /* Return 1 on success, 0 on unexpected EOF. */ + return depth == 0; +} + +/* Pick up a token. */ + +static int +get_token (idx, in, name) + int idx; + sb *in; + sb *name; +{ + if (idx < in->len + && (ISALPHA (in->ptr[idx]) + || in->ptr[idx] == '_' + || in->ptr[idx] == '$')) + { + sb_add_char (name, in->ptr[idx++]); + while (idx < in->len + && (ISALNUM (in->ptr[idx]) + || in->ptr[idx] == '_' + || in->ptr[idx] == '$')) + { + sb_add_char (name, in->ptr[idx++]); + } + } + /* Ignore trailing &. */ + if (macro_alternate && idx < in->len && in->ptr[idx] == '&') + idx++; + return idx; +} + +/* Pick up a string. */ + +static int +getstring (idx, in, acc) + int idx; + sb *in; + sb *acc; +{ + idx = sb_skip_white (idx, in); + + while (idx < in->len + && (in->ptr[idx] == '"' + || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) + || (in->ptr[idx] == '\'' && macro_alternate))) + { + if (in->ptr[idx] == '<') + { + int nest = 0; + idx++; + while ((in->ptr[idx] != '>' || nest) + && idx < in->len) + { + if (in->ptr[idx] == '!') + { + idx++; + sb_add_char (acc, in->ptr[idx++]); + } + else + { + if (in->ptr[idx] == '>') + nest--; + if (in->ptr[idx] == '<') + nest++; + sb_add_char (acc, in->ptr[idx++]); + } + } + idx++; + } + else if (in->ptr[idx] == '"' || in->ptr[idx] == '\'') + { + char tchar = in->ptr[idx]; + int escaped = 0; + + idx++; + + while (idx < in->len) + { + if (in->ptr[idx - 1] == '\\') + escaped ^= 1; + else + escaped = 0; + + if (macro_alternate && in->ptr[idx] == '!') + { + idx ++; + + sb_add_char (acc, in->ptr[idx]); + + idx ++; + } + else if (escaped && in->ptr[idx] == tchar) + { + sb_add_char (acc, tchar); + idx ++; + } + else + { + if (in->ptr[idx] == tchar) + { + idx ++; + + if (idx >= in->len || in->ptr[idx] != tchar) + break; + } + + sb_add_char (acc, in->ptr[idx]); + idx ++; + } + } + } + } + + return idx; +} + +/* Fetch string from the input stream, + rules: + 'Bxyx -> return 'Bxyza + % -> return string of decimal value of x + "" -> return string + xyx -> return xyz +*/ + +static int +get_any_string (idx, in, out, expand, pretend_quoted) + int idx; + sb *in; + sb *out; + int expand; + int pretend_quoted; +{ + sb_reset (out); + idx = sb_skip_white (idx, in); + + if (idx < in->len) + { + if (in->len > idx + 2 && in->ptr[idx + 1] == '\'' && ISBASE (in->ptr[idx])) + { + while (!ISSEP (in->ptr[idx])) + sb_add_char (out, in->ptr[idx++]); + } + else if (in->ptr[idx] == '%' + && macro_alternate + && expand) + { + int val; + char buf[20]; + /* Turns the next expression into a string. */ + /* xgettext: no-c-format */ + idx = (*macro_expr) (_("% operator needs absolute expression"), + idx + 1, + in, + &val); + sprintf (buf, "%d", val); + sb_add_string (out, buf); + } + else if (in->ptr[idx] == '"' + || (in->ptr[idx] == '<' && (macro_alternate || macro_mri)) + || (macro_alternate && in->ptr[idx] == '\'')) + { + if (macro_alternate + && ! macro_strip_at + && expand) + { + /* Keep the quotes. */ + sb_add_char (out, '\"'); + + idx = getstring (idx, in, out); + sb_add_char (out, '\"'); + } + else + { + idx = getstring (idx, in, out); + } + } + else + { + while (idx < in->len + && (in->ptr[idx] == '"' + || in->ptr[idx] == '\'' + || pretend_quoted + || (in->ptr[idx] != ' ' + && in->ptr[idx] != '\t' + && in->ptr[idx] != ',' + && (in->ptr[idx] != '<' + || (! macro_alternate && ! macro_mri))))) + { + if (in->ptr[idx] == '"' + || in->ptr[idx] == '\'') + { + char tchar = in->ptr[idx]; + sb_add_char (out, in->ptr[idx++]); + while (idx < in->len + && in->ptr[idx] != tchar) + sb_add_char (out, in->ptr[idx++]); + if (idx == in->len) + return idx; + } + sb_add_char (out, in->ptr[idx++]); + } + } + } + + return idx; +} + +/* Pick up the formal parameters of a macro definition. */ + +static int +do_formals (macro, idx, in) + macro_entry *macro; + int idx; + sb *in; +{ + formal_entry **p = ¯o->formals; + + macro->formal_count = 0; + macro->formal_hash = hash_new (); + while (idx < in->len) + { + formal_entry *formal; + + formal = (formal_entry *) xmalloc (sizeof (formal_entry)); + + sb_new (&formal->name); + sb_new (&formal->def); + sb_new (&formal->actual); + + idx = sb_skip_white (idx, in); + idx = get_token (idx, in, &formal->name); + if (formal->name.len == 0) + break; + idx = sb_skip_white (idx, in); + if (formal->name.len) + { + /* This is a formal. */ + if (idx < in->len && in->ptr[idx] == '=') + { + /* Got a default. */ + idx = get_any_string (idx + 1, in, &formal->def, 1, 0); + } + } + + /* Add to macro's hash table. */ + hash_jam (macro->formal_hash, sb_terminate (&formal->name), formal); + + formal->index = macro->formal_count; + idx = sb_skip_comma (idx, in); + macro->formal_count++; + *p = formal; + p = &formal->next; + *p = NULL; + } + + if (macro_mri) + { + formal_entry *formal; + const char *name; + + /* Add a special NARG formal, which macro_expand will set to the + number of arguments. */ + formal = (formal_entry *) xmalloc (sizeof (formal_entry)); + + sb_new (&formal->name); + sb_new (&formal->def); + sb_new (&formal->actual); + + /* The same MRI assemblers which treat '@' characters also use + the name $NARG. At least until we find an exception. */ + if (macro_strip_at) + name = "$NARG"; + else + name = "NARG"; + + sb_add_string (&formal->name, name); + + /* Add to macro's hash table. */ + hash_jam (macro->formal_hash, name, formal); + + formal->index = NARG_INDEX; + *p = formal; + formal->next = NULL; + } + + return idx; +} + +/* Define a new macro. Returns NULL on success, otherwise returns an + error message. If NAMEP is not NULL, *NAMEP is set to the name of + the macro which was defined. */ + +const char * +define_macro (idx, in, label, get_line, namep) + int idx; + sb *in; + sb *label; + int (*get_line) PARAMS ((sb *)); + const char **namep; +{ + macro_entry *macro; + sb name; + const char *namestr; + + macro = (macro_entry *) xmalloc (sizeof (macro_entry)); + sb_new (¯o->sub); + sb_new (&name); + + macro->formal_count = 0; + macro->formals = 0; + + idx = sb_skip_white (idx, in); + if (! buffer_and_nest ("MACRO", "ENDM", ¯o->sub, get_line)) + return _("unexpected end of file in macro definition"); + if (label != NULL && label->len != 0) + { + sb_add_sb (&name, label); + if (idx < in->len && in->ptr[idx] == '(') + { + /* It's the label: MACRO (formals,...) sort */ + idx = do_formals (macro, idx + 1, in); + if (in->ptr[idx] != ')') + return _("missing ) after formals"); + } + else + { + /* It's the label: MACRO formals,... sort */ + idx = do_formals (macro, idx, in); + } + } + else + { + idx = get_token (idx, in, &name); + idx = sb_skip_comma (idx, in); + idx = do_formals (macro, idx, in); + } + + /* And stick it in the macro hash table. */ + for (idx = 0; idx < name.len; idx++) + name.ptr[idx] = TOLOWER (name.ptr[idx]); + namestr = sb_terminate (&name); + hash_jam (macro_hash, namestr, (PTR) macro); + + macro_defined = 1; + + if (namep != NULL) + *namep = namestr; + + return NULL; +} + +/* Scan a token, and then skip KIND. */ + +static int +get_apost_token (idx, in, name, kind) + int idx; + sb *in; + sb *name; + int kind; +{ + idx = get_token (idx, in, name); + if (idx < in->len + && in->ptr[idx] == kind + && (! macro_mri || macro_strip_at) + && (! macro_strip_at || kind == '@')) + idx++; + return idx; +} + +/* Substitute the actual value for a formal parameter. */ + +static int +sub_actual (start, in, t, formal_hash, kind, out, copyifnotthere) + int start; + sb *in; + sb *t; + struct hash_control *formal_hash; + int kind; + sb *out; + int copyifnotthere; +{ + int src; + formal_entry *ptr; + + src = get_apost_token (start, in, t, kind); + /* See if it's in the macro's hash table, unless this is + macro_strip_at and kind is '@' and the token did not end in '@'. */ + if (macro_strip_at + && kind == '@' + && (src == start || in->ptr[src - 1] != '@')) + ptr = NULL; + else + ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (t)); + if (ptr) + { + if (ptr->actual.len) + { + sb_add_sb (out, &ptr->actual); + } + else + { + sb_add_sb (out, &ptr->def); + } + } + else if (kind == '&') + { + /* Doing this permits people to use & in macro bodies. */ + sb_add_char (out, '&'); + sb_add_sb (out, t); + } + else if (copyifnotthere) + { + sb_add_sb (out, t); + } + else + { + sb_add_char (out, '\\'); + sb_add_sb (out, t); + } + return src; +} + +/* Expand the body of a macro. */ + +static const char * +macro_expand_body (in, out, formals, formal_hash, locals) + sb *in; + sb *out; + formal_entry *formals; + struct hash_control *formal_hash; + int locals; +{ + sb t; + int src = 0; + int inquote = 0; + formal_entry *loclist = NULL; + + sb_new (&t); + + while (src < in->len) + { + if (in->ptr[src] == '&') + { + sb_reset (&t); + if (macro_mri) + { + if (src + 1 < in->len && in->ptr[src + 1] == '&') + src = sub_actual (src + 2, in, &t, formal_hash, '\'', out, 1); + else + sb_add_char (out, in->ptr[src++]); + } + else + { + /* FIXME: Why do we do this? */ + src = sub_actual (src + 1, in, &t, formal_hash, '&', out, 0); + } + } + else if (in->ptr[src] == '\\') + { + src++; + if (in->ptr[src] == '(') + { + /* Sub in till the next ')' literally. */ + src++; + while (src < in->len && in->ptr[src] != ')') + { + sb_add_char (out, in->ptr[src++]); + } + if (in->ptr[src] == ')') + src++; + else + return _("missplaced )"); + } + else if (in->ptr[src] == '@') + { + /* Sub in the macro invocation number. */ + + char buffer[10]; + src++; + sprintf (buffer, "%d", macro_number); + sb_add_string (out, buffer); + } + else if (in->ptr[src] == '&') + { + /* This is a preprocessor variable name, we don't do them + here. */ + sb_add_char (out, '\\'); + sb_add_char (out, '&'); + src++; + } + else if (macro_mri && ISALNUM (in->ptr[src])) + { + int ind; + formal_entry *f; + + if (ISDIGIT (in->ptr[src])) + ind = in->ptr[src] - '0'; + else if (ISUPPER (in->ptr[src])) + ind = in->ptr[src] - 'A' + 10; + else + ind = in->ptr[src] - 'a' + 10; + ++src; + for (f = formals; f != NULL; f = f->next) + { + if (f->index == ind - 1) + { + if (f->actual.len != 0) + sb_add_sb (out, &f->actual); + else + sb_add_sb (out, &f->def); + break; + } + } + } + else + { + sb_reset (&t); + src = sub_actual (src, in, &t, formal_hash, '\'', out, 0); + } + } + else if ((macro_alternate || macro_mri) + && (ISALPHA (in->ptr[src]) + || in->ptr[src] == '_' + || in->ptr[src] == '$') + && (! inquote + || ! macro_strip_at + || (src > 0 && in->ptr[src - 1] == '@'))) + { + if (! locals + || src + 5 >= in->len + || strncasecmp (in->ptr + src, "LOCAL", 5) != 0 + || ! ISWHITE (in->ptr[src + 5])) + { + sb_reset (&t); + src = sub_actual (src, in, &t, formal_hash, + (macro_strip_at && inquote) ? '@' : '\'', + out, 1); + } + else + { + formal_entry *f; + + src = sb_skip_white (src + 5, in); + while (in->ptr[src] != '\n') + { + static int loccnt; + char buf[20]; + const char *err; + + f = (formal_entry *) xmalloc (sizeof (formal_entry)); + sb_new (&f->name); + sb_new (&f->def); + sb_new (&f->actual); + f->index = LOCAL_INDEX; + f->next = loclist; + loclist = f; + + src = get_token (src, in, &f->name); + ++loccnt; + sprintf (buf, "LL%04x", loccnt); + sb_add_string (&f->actual, buf); + + err = hash_jam (formal_hash, sb_terminate (&f->name), f); + if (err != NULL) + return err; + + src = sb_skip_comma (src, in); + } + } + } + else if (in->ptr[src] == '"' + || (macro_mri && in->ptr[src] == '\'')) + { + inquote = !inquote; + sb_add_char (out, in->ptr[src++]); + } + else if (in->ptr[src] == '@' && macro_strip_at) + { + ++src; + if (src < in->len + && in->ptr[src] == '@') + { + sb_add_char (out, '@'); + ++src; + } + } + else if (macro_mri + && in->ptr[src] == '=' + && src + 1 < in->len + && in->ptr[src + 1] == '=') + { + formal_entry *ptr; + + sb_reset (&t); + src = get_token (src + 2, in, &t); + ptr = (formal_entry *) hash_find (formal_hash, sb_terminate (&t)); + if (ptr == NULL) + { + /* FIXME: We should really return a warning string here, + but we can't, because the == might be in the MRI + comment field, and, since the nature of the MRI + comment field depends upon the exact instruction + being used, we don't have enough information here to + figure out whether it is or not. Instead, we leave + the == in place, which should cause a syntax error if + it is not in a comment. */ + sb_add_char (out, '='); + sb_add_char (out, '='); + sb_add_sb (out, &t); + } + else + { + if (ptr->actual.len) + { + sb_add_string (out, "-1"); + } + else + { + sb_add_char (out, '0'); + } + } + } + else + { + sb_add_char (out, in->ptr[src++]); + } + } + + sb_kill (&t); + + while (loclist != NULL) + { + formal_entry *f; + + f = loclist->next; + /* Setting the value to NULL effectively deletes the entry. We + avoid calling hash_delete because it doesn't reclaim memory. */ + hash_jam (formal_hash, sb_terminate (&loclist->name), NULL); + sb_kill (&loclist->name); + sb_kill (&loclist->def); + sb_kill (&loclist->actual); + free (loclist); + loclist = f; + } + + return NULL; +} + +/* Assign values to the formal parameters of a macro, and expand the + body. */ + +static const char * +macro_expand (idx, in, m, out) + int idx; + sb *in; + macro_entry *m; + sb *out; +{ + sb t; + formal_entry *ptr; + formal_entry *f; + int is_positional = 0; + int is_keyword = 0; + int narg = 0; + const char *err; + + sb_new (&t); + + /* Reset any old value the actuals may have. */ + for (f = m->formals; f; f = f->next) + sb_reset (&f->actual); + f = m->formals; + while (f != NULL && f->index < 0) + f = f->next; + + if (macro_mri) + { + /* The macro may be called with an optional qualifier, which may + be referred to in the macro body as \0. */ + if (idx < in->len && in->ptr[idx] == '.') + { + /* The Microtec assembler ignores this if followed by a white space. + (Macro invocation with empty extension) */ + idx++; + if ( idx < in->len + && in->ptr[idx] != ' ' + && in->ptr[idx] != '\t') + { + formal_entry *n; + + n = (formal_entry *) xmalloc (sizeof (formal_entry)); + sb_new (&n->name); + sb_new (&n->def); + sb_new (&n->actual); + n->index = QUAL_INDEX; + + n->next = m->formals; + m->formals = n; + + idx = get_any_string (idx, in, &n->actual, 1, 0); + } + } + } + + /* Peel off the actuals and store them away in the hash tables' actuals. */ + idx = sb_skip_white (idx, in); + while (idx < in->len) + { + int scan; + + /* Look and see if it's a positional or keyword arg. */ + scan = idx; + while (scan < in->len + && !ISSEP (in->ptr[scan]) + && !(macro_mri && in->ptr[scan] == '\'') + && (!macro_alternate && in->ptr[scan] != '=')) + scan++; + if (scan < in->len && !macro_alternate && in->ptr[scan] == '=') + { + is_keyword = 1; + + /* It's OK to go from positional to keyword. */ + + /* This is a keyword arg, fetch the formal name and + then the actual stuff. */ + sb_reset (&t); + idx = get_token (idx, in, &t); + if (in->ptr[idx] != '=') + return _("confusion in formal parameters"); + + /* Lookup the formal in the macro's list. */ + ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); + if (!ptr) + return _("macro formal argument does not exist"); + else + { + /* Insert this value into the right place. */ + sb_reset (&ptr->actual); + idx = get_any_string (idx + 1, in, &ptr->actual, 0, 0); + if (ptr->actual.len > 0) + ++narg; + } + } + else + { + /* This is a positional arg. */ + is_positional = 1; + if (is_keyword) + return _("can't mix positional and keyword arguments"); + + if (!f) + { + formal_entry **pf; + int c; + + if (!macro_mri) + return _("too many positional arguments"); + + f = (formal_entry *) xmalloc (sizeof (formal_entry)); + sb_new (&f->name); + sb_new (&f->def); + sb_new (&f->actual); + f->next = NULL; + + c = -1; + for (pf = &m->formals; *pf != NULL; pf = &(*pf)->next) + if ((*pf)->index >= c) + c = (*pf)->index + 1; + if (c == -1) + c = 0; + *pf = f; + f->index = c; + } + + sb_reset (&f->actual); + idx = get_any_string (idx, in, &f->actual, 1, 0); + if (f->actual.len > 0) + ++narg; + do + { + f = f->next; + } + while (f != NULL && f->index < 0); + } + + if (! macro_mri) + idx = sb_skip_comma (idx, in); + else + { + if (in->ptr[idx] == ',') + ++idx; + if (ISWHITE (in->ptr[idx])) + break; + } + } + + if (macro_mri) + { + char buffer[20]; + + sb_reset (&t); + sb_add_string (&t, macro_strip_at ? "$NARG" : "NARG"); + ptr = (formal_entry *) hash_find (m->formal_hash, sb_terminate (&t)); + sb_reset (&ptr->actual); + sprintf (buffer, "%d", narg); + sb_add_string (&ptr->actual, buffer); + } + + err = macro_expand_body (&m->sub, out, m->formals, m->formal_hash, 1); + if (err != NULL) + return err; + + /* Discard any unnamed formal arguments. */ + if (macro_mri) + { + formal_entry **pf; + + pf = &m->formals; + while (*pf != NULL) + { + if ((*pf)->name.len != 0) + pf = &(*pf)->next; + else + { + sb_kill (&(*pf)->name); + sb_kill (&(*pf)->def); + sb_kill (&(*pf)->actual); + f = (*pf)->next; + free (*pf); + *pf = f; + } + } + } + + sb_kill (&t); + macro_number++; + + return NULL; +} + +/* Check for a macro. If one is found, put the expansion into + *EXPAND. Return 1 if a macro is found, 0 otherwise. */ + +int +check_macro (line, expand, error, info) + const char *line; + sb *expand; + const char **error; + macro_entry **info; +{ + const char *s; + char *copy, *cs; + macro_entry *macro; + sb line_sb; + + if (! ISALPHA (*line) + && *line != '_' + && *line != '$' + && (! macro_mri || *line != '.')) + return 0; + + s = line + 1; + while (ISALNUM (*s) + || *s == '_' + || *s == '$') + ++s; + + copy = (char *) alloca (s - line + 1); + memcpy (copy, line, s - line); + copy[s - line] = '\0'; + for (cs = copy; *cs != '\0'; cs++) + *cs = TOLOWER (*cs); + + macro = (macro_entry *) hash_find (macro_hash, copy); + + if (macro == NULL) + return 0; + + /* Wrap the line up in an sb. */ + sb_new (&line_sb); + while (*s != '\0' && *s != '\n' && *s != '\r') + sb_add_char (&line_sb, *s++); + + sb_new (expand); + *error = macro_expand (0, &line_sb, macro, expand); + + sb_kill (&line_sb); + + /* Export the macro information if requested. */ + if (info) + *info = macro; + + return 1; +} + +/* Delete a macro. */ + +void +delete_macro (name) + const char *name; +{ + hash_delete (macro_hash, name); +} + +/* Handle the MRI IRP and IRPC pseudo-ops. These are handled as a + combined macro definition and execution. This returns NULL on + success, or an error message otherwise. */ + +const char * +expand_irp (irpc, idx, in, out, get_line) + int irpc; + int idx; + sb *in; + sb *out; + int (*get_line) PARAMS ((sb *)); +{ + const char *mn; + sb sub; + formal_entry f; + struct hash_control *h; + const char *err; + + if (irpc) + mn = "IRPC"; + else + mn = "IRP"; + + idx = sb_skip_white (idx, in); + + sb_new (&sub); + if (! buffer_and_nest (mn, "ENDR", &sub, get_line)) + return _("unexpected end of file in irp or irpc"); + + sb_new (&f.name); + sb_new (&f.def); + sb_new (&f.actual); + + idx = get_token (idx, in, &f.name); + if (f.name.len == 0) + return _("missing model parameter"); + + h = hash_new (); + err = hash_jam (h, sb_terminate (&f.name), &f); + if (err != NULL) + return err; + + f.index = 1; + f.next = NULL; + + sb_reset (out); + + idx = sb_skip_comma (idx, in); + if (idx >= in->len) + { + /* Expand once with a null string. */ + err = macro_expand_body (&sub, out, &f, h, 0); + if (err != NULL) + return err; + } + else + { + if (irpc && in->ptr[idx] == '"') + ++idx; + while (idx < in->len) + { + if (!irpc) + idx = get_any_string (idx, in, &f.actual, 1, 0); + else + { + if (in->ptr[idx] == '"') + { + int nxt; + + nxt = sb_skip_white (idx + 1, in); + if (nxt >= in->len) + { + idx = nxt; + break; + } + } + sb_reset (&f.actual); + sb_add_char (&f.actual, in->ptr[idx]); + ++idx; + } + err = macro_expand_body (&sub, out, &f, h, 0); + if (err != NULL) + return err; + if (!irpc) + idx = sb_skip_comma (idx, in); + else + idx = sb_skip_white (idx, in); + } + } + + hash_die (h); + sb_kill (&sub); + + return NULL; +} diff --git a/contrib/binutils-2.14/gas/macro.h b/contrib/binutils-2.14/gas/macro.h new file mode 100644 index 0000000000..7710215073 --- /dev/null +++ b/contrib/binutils-2.14/gas/macro.h @@ -0,0 +1,88 @@ +/* macro.h - header file for macro support for gas + Copyright 1994, 1995, 1996, 1997, 1998, 2000, 2002 + Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef MACRO_H + +#define MACRO_H + +#include "ansidecl.h" +#include "sb.h" + +/* Structures used to store macros. + + Each macro knows its name and included text. It gets built with a + list of formal arguments, and also keeps a hash table which points + into the list to speed up formal search. Each formal knows its + name and its default value. Each time the macro is expanded, the + formals get the actual values attatched to them. */ + +/* Describe the formal arguments to a macro. */ + +typedef struct formal_struct { + struct formal_struct *next; /* Next formal in list. */ + sb name; /* Name of the formal. */ + sb def; /* The default value. */ + sb actual; /* The actual argument (changed on each expansion). */ + int index; /* The index of the formal 0..formal_count - 1. */ +} formal_entry; + +/* Other values found in the index field of a formal_entry. */ +#define QUAL_INDEX (-1) +#define NARG_INDEX (-2) +#define LOCAL_INDEX (-3) + +/* Describe the macro. */ + +typedef struct macro_struct +{ + sb sub; /* Substitution text. */ + int formal_count; /* Number of formal args. */ + formal_entry *formals; /* Pointer to list of formal_structs. */ + struct hash_control *formal_hash; /* Hash table of formals. */ +} macro_entry; + +/* Whether any macros have been defined. */ + +extern int macro_defined; + +/* The macro nesting level. */ + +extern int macro_nest; + +extern int buffer_and_nest + PARAMS ((const char *, const char *, sb *, int (*) PARAMS ((sb *)))); +extern void macro_init + PARAMS ((int, int, int, int (*) PARAMS ((const char *, int, sb *, int *)))); +extern void macro_mri_mode + PARAMS ((int)); +extern const char *define_macro + PARAMS ((int, sb *, sb *, int (*) PARAMS ((sb *)), const char **)); +extern int check_macro + PARAMS ((const char *, sb *, const char **, macro_entry **)); +extern void delete_macro + PARAMS ((const char *)); +extern const char *expand_irp + PARAMS ((int, int, sb *, sb *, int (*) PARAMS ((sb *)))); + +#endif diff --git a/contrib/binutils-2.14/gas/messages.c b/contrib/binutils-2.14/gas/messages.c new file mode 100644 index 0000000000..e85deec3bd --- /dev/null +++ b/contrib/binutils-2.14/gas/messages.c @@ -0,0 +1,519 @@ +/* messages.c - error reporter - + Copyright 1987, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001 + Free Software Foundation, Inc. + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "as.h" + +#include +#ifdef HAVE_ERRNO_H +#include +#endif + +#ifdef USE_STDARG +#include +#endif + +#ifdef USE_VARARGS +#include +#endif + +#if !defined (USE_STDARG) && !defined (USE_VARARGS) +/* Roll our own. */ +#define va_alist REST +#define va_dcl +typedef int * va_list; +#define va_start(ARGS) ARGS = &REST +#define va_end(ARGS) +#endif + +static void identify PARAMS ((char *)); +static void as_show_where PARAMS ((void)); +static void as_warn_internal PARAMS ((char *, unsigned int, char *)); +static void as_bad_internal PARAMS ((char *, unsigned int, char *)); + +/* Despite the rest of the comments in this file, (FIXME-SOON), + * here is the current scheme for error messages etc: + * + * as_fatal() is used when gas is quite confused and + * continuing the assembly is pointless. In this case we + * exit immediately with error status. + * + * as_bad() is used to mark errors that result in what we + * presume to be a useless object file. Say, we ignored + * something that might have been vital. If we see any of + * these, assembly will continue to the end of the source, + * no object file will be produced, and we will terminate + * with error status. The new option, -Z, tells us to + * produce an object file anyway but we still exit with + * error status. The assumption here is that you don't want + * this object file but we could be wrong. + * + * as_warn() is used when we have an error from which we + * have a plausible error recovery. eg, masking the top + * bits of a constant that is longer than will fit in the + * destination. In this case we will continue to assemble + * the source, although we may have made a bad assumption, + * and we will produce an object file and return normal exit + * status (ie, no error). The new option -X tells us to + * treat all as_warn() errors as as_bad() errors. That is, + * no object file will be produced and we will exit with + * error status. The idea here is that we don't kill an + * entire make because of an error that we knew how to + * correct. On the other hand, sometimes you might want to + * stop the make at these points. + * + * as_tsktsk() is used when we see a minor error for which + * our error recovery action is almost certainly correct. + * In this case, we print a message and then assembly + * continues as though no error occurred. + */ + +static void +identify (file) + char *file; +{ + static int identified; + if (identified) + return; + identified++; + + if (!file) + { + unsigned int x; + as_where (&file, &x); + } + + if (file) + fprintf (stderr, "%s: ", file); + fprintf (stderr, _("Assembler messages:\n")); +} + +/* The number of warnings issued. */ +static int warning_count; + +int +had_warnings () +{ + return (warning_count); +} + +/* Nonzero if we've hit a 'bad error', and should not write an obj file, + and exit with a nonzero error code. */ + +static int error_count; + +int +had_errors () +{ + return (error_count); +} + +/* Print the current location to stderr. */ + +static void +as_show_where () +{ + char *file; + unsigned int line; + + as_where (&file, &line); + identify (file); + if (file) + fprintf (stderr, "%s:%u: ", file, line); +} + +/* Like perror(3), but with more info. */ + +void +as_perror (gripe, filename) + const char *gripe; /* Unpunctuated error theme. */ + const char *filename; +{ + const char *errtxt; + + as_show_where (); + fprintf (stderr, gripe, filename); +#ifdef BFD_ASSEMBLER + errtxt = bfd_errmsg (bfd_get_error ()); +#else + errtxt = xstrerror (errno); +#endif + fprintf (stderr, ": %s\n", errtxt); + errno = 0; +#ifdef BFD_ASSEMBLER + bfd_set_error (bfd_error_no_error); +#endif +} + +/* Send to stderr a string as a warning, and locate warning + in input file(s). + Please only use this for when we have some recovery action. + Please explain in string (which may have '\n's) what recovery was + done. */ + +#ifdef USE_STDARG +void +as_tsktsk (const char *format, ...) +{ + va_list args; + + as_show_where (); + va_start (args, format); + vfprintf (stderr, format, args); + va_end (args); + (void) putc ('\n', stderr); +} +#else +void +as_tsktsk (format, va_alist) + const char *format; + va_dcl +{ + va_list args; + + as_show_where (); + va_start (args); + vfprintf (stderr, format, args); + va_end (args); + (void) putc ('\n', stderr); +} +#endif /* not NO_STDARG */ + +/* The common portion of as_warn and as_warn_where. */ + +static void +as_warn_internal (file, line, buffer) + char *file; + unsigned int line; + char *buffer; +{ + ++warning_count; + + if (file == NULL) + as_where (&file, &line); + + identify (file); + if (file) + fprintf (stderr, "%s:%u: ", file, line); + fprintf (stderr, _("Warning: ")); + fputs (buffer, stderr); + (void) putc ('\n', stderr); +#ifndef NO_LISTING + listing_warning (buffer); +#endif +} + +/* Send to stderr a string as a warning, and locate warning + in input file(s). + Please only use this for when we have some recovery action. + Please explain in string (which may have '\n's) what recovery was + done. */ + +#ifdef USE_STDARG +void +as_warn (const char *format, ...) +{ + va_list args; + char buffer[2000]; + + if (!flag_no_warnings) + { + va_start (args, format); + vsprintf (buffer, format, args); + va_end (args); + as_warn_internal ((char *) NULL, 0, buffer); + } +} +#else +void +as_warn (format, va_alist) + const char *format; + va_dcl +{ + va_list args; + char buffer[2000]; + + if (!flag_no_warnings) + { + va_start (args); + vsprintf (buffer, format, args); + va_end (args); + as_warn_internal ((char *) NULL, 0, buffer); + } +} +#endif /* not NO_STDARG */ + +/* Like as_bad but the file name and line number are passed in. + Unfortunately, we have to repeat the function in order to handle + the varargs correctly and portably. */ + +#ifdef USE_STDARG +void +as_warn_where (char *file, unsigned int line, const char *format, ...) +{ + va_list args; + char buffer[2000]; + + if (!flag_no_warnings) + { + va_start (args, format); + vsprintf (buffer, format, args); + va_end (args); + as_warn_internal (file, line, buffer); + } +} +#else +void +as_warn_where (file, line, format, va_alist) + char *file; + unsigned int line; + const char *format; + va_dcl +{ + va_list args; + char buffer[2000]; + + if (!flag_no_warnings) + { + va_start (args); + vsprintf (buffer, format, args); + va_end (args); + as_warn_internal (file, line, buffer); + } +} +#endif /* not NO_STDARG */ + +/* The common portion of as_bad and as_bad_where. */ + +static void +as_bad_internal (file, line, buffer) + char *file; + unsigned int line; + char *buffer; +{ + ++error_count; + + if (file == NULL) + as_where (&file, &line); + + identify (file); + if (file) + fprintf (stderr, "%s:%u: ", file, line); + fprintf (stderr, _("Error: ")); + fputs (buffer, stderr); + (void) putc ('\n', stderr); +#ifndef NO_LISTING + listing_error (buffer); +#endif +} + +/* Send to stderr a string as a warning, and locate warning in input + file(s). Please us when there is no recovery, but we want to + continue processing but not produce an object file. + Please explain in string (which may have '\n's) what recovery was + done. */ + +#ifdef USE_STDARG +void +as_bad (const char *format, ...) +{ + va_list args; + char buffer[2000]; + + va_start (args, format); + vsprintf (buffer, format, args); + va_end (args); + + as_bad_internal ((char *) NULL, 0, buffer); +} + +#else +void +as_bad (format, va_alist) + const char *format; + va_dcl +{ + va_list args; + char buffer[2000]; + + va_start (args); + vsprintf (buffer, format, args); + va_end (args); + + as_bad_internal ((char *) NULL, 0, buffer); +} +#endif /* not NO_STDARG */ + +/* Like as_bad but the file name and line number are passed in. + Unfortunately, we have to repeat the function in order to handle + the varargs correctly and portably. */ + +#ifdef USE_STDARG +void +as_bad_where (char *file, unsigned int line, const char *format, ...) +{ + va_list args; + char buffer[2000]; + + va_start (args, format); + vsprintf (buffer, format, args); + va_end (args); + + as_bad_internal (file, line, buffer); +} + +#else +void +as_bad_where (file, line, format, va_alist) + char *file; + unsigned int line; + const char *format; + va_dcl +{ + va_list args; + char buffer[2000]; + + va_start (args); + vsprintf (buffer, format, args); + va_end (args); + + as_bad_internal (file, line, buffer); +} +#endif /* not NO_STDARG */ + +/* Send to stderr a string as a fatal message, and print location of + error in input file(s). + Please only use this for when we DON'T have some recovery action. + It xexit()s with a warning status. */ + +#ifdef USE_STDARG +void +as_fatal (const char *format, ...) +{ + va_list args; + + as_show_where (); + va_start (args, format); + fprintf (stderr, _("Fatal error: ")); + vfprintf (stderr, format, args); + (void) putc ('\n', stderr); + va_end (args); + /* Delete the output file, if it exists. This will prevent make from + thinking that a file was created and hence does not need rebuilding. */ + if (out_file_name != NULL) + unlink (out_file_name); + xexit (EXIT_FAILURE); +} +#else +void +as_fatal (format, va_alist) + char *format; + va_dcl +{ + va_list args; + + as_show_where (); + va_start (args); + fprintf (stderr, _("Fatal error: ")); + vfprintf (stderr, format, args); + (void) putc ('\n', stderr); + va_end (args); + xexit (EXIT_FAILURE); +} +#endif /* not NO_STDARG */ + +/* Indicate assertion failure. + Arguments: Filename, line number, optional function name. */ + +void +as_assert (file, line, fn) + const char *file, *fn; + int line; +{ + as_show_where (); + fprintf (stderr, _("Internal error!\n")); + if (fn) + fprintf (stderr, _("Assertion failure in %s at %s line %d.\n"), + fn, file, line); + else + fprintf (stderr, _("Assertion failure at %s line %d.\n"), file, line); + fprintf (stderr, _("Please report this bug.\n")); + xexit (EXIT_FAILURE); +} + +/* as_abort: Print a friendly message saying how totally hosed we are, + and exit without producing a core file. */ + +void +as_abort (file, line, fn) + const char *file, *fn; + int line; +{ + as_show_where (); + if (fn) + fprintf (stderr, _("Internal error, aborting at %s line %d in %s\n"), + file, line, fn); + else + fprintf (stderr, _("Internal error, aborting at %s line %d\n"), + file, line); + fprintf (stderr, _("Please report this bug.\n")); + xexit (EXIT_FAILURE); +} + +/* Support routines. */ + +void +fprint_value (file, val) + FILE *file; + valueT val; +{ + if (sizeof (val) <= sizeof (long)) + { + fprintf (file, "%ld", (long) val); + return; + } +#ifdef BFD_ASSEMBLER + if (sizeof (val) <= sizeof (bfd_vma)) + { + fprintf_vma (file, val); + return; + } +#endif + abort (); +} + +void +sprint_value (buf, val) + char *buf; + valueT val; +{ + if (sizeof (val) <= sizeof (long)) + { + sprintf (buf, "%ld", (long) val); + return; + } +#ifdef BFD_ASSEMBLER + if (sizeof (val) <= sizeof (bfd_vma)) + { + sprintf_vma (buf, val); + return; + } +#endif + abort (); +} diff --git a/contrib/binutils-2.14/gas/obj.h b/contrib/binutils-2.14/gas/obj.h new file mode 100644 index 0000000000..f7c1217f8e --- /dev/null +++ b/contrib/binutils-2.14/gas/obj.h @@ -0,0 +1,94 @@ +/* obj.h - defines the object dependent hooks for all object + format backends. + + Copyright 1987, 1990, 1991, 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2002 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +char *obj_default_output_file_name PARAMS ((void)); +void obj_emit_relocations PARAMS ((char **where, fixS * fixP, + relax_addressT segment_address_in_file)); +void obj_emit_strings PARAMS ((char **where)); +void obj_emit_symbols PARAMS ((char **where, symbolS * symbols)); +#ifndef obj_read_begin_hook +void obj_read_begin_hook PARAMS ((void)); +#endif +#ifndef BFD_ASSEMBLER +void obj_crawl_symbol_chain PARAMS ((object_headers * headers)); +void obj_header_append PARAMS ((char **where, object_headers * headers)); +#ifndef obj_pre_write_hook +void obj_pre_write_hook PARAMS ((object_headers * headers)); +#endif +#endif + +#ifndef obj_symbol_new_hook +void obj_symbol_new_hook PARAMS ((symbolS * symbolP)); +#endif + +void obj_symbol_to_chars PARAMS ((char **where, symbolS * symbolP)); + +extern const pseudo_typeS obj_pseudo_table[]; + +#ifdef BFD_ASSEMBLER +struct format_ops { + int flavor; + unsigned dfl_leading_underscore : 1; + unsigned emit_section_symbols : 1; + void (*begin) PARAMS ((void)); + void (*app_file) PARAMS ((const char *)); + void (*frob_symbol) PARAMS ((symbolS *, int *)); + void (*frob_file) PARAMS ((void)); + void (*frob_file_before_adjust) PARAMS ((void)); + void (*frob_file_before_fix) PARAMS ((void)); + void (*frob_file_after_relocs) PARAMS ((void)); + bfd_vma (*s_get_size) PARAMS ((symbolS *)); + void (*s_set_size) PARAMS ((symbolS *, bfd_vma)); + bfd_vma (*s_get_align) PARAMS ((symbolS *)); + void (*s_set_align) PARAMS ((symbolS *, bfd_vma)); + int (*s_get_other) PARAMS ((symbolS *)); + void (*s_set_other) PARAMS ((symbolS *, int)); + int (*s_get_desc) PARAMS ((symbolS *)); + void (*s_set_desc) PARAMS ((symbolS *, int)); + int (*s_get_type) PARAMS ((symbolS *)); + void (*s_set_type) PARAMS ((symbolS *, int)); + void (*copy_symbol_attributes) PARAMS ((symbolS *, symbolS *)); + void (*generate_asm_lineno) PARAMS ((void)); + void (*process_stab) PARAMS ((segT, int, const char *, int, int, int)); + int (*separate_stab_sections) PARAMS ((void)); + void (*init_stab_section) PARAMS ((segT)); + int (*sec_sym_ok_for_reloc) PARAMS ((asection *)); + void (*pop_insert) PARAMS ((void)); + /* For configurations using ECOFF_DEBUGGING, this callback is used. */ + void (*ecoff_set_ext) PARAMS ((symbolS *, struct ecoff_extr *)); + + void (*read_begin_hook) PARAMS ((void)); + void (*symbol_new_hook) PARAMS ((symbolS *)); +}; + +extern const struct format_ops elf_format_ops; +extern const struct format_ops ecoff_format_ops; +extern const struct format_ops coff_format_ops; +extern const struct format_ops aout_format_ops; + +#ifndef this_format +COMMON const struct format_ops *this_format; +#endif +#endif + +/* end of obj.h */ diff --git a/contrib/binutils-2.14/gas/output-file.c b/contrib/binutils-2.14/gas/output-file.c new file mode 100644 index 0000000000..531e35fa69 --- /dev/null +++ b/contrib/binutils-2.14/gas/output-file.c @@ -0,0 +1,154 @@ +/* output-file.c - Deal with the output file + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1996, 1998, 1999, 2001 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include + +#include "as.h" + +#include "output-file.h" + +#ifdef BFD_HEADERS +#define USE_BFD +#endif + +#ifdef BFD_ASSEMBLER +#define USE_BFD +#ifndef TARGET_MACH +#define TARGET_MACH 0 +#endif +#endif + +#ifdef USE_BFD +#include "bfd.h" +bfd *stdoutput; + +void +output_file_create (name) + char *name; +{ + if (name[0] == '-' && name[1] == '\0') + as_fatal (_("can't open a bfd on stdout %s"), name); + + else if (!(stdoutput = bfd_openw (name, TARGET_FORMAT))) + { + as_perror (_("FATAL: can't create %s"), name); + exit (EXIT_FAILURE); + } + + bfd_set_format (stdoutput, bfd_object); +#ifdef BFD_ASSEMBLER + bfd_set_arch_mach (stdoutput, TARGET_ARCH, TARGET_MACH); +#endif + if (flag_traditional_format) + stdoutput->flags |= BFD_TRADITIONAL_FORMAT; +} + +void +output_file_close (filename) + char *filename; +{ +#ifdef BFD_ASSEMBLER + /* Close the bfd. */ + if (bfd_close (stdoutput) == 0) + { + bfd_perror (filename); + as_perror (_("FATAL: can't close %s\n"), filename); + exit (EXIT_FAILURE); + } +#else + /* Close the bfd without getting bfd to write out anything by itself. */ + if (bfd_close_all_done (stdoutput) == 0) + { + as_perror (_("FATAL: can't close %s\n"), filename); + exit (EXIT_FAILURE); + } +#endif + stdoutput = NULL; /* Trust nobody! */ +} + +#ifndef BFD_ASSEMBLER +void +output_file_append (where, length, filename) + char *where ATTRIBUTE_UNUSED; + long length ATTRIBUTE_UNUSED; + char *filename ATTRIBUTE_UNUSED; +{ + abort (); +} +#endif + +#else + +static FILE *stdoutput; + +void +output_file_create (name) + char *name; +{ + if (name[0] == '-' && name[1] == '\0') + { + stdoutput = stdout; + return; + } + + stdoutput = fopen (name, FOPEN_WB); + if (stdoutput == NULL) + { + as_perror (_("FATAL: can't create %s"), name); + exit (EXIT_FAILURE); + } +} + +void +output_file_close (filename) + char *filename; +{ + if (EOF == fclose (stdoutput)) + { + as_perror (_("FATAL: can't close %s"), filename); + exit (EXIT_FAILURE); + } + + /* Trust nobody! */ + stdoutput = NULL; +} + +void +output_file_append (where, length, filename) + char * where; + long length; + char * filename; +{ + for (; length; length--, where++) + { + (void) putc (*where, stdoutput); + + if (ferror (stdoutput)) + /* if ( EOF == (putc( *where, stdoutput )) ) */ + { + as_perror (_("Failed to emit an object byte"), filename); + as_fatal (_("can't continue")); + } + } +} + +#endif + diff --git a/contrib/binutils-2.14/gas/output-file.h b/contrib/binutils-2.14/gas/output-file.h new file mode 100644 index 0000000000..48b7a6a29c --- /dev/null +++ b/contrib/binutils-2.14/gas/output-file.h @@ -0,0 +1,26 @@ +/* This file is output-file.h + + Copyright 1987, 1988, 1989, 1990, 1991, 1992 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +void output_file_append PARAMS ((char *where, long length, char *filename)); +void output_file_close PARAMS ((char *filename)); +void output_file_create PARAMS ((char *name)); + +/* end of output-file.h */ diff --git a/contrib/binutils-2.14/gas/read.c b/contrib/binutils-2.14/gas/read.c new file mode 100644 index 0000000000..2037f0bf09 --- /dev/null +++ b/contrib/binutils-2.14/gas/read.c @@ -0,0 +1,5346 @@ +/* read.c - read a source file - + Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler. + +GAS is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GAS is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GAS; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#if 0 +/* If your chars aren't 8 bits, you will change this a bit. + But then, GNU isn't spozed to run on your machine anyway. + (RMS is so shortsighted sometimes.) */ +#define MASK_CHAR (0xFF) +#else +#define MASK_CHAR ((int)(unsigned char) -1) +#endif + +/* This is the largest known floating point format (for now). It will + grow when we do 4361 style flonums. */ +#define MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT (16) + +/* Routines that read assembler source text to build spagetti in memory. + Another group of these functions is in the expr.c module. */ + +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "sb.h" +#include "macro.h" +#include "obstack.h" +#include "listing.h" +#include "ecoff.h" + +#ifndef TC_START_LABEL +#define TC_START_LABEL(x,y) (x == ':') +#endif + +/* Set by the object-format or the target. */ +#ifndef TC_IMPLICIT_LCOMM_ALIGNMENT +#define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) \ + do \ + { \ + if ((SIZE) >= 8) \ + (P2VAR) = 3; \ + else if ((SIZE) >= 4) \ + (P2VAR) = 2; \ + else if ((SIZE) >= 2) \ + (P2VAR) = 1; \ + else \ + (P2VAR) = 0; \ + } \ + while (0) +#endif + +char *input_line_pointer; /*->next char of source file to parse. */ + +#if BITS_PER_CHAR != 8 +/* The following table is indexed by[(char)] and will break if + a char does not have exactly 256 states (hopefully 0:255!)! */ +die horribly; +#endif + +#ifndef LEX_AT +/* The m88k unfortunately uses @ as a label beginner. */ +#define LEX_AT 0 +#endif + +#ifndef LEX_BR +/* The RS/6000 assembler uses {,},[,] as parts of symbol names. */ +#define LEX_BR 0 +#endif + +#ifndef LEX_PCT +/* The Delta 68k assembler permits % inside label names. */ +#define LEX_PCT 0 +#endif + +#ifndef LEX_QM +/* The PowerPC Windows NT assemblers permits ? inside label names. */ +#define LEX_QM 0 +#endif + +#ifndef LEX_HASH +/* The IA-64 assembler uses # as a suffix designating a symbol. We include + it in the symbol and strip it out in tc_canonicalize_symbol_name. */ +#define LEX_HASH 0 +#endif + +#ifndef LEX_DOLLAR +/* The a29k assembler does not permits labels to start with $. */ +#define LEX_DOLLAR 3 +#endif + +#ifndef LEX_TILDE +/* The Delta 68k assembler permits ~ at start of label names. */ +#define LEX_TILDE 0 +#endif + +/* Used by is_... macros. our ctype[]. */ +char lex_type[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ABCDEFGHIJKLMNO */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ[\]^_ */ + 0, 0, 0, LEX_HASH, LEX_DOLLAR, LEX_PCT, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, /* _!"#$%&'()*+,-./ */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, LEX_QM, /* 0123456789:;<=>? */ + LEX_AT, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, 0, 3, /* PQRSTUVWXYZ[\]^_ */ + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, LEX_BR, 0, LEX_BR, LEX_TILDE, 0, /* pqrstuvwxyz{|}~. */ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 +}; + +/* In: a character. + Out: 1 if this character ends a line. */ +char is_end_of_line[256] = { +#ifdef CR_EOL + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, /* @abcdefghijklmno */ +#else + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* @abcdefghijklmno */ +#endif + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* _!"#$%&'()*+,-./ */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0123456789:;<=>? */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* */ +}; + +#ifdef IGNORE_OPCODE_CASE +char original_case_string[128]; +#endif + +/* Functions private to this file. */ + +static char *buffer; /* 1st char of each buffer of lines is here. */ +static char *buffer_limit; /*->1 + last char in buffer. */ + +/* TARGET_BYTES_BIG_ENDIAN is required to be defined to either 0 or 1 + in the tc-.h file. See the "Porting GAS" section of the + internals manual. */ +int target_big_endian = TARGET_BYTES_BIG_ENDIAN; + +/* Variables for handling include file directory table. */ + +/* Table of pointers to directories to search for .include's. */ +char **include_dirs; + +/* How many are in the table. */ +int include_dir_count; + +/* Length of longest in table. */ +int include_dir_maxlen = 1; + +#ifndef WORKING_DOT_WORD +struct broken_word *broken_words; +int new_broken_words; +#endif + +/* The current offset into the absolute section. We don't try to + build frags in the absolute section, since no data can be stored + there. We just keep track of the current offset. */ +addressT abs_section_offset; + +/* If this line had an MRI style label, it is stored in this variable. + This is used by some of the MRI pseudo-ops. */ +symbolS *line_label; + +/* This global variable is used to support MRI common sections. We + translate such sections into a common symbol. This variable is + non-NULL when we are in an MRI common section. */ +symbolS *mri_common_symbol; + +/* In MRI mode, after a dc.b pseudo-op with an odd number of bytes, we + need to align to an even byte boundary unless the next pseudo-op is + dc.b, ds.b, or dcb.b. This variable is set to 1 if an alignment + may be needed. */ +static int mri_pending_align; + +#ifndef NO_LISTING +#ifdef OBJ_ELF +/* This variable is set to be non-zero if the next string we see might + be the name of the source file in DWARF debugging information. See + the comment in emit_expr for the format we look for. */ +static int dwarf_file_string; +#endif +#endif + +static void cons_worker PARAMS ((int, int)); +static int scrub_from_string PARAMS ((char *, int)); +static void do_align PARAMS ((int, char *, int, int)); +static void s_align PARAMS ((int, int)); +static void s_lcomm_internal PARAMS ((int, int)); +static int hex_float PARAMS ((int, char *)); +static inline int sizeof_sleb128 PARAMS ((offsetT)); +static inline int sizeof_uleb128 PARAMS ((valueT)); +static inline int output_sleb128 PARAMS ((char *, offsetT)); +static inline int output_uleb128 PARAMS ((char *, valueT)); +static inline int output_big_sleb128 PARAMS ((char *, LITTLENUM_TYPE *, int)); +static inline int output_big_uleb128 PARAMS ((char *, LITTLENUM_TYPE *, int)); +static int output_big_leb128 PARAMS ((char *, LITTLENUM_TYPE *, int, int)); +static void do_org PARAMS ((segT, expressionS *, int)); +char *demand_copy_string PARAMS ((int *lenP)); +static segT get_segmented_expression PARAMS ((expressionS *expP)); +static segT get_known_segmented_expression PARAMS ((expressionS * expP)); +static void pobegin PARAMS ((void)); +static int get_line_sb PARAMS ((sb *)); +static void generate_file_debug PARAMS ((void)); + +void +read_begin () +{ + const char *p; + + pobegin (); + obj_read_begin_hook (); + + /* Something close -- but not too close -- to a multiple of 1024. + The debugging malloc I'm using has 24 bytes of overhead. */ + obstack_begin (¬es, chunksize); + obstack_begin (&cond_obstack, chunksize); + + /* Use machine dependent syntax. */ + for (p = line_separator_chars; *p; p++) + is_end_of_line[(unsigned char) *p] = 1; + /* Use more. FIXME-SOMEDAY. */ + + if (flag_mri) + lex_type['?'] = 3; +} + +/* Set up pseudo-op tables. */ + +static struct hash_control *po_hash; + +static const pseudo_typeS potable[] = { + {"abort", s_abort, 0}, + {"align", s_align_ptwo, 0}, + {"ascii", stringer, 0}, + {"asciz", stringer, 1}, + {"balign", s_align_bytes, 0}, + {"balignw", s_align_bytes, -2}, + {"balignl", s_align_bytes, -4}, +/* block */ + {"byte", cons, 1}, + {"comm", s_comm, 0}, + {"common", s_mri_common, 0}, + {"common.s", s_mri_common, 1}, + {"data", s_data, 0}, + {"dc", cons, 2}, + {"dc.b", cons, 1}, + {"dc.d", float_cons, 'd'}, + {"dc.l", cons, 4}, + {"dc.s", float_cons, 'f'}, + {"dc.w", cons, 2}, + {"dc.x", float_cons, 'x'}, + {"dcb", s_space, 2}, + {"dcb.b", s_space, 1}, + {"dcb.d", s_float_space, 'd'}, + {"dcb.l", s_space, 4}, + {"dcb.s", s_float_space, 'f'}, + {"dcb.w", s_space, 2}, + {"dcb.x", s_float_space, 'x'}, + {"ds", s_space, 2}, + {"ds.b", s_space, 1}, + {"ds.d", s_space, 8}, + {"ds.l", s_space, 4}, + {"ds.p", s_space, 12}, + {"ds.s", s_space, 4}, + {"ds.w", s_space, 2}, + {"ds.x", s_space, 12}, + {"debug", s_ignore, 0}, +#ifdef S_SET_DESC + {"desc", s_desc, 0}, +#endif +/* dim */ + {"double", float_cons, 'd'}, +/* dsect */ + {"eject", listing_eject, 0}, /* Formfeed listing. */ + {"else", s_else, 0}, + {"elsec", s_else, 0}, + {"elseif", s_elseif, (int) O_ne}, + {"end", s_end, 0}, + {"endc", s_endif, 0}, + {"endfunc", s_func, 1}, + {"endif", s_endif, 0}, + {"endr", s_bad_endr, 0}, +/* endef */ + {"equ", s_set, 0}, + {"equiv", s_set, 1}, + {"err", s_err, 0}, + {"exitm", s_mexit, 0}, +/* extend */ + {"extern", s_ignore, 0}, /* We treat all undef as ext. */ + {"appfile", s_app_file, 1}, + {"appline", s_app_line, 0}, + {"fail", s_fail, 0}, + {"file", s_app_file, 0}, + {"fill", s_fill, 0}, + {"float", float_cons, 'f'}, + {"format", s_ignore, 0}, + {"func", s_func, 0}, + {"global", s_globl, 0}, + {"globl", s_globl, 0}, + {"hword", cons, 2}, + {"if", s_if, (int) O_ne}, + {"ifc", s_ifc, 0}, + {"ifdef", s_ifdef, 0}, + {"ifeq", s_if, (int) O_eq}, + {"ifeqs", s_ifeqs, 0}, + {"ifge", s_if, (int) O_ge}, + {"ifgt", s_if, (int) O_gt}, + {"ifle", s_if, (int) O_le}, + {"iflt", s_if, (int) O_lt}, + {"ifnc", s_ifc, 1}, + {"ifndef", s_ifdef, 1}, + {"ifne", s_if, (int) O_ne}, + {"ifnes", s_ifeqs, 1}, + {"ifnotdef", s_ifdef, 1}, + {"incbin", s_incbin, 0}, + {"include", s_include, 0}, + {"int", cons, 4}, + {"irp", s_irp, 0}, + {"irep", s_irp, 0}, + {"irpc", s_irp, 1}, + {"irepc", s_irp, 1}, + {"lcomm", s_lcomm, 0}, + {"lflags", listing_flags, 0}, /* Listing flags. */ + {"linkonce", s_linkonce, 0}, + {"list", listing_list, 1}, /* Turn listing on. */ + {"llen", listing_psize, 1}, + {"long", cons, 4}, + {"lsym", s_lsym, 0}, + {"macro", s_macro, 0}, + {"mexit", s_mexit, 0}, + {"mri", s_mri, 0}, + {".mri", s_mri, 0}, /* Special case so .mri works in MRI mode. */ + {"name", s_ignore, 0}, + {"noformat", s_ignore, 0}, + {"nolist", listing_list, 0}, /* Turn listing off. */ + {"nopage", listing_nopage, 0}, + {"octa", cons, 16}, + {"offset", s_struct, 0}, + {"org", s_org, 0}, + {"p2align", s_align_ptwo, 0}, + {"p2alignw", s_align_ptwo, -2}, + {"p2alignl", s_align_ptwo, -4}, + {"page", listing_eject, 0}, + {"plen", listing_psize, 0}, + {"print", s_print, 0}, + {"psize", listing_psize, 0}, /* Set paper size. */ + {"purgem", s_purgem, 0}, + {"quad", cons, 8}, + {"rep", s_rept, 0}, + {"rept", s_rept, 0}, + {"rva", s_rva, 4}, + {"sbttl", listing_title, 1}, /* Subtitle of listing. */ +/* scl */ +/* sect */ + {"set", s_set, 0}, + {"short", cons, 2}, + {"single", float_cons, 'f'}, +/* size */ + {"space", s_space, 0}, + {"skip", s_space, 0}, + {"sleb128", s_leb128, 1}, + {"spc", s_ignore, 0}, + {"stabd", s_stab, 'd'}, + {"stabn", s_stab, 'n'}, + {"stabs", s_stab, 's'}, + {"string", stringer, 1}, + {"struct", s_struct, 0}, +/* tag */ + {"text", s_text, 0}, + + /* This is for gcc to use. It's only just been added (2/94), so gcc + won't be able to use it for a while -- probably a year or more. + But once this has been released, check with gcc maintainers + before deleting it or even changing the spelling. */ + {"this_GCC_requires_the_GNU_assembler", s_ignore, 0}, + /* If we're folding case -- done for some targets, not necessarily + all -- the above string in an input file will be converted to + this one. Match it either way... */ + {"this_gcc_requires_the_gnu_assembler", s_ignore, 0}, + + {"title", listing_title, 0}, /* Listing title. */ + {"ttl", listing_title, 0}, +/* type */ + {"uleb128", s_leb128, 0}, +/* use */ +/* val */ + {"xcom", s_comm, 0}, + {"xdef", s_globl, 0}, + {"xref", s_ignore, 0}, + {"xstabs", s_xstab, 's'}, + {"word", cons, 2}, + {"zero", s_space, 0}, + {NULL, NULL, 0} /* End sentinel. */ +}; + +static int pop_override_ok = 0; +static const char *pop_table_name; + +void +pop_insert (table) + const pseudo_typeS *table; +{ + const char *errtxt; + const pseudo_typeS *pop; + for (pop = table; pop->poc_name; pop++) + { + errtxt = hash_insert (po_hash, pop->poc_name, (char *) pop); + if (errtxt && (!pop_override_ok || strcmp (errtxt, "exists"))) + as_fatal (_("error constructing %s pseudo-op table: %s"), pop_table_name, + errtxt); + } +} + +#ifndef md_pop_insert +#define md_pop_insert() pop_insert(md_pseudo_table) +#endif + +#ifndef obj_pop_insert +#define obj_pop_insert() pop_insert(obj_pseudo_table) +#endif + +static void +pobegin () +{ + po_hash = hash_new (); + + /* Do the target-specific pseudo ops. */ + pop_table_name = "md"; + md_pop_insert (); + + /* Now object specific. Skip any that were in the target table. */ + pop_table_name = "obj"; + pop_override_ok = 1; + obj_pop_insert (); + + /* Now portable ones. Skip any that we've seen already. */ + pop_table_name = "standard"; + pop_insert (potable); +} + +#define HANDLE_CONDITIONAL_ASSEMBLY() \ + if (ignore_input ()) \ + { \ + while (!is_end_of_line[(unsigned char) *input_line_pointer++]) \ + if (input_line_pointer == buffer_limit) \ + break; \ + continue; \ + } + +/* This function is used when scrubbing the characters between #APP + and #NO_APP. */ + +static char *scrub_string; +static char *scrub_string_end; + +static int +scrub_from_string (buf, buflen) + char *buf; + int buflen; +{ + int copy; + + copy = scrub_string_end - scrub_string; + if (copy > buflen) + copy = buflen; + memcpy (buf, scrub_string, copy); + scrub_string += copy; + return copy; +} + +/* We read the file, putting things into a web that represents what we + have been reading. */ +void +read_a_source_file (name) + char *name; +{ + register char c; + register char *s; /* String of symbol, '\0' appended. */ + register int temp; + pseudo_typeS *pop; + +#ifdef WARN_COMMENTS + found_comment = 0; +#endif + + buffer = input_scrub_new_file (name); + + listing_file (name); + listing_newline (NULL); + register_dependency (name); + + /* Generate debugging information before we've read anything in to denote + this file as the "main" source file and not a subordinate one + (e.g. N_SO vs N_SOL in stabs). */ + generate_file_debug (); + + while ((buffer_limit = input_scrub_next_buffer (&input_line_pointer)) != 0) + { /* We have another line to parse. */ + know (buffer_limit[-1] == '\n'); /* Must have a sentinel. */ + + while (input_line_pointer < buffer_limit) + { + /* We have more of this buffer to parse. */ + + /* We now have input_line_pointer->1st char of next line. + If input_line_pointer [-1] == '\n' then we just + scanned another line: so bump line counters. */ + if (is_end_of_line[(unsigned char) input_line_pointer[-1]]) + { +#ifdef md_start_line_hook + md_start_line_hook (); +#endif + if (input_line_pointer[-1] == '\n') + bump_line_counters (); + + line_label = NULL; + + if (LABELS_WITHOUT_COLONS || flag_m68k_mri) + { + /* Text at the start of a line must be a label, we + run down and stick a colon in. */ + if (is_name_beginner (*input_line_pointer)) + { + char *line_start = input_line_pointer; + char c; + int mri_line_macro; + + LISTING_NEWLINE (); + HANDLE_CONDITIONAL_ASSEMBLY (); + + c = get_symbol_end (); + + /* In MRI mode, the EQU and MACRO pseudoops must + be handled specially. */ + mri_line_macro = 0; + if (flag_m68k_mri) + { + char *rest = input_line_pointer + 1; + + if (*rest == ':') + ++rest; + if (*rest == ' ' || *rest == '\t') + ++rest; + if ((strncasecmp (rest, "EQU", 3) == 0 + || strncasecmp (rest, "SET", 3) == 0) + && (rest[3] == ' ' || rest[3] == '\t')) + { + input_line_pointer = rest + 3; + equals (line_start, + strncasecmp (rest, "SET", 3) == 0); + continue; + } + if (strncasecmp (rest, "MACRO", 5) == 0 + && (rest[5] == ' ' + || rest[5] == '\t' + || is_end_of_line[(unsigned char) rest[5]])) + mri_line_macro = 1; + } + + /* In MRI mode, we need to handle the MACRO + pseudo-op specially: we don't want to put the + symbol in the symbol table. */ + if (!mri_line_macro +#ifdef TC_START_LABEL_WITHOUT_COLON + && TC_START_LABEL_WITHOUT_COLON(c, + input_line_pointer) +#endif + ) + line_label = colon (line_start); + else + line_label = symbol_create (line_start, + absolute_section, + (valueT) 0, + &zero_address_frag); + + *input_line_pointer = c; + if (c == ':') + input_line_pointer++; + } + } + } + + /* We are at the begining of a line, or similar place. + We expect a well-formed assembler statement. + A "symbol-name:" is a statement. + + Depending on what compiler is used, the order of these tests + may vary to catch most common case 1st. + Each test is independent of all other tests at the (top) level. + PLEASE make a compiler that doesn't use this assembler. + It is crufty to waste a compiler's time encoding things for this + assembler, which then wastes more time decoding it. + (And communicating via (linear) files is silly! + If you must pass stuff, please pass a tree!) */ + if ((c = *input_line_pointer++) == '\t' + || c == ' ' + || c == '\f' + || c == 0) + c = *input_line_pointer++; + + know (c != ' '); /* No further leading whitespace. */ + +#ifndef NO_LISTING + /* If listing is on, and we are expanding a macro, then give + the listing code the contents of the expanded line. */ + if (listing) + { + if ((listing & LISTING_MACEXP) && macro_nest > 0) + { + char *copy; + int len; + + /* Find the end of the current expanded macro line. */ + for (s = input_line_pointer - 1; *s; ++s) + if (is_end_of_line[(unsigned char) *s]) + break; + + /* Copy it for safe keeping. Also give an indication of + how much macro nesting is involved at this point. */ + len = s - (input_line_pointer - 1); + copy = (char *) xmalloc (len + macro_nest + 2); + memset (copy, '>', macro_nest); + copy[macro_nest] = ' '; + memcpy (copy + macro_nest + 1, input_line_pointer - 1, len); + copy[macro_nest + 1 + len] = '\0'; + + /* Install the line with the listing facility. */ + listing_newline (copy); + } + else + listing_newline (NULL); + } +#endif + /* C is the 1st significant character. + Input_line_pointer points after that character. */ + if (is_name_beginner (c)) + { + /* Want user-defined label or pseudo/opcode. */ + HANDLE_CONDITIONAL_ASSEMBLY (); + + s = --input_line_pointer; + c = get_symbol_end (); /* name's delimiter. */ + + /* C is character after symbol. + That character's place in the input line is now '\0'. + S points to the beginning of the symbol. + [In case of pseudo-op, s->'.'.] + Input_line_pointer->'\0' where c was. */ + if (TC_START_LABEL (c, input_line_pointer)) + { + if (flag_m68k_mri) + { + char *rest = input_line_pointer + 1; + + /* In MRI mode, \tsym: set 0 is permitted. */ + if (*rest == ':') + ++rest; + + if (*rest == ' ' || *rest == '\t') + ++rest; + + if ((strncasecmp (rest, "EQU", 3) == 0 + || strncasecmp (rest, "SET", 3) == 0) + && (rest[3] == ' ' || rest[3] == '\t')) + { + input_line_pointer = rest + 3; + equals (s, 1); + continue; + } + } + + line_label = colon (s); /* User-defined label. */ + /* Put ':' back for error messages' sake. */ + *input_line_pointer++ = ':'; + /* Input_line_pointer->after ':'. */ + SKIP_WHITESPACE (); + } + else if (c == '=' + || ((c == ' ' || c == '\t') + && input_line_pointer[1] == '=' +#ifdef TC_EQUAL_IN_INSN + && !TC_EQUAL_IN_INSN (c, input_line_pointer) +#endif + )) + { + equals (s, 1); + demand_empty_rest_of_line (); + } + else + { + /* Expect pseudo-op or machine instruction. */ + pop = NULL; + +#ifdef IGNORE_OPCODE_CASE + { + char *s2 = s; + + strncpy (original_case_string, s2, sizeof (original_case_string)); + original_case_string[sizeof (original_case_string) - 1] = 0; + + while (*s2) + { + *s2 = TOLOWER (*s2); + s2++; + } + } +#endif + if (NO_PSEUDO_DOT || flag_m68k_mri) + { + /* The MRI assembler and the m88k use pseudo-ops + without a period. */ + pop = (pseudo_typeS *) hash_find (po_hash, s); + if (pop != NULL && pop->poc_handler == NULL) + pop = NULL; + } + + if (pop != NULL + || (!flag_m68k_mri && *s == '.')) + { + /* PSEUDO - OP. + + WARNING: c has next char, which may be end-of-line. + We lookup the pseudo-op table with s+1 because we + already know that the pseudo-op begins with a '.'. */ + + if (pop == NULL) + pop = (pseudo_typeS *) hash_find (po_hash, s + 1); + + /* In MRI mode, we may need to insert an + automatic alignment directive. What a hack + this is. */ + if (mri_pending_align + && (pop == NULL + || !((pop->poc_handler == cons + && pop->poc_val == 1) + || (pop->poc_handler == s_space + && pop->poc_val == 1) +#ifdef tc_conditional_pseudoop + || tc_conditional_pseudoop (pop) +#endif + || pop->poc_handler == s_if + || pop->poc_handler == s_ifdef + || pop->poc_handler == s_ifc + || pop->poc_handler == s_ifeqs + || pop->poc_handler == s_else + || pop->poc_handler == s_endif + || pop->poc_handler == s_globl + || pop->poc_handler == s_ignore))) + { + do_align (1, (char *) NULL, 0, 0); + mri_pending_align = 0; + + if (line_label != NULL) + { + symbol_set_frag (line_label, frag_now); + S_SET_VALUE (line_label, frag_now_fix ()); + } + } + + /* Print the error msg now, while we still can. */ + if (pop == NULL) + { + as_bad (_("unknown pseudo-op: `%s'"), s); + *input_line_pointer = c; + s_ignore (0); + continue; + } + + /* Put it back for error messages etc. */ + *input_line_pointer = c; + /* The following skip of whitespace is compulsory. + A well shaped space is sometimes all that separates + keyword from operands. */ + if (c == ' ' || c == '\t') + input_line_pointer++; + + /* Input_line is restored. + Input_line_pointer->1st non-blank char + after pseudo-operation. */ + (*pop->poc_handler) (pop->poc_val); + + /* If that was .end, just get out now. */ + if (pop->poc_handler == s_end) + goto quit; + } + else + { + int inquote = 0; +#ifdef QUOTES_IN_INSN + int inescape = 0; +#endif + + /* WARNING: c has char, which may be end-of-line. */ + /* Also: input_line_pointer->`\0` where c was. */ + *input_line_pointer = c; + while (!is_end_of_line[(unsigned char) *input_line_pointer] + || inquote +#ifdef TC_EOL_IN_INSN + || TC_EOL_IN_INSN (input_line_pointer) +#endif + ) + { + if (flag_m68k_mri && *input_line_pointer == '\'') + inquote = !inquote; +#ifdef QUOTES_IN_INSN + if (inescape) + inescape = 0; + else if (*input_line_pointer == '"') + inquote = !inquote; + else if (*input_line_pointer == '\\') + inescape = 1; +#endif + input_line_pointer++; + } + + c = *input_line_pointer; + *input_line_pointer = '\0'; + + generate_lineno_debug (); + + if (macro_defined) + { + sb out; + const char *err; + macro_entry *macro; + + if (check_macro (s, &out, &err, ¯o)) + { + if (err != NULL) + as_bad ("%s", err); + *input_line_pointer++ = c; + input_scrub_include_sb (&out, + input_line_pointer, 1); + sb_kill (&out); + buffer_limit = + input_scrub_next_buffer (&input_line_pointer); +#ifdef md_macro_info + md_macro_info (macro); +#endif + continue; + } + } + + if (mri_pending_align) + { + do_align (1, (char *) NULL, 0, 0); + mri_pending_align = 0; + if (line_label != NULL) + { + symbol_set_frag (line_label, frag_now); + S_SET_VALUE (line_label, frag_now_fix ()); + } + } + + md_assemble (s); /* Assemble 1 instruction. */ + + *input_line_pointer++ = c; + + /* We resume loop AFTER the end-of-line from + this instruction. */ + } + } + continue; + } + + /* Empty statement? */ + if (is_end_of_line[(unsigned char) c]) + continue; + + if ((LOCAL_LABELS_DOLLAR || LOCAL_LABELS_FB) && ISDIGIT (c)) + { + /* local label ("4:") */ + char *backup = input_line_pointer; + + HANDLE_CONDITIONAL_ASSEMBLY (); + + temp = c - '0'; + + /* Read the whole number. */ + while (ISDIGIT (*input_line_pointer)) + { + temp = (temp * 10) + *input_line_pointer - '0'; + ++input_line_pointer; + } + + if (LOCAL_LABELS_DOLLAR + && *input_line_pointer == '$' + && *(input_line_pointer + 1) == ':') + { + input_line_pointer += 2; + + if (dollar_label_defined (temp)) + { + as_fatal (_("label \"%d$\" redefined"), temp); + } + + define_dollar_label (temp); + colon (dollar_label_name (temp, 0)); + continue; + } + + if (LOCAL_LABELS_FB + && *input_line_pointer++ == ':') + { + fb_label_instance_inc (temp); + colon (fb_label_name (temp, 0)); + continue; + } + + input_line_pointer = backup; + } /* local label ("4:") */ + + if (c && strchr (line_comment_chars, c)) + { /* Its a comment. Better say APP or NO_APP. */ + sb sbuf; + char *ends; + char *new_buf; + char *new_tmp; + unsigned int new_length; + char *tmp_buf = 0; + + bump_line_counters (); + s = input_line_pointer; + if (strncmp (s, "APP\n", 4)) + continue; /* We ignore it */ + s += 4; + + sb_new (&sbuf); + ends = strstr (s, "#NO_APP\n"); + + if (!ends) + { + unsigned int tmp_len; + unsigned int num; + + /* The end of the #APP wasn't in this buffer. We + keep reading in buffers until we find the #NO_APP + that goes with this #APP There is one. The specs + guarentee it... */ + tmp_len = buffer_limit - s; + tmp_buf = xmalloc (tmp_len + 1); + memcpy (tmp_buf, s, tmp_len); + do + { + new_tmp = input_scrub_next_buffer (&buffer); + if (!new_tmp) + break; + else + buffer_limit = new_tmp; + input_line_pointer = buffer; + ends = strstr (buffer, "#NO_APP\n"); + if (ends) + num = ends - buffer; + else + num = buffer_limit - buffer; + + tmp_buf = xrealloc (tmp_buf, tmp_len + num); + memcpy (tmp_buf + tmp_len, buffer, num); + tmp_len += num; + } + while (!ends); + + input_line_pointer = ends ? ends + 8 : NULL; + + s = tmp_buf; + ends = s + tmp_len; + + } + else + { + input_line_pointer = ends + 8; + } + + scrub_string = s; + scrub_string_end = ends; + + new_length = ends - s; + new_buf = (char *) xmalloc (new_length); + new_tmp = new_buf; + for (;;) + { + int space; + int size; + + space = (new_buf + new_length) - new_tmp; + size = do_scrub_chars (scrub_from_string, new_tmp, space); + + if (size < space) + { + new_tmp[size] = 0; + break; + } + + new_buf = xrealloc (new_buf, new_length + 100); + new_tmp = new_buf + new_length; + new_length += 100; + } + + if (tmp_buf) + free (tmp_buf); + + /* We've "scrubbed" input to the preferred format. In the + process we may have consumed the whole of the remaining + file (and included files). We handle this formatted + input similar to that of macro expansion, letting + actual macro expansion (possibly nested) and other + input expansion work. Beware that in messages, line + numbers and possibly file names will be incorrect. */ + sb_add_string (&sbuf, new_buf); + input_scrub_include_sb (&sbuf, input_line_pointer, 0); + sb_kill (&sbuf); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); + free (new_buf); + continue; + } + + HANDLE_CONDITIONAL_ASSEMBLY (); + +#ifdef tc_unrecognized_line + if (tc_unrecognized_line (c)) + continue; +#endif + input_line_pointer--; + /* Report unknown char as ignored. */ + ignore_rest_of_line (); + } + +#ifdef md_after_pass_hook + md_after_pass_hook (); +#endif + } + + quit: + +#ifdef md_cleanup + md_cleanup (); +#endif + /* Close the input file. */ + input_scrub_close (); +#ifdef WARN_COMMENTS + { + if (warn_comment && found_comment) + as_warn_where (found_comment_file, found_comment, + "first comment found here"); + } +#endif +} + +/* For most MRI pseudo-ops, the line actually ends at the first + nonquoted space. This function looks for that point, stuffs a null + in, and sets *STOPCP to the character that used to be there, and + returns the location. + + Until I hear otherwise, I am going to assume that this is only true + for the m68k MRI assembler. */ + +char * +mri_comment_field (stopcp) + char *stopcp; +{ + char *s; +#ifdef TC_M68K + int inquote = 0; + + know (flag_m68k_mri); + + for (s = input_line_pointer; + ((!is_end_of_line[(unsigned char) *s] && *s != ' ' && *s != '\t') + || inquote); + s++) + { + if (*s == '\'') + inquote = !inquote; + } +#else + for (s = input_line_pointer; + !is_end_of_line[(unsigned char) *s]; + s++) + ; +#endif + *stopcp = *s; + *s = '\0'; + + return s; +} + +/* Skip to the end of an MRI comment field. */ + +void +mri_comment_end (stop, stopc) + char *stop; + int stopc; +{ + know (flag_mri); + + input_line_pointer = stop; + *stop = stopc; + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; +} + +void +s_abort (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + as_fatal (_(".abort detected. Abandoning ship.")); +} + +/* Guts of .align directive. N is the power of two to which to align. + FILL may be NULL, or it may point to the bytes of the fill pattern. + LEN is the length of whatever FILL points to, if anything. MAX is + the maximum number of characters to skip when doing the alignment, + or 0 if there is no maximum. */ + +static void +do_align (n, fill, len, max) + int n; + char *fill; + int len; + int max; +{ + if (now_seg == absolute_section) + { + if (fill != NULL) + while (len-- > 0) + if (*fill++ != '\0') + { + as_warn (_("ignoring fill value in absolute section")); + break; + } + fill = NULL; + len = 0; + } + +#ifdef md_do_align + md_do_align (n, fill, len, max, just_record_alignment); +#endif + + /* Only make a frag if we HAVE to... */ + if (n != 0 && !need_pass_2) + { + if (fill == NULL) + { + if (subseg_text_p (now_seg)) + frag_align_code (n, max); + else + frag_align (n, 0, max); + } + else if (len <= 1) + frag_align (n, *fill, max); + else + frag_align_pattern (n, fill, len, max); + } + +#ifdef md_do_align + just_record_alignment: ATTRIBUTE_UNUSED_LABEL +#endif + + record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER); +} + +/* Handle the .align pseudo-op. A positive ARG is a default alignment + (in bytes). A negative ARG is the negative of the length of the + fill pattern. BYTES_P is non-zero if the alignment value should be + interpreted as the byte boundary, rather than the power of 2. */ + +static void +s_align (arg, bytes_p) + int arg; + int bytes_p; +{ + register unsigned int align; + char *stop = NULL; + char stopc; + offsetT fill = 0; + int max; + int fill_p; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + if (is_end_of_line[(unsigned char) *input_line_pointer]) + { + if (arg < 0) + align = 0; + else + align = arg; /* Default value from pseudo-op table. */ + } + else + { + align = get_absolute_expression (); + SKIP_WHITESPACE (); + } + + if (bytes_p) + { + /* Convert to a power of 2. */ + if (align != 0) + { + unsigned int i; + + for (i = 0; (align & 1) == 0; align >>= 1, ++i) + ; + if (align != 1) + as_bad (_("alignment not a power of 2")); + + align = i; + } + } + + if (align > 15) + { + align = 15; + as_warn (_("alignment too large: %u assumed"), align); + } + + if (*input_line_pointer != ',') + { + fill_p = 0; + max = 0; + } + else + { + ++input_line_pointer; + if (*input_line_pointer == ',') + fill_p = 0; + else + { + fill = get_absolute_expression (); + SKIP_WHITESPACE (); + fill_p = 1; + } + + if (*input_line_pointer != ',') + max = 0; + else + { + ++input_line_pointer; + max = get_absolute_expression (); + } + } + + if (!fill_p) + { + if (arg < 0) + as_warn (_("expected fill pattern missing")); + do_align (align, (char *) NULL, 0, max); + } + else + { + int fill_len; + + if (arg >= 0) + fill_len = 1; + else + fill_len = -arg; + if (fill_len <= 1) + { + char fill_char; + + fill_char = fill; + do_align (align, &fill_char, fill_len, max); + } + else + { + char ab[16]; + + if ((size_t) fill_len > sizeof ab) + abort (); + md_number_to_chars (ab, fill, fill_len); + do_align (align, ab, fill_len, max); + } + } + + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); +} + +/* Handle the .align pseudo-op on machines where ".align 4" means + align to a 4 byte boundary. */ + +void +s_align_bytes (arg) + int arg; +{ + s_align (arg, 1); +} + +/* Handle the .align pseudo-op on machines where ".align 4" means align + to a 2**4 boundary. */ + +void +s_align_ptwo (arg) + int arg; +{ + s_align (arg, 0); +} + +void +s_comm (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + register char *name; + register char c; + register char *p; + offsetT temp; + register symbolS *symbolP; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + name = input_line_pointer; + c = get_symbol_end (); + /* Just after name is now '\0'. */ + p = input_line_pointer; + *p = c; + + if (name == p) + { + as_bad (_("expected symbol name")); + discard_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + *p = 0; + as_bad (_("expected comma after \"%s\""), name); + *p = c; + ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); + return; + } + + input_line_pointer++; /* skip ',' */ + + if ((temp = get_absolute_expression ()) < 0) + { + as_warn (_(".COMMon length (%ld) < 0 ignored"), (long) temp); + ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); + return; + } + + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + + if (S_IS_DEFINED (symbolP) && !S_IS_COMMON (symbolP)) + { + as_bad (_("symbol `%s' is already defined"), + S_GET_NAME (symbolP)); + ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); + return; + } + + if (S_GET_VALUE (symbolP)) + { + if (S_GET_VALUE (symbolP) != (valueT) temp) + as_bad (_("length of .comm \"%s\" is already %ld; not changing to %ld"), + S_GET_NAME (symbolP), + (long) S_GET_VALUE (symbolP), + (long) temp); + } + else + { + S_SET_VALUE (symbolP, (valueT) temp); + S_SET_EXTERNAL (symbolP); + } +#ifdef OBJ_VMS + { + extern int flag_one; + if (!temp || !flag_one) + S_GET_OTHER(symbolP) = const_flag; + } +#endif /* not OBJ_VMS */ + know (symbolP->sy_frag == &zero_address_frag); + + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); +} /* s_comm() */ + +/* The MRI COMMON pseudo-op. We handle this by creating a common + symbol with the appropriate name. We make s_space do the right + thing by increasing the size. */ + +void +s_mri_common (small) + int small ATTRIBUTE_UNUSED; +{ + char *name; + char c; + char *alc = NULL; + symbolS *sym; + offsetT align; + char *stop = NULL; + char stopc; + + if (!flag_mri) + { + s_comm (0); + return; + } + + stop = mri_comment_field (&stopc); + + SKIP_WHITESPACE (); + + name = input_line_pointer; + if (!ISDIGIT (*name)) + c = get_symbol_end (); + else + { + do + { + ++input_line_pointer; + } + while (ISDIGIT (*input_line_pointer)); + + c = *input_line_pointer; + *input_line_pointer = '\0'; + + if (line_label != NULL) + { + alc = (char *) xmalloc (strlen (S_GET_NAME (line_label)) + + (input_line_pointer - name) + + 1); + sprintf (alc, "%s%s", name, S_GET_NAME (line_label)); + name = alc; + } + } + + sym = symbol_find_or_make (name); + *input_line_pointer = c; + if (alc != NULL) + free (alc); + + if (*input_line_pointer != ',') + align = 0; + else + { + ++input_line_pointer; + align = get_absolute_expression (); + } + + if (S_IS_DEFINED (sym) && !S_IS_COMMON (sym)) + { + as_bad (_("symbol `%s' is already defined"), S_GET_NAME (sym)); + ignore_rest_of_line (); + mri_comment_end (stop, stopc); + return; + } + + S_SET_EXTERNAL (sym); + mri_common_symbol = sym; + +#ifdef S_SET_ALIGN + if (align != 0) + S_SET_ALIGN (sym, align); +#endif + + if (line_label != NULL) + { + expressionS exp; + exp.X_op = O_symbol; + exp.X_add_symbol = sym; + exp.X_add_number = 0; + symbol_set_value_expression (line_label, &exp); + symbol_set_frag (line_label, &zero_address_frag); + S_SET_SEGMENT (line_label, expr_section); + } + + /* FIXME: We just ignore the small argument, which distinguishes + COMMON and COMMON.S. I don't know what we can do about it. */ + + /* Ignore the type and hptype. */ + if (*input_line_pointer == ',') + input_line_pointer += 2; + if (*input_line_pointer == ',') + input_line_pointer += 2; + + demand_empty_rest_of_line (); + + mri_comment_end (stop, stopc); +} + +void +s_data (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + segT section; + register int temp; + + temp = get_absolute_expression (); + if (flag_readonly_data_in_text) + { + section = text_section; + temp += 1000; + } + else + section = data_section; + + subseg_set (section, (subsegT) temp); + +#ifdef OBJ_VMS + const_flag = 0; +#endif + demand_empty_rest_of_line (); +} + +/* Handle the .appfile pseudo-op. This is automatically generated by + do_scrub_chars when a preprocessor # line comment is seen with a + file name. This default definition may be overridden by the object + or CPU specific pseudo-ops. This function is also the default + definition for .file; the APPFILE argument is 1 for .appfile, 0 for + .file. */ + +void +s_app_file_string (file) + char *file; +{ +#ifdef LISTING + if (listing) + listing_source_file (file); +#endif + register_dependency (file); +#ifdef obj_app_file + obj_app_file (file); +#endif +} + +void +s_app_file (appfile) + int appfile; +{ + register char *s; + int length; + + /* Some assemblers tolerate immediately following '"'. */ + if ((s = demand_copy_string (&length)) != 0) + { + /* If this is a fake .appfile, a fake newline was inserted into + the buffer. Passing -2 to new_logical_line tells it to + account for it. */ + int may_omit + = (!new_logical_line (s, appfile ? -2 : -1) && appfile); + + /* In MRI mode, the preprocessor may have inserted an extraneous + backquote. */ + if (flag_m68k_mri + && *input_line_pointer == '\'' + && is_end_of_line[(unsigned char) input_line_pointer[1]]) + ++input_line_pointer; + + demand_empty_rest_of_line (); + if (!may_omit) + s_app_file_string (s); + } +} + +/* Handle the .appline pseudo-op. This is automatically generated by + do_scrub_chars when a preprocessor # line comment is seen. This + default definition may be overridden by the object or CPU specific + pseudo-ops. */ + +void +s_app_line (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + int l; + + /* The given number is that of the next line. */ + l = get_absolute_expression () - 1; + if (l < 0) + /* Some of the back ends can't deal with non-positive line numbers. + Besides, it's silly. */ + as_warn (_("line numbers must be positive; line number %d rejected"), + l + 1); + else + { + new_logical_line ((char *) NULL, l); +#ifdef LISTING + if (listing) + listing_source_line (l); +#endif + } + demand_empty_rest_of_line (); +} + +/* Handle the .end pseudo-op. Actually, the real work is done in + read_a_source_file. */ + +void +s_end (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + if (flag_mri) + { + /* The MRI assembler permits the start symbol to follow .end, + but we don't support that. */ + SKIP_WHITESPACE (); + if (!is_end_of_line[(unsigned char) *input_line_pointer] + && *input_line_pointer != '*' + && *input_line_pointer != '!') + as_warn (_("start address not supported")); + } +} + +/* Handle the .err pseudo-op. */ + +void +s_err (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + as_bad (_(".err encountered")); + demand_empty_rest_of_line (); +} + +/* Handle the MRI fail pseudo-op. */ + +void +s_fail (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + offsetT temp; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + temp = get_absolute_expression (); + if (temp >= 500) + as_warn (_(".fail %ld encountered"), (long) temp); + else + as_bad (_(".fail %ld encountered"), (long) temp); + + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); +} + +void +s_fill (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + expressionS rep_exp; + long size = 1; + register long fill = 0; + char *p; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + get_known_segmented_expression (&rep_exp); + if (*input_line_pointer == ',') + { + input_line_pointer++; + size = get_absolute_expression (); + if (*input_line_pointer == ',') + { + input_line_pointer++; + fill = get_absolute_expression (); + } + } + + /* This is to be compatible with BSD 4.2 AS, not for any rational reason. */ +#define BSD_FILL_SIZE_CROCK_8 (8) + if (size > BSD_FILL_SIZE_CROCK_8) + { + as_warn (_(".fill size clamped to %d"), BSD_FILL_SIZE_CROCK_8); + size = BSD_FILL_SIZE_CROCK_8; + } + if (size < 0) + { + as_warn (_("size negative; .fill ignored")); + size = 0; + } + else if (rep_exp.X_op == O_constant && rep_exp.X_add_number <= 0) + { + if (rep_exp.X_add_number < 0) + as_warn (_("repeat < 0; .fill ignored")); + size = 0; + } + + if (size && !need_pass_2) + { + if (rep_exp.X_op == O_constant) + { + p = frag_var (rs_fill, (int) size, (int) size, + (relax_substateT) 0, (symbolS *) 0, + (offsetT) rep_exp.X_add_number, + (char *) 0); + } + else + { + /* We don't have a constant repeat count, so we can't use + rs_fill. We can get the same results out of rs_space, + but its argument is in bytes, so we must multiply the + repeat count by size. */ + + symbolS *rep_sym; + rep_sym = make_expr_symbol (&rep_exp); + if (size != 1) + { + expressionS size_exp; + size_exp.X_op = O_constant; + size_exp.X_add_number = size; + + rep_exp.X_op = O_multiply; + rep_exp.X_add_symbol = rep_sym; + rep_exp.X_op_symbol = make_expr_symbol (&size_exp); + rep_exp.X_add_number = 0; + rep_sym = make_expr_symbol (&rep_exp); + } + + p = frag_var (rs_space, (int) size, (int) size, + (relax_substateT) 0, rep_sym, (offsetT) 0, (char *) 0); + } + + memset (p, 0, (unsigned int) size); + + /* The magic number BSD_FILL_SIZE_CROCK_4 is from BSD 4.2 VAX + flavoured AS. The following bizarre behaviour is to be + compatible with above. I guess they tried to take up to 8 + bytes from a 4-byte expression and they forgot to sign + extend. */ +#define BSD_FILL_SIZE_CROCK_4 (4) + md_number_to_chars (p, (valueT) fill, + (size > BSD_FILL_SIZE_CROCK_4 + ? BSD_FILL_SIZE_CROCK_4 + : (int) size)); + /* Note: .fill (),0 emits no frag (since we are asked to .fill 0 bytes) + but emits no error message because it seems a legal thing to do. + It is a degenerate case of .fill but could be emitted by a + compiler. */ + } + demand_empty_rest_of_line (); +} + +void +s_globl (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + int c; + symbolS *symbolP; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + do + { + name = input_line_pointer; + c = get_symbol_end (); + symbolP = symbol_find_or_make (name); + S_SET_EXTERNAL (symbolP); + + *input_line_pointer = c; + SKIP_WHITESPACE (); + c = *input_line_pointer; + if (c == ',') + { + input_line_pointer++; + SKIP_WHITESPACE (); + if (is_end_of_line[(unsigned char) *input_line_pointer]) + c = '\n'; + } + } + while (c == ','); + + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); +} + +/* Handle the MRI IRP and IRPC pseudo-ops. */ + +void +s_irp (irpc) + int irpc; +{ + char *file; + unsigned int line; + sb s; + const char *err; + sb out; + + as_where (&file, &line); + + sb_new (&s); + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + sb_add_char (&s, *input_line_pointer++); + + sb_new (&out); + + err = expand_irp (irpc, 0, &s, &out, get_line_sb); + if (err != NULL) + as_bad_where (file, line, "%s", err); + + sb_kill (&s); + + input_scrub_include_sb (&out, input_line_pointer, 1); + sb_kill (&out); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + +/* Handle the .linkonce pseudo-op. This tells the assembler to mark + the section to only be linked once. However, this is not supported + by most object file formats. This takes an optional argument, + which is what to do about duplicates. */ + +void +s_linkonce (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + enum linkonce_type type; + + SKIP_WHITESPACE (); + + type = LINKONCE_DISCARD; + + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *s; + char c; + + s = input_line_pointer; + c = get_symbol_end (); + if (strcasecmp (s, "discard") == 0) + type = LINKONCE_DISCARD; + else if (strcasecmp (s, "one_only") == 0) + type = LINKONCE_ONE_ONLY; + else if (strcasecmp (s, "same_size") == 0) + type = LINKONCE_SAME_SIZE; + else if (strcasecmp (s, "same_contents") == 0) + type = LINKONCE_SAME_CONTENTS; + else + as_warn (_("unrecognized .linkonce type `%s'"), s); + + *input_line_pointer = c; + } + +#ifdef obj_handle_link_once + obj_handle_link_once (type); +#else /* ! defined (obj_handle_link_once) */ +#ifdef BFD_ASSEMBLER + { + flagword flags; + + if ((bfd_applicable_section_flags (stdoutput) & SEC_LINK_ONCE) == 0) + as_warn (_(".linkonce is not supported for this object file format")); + + flags = bfd_get_section_flags (stdoutput, now_seg); + flags |= SEC_LINK_ONCE; + switch (type) + { + default: + abort (); + case LINKONCE_DISCARD: + flags |= SEC_LINK_DUPLICATES_DISCARD; + break; + case LINKONCE_ONE_ONLY: + flags |= SEC_LINK_DUPLICATES_ONE_ONLY; + break; + case LINKONCE_SAME_SIZE: + flags |= SEC_LINK_DUPLICATES_SAME_SIZE; + break; + case LINKONCE_SAME_CONTENTS: + flags |= SEC_LINK_DUPLICATES_SAME_CONTENTS; + break; + } + if (!bfd_set_section_flags (stdoutput, now_seg, flags)) + as_bad (_("bfd_set_section_flags: %s"), + bfd_errmsg (bfd_get_error ())); + } +#else /* ! defined (BFD_ASSEMBLER) */ + as_warn (_(".linkonce is not supported for this object file format")); +#endif /* ! defined (BFD_ASSEMBLER) */ +#endif /* ! defined (obj_handle_link_once) */ + + demand_empty_rest_of_line (); +} + +static void +s_lcomm_internal (needs_align, bytes_p) + /* 1 if this was a ".bss" directive, which may require a 3rd argument + (alignment); 0 if it was an ".lcomm" (2 args only). */ + int needs_align; + /* 1 if the alignment value should be interpreted as the byte boundary, + rather than the power of 2. */ + int bytes_p; +{ + register char *name; + register char c; + register char *p; + register int temp; + register symbolS *symbolP; + segT current_seg = now_seg; + subsegT current_subseg = now_subseg; + const int max_alignment = 15; + int align = 0; + segT bss_seg = bss_section; + + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + *p = c; + + if (name == p) + { + as_bad (_("expected symbol name")); + discard_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + + /* Accept an optional comma after the name. The comma used to be + required, but Irix 5 cc does not generate it. */ + if (*input_line_pointer == ',') + { + ++input_line_pointer; + SKIP_WHITESPACE (); + } + + if (is_end_of_line[(unsigned char) *input_line_pointer]) + { + as_bad (_("missing size expression")); + return; + } + + if ((temp = get_absolute_expression ()) < 0) + { + as_warn (_("BSS length (%d) < 0 ignored"), temp); + ignore_rest_of_line (); + return; + } + +#if defined (TC_MIPS) || defined (TC_ALPHA) + if (OUTPUT_FLAVOR == bfd_target_ecoff_flavour + || OUTPUT_FLAVOR == bfd_target_elf_flavour) + { + /* For MIPS and Alpha ECOFF or ELF, small objects are put in .sbss. */ + if ((unsigned) temp <= bfd_get_gp_size (stdoutput)) + { + bss_seg = subseg_new (".sbss", 1); + seg_info (bss_seg)->bss = 1; +#ifdef BFD_ASSEMBLER + if (!bfd_set_section_flags (stdoutput, bss_seg, SEC_ALLOC)) + as_warn (_("error setting flags for \".sbss\": %s"), + bfd_errmsg (bfd_get_error ())); +#endif + } + } +#endif + + if (!needs_align) + { + TC_IMPLICIT_LCOMM_ALIGNMENT (temp, align); + + /* Still zero unless TC_IMPLICIT_LCOMM_ALIGNMENT set it. */ + if (align) + record_alignment (bss_seg, align); + } + + if (needs_align) + { + align = 0; + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + as_bad (_("expected comma after size")); + ignore_rest_of_line (); + return; + } + + input_line_pointer++; + SKIP_WHITESPACE (); + + if (is_end_of_line[(unsigned char) *input_line_pointer]) + { + as_bad (_("missing alignment")); + return; + } + + align = get_absolute_expression (); + + if (bytes_p) + { + /* Convert to a power of 2. */ + if (align != 0) + { + unsigned int i; + + for (i = 0; (align & 1) == 0; align >>= 1, ++i) + ; + if (align != 1) + as_bad (_("alignment not a power of 2")); + align = i; + } + } + + if (align > max_alignment) + { + align = max_alignment; + as_warn (_("alignment too large; %d assumed"), align); + } + else if (align < 0) + { + align = 0; + as_warn (_("alignment negative; 0 assumed")); + } + + record_alignment (bss_seg, align); + } + else + { + /* Assume some objects may require alignment on some systems. */ +#if defined (TC_ALPHA) && ! defined (VMS) + if (temp > 1) + { + align = ffs (temp) - 1; + if (temp % (1 << align)) + abort (); + } +#endif + } + + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + + if ( +#if (defined (OBJ_AOUT) || defined (OBJ_MAYBE_AOUT) \ + || defined (OBJ_BOUT) || defined (OBJ_MAYBE_BOUT)) +#ifdef BFD_ASSEMBLER + (OUTPUT_FLAVOR != bfd_target_aout_flavour + || (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0)) && +#else + (S_GET_OTHER (symbolP) == 0 && S_GET_DESC (symbolP) == 0) && +#endif +#endif + (S_GET_SEGMENT (symbolP) == bss_seg + || (!S_IS_DEFINED (symbolP) && S_GET_VALUE (symbolP) == 0))) + { + char *pfrag; + + subseg_set (bss_seg, 1); + + if (align) + frag_align (align, 0, 0); + + /* Detach from old frag. */ + if (S_GET_SEGMENT (symbolP) == bss_seg) + symbol_get_frag (symbolP)->fr_symbol = NULL; + + symbol_set_frag (symbolP, frag_now); + pfrag = frag_var (rs_org, 1, 1, (relax_substateT) 0, symbolP, + (offsetT) temp, (char *) 0); + *pfrag = 0; + + S_SET_SEGMENT (symbolP, bss_seg); + +#ifdef OBJ_COFF + /* The symbol may already have been created with a preceding + ".globl" directive -- be careful not to step on storage class + in that case. Otherwise, set it to static. */ + if (S_GET_STORAGE_CLASS (symbolP) != C_EXT) + { + S_SET_STORAGE_CLASS (symbolP, C_STAT); + } +#endif /* OBJ_COFF */ + +#ifdef S_SET_SIZE + S_SET_SIZE (symbolP, temp); +#endif + } + else + as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP)); + + subseg_set (current_seg, current_subseg); + + demand_empty_rest_of_line (); +} + +void +s_lcomm (needs_align) + int needs_align; +{ + s_lcomm_internal (needs_align, 0); +} + +void +s_lcomm_bytes (needs_align) + int needs_align; +{ + s_lcomm_internal (needs_align, 1); +} + +void +s_lsym (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + register char *name; + register char c; + register char *p; + expressionS exp; + register symbolS *symbolP; + + /* We permit ANY defined expression: BSD4.2 demands constants. */ + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + *p = c; + + if (name == p) + { + as_bad (_("expected symbol name")); + discard_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + *p = 0; + as_bad (_("expected comma after \"%s\""), name); + *p = c; + ignore_rest_of_line (); + return; + } + + input_line_pointer++; + expression (&exp); + + if (exp.X_op != O_constant + && exp.X_op != O_register) + { + as_bad (_("bad expression")); + ignore_rest_of_line (); + return; + } + + *p = 0; + symbolP = symbol_find_or_make (name); + + /* FIXME-SOON I pulled a (&& symbolP->sy_other == 0 && + symbolP->sy_desc == 0) out of this test because coff doesn't have + those fields, and I can't see when they'd ever be tripped. I + don't think I understand why they were here so I may have + introduced a bug. As recently as 1.37 didn't have this test + anyway. xoxorich. */ + + if (S_GET_SEGMENT (symbolP) == undefined_section + && S_GET_VALUE (symbolP) == 0) + { + /* The name might be an undefined .global symbol; be sure to + keep the "external" bit. */ + S_SET_SEGMENT (symbolP, + (exp.X_op == O_constant + ? absolute_section + : reg_section)); + S_SET_VALUE (symbolP, (valueT) exp.X_add_number); + } + else + { + as_bad (_("symbol `%s' is already defined"), name); + } + + *p = c; + demand_empty_rest_of_line (); +} + +/* Read a line into an sb. Returns the character that ended the line + or zero if there are no more lines. */ + +static int +get_line_sb (line) + sb *line; +{ + char quote1, quote2, inquote; + unsigned char c; + + if (input_line_pointer[-1] == '\n') + bump_line_counters (); + + if (input_line_pointer >= buffer_limit) + { + buffer_limit = input_scrub_next_buffer (&input_line_pointer); + if (buffer_limit == 0) + return 0; + } + + /* If app.c sets any other characters to LEX_IS_STRINGQUOTE, this + code needs to be changed. */ + if (!flag_m68k_mri) + quote1 = '"'; + else + quote1 = '\0'; + + quote2 = '\0'; + if (flag_m68k_mri) + quote2 = '\''; +#ifdef LEX_IS_STRINGQUOTE + quote2 = '\''; +#endif + + inquote = '\0'; + + while ((c = * input_line_pointer ++) != 0 + && (!is_end_of_line[c] + || (inquote != '\0' && c != '\n'))) + { + if (inquote == c) + inquote = '\0'; + else if (inquote == '\0') + { + if (c == quote1) + inquote = quote1; + else if (c == quote2) + inquote = quote2; + } + + sb_add_char (line, c); + } + + /* Don't skip multiple end-of-line characters, because that breaks support + for the IA-64 stop bit (;;) which looks like two consecutive end-of-line + characters but isn't. Instead just skip one end of line character and + return the character skipped so that the caller can re-insert it if + necessary. */ + return c; +} + +/* Define a macro. This is an interface to macro.c. */ + +void +s_macro (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *file; + unsigned int line; + sb s; + sb label; + const char *err; + const char *name; + + as_where (&file, &line); + + sb_new (&s); + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + sb_add_char (&s, *input_line_pointer++); + + sb_new (&label); + if (line_label != NULL) + sb_add_string (&label, S_GET_NAME (line_label)); + + err = define_macro (0, &s, &label, get_line_sb, &name); + if (err != NULL) + as_bad_where (file, line, "%s", err); + else + { + if (line_label != NULL) + { + S_SET_SEGMENT (line_label, undefined_section); + S_SET_VALUE (line_label, 0); + symbol_set_frag (line_label, &zero_address_frag); + } + + if (((NO_PSEUDO_DOT || flag_m68k_mri) + && hash_find (po_hash, name) != NULL) + || (!flag_m68k_mri + && *name == '.' + && hash_find (po_hash, name + 1) != NULL)) + as_warn (_("attempt to redefine pseudo-op `%s' ignored"), + name); + } + + sb_kill (&s); +} + +/* Handle the .mexit pseudo-op, which immediately exits a macro + expansion. */ + +void +s_mexit (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + cond_exit_macro (macro_nest); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + +/* Switch in and out of MRI mode. */ + +void +s_mri (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + int on, old_flag; + + on = get_absolute_expression (); + old_flag = flag_mri; + if (on != 0) + { + flag_mri = 1; +#ifdef TC_M68K + flag_m68k_mri = 1; +#endif + macro_mri_mode (1); + } + else + { + flag_mri = 0; +#ifdef TC_M68K + flag_m68k_mri = 0; +#endif + macro_mri_mode (0); + } + + /* Operator precedence changes in m68k MRI mode, so we need to + update the operator rankings. */ + expr_set_precedence (); + +#ifdef MRI_MODE_CHANGE + if (on != old_flag) + MRI_MODE_CHANGE (on); +#endif + + demand_empty_rest_of_line (); +} + +/* Handle changing the location counter. */ + +static void +do_org (segment, exp, fill) + segT segment; + expressionS *exp; + int fill; +{ + if (segment != now_seg && segment != absolute_section) + as_bad (_("invalid segment \"%s\""), segment_name (segment)); + + if (now_seg == absolute_section) + { + if (fill != 0) + as_warn (_("ignoring fill value in absolute section")); + if (exp->X_op != O_constant) + { + as_bad (_("only constant offsets supported in absolute section")); + exp->X_add_number = 0; + } + abs_section_offset = exp->X_add_number; + } + else + { + char *p; + symbolS *sym = exp->X_add_symbol; + offsetT off = exp->X_add_number * OCTETS_PER_BYTE; + + if (exp->X_op != O_constant && exp->X_op != O_symbol) + { + /* Handle complex expressions. */ + sym = make_expr_symbol (exp); + off = 0; + } + + p = frag_var (rs_org, 1, 1, (relax_substateT) 0, sym, off, (char *) 0); + *p = fill; + } +} + +void +s_org (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + register segT segment; + expressionS exp; + register long temp_fill; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + /* The m68k MRI assembler has a different meaning for .org. It + means to create an absolute section at a given address. We can't + support that--use a linker script instead. */ + if (flag_m68k_mri) + { + as_bad (_("MRI style ORG pseudo-op not supported")); + ignore_rest_of_line (); + return; + } + + /* Don't believe the documentation of BSD 4.2 AS. There is no such + thing as a sub-segment-relative origin. Any absolute origin is + given a warning, then assumed to be segment-relative. Any + segmented origin expression ("foo+42") had better be in the right + segment or the .org is ignored. + + BSD 4.2 AS warns if you try to .org backwards. We cannot because + we never know sub-segment sizes when we are reading code. BSD + will crash trying to emit negative numbers of filler bytes in + certain .orgs. We don't crash, but see as-write for that code. + + Don't make frag if need_pass_2==1. */ + segment = get_known_segmented_expression (&exp); + if (*input_line_pointer == ',') + { + input_line_pointer++; + temp_fill = get_absolute_expression (); + } + else + temp_fill = 0; + + if (!need_pass_2) + do_org (segment, &exp, temp_fill); + + demand_empty_rest_of_line (); +} + +/* Handle parsing for the MRI SECT/SECTION pseudo-op. This should be + called by the obj-format routine which handles section changing + when in MRI mode. It will create a new section, and return it. It + will set *TYPE to the section type: one of 'C' (code), 'D' (data), + 'M' (mixed), or 'R' (romable). If BFD_ASSEMBLER is defined, the + flags will be set in the section. */ + +void +s_mri_sect (type) + char *type ATTRIBUTE_UNUSED; +{ +#ifdef TC_M68K + + char *name; + char c; + segT seg; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + if (!ISDIGIT (*name)) + c = get_symbol_end (); + else + { + do + { + ++input_line_pointer; + } + while (ISDIGIT (*input_line_pointer)); + + c = *input_line_pointer; + *input_line_pointer = '\0'; + } + + name = xstrdup (name); + + *input_line_pointer = c; + + seg = subseg_new (name, 0); + + if (*input_line_pointer == ',') + { + int align; + + ++input_line_pointer; + align = get_absolute_expression (); + record_alignment (seg, align); + } + + *type = 'C'; + if (*input_line_pointer == ',') + { + c = *++input_line_pointer; + c = TOUPPER (c); + if (c == 'C' || c == 'D' || c == 'M' || c == 'R') + *type = c; + else + as_bad (_("unrecognized section type")); + ++input_line_pointer; + +#ifdef BFD_ASSEMBLER + { + flagword flags; + + flags = SEC_NO_FLAGS; + if (*type == 'C') + flags = SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE; + else if (*type == 'D' || *type == 'M') + flags = SEC_ALLOC | SEC_LOAD | SEC_DATA; + else if (*type == 'R') + flags = SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_READONLY | SEC_ROM; + if (flags != SEC_NO_FLAGS) + { + if (!bfd_set_section_flags (stdoutput, seg, flags)) + as_warn (_("error setting flags for \"%s\": %s"), + bfd_section_name (stdoutput, seg), + bfd_errmsg (bfd_get_error ())); + } + } +#endif + } + + /* Ignore the HP type. */ + if (*input_line_pointer == ',') + input_line_pointer += 2; + + demand_empty_rest_of_line (); + +#else /* ! TC_M68K */ +#ifdef TC_I960 + + char *name; + char c; + segT seg; + + SKIP_WHITESPACE (); + + name = input_line_pointer; + c = get_symbol_end (); + + name = xstrdup (name); + + *input_line_pointer = c; + + seg = subseg_new (name, 0); + + if (*input_line_pointer != ',') + *type = 'C'; + else + { + char *sectype; + + ++input_line_pointer; + SKIP_WHITESPACE (); + sectype = input_line_pointer; + c = get_symbol_end (); + if (*sectype == '\0') + *type = 'C'; + else if (strcasecmp (sectype, "text") == 0) + *type = 'C'; + else if (strcasecmp (sectype, "data") == 0) + *type = 'D'; + else if (strcasecmp (sectype, "romdata") == 0) + *type = 'R'; + else + as_warn (_("unrecognized section type `%s'"), sectype); + *input_line_pointer = c; + } + + if (*input_line_pointer == ',') + { + char *seccmd; + + ++input_line_pointer; + SKIP_WHITESPACE (); + seccmd = input_line_pointer; + c = get_symbol_end (); + if (strcasecmp (seccmd, "absolute") == 0) + { + as_bad (_("absolute sections are not supported")); + *input_line_pointer = c; + ignore_rest_of_line (); + return; + } + else if (strcasecmp (seccmd, "align") == 0) + { + int align; + + *input_line_pointer = c; + align = get_absolute_expression (); + record_alignment (seg, align); + } + else + { + as_warn (_("unrecognized section command `%s'"), seccmd); + *input_line_pointer = c; + } + } + + demand_empty_rest_of_line (); + +#else /* ! TC_I960 */ + /* The MRI assembler seems to use different forms of .sect for + different targets. */ + as_bad ("MRI mode not supported for this target"); + ignore_rest_of_line (); +#endif /* ! TC_I960 */ +#endif /* ! TC_M68K */ +} + +/* Handle the .print pseudo-op. */ + +void +s_print (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *s; + int len; + + s = demand_copy_C_string (&len); + printf ("%s\n", s); + demand_empty_rest_of_line (); +} + +/* Handle the .purgem pseudo-op. */ + +void +s_purgem (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + + do + { + char *name; + char c; + + SKIP_WHITESPACE (); + name = input_line_pointer; + c = get_symbol_end (); + delete_macro (name); + *input_line_pointer = c; + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + + --input_line_pointer; + demand_empty_rest_of_line (); +} + +/* Handle the .rept pseudo-op. */ + +void +s_bad_endr (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + as_warn (_(".endr encountered without preceeding .rept, .irc, or .irp")); + demand_empty_rest_of_line (); +} + +/* Handle the .rept pseudo-op. */ + +void +s_rept (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + int count; + + count = get_absolute_expression (); + + do_repeat (count, "REPT", "ENDR"); +} + +/* This function provides a generic repeat block implementation. It allows + different directives to be used as the start/end keys. */ + +void +do_repeat (count, start, end) + int count; + const char *start; + const char *end; +{ + sb one; + sb many; + + sb_new (&one); + if (!buffer_and_nest (start, end, &one, get_line_sb)) + { + as_bad (_("%s without %s"), start, end); + return; + } + + sb_new (&many); + while (count-- > 0) + sb_add_sb (&many, &one); + + sb_kill (&one); + + input_scrub_include_sb (&many, input_line_pointer, 1); + sb_kill (&many); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + +/* Skip to end of current repeat loop; EXTRA indicates how many additional + input buffers to skip. Assumes that conditionals preceding the loop end + are properly nested. + + This function makes it easier to implement a premature "break" out of the + loop. The EXTRA arg accounts for other buffers we might have inserted, + such as line substitutions. */ + +void +end_repeat (extra) + int extra; +{ + cond_exit_macro (macro_nest); + while (extra-- >= 0) + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + +/* Handle the .equ, .equiv and .set directives. If EQUIV is 1, then + this is .equiv, and it is an error if the symbol is already + defined. */ + +void +s_set (equiv) + int equiv; +{ + register char *name; + register char delim; + register char *end_name; + register symbolS *symbolP; + + /* Especial apologies for the random logic: + this just grew, and could be parsed much more simply! + Dean in haste. */ + name = input_line_pointer; + delim = get_symbol_end (); + end_name = input_line_pointer; + *end_name = delim; + + if (name == end_name) + { + as_bad (_("expected symbol name")); + discard_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + *end_name = 0; + as_bad (_("expected comma after \"%s\""), name); + *end_name = delim; + ignore_rest_of_line (); + return; + } + + input_line_pointer++; + *end_name = 0; + + if (name[0] == '.' && name[1] == '\0') + { + /* Turn '. = mumble' into a .org mumble. */ + register segT segment; + expressionS exp; + + segment = get_known_segmented_expression (&exp); + + if (!need_pass_2) + do_org (segment, &exp, 0); + + *end_name = delim; + return; + } + + if ((symbolP = symbol_find (name)) == NULL + && (symbolP = md_undefined_symbol (name)) == NULL) + { +#ifndef NO_LISTING + /* When doing symbol listings, play games with dummy fragments living + outside the normal fragment chain to record the file and line info + for this symbol. */ + if (listing & LISTING_SYMBOLS) + { + extern struct list_info_struct *listing_tail; + fragS *dummy_frag = (fragS *) xmalloc (sizeof (fragS)); + memset (dummy_frag, 0, sizeof (fragS)); + dummy_frag->fr_type = rs_fill; + dummy_frag->line = listing_tail; + symbolP = symbol_new (name, undefined_section, 0, dummy_frag); + dummy_frag->fr_symbol = symbolP; + } + else +#endif + symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag); + +#ifdef OBJ_COFF + /* "set" symbols are local unless otherwise specified. */ + SF_SET_LOCAL (symbolP); +#endif /* OBJ_COFF */ + } + + symbol_table_insert (symbolP); + + *end_name = delim; + + if (equiv + && S_IS_DEFINED (symbolP) + && S_GET_SEGMENT (symbolP) != reg_section) + as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP)); + + pseudo_set (symbolP); + demand_empty_rest_of_line (); +} + +void +s_space (mult) + int mult; +{ + expressionS exp; + expressionS val; + char *p = 0; + char *stop = NULL; + char stopc; + int bytes; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (flag_mri) + stop = mri_comment_field (&stopc); + + /* In m68k MRI mode, we need to align to a word boundary, unless + this is ds.b. */ + if (flag_m68k_mri && mult > 1) + { + if (now_seg == absolute_section) + { + abs_section_offset += abs_section_offset & 1; + if (line_label != NULL) + S_SET_VALUE (line_label, abs_section_offset); + } + else if (mri_common_symbol != NULL) + { + valueT val; + + val = S_GET_VALUE (mri_common_symbol); + if ((val & 1) != 0) + { + S_SET_VALUE (mri_common_symbol, val + 1); + if (line_label != NULL) + { + expressionS *symexp; + + symexp = symbol_get_value_expression (line_label); + know (symexp->X_op == O_symbol); + know (symexp->X_add_symbol == mri_common_symbol); + symexp->X_add_number += 1; + } + } + } + else + { + do_align (1, (char *) NULL, 0, 0); + if (line_label != NULL) + { + symbol_set_frag (line_label, frag_now); + S_SET_VALUE (line_label, frag_now_fix ()); + } + } + } + + bytes = mult; + + expression (&exp); + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + ++input_line_pointer; + expression (&val); + } + else + { + val.X_op = O_constant; + val.X_add_number = 0; + } + + if (val.X_op != O_constant + || val.X_add_number < - 0x80 + || val.X_add_number > 0xff + || (mult != 0 && mult != 1 && val.X_add_number != 0)) + { + if (exp.X_op != O_constant) + as_bad (_("unsupported variable size or fill value")); + else + { + offsetT i; + + if (mult == 0) + mult = 1; + bytes = mult * exp.X_add_number; + for (i = 0; i < exp.X_add_number; i++) + emit_expr (&val, mult); + } + } + else + { + if (exp.X_op == O_constant) + { + long repeat; + + repeat = exp.X_add_number; + if (mult) + repeat *= mult; + bytes = repeat; + if (repeat <= 0) + { + if (!flag_mri) + as_warn (_(".space repeat count is zero, ignored")); + else if (repeat < 0) + as_warn (_(".space repeat count is negative, ignored")); + goto getout; + } + + /* If we are in the absolute section, just bump the offset. */ + if (now_seg == absolute_section) + { + abs_section_offset += repeat; + goto getout; + } + + /* If we are secretly in an MRI common section, then + creating space just increases the size of the common + symbol. */ + if (mri_common_symbol != NULL) + { + S_SET_VALUE (mri_common_symbol, + S_GET_VALUE (mri_common_symbol) + repeat); + goto getout; + } + + if (!need_pass_2) + p = frag_var (rs_fill, 1, 1, (relax_substateT) 0, (symbolS *) 0, + (offsetT) repeat, (char *) 0); + } + else + { + if (now_seg == absolute_section) + { + as_bad (_("space allocation too complex in absolute section")); + subseg_set (text_section, 0); + } + + if (mri_common_symbol != NULL) + { + as_bad (_("space allocation too complex in common section")); + mri_common_symbol = NULL; + } + + if (!need_pass_2) + p = frag_var (rs_space, 1, 1, (relax_substateT) 0, + make_expr_symbol (&exp), (offsetT) 0, (char *) 0); + } + + if (p) + *p = val.X_add_number; + } + + getout: + + /* In MRI mode, after an odd number of bytes, we must align to an + even word boundary, unless the next instruction is a dc.b, ds.b + or dcb.b. */ + if (flag_mri && (bytes & 1) != 0) + mri_pending_align = 1; + + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); +} + +/* This is like s_space, but the value is a floating point number with + the given precision. This is for the MRI dcb.s pseudo-op and + friends. */ + +void +s_float_space (float_type) + int float_type; +{ + offsetT count; + int flen; + char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + count = get_absolute_expression (); + + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + as_bad (_("missing value")); + ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); + return; + } + + ++input_line_pointer; + + SKIP_WHITESPACE (); + + /* Skip any 0{letter} that may be present. Don't even check if the + * letter is legal. */ + if (input_line_pointer[0] == '0' + && ISALPHA (input_line_pointer[1])) + input_line_pointer += 2; + + /* Accept :xxxx, where the x's are hex digits, for a floating point + with the exact digits specified. */ + if (input_line_pointer[0] == ':') + { + flen = hex_float (float_type, temp); + if (flen < 0) + { + ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); + return; + } + } + else + { + char *err; + + err = md_atof (float_type, temp, &flen); + know (flen <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); + know (flen > 0); + if (err) + { + as_bad (_("bad floating literal: %s"), err); + ignore_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); + return; + } + } + + while (--count >= 0) + { + char *p; + + p = frag_more (flen); + memcpy (p, temp, (unsigned int) flen); + } + + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); +} + +/* Handle the .struct pseudo-op, as found in MIPS assemblers. */ + +void +s_struct (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *stop = NULL; + char stopc; + + if (flag_mri) + stop = mri_comment_field (&stopc); + abs_section_offset = get_absolute_expression (); + subseg_set (absolute_section, 0); + demand_empty_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); +} + +void +s_text (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + register int temp; + + temp = get_absolute_expression (); + subseg_set (text_section, (subsegT) temp); + demand_empty_rest_of_line (); +#ifdef OBJ_VMS + const_flag &= ~IN_DEFAULT_SECTION; +#endif +} + +void +demand_empty_rest_of_line () +{ + SKIP_WHITESPACE (); + if (is_end_of_line[(unsigned char) *input_line_pointer]) + input_line_pointer++; + else + ignore_rest_of_line (); + + /* Return having already swallowed end-of-line. */ +} + +void +ignore_rest_of_line () +{ + /* For suspect lines: gives warning. */ + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + if (ISPRINT (*input_line_pointer)) + as_warn (_("rest of line ignored; first ignored character is `%c'"), + *input_line_pointer); + else + as_warn (_("rest of line ignored; first ignored character valued 0x%x"), + *input_line_pointer); + + while (input_line_pointer < buffer_limit + && !is_end_of_line[(unsigned char) *input_line_pointer]) + input_line_pointer++; + } + + input_line_pointer++; + + /* Return pointing just after end-of-line. */ + know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); +} + +void +discard_rest_of_line () +{ + while (input_line_pointer < buffer_limit + && !is_end_of_line[(unsigned char) *input_line_pointer]) + input_line_pointer++; + + input_line_pointer++; + + /* Return pointing just after end-of-line. */ + know (is_end_of_line[(unsigned char) input_line_pointer[-1]]); +} + +/* In: Pointer to a symbol. + Input_line_pointer->expression. + + Out: Input_line_pointer->just after any whitespace after expression. + Tried to set symbol to value of expression. + Will change symbols type, value, and frag; */ + +void +pseudo_set (symbolP) + symbolS *symbolP; +{ + expressionS exp; +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) + int ext; +#endif /* OBJ_AOUT or OBJ_BOUT */ + + know (symbolP); /* NULL pointer is logic error. */ +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) + ext = S_IS_EXTERNAL (symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + + (void) expression (&exp); + + if (exp.X_op == O_illegal) + as_bad (_("illegal expression")); + else if (exp.X_op == O_absent) + as_bad (_("missing expression")); + else if (exp.X_op == O_big) + { + if (exp.X_add_number > 0) + as_bad (_("bignum invalid")); + else + as_bad (_("floating point number invalid")); + } + else if (exp.X_op == O_subtract + && SEG_NORMAL (S_GET_SEGMENT (exp.X_add_symbol)) + && (symbol_get_frag (exp.X_add_symbol) + == symbol_get_frag (exp.X_op_symbol))) + { + exp.X_op = O_constant; + exp.X_add_number = (S_GET_VALUE (exp.X_add_symbol) + - S_GET_VALUE (exp.X_op_symbol)); + } + + switch (exp.X_op) + { + case O_illegal: + case O_absent: + case O_big: + exp.X_add_number = 0; + /* Fall through. */ + case O_constant: + S_SET_SEGMENT (symbolP, absolute_section); +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) + if (ext) + S_SET_EXTERNAL (symbolP); + else + S_CLEAR_EXTERNAL (symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + S_SET_VALUE (symbolP, (valueT) exp.X_add_number); + if (exp.X_op != O_constant) + symbol_set_frag (symbolP, &zero_address_frag); + break; + + case O_register: + S_SET_SEGMENT (symbolP, reg_section); + S_SET_VALUE (symbolP, (valueT) exp.X_add_number); + symbol_set_frag (symbolP, &zero_address_frag); + break; + + case O_symbol: + if (S_GET_SEGMENT (exp.X_add_symbol) == undefined_section + || exp.X_add_number != 0) + symbol_set_value_expression (symbolP, &exp); + else if (symbol_section_p (symbolP)) + as_bad ("attempt to set value of section symbol"); + else + { + symbolS *s = exp.X_add_symbol; + + S_SET_SEGMENT (symbolP, S_GET_SEGMENT (s)); +#if (defined (OBJ_AOUT) || defined (OBJ_BOUT)) && ! defined (BFD_ASSEMBLER) + if (ext) + S_SET_EXTERNAL (symbolP); + else + S_CLEAR_EXTERNAL (symbolP); +#endif /* OBJ_AOUT or OBJ_BOUT */ + S_SET_VALUE (symbolP, + exp.X_add_number + S_GET_VALUE (s)); + symbol_set_frag (symbolP, symbol_get_frag (s)); + copy_symbol_attributes (symbolP, s); + } + break; + + default: + /* The value is some complex expression. + FIXME: Should we set the segment to anything? */ + symbol_set_value_expression (symbolP, &exp); + break; + } +} + +/* cons() + + CONStruct more frag of .bytes, or .words etc. + Should need_pass_2 be 1 then emit no frag(s). + This understands EXPRESSIONS. + + Bug (?) + + This has a split personality. We use expression() to read the + value. We can detect if the value won't fit in a byte or word. + But we can't detect if expression() discarded significant digits + in the case of a long. Not worth the crocks required to fix it. */ + +/* Select a parser for cons expressions. */ + +/* Some targets need to parse the expression in various fancy ways. + You can define TC_PARSE_CONS_EXPRESSION to do whatever you like + (for example, the HPPA does this). Otherwise, you can define + BITFIELD_CONS_EXPRESSIONS to permit bitfields to be specified, or + REPEAT_CONS_EXPRESSIONS to permit repeat counts. If none of these + are defined, which is the normal case, then only simple expressions + are permitted. */ + +#ifdef TC_M68K +static void +parse_mri_cons PARAMS ((expressionS *exp, unsigned int nbytes)); +#endif + +#ifndef TC_PARSE_CONS_EXPRESSION +#ifdef BITFIELD_CONS_EXPRESSIONS +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_bitfield_cons (EXP, NBYTES) +static void +parse_bitfield_cons PARAMS ((expressionS *exp, unsigned int nbytes)); +#endif +#ifdef REPEAT_CONS_EXPRESSIONS +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) parse_repeat_cons (EXP, NBYTES) +static void +parse_repeat_cons PARAMS ((expressionS *exp, unsigned int nbytes)); +#endif + +/* If we haven't gotten one yet, just call expression. */ +#ifndef TC_PARSE_CONS_EXPRESSION +#define TC_PARSE_CONS_EXPRESSION(EXP, NBYTES) expression (EXP) +#endif +#endif + +/* Worker to do .byte etc statements. + Clobbers input_line_pointer and checks end-of-line. */ + +static void +cons_worker (nbytes, rva) + register int nbytes; /* 1=.byte, 2=.word, 4=.long. */ + int rva; +{ + int c; + expressionS exp; + char *stop = NULL; + char stopc; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (flag_mri) + stop = mri_comment_field (&stopc); + + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + if (flag_mri) + mri_comment_end (stop, stopc); + return; + } + +#ifdef md_cons_align + md_cons_align (nbytes); +#endif + + c = 0; + do + { +#ifdef TC_M68K + if (flag_m68k_mri) + parse_mri_cons (&exp, (unsigned int) nbytes); + else +#endif + TC_PARSE_CONS_EXPRESSION (&exp, (unsigned int) nbytes); + + if (rva) + { + if (exp.X_op == O_symbol) + exp.X_op = O_symbol_rva; + else + as_fatal (_("rva without symbol")); + } + emit_expr (&exp, (unsigned int) nbytes); + ++c; + } + while (*input_line_pointer++ == ','); + + /* In MRI mode, after an odd number of bytes, we must align to an + even word boundary, unless the next instruction is a dc.b, ds.b + or dcb.b. */ + if (flag_mri && nbytes == 1 && (c & 1) != 0) + mri_pending_align = 1; + + input_line_pointer--; /* Put terminator back into stream. */ + + demand_empty_rest_of_line (); + + if (flag_mri) + mri_comment_end (stop, stopc); +} + +void +cons (size) + int size; +{ + cons_worker (size, 0); +} + +void +s_rva (size) + int size; +{ + cons_worker (size, 1); +} + +/* Put the contents of expression EXP into the object file using + NBYTES bytes. If need_pass_2 is 1, this does nothing. */ + +void +emit_expr (exp, nbytes) + expressionS *exp; + unsigned int nbytes; +{ + operatorT op; + register char *p; + valueT extra_digit = 0; + + /* Don't do anything if we are going to make another pass. */ + if (need_pass_2) + return; + +#ifndef NO_LISTING +#ifdef OBJ_ELF + /* When gcc emits DWARF 1 debugging pseudo-ops, a line number will + appear as a four byte positive constant in the .line section, + followed by a 2 byte 0xffff. Look for that case here. */ + { + static int dwarf_line = -1; + + if (strcmp (segment_name (now_seg), ".line") != 0) + dwarf_line = -1; + else if (dwarf_line >= 0 + && nbytes == 2 + && exp->X_op == O_constant + && (exp->X_add_number == -1 || exp->X_add_number == 0xffff)) + listing_source_line ((unsigned int) dwarf_line); + else if (nbytes == 4 + && exp->X_op == O_constant + && exp->X_add_number >= 0) + dwarf_line = exp->X_add_number; + else + dwarf_line = -1; + } + + /* When gcc emits DWARF 1 debugging pseudo-ops, a file name will + appear as a 2 byte TAG_compile_unit (0x11) followed by a 2 byte + AT_sibling (0x12) followed by a four byte address of the sibling + followed by a 2 byte AT_name (0x38) followed by the name of the + file. We look for that case here. */ + { + static int dwarf_file = 0; + + if (strcmp (segment_name (now_seg), ".debug") != 0) + dwarf_file = 0; + else if (dwarf_file == 0 + && nbytes == 2 + && exp->X_op == O_constant + && exp->X_add_number == 0x11) + dwarf_file = 1; + else if (dwarf_file == 1 + && nbytes == 2 + && exp->X_op == O_constant + && exp->X_add_number == 0x12) + dwarf_file = 2; + else if (dwarf_file == 2 + && nbytes == 4) + dwarf_file = 3; + else if (dwarf_file == 3 + && nbytes == 2 + && exp->X_op == O_constant + && exp->X_add_number == 0x38) + dwarf_file = 4; + else + dwarf_file = 0; + + /* The variable dwarf_file_string tells stringer that the string + may be the name of the source file. */ + if (dwarf_file == 4) + dwarf_file_string = 1; + else + dwarf_file_string = 0; + } +#endif +#endif + + if (check_eh_frame (exp, &nbytes)) + return; + + op = exp->X_op; + + /* Allow `.word 0' in the absolute section. */ + if (now_seg == absolute_section) + { + if (op != O_constant || exp->X_add_number != 0) + as_bad (_("attempt to store value in absolute section")); + abs_section_offset += nbytes; + return; + } + + /* Handle a negative bignum. */ + if (op == O_uminus + && exp->X_add_number == 0 + && symbol_get_value_expression (exp->X_add_symbol)->X_op == O_big + && symbol_get_value_expression (exp->X_add_symbol)->X_add_number > 0) + { + int i; + unsigned long carry; + + exp = symbol_get_value_expression (exp->X_add_symbol); + + /* Negate the bignum: one's complement each digit and add 1. */ + carry = 1; + for (i = 0; i < exp->X_add_number; i++) + { + unsigned long next; + + next = (((~(generic_bignum[i] & LITTLENUM_MASK)) + & LITTLENUM_MASK) + + carry); + generic_bignum[i] = next & LITTLENUM_MASK; + carry = next >> LITTLENUM_NUMBER_OF_BITS; + } + + /* We can ignore any carry out, because it will be handled by + extra_digit if it is needed. */ + + extra_digit = (valueT) -1; + op = O_big; + } + + if (op == O_absent || op == O_illegal) + { + as_warn (_("zero assumed for missing expression")); + exp->X_add_number = 0; + op = O_constant; + } + else if (op == O_big && exp->X_add_number <= 0) + { + as_bad (_("floating point number invalid")); + exp->X_add_number = 0; + op = O_constant; + } + else if (op == O_register) + { + as_warn (_("register value used as expression")); + op = O_constant; + } + + p = frag_more ((int) nbytes); + +#ifndef WORKING_DOT_WORD + /* If we have the difference of two symbols in a word, save it on + the broken_words list. See the code in write.c. */ + if (op == O_subtract && nbytes == 2) + { + struct broken_word *x; + + x = (struct broken_word *) xmalloc (sizeof (struct broken_word)); + x->next_broken_word = broken_words; + broken_words = x; + x->seg = now_seg; + x->subseg = now_subseg; + x->frag = frag_now; + x->word_goes_here = p; + x->dispfrag = 0; + x->add = exp->X_add_symbol; + x->sub = exp->X_op_symbol; + x->addnum = exp->X_add_number; + x->added = 0; + x->use_jump = 0; + new_broken_words++; + return; + } +#endif + + /* If we have an integer, but the number of bytes is too large to + pass to md_number_to_chars, handle it as a bignum. */ + if (op == O_constant && nbytes > sizeof (valueT)) + { + valueT val; + int gencnt; + + if (!exp->X_unsigned && exp->X_add_number < 0) + extra_digit = (valueT) -1; + val = (valueT) exp->X_add_number; + gencnt = 0; + do + { + generic_bignum[gencnt] = val & LITTLENUM_MASK; + val >>= LITTLENUM_NUMBER_OF_BITS; + ++gencnt; + } + while (val != 0); + op = exp->X_op = O_big; + exp->X_add_number = gencnt; + } + + if (op == O_constant) + { + register valueT get; + register valueT use; + register valueT mask; + valueT hibit; + register valueT unmask; + + /* JF << of >= number of bits in the object is undefined. In + particular SPARC (Sun 4) has problems. */ + if (nbytes >= sizeof (valueT)) + { + mask = 0; + if (nbytes > sizeof (valueT)) + hibit = 0; + else + hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); + } + else + { + /* Don't store these bits. */ + mask = ~(valueT) 0 << (BITS_PER_CHAR * nbytes); + hibit = (valueT) 1 << (nbytes * BITS_PER_CHAR - 1); + } + + unmask = ~mask; /* Do store these bits. */ + +#ifdef NEVER + "Do this mod if you want every overflow check to assume SIGNED 2's complement data."; + mask = ~(unmask >> 1); /* Includes sign bit now. */ +#endif + + get = exp->X_add_number; + use = get & unmask; + if ((get & mask) != 0 + && ((get & mask) != mask + || (get & hibit) == 0)) + { /* Leading bits contain both 0s & 1s. */ + as_warn (_("value 0x%lx truncated to 0x%lx"), + (unsigned long) get, (unsigned long) use); + } + /* Put bytes in right order. */ + md_number_to_chars (p, use, (int) nbytes); + } + else if (op == O_big) + { + unsigned int size; + LITTLENUM_TYPE *nums; + + know (nbytes % CHARS_PER_LITTLENUM == 0); + + size = exp->X_add_number * CHARS_PER_LITTLENUM; + if (nbytes < size) + { + as_warn (_("bignum truncated to %d bytes"), nbytes); + size = nbytes; + } + + if (target_big_endian) + { + while (nbytes > size) + { + md_number_to_chars (p, extra_digit, CHARS_PER_LITTLENUM); + nbytes -= CHARS_PER_LITTLENUM; + p += CHARS_PER_LITTLENUM; + } + + nums = generic_bignum + size / CHARS_PER_LITTLENUM; + while (size >= CHARS_PER_LITTLENUM) + { + --nums; + md_number_to_chars (p, (valueT) *nums, CHARS_PER_LITTLENUM); + size -= CHARS_PER_LITTLENUM; + p += CHARS_PER_LITTLENUM; + } + } + else + { + nums = generic_bignum; + while (size >= CHARS_PER_LITTLENUM) + { + md_number_to_chars (p, (valueT) *nums, CHARS_PER_LITTLENUM); + ++nums; + size -= CHARS_PER_LITTLENUM; + p += CHARS_PER_LITTLENUM; + nbytes -= CHARS_PER_LITTLENUM; + } + + while (nbytes >= CHARS_PER_LITTLENUM) + { + md_number_to_chars (p, extra_digit, CHARS_PER_LITTLENUM); + nbytes -= CHARS_PER_LITTLENUM; + p += CHARS_PER_LITTLENUM; + } + } + } + else + { + memset (p, 0, nbytes); + + /* Now we need to generate a fixS to record the symbol value. + This is easy for BFD. For other targets it can be more + complex. For very complex cases (currently, the HPPA and + NS32K), you can define TC_CONS_FIX_NEW to do whatever you + want. For simpler cases, you can define TC_CONS_RELOC to be + the name of the reloc code that should be stored in the fixS. + If neither is defined, the code uses NO_RELOC if it is + defined, and otherwise uses 0. */ + +#ifdef BFD_ASSEMBLER +#ifdef TC_CONS_FIX_NEW + TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp); +#else + { + bfd_reloc_code_real_type r; + + switch (nbytes) + { + case 1: + r = BFD_RELOC_8; + break; + case 2: + r = BFD_RELOC_16; + break; + case 4: + r = BFD_RELOC_32; + break; + case 8: + r = BFD_RELOC_64; + break; + default: + as_bad (_("unsupported BFD relocation size %u"), nbytes); + r = BFD_RELOC_32; + break; + } + fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, + 0, r); + } +#endif +#else +#ifdef TC_CONS_FIX_NEW + TC_CONS_FIX_NEW (frag_now, p - frag_now->fr_literal, nbytes, exp); +#else + /* Figure out which reloc number to use. Use TC_CONS_RELOC if + it is defined, otherwise use NO_RELOC if it is defined, + otherwise use 0. */ +#ifndef TC_CONS_RELOC +#ifdef NO_RELOC +#define TC_CONS_RELOC NO_RELOC +#else +#define TC_CONS_RELOC 0 +#endif +#endif + fix_new_exp (frag_now, p - frag_now->fr_literal, (int) nbytes, exp, 0, + TC_CONS_RELOC); +#endif /* TC_CONS_FIX_NEW */ +#endif /* BFD_ASSEMBLER */ + } +} + +#ifdef BITFIELD_CONS_EXPRESSIONS + +/* i960 assemblers, (eg, asm960), allow bitfields after ".byte" as + w:x,y:z, where w and y are bitwidths and x and y are values. They + then pack them all together. We do a little better in that we allow + them in words, longs, etc. and we'll pack them in target byte order + for you. + + The rules are: pack least significat bit first, if a field doesn't + entirely fit, put it in the next unit. Overflowing the bitfield is + explicitly *not* even a warning. The bitwidth should be considered + a "mask". + + To use this function the tc-XXX.h file should define + BITFIELD_CONS_EXPRESSIONS. */ + +static void +parse_bitfield_cons (exp, nbytes) + expressionS *exp; + unsigned int nbytes; +{ + unsigned int bits_available = BITS_PER_CHAR * nbytes; + char *hold = input_line_pointer; + + (void) expression (exp); + + if (*input_line_pointer == ':') + { + /* Bitfields. */ + long value = 0; + + for (;;) + { + unsigned long width; + + if (*input_line_pointer != ':') + { + input_line_pointer = hold; + break; + } /* Next piece is not a bitfield. */ + + /* In the general case, we can't allow + full expressions with symbol + differences and such. The relocation + entries for symbols not defined in this + assembly would require arbitrary field + widths, positions, and masks which most + of our current object formats don't + support. + + In the specific case where a symbol + *is* defined in this assembly, we + *could* build fixups and track it, but + this could lead to confusion for the + backends. I'm lazy. I'll take any + SEG_ABSOLUTE. I think that means that + you can use a previous .set or + .equ type symbol. xoxorich. */ + + if (exp->X_op == O_absent) + { + as_warn (_("using a bit field width of zero")); + exp->X_add_number = 0; + exp->X_op = O_constant; + } /* Implied zero width bitfield. */ + + if (exp->X_op != O_constant) + { + *input_line_pointer = '\0'; + as_bad (_("field width \"%s\" too complex for a bitfield"), hold); + *input_line_pointer = ':'; + demand_empty_rest_of_line (); + return; + } /* Too complex. */ + + if ((width = exp->X_add_number) > (BITS_PER_CHAR * nbytes)) + { + as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), + width, nbytes, (BITS_PER_CHAR * nbytes)); + width = BITS_PER_CHAR * nbytes; + } /* Too big. */ + + if (width > bits_available) + { + /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */ + input_line_pointer = hold; + exp->X_add_number = value; + break; + } /* Won't fit. */ + + /* Skip ':'. */ + hold = ++input_line_pointer; + + (void) expression (exp); + if (exp->X_op != O_constant) + { + char cache = *input_line_pointer; + + *input_line_pointer = '\0'; + as_bad (_("field value \"%s\" too complex for a bitfield"), hold); + *input_line_pointer = cache; + demand_empty_rest_of_line (); + return; + } /* Too complex. */ + + value |= ((~(-1 << width) & exp->X_add_number) + << ((BITS_PER_CHAR * nbytes) - bits_available)); + + if ((bits_available -= width) == 0 + || is_it_end_of_statement () + || *input_line_pointer != ',') + { + break; + } /* All the bitfields we're gonna get. */ + + hold = ++input_line_pointer; + (void) expression (exp); + } + + exp->X_add_number = value; + exp->X_op = O_constant; + exp->X_unsigned = 1; + } +} + +#endif /* BITFIELD_CONS_EXPRESSIONS */ + +/* Handle an MRI style string expression. */ + +#ifdef TC_M68K +static void +parse_mri_cons (exp, nbytes) + expressionS *exp; + unsigned int nbytes; +{ + if (*input_line_pointer != '\'' + && (input_line_pointer[1] != '\'' + || (*input_line_pointer != 'A' + && *input_line_pointer != 'E'))) + TC_PARSE_CONS_EXPRESSION (exp, nbytes); + else + { + unsigned int scan; + unsigned int result = 0; + + /* An MRI style string. Cut into as many bytes as will fit into + a nbyte chunk, left justify if necessary, and separate with + commas so we can try again later. */ + if (*input_line_pointer == 'A') + ++input_line_pointer; + else if (*input_line_pointer == 'E') + { + as_bad (_("EBCDIC constants are not supported")); + ++input_line_pointer; + } + + input_line_pointer++; + for (scan = 0; scan < nbytes; scan++) + { + if (*input_line_pointer == '\'') + { + if (input_line_pointer[1] == '\'') + { + input_line_pointer++; + } + else + break; + } + result = (result << 8) | (*input_line_pointer++); + } + + /* Left justify. */ + while (scan < nbytes) + { + result <<= 8; + scan++; + } + + /* Create correct expression. */ + exp->X_op = O_constant; + exp->X_add_number = result; + + /* Fake it so that we can read the next char too. */ + if (input_line_pointer[0] != '\'' || + (input_line_pointer[0] == '\'' && input_line_pointer[1] == '\'')) + { + input_line_pointer -= 2; + input_line_pointer[0] = ','; + input_line_pointer[1] = '\''; + } + else + input_line_pointer++; + } +} +#endif /* TC_M68K */ + +#ifdef REPEAT_CONS_EXPRESSIONS + +/* Parse a repeat expression for cons. This is used by the MIPS + assembler. The format is NUMBER:COUNT; NUMBER appears in the + object file COUNT times. + + To use this for a target, define REPEAT_CONS_EXPRESSIONS. */ + +static void +parse_repeat_cons (exp, nbytes) + expressionS *exp; + unsigned int nbytes; +{ + expressionS count; + register int i; + + expression (exp); + + if (*input_line_pointer != ':') + { + /* No repeat count. */ + return; + } + + ++input_line_pointer; + expression (&count); + if (count.X_op != O_constant + || count.X_add_number <= 0) + { + as_warn (_("unresolvable or nonpositive repeat count; using 1")); + return; + } + + /* The cons function is going to output this expression once. So we + output it count - 1 times. */ + for (i = count.X_add_number - 1; i > 0; i--) + emit_expr (exp, nbytes); +} + +#endif /* REPEAT_CONS_EXPRESSIONS */ + +/* Parse a floating point number represented as a hex constant. This + permits users to specify the exact bits they want in the floating + point number. */ + +static int +hex_float (float_type, bytes) + int float_type; + char *bytes; +{ + int length; + int i; + + switch (float_type) + { + case 'f': + case 'F': + case 's': + case 'S': + length = 4; + break; + + case 'd': + case 'D': + case 'r': + case 'R': + length = 8; + break; + + case 'x': + case 'X': + length = 12; + break; + + case 'p': + case 'P': + length = 12; + break; + + default: + as_bad (_("unknown floating type type '%c'"), float_type); + return -1; + } + + /* It would be nice if we could go through expression to parse the + hex constant, but if we get a bignum it's a pain to sort it into + the buffer correctly. */ + i = 0; + while (hex_p (*input_line_pointer) || *input_line_pointer == '_') + { + int d; + + /* The MRI assembler accepts arbitrary underscores strewn about + through the hex constant, so we ignore them as well. */ + if (*input_line_pointer == '_') + { + ++input_line_pointer; + continue; + } + + if (i >= length) + { + as_warn (_("floating point constant too large")); + return -1; + } + d = hex_value (*input_line_pointer) << 4; + ++input_line_pointer; + while (*input_line_pointer == '_') + ++input_line_pointer; + if (hex_p (*input_line_pointer)) + { + d += hex_value (*input_line_pointer); + ++input_line_pointer; + } + if (target_big_endian) + bytes[i] = d; + else + bytes[length - i - 1] = d; + ++i; + } + + if (i < length) + { + if (target_big_endian) + memset (bytes + i, 0, length - i); + else + memset (bytes, 0, length - i); + } + + return length; +} + +/* float_cons() + + CONStruct some more frag chars of .floats .ffloats etc. + Makes 0 or more new frags. + If need_pass_2 == 1, no frags are emitted. + This understands only floating literals, not expressions. Sorry. + + A floating constant is defined by atof_generic(), except it is preceded + by 0d 0f 0g or 0h. After observing the STRANGE way my BSD AS does its + reading, I decided to be incompatible. This always tries to give you + rounded bits to the precision of the pseudo-op. Former AS did premature + truncatation, restored noisy bits instead of trailing 0s AND gave you + a choice of 2 flavours of noise according to which of 2 floating-point + scanners you directed AS to use. + + In: input_line_pointer->whitespace before, or '0' of flonum. */ + +void +float_cons (float_type) + /* Clobbers input_line-pointer, checks end-of-line. */ + register int float_type; /* 'f':.ffloat ... 'F':.float ... */ +{ + register char *p; + int length; /* Number of chars in an object. */ + register char *err; /* Error from scanning floating literal. */ + char temp[MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT]; + + if (is_it_end_of_statement ()) + { + demand_empty_rest_of_line (); + return; + } + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + do + { + /* input_line_pointer->1st char of a flonum (we hope!). */ + SKIP_WHITESPACE (); + + /* Skip any 0{letter} that may be present. Don't even check if the + letter is legal. Someone may invent a "z" format and this routine + has no use for such information. Lusers beware: you get + diagnostics if your input is ill-conditioned. */ + if (input_line_pointer[0] == '0' + && ISALPHA (input_line_pointer[1])) + input_line_pointer += 2; + + /* Accept :xxxx, where the x's are hex digits, for a floating + point with the exact digits specified. */ + if (input_line_pointer[0] == ':') + { + ++input_line_pointer; + length = hex_float (float_type, temp); + if (length < 0) + { + ignore_rest_of_line (); + return; + } + } + else + { + err = md_atof (float_type, temp, &length); + know (length <= MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT); + know (length > 0); + if (err) + { + as_bad (_("bad floating literal: %s"), err); + ignore_rest_of_line (); + return; + } + } + + if (!need_pass_2) + { + int count; + + count = 1; + +#ifdef REPEAT_CONS_EXPRESSIONS + if (*input_line_pointer == ':') + { + expressionS count_exp; + + ++input_line_pointer; + expression (&count_exp); + + if (count_exp.X_op != O_constant + || count_exp.X_add_number <= 0) + as_warn (_("unresolvable or nonpositive repeat count; using 1")); + else + count = count_exp.X_add_number; + } +#endif + + while (--count >= 0) + { + p = frag_more (length); + memcpy (p, temp, (unsigned int) length); + } + } + SKIP_WHITESPACE (); + } + while (*input_line_pointer++ == ','); + + /* Put terminator back into stream. */ + --input_line_pointer; + demand_empty_rest_of_line (); +} + +/* Return the size of a LEB128 value. */ + +static inline int +sizeof_sleb128 (value) + offsetT value; +{ + register int size = 0; + register unsigned byte; + + do + { + byte = (value & 0x7f); + /* Sadly, we cannot rely on typical arithmetic right shift behaviour. + Fortunately, we can structure things so that the extra work reduces + to a noop on systems that do things "properly". */ + value = (value >> 7) | ~(-(offsetT)1 >> 7); + size += 1; + } + while (!(((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + + return size; +} + +static inline int +sizeof_uleb128 (value) + valueT value; +{ + register int size = 0; + register unsigned byte; + + do + { + byte = (value & 0x7f); + value >>= 7; + size += 1; + } + while (value != 0); + + return size; +} + +int +sizeof_leb128 (value, sign) + valueT value; + int sign; +{ + if (sign) + return sizeof_sleb128 ((offsetT) value); + else + return sizeof_uleb128 (value); +} + +/* Output a LEB128 value. */ + +static inline int +output_sleb128 (p, value) + char *p; + offsetT value; +{ + register char *orig = p; + register int more; + + do + { + unsigned byte = (value & 0x7f); + + /* Sadly, we cannot rely on typical arithmetic right shift behaviour. + Fortunately, we can structure things so that the extra work reduces + to a noop on systems that do things "properly". */ + value = (value >> 7) | ~(-(offsetT)1 >> 7); + + more = !((((value == 0) && ((byte & 0x40) == 0)) + || ((value == -1) && ((byte & 0x40) != 0)))); + if (more) + byte |= 0x80; + + *p++ = byte; + } + while (more); + + return p - orig; +} + +static inline int +output_uleb128 (p, value) + char *p; + valueT value; +{ + char *orig = p; + + do + { + unsigned byte = (value & 0x7f); + value >>= 7; + if (value != 0) + /* More bytes to follow. */ + byte |= 0x80; + + *p++ = byte; + } + while (value != 0); + + return p - orig; +} + +int +output_leb128 (p, value, sign) + char *p; + valueT value; + int sign; +{ + if (sign) + return output_sleb128 (p, (offsetT) value); + else + return output_uleb128 (p, value); +} + +/* Do the same for bignums. We combine sizeof with output here in that + we don't output for NULL values of P. It isn't really as critical as + for "normal" values that this be streamlined. */ + +static inline int +output_big_sleb128 (p, bignum, size) + char *p; + LITTLENUM_TYPE *bignum; + int size; +{ + char *orig = p; + valueT val = 0; + int loaded = 0; + unsigned byte; + + /* Strip leading sign extensions off the bignum. */ + while (size > 0 && bignum[size - 1] == (LITTLENUM_TYPE) -1) + size--; + + do + { + if (loaded < 7 && size > 0) + { + val |= (*bignum << loaded); + loaded += 8 * CHARS_PER_LITTLENUM; + size--; + bignum++; + } + + byte = val & 0x7f; + loaded -= 7; + val >>= 7; + + if (size == 0) + { + if ((val == 0 && (byte & 0x40) == 0) + || (~(val | ~(((valueT) 1 << loaded) - 1)) == 0 + && (byte & 0x40) != 0)) + byte |= 0x80; + } + + if (orig) + *p = byte; + p++; + } + while (byte & 0x80); + + return p - orig; +} + +static inline int +output_big_uleb128 (p, bignum, size) + char *p; + LITTLENUM_TYPE *bignum; + int size; +{ + char *orig = p; + valueT val = 0; + int loaded = 0; + unsigned byte; + + /* Strip leading zeros off the bignum. */ + /* XXX: Is this needed? */ + while (size > 0 && bignum[size - 1] == 0) + size--; + + do + { + if (loaded < 7 && size > 0) + { + val |= (*bignum << loaded); + loaded += 8 * CHARS_PER_LITTLENUM; + size--; + bignum++; + } + + byte = val & 0x7f; + loaded -= 7; + val >>= 7; + + if (size > 0 || val) + byte |= 0x80; + + if (orig) + *p = byte; + p++; + } + while (byte & 0x80); + + return p - orig; +} + +static int +output_big_leb128 (p, bignum, size, sign) + char *p; + LITTLENUM_TYPE *bignum; + int size, sign; +{ + if (sign) + return output_big_sleb128 (p, bignum, size); + else + return output_big_uleb128 (p, bignum, size); +} + +/* Generate the appropriate fragments for a given expression to emit a + leb128 value. */ + +void +emit_leb128_expr (exp, sign) + expressionS *exp; + int sign; +{ + operatorT op = exp->X_op; + int nbytes; + + if (op == O_absent || op == O_illegal) + { + as_warn (_("zero assumed for missing expression")); + exp->X_add_number = 0; + op = O_constant; + } + else if (op == O_big && exp->X_add_number <= 0) + { + as_bad (_("floating point number invalid")); + exp->X_add_number = 0; + op = O_constant; + } + else if (op == O_register) + { + as_warn (_("register value used as expression")); + op = O_constant; + } + + /* Let check_eh_frame know that data is being emitted. nbytes == -1 is + a signal that this is leb128 data. It shouldn't optimize this away. */ + nbytes = -1; + if (check_eh_frame (exp, &nbytes)) + abort (); + + /* Let the backend know that subsequent data may be byte aligned. */ +#ifdef md_cons_align + md_cons_align (1); +#endif + + if (op == O_constant) + { + /* If we've got a constant, emit the thing directly right now. */ + + valueT value = exp->X_add_number; + int size; + char *p; + + size = sizeof_leb128 (value, sign); + p = frag_more (size); + output_leb128 (p, value, sign); + } + else if (op == O_big) + { + /* O_big is a different sort of constant. */ + + int size; + char *p; + + size = output_big_leb128 (NULL, generic_bignum, exp->X_add_number, sign); + p = frag_more (size); + output_big_leb128 (p, generic_bignum, exp->X_add_number, sign); + } + else + { + /* Otherwise, we have to create a variable sized fragment and + resolve things later. */ + + frag_var (rs_leb128, sizeof_uleb128 (~(valueT) 0), 0, sign, + make_expr_symbol (exp), 0, (char *) NULL); + } +} + +/* Parse the .sleb128 and .uleb128 pseudos. */ + +void +s_leb128 (sign) + int sign; +{ + expressionS exp; + + do + { + expression (&exp); + emit_leb128_expr (&exp, sign); + } + while (*input_line_pointer++ == ','); + + input_line_pointer--; + demand_empty_rest_of_line (); +} + +/* We read 0 or more ',' separated, double-quoted strings. + Caller should have checked need_pass_2 is FALSE because we don't + check it. */ + +void +stringer (append_zero) /* Worker to do .ascii etc statements. */ + /* Checks end-of-line. */ + register int append_zero; /* 0: don't append '\0', else 1. */ +{ + register unsigned int c; + char *start; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + /* The following awkward logic is to parse ZERO or more strings, + comma separated. Recall a string expression includes spaces + before the opening '\"' and spaces after the closing '\"'. + We fake a leading ',' if there is (supposed to be) + a 1st, expression. We keep demanding expressions for each ','. */ + if (is_it_end_of_statement ()) + { + c = 0; /* Skip loop. */ + ++input_line_pointer; /* Compensate for end of loop. */ + } + else + { + c = ','; /* Do loop. */ + } + /* If we have been switched into the abs_section then we + will not have an obstack onto which we can hang strings. */ + if (now_seg == absolute_section) + { + as_bad (_("strings must be placed into a section")); + c = 0; + ignore_rest_of_line (); + } + + while (c == ',' || c == '<' || c == '"') + { + SKIP_WHITESPACE (); + switch (*input_line_pointer) + { + case '\"': + ++input_line_pointer; /*->1st char of string. */ + start = input_line_pointer; + while (is_a_char (c = next_char_of_string ())) + { + FRAG_APPEND_1_CHAR (c); + } + if (append_zero) + { + FRAG_APPEND_1_CHAR (0); + } + know (input_line_pointer[-1] == '\"'); + +#ifndef NO_LISTING +#ifdef OBJ_ELF + /* In ELF, when gcc is emitting DWARF 1 debugging output, it + will emit .string with a filename in the .debug section + after a sequence of constants. See the comment in + emit_expr for the sequence. emit_expr will set + dwarf_file_string to non-zero if this string might be a + source file name. */ + if (strcmp (segment_name (now_seg), ".debug") != 0) + dwarf_file_string = 0; + else if (dwarf_file_string) + { + c = input_line_pointer[-1]; + input_line_pointer[-1] = '\0'; + listing_source_file (start); + input_line_pointer[-1] = c; + } +#endif +#endif + + break; + case '<': + input_line_pointer++; + c = get_single_number (); + FRAG_APPEND_1_CHAR (c); + if (*input_line_pointer != '>') + { + as_bad (_("expected ")); + } + input_line_pointer++; + break; + case ',': + input_line_pointer++; + break; + } + SKIP_WHITESPACE (); + c = *input_line_pointer; + } + + demand_empty_rest_of_line (); +} /* stringer() */ + +/* FIXME-SOMEDAY: I had trouble here on characters with the + high bits set. We'll probably also have trouble with + multibyte chars, wide chars, etc. Also be careful about + returning values bigger than 1 byte. xoxorich. */ + +unsigned int +next_char_of_string () +{ + register unsigned int c; + + c = *input_line_pointer++ & CHAR_MASK; + switch (c) + { + case '\"': + c = NOT_A_CHAR; + break; + + case '\n': + as_warn (_("unterminated string; newline inserted")); + bump_line_counters (); + break; + +#ifndef NO_STRING_ESCAPES + case '\\': + switch (c = *input_line_pointer++) + { + case 'b': + c = '\b'; + break; + + case 'f': + c = '\f'; + break; + + case 'n': + c = '\n'; + break; + + case 'r': + c = '\r'; + break; + + case 't': + c = '\t'; + break; + + case 'v': + c = '\013'; + break; + + case '\\': + case '"': + break; /* As itself. */ + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + long number; + int i; + + for (i = 0, number = 0; + ISDIGIT (c) && i < 3; + c = *input_line_pointer++, i++) + { + number = number * 8 + c - '0'; + } + + c = number & 0xff; + } + --input_line_pointer; + break; + + case 'x': + case 'X': + { + long number; + + number = 0; + c = *input_line_pointer++; + while (ISXDIGIT (c)) + { + if (ISDIGIT (c)) + number = number * 16 + c - '0'; + else if (ISUPPER (c)) + number = number * 16 + c - 'A' + 10; + else + number = number * 16 + c - 'a' + 10; + c = *input_line_pointer++; + } + c = number & 0xff; + --input_line_pointer; + } + break; + + case '\n': + /* To be compatible with BSD 4.2 as: give the luser a linefeed!! */ + as_warn (_("unterminated string; newline inserted")); + c = '\n'; + bump_line_counters (); + break; + + default: + +#ifdef ONLY_STANDARD_ESCAPES + as_bad (_("bad escaped character in string")); + c = '?'; +#endif /* ONLY_STANDARD_ESCAPES */ + + break; + } + break; +#endif /* ! defined (NO_STRING_ESCAPES) */ + + default: + break; + } + return (c); +} + +static segT +get_segmented_expression (expP) + register expressionS *expP; +{ + register segT retval; + + retval = expression (expP); + if (expP->X_op == O_illegal + || expP->X_op == O_absent + || expP->X_op == O_big) + { + as_bad (_("expected address expression")); + expP->X_op = O_constant; + expP->X_add_number = 0; + retval = absolute_section; + } + return retval; +} + +static segT +get_known_segmented_expression (expP) + register expressionS *expP; +{ + register segT retval; + + if ((retval = get_segmented_expression (expP)) == undefined_section) + { + /* There is no easy way to extract the undefined symbol from the + expression. */ + if (expP->X_add_symbol != NULL + && S_GET_SEGMENT (expP->X_add_symbol) != expr_section) + as_warn (_("symbol \"%s\" undefined; zero assumed"), + S_GET_NAME (expP->X_add_symbol)); + else + as_warn (_("some symbol undefined; zero assumed")); + retval = absolute_section; + expP->X_op = O_constant; + expP->X_add_number = 0; + } + know (retval == absolute_section || SEG_NORMAL (retval)); + return (retval); +} + +offsetT +get_absolute_expr (exp) + expressionS *exp; +{ + expression (exp); + if (exp->X_op != O_constant) + { + if (exp->X_op != O_absent) + as_bad (_("bad or irreducible absolute expression")); + exp->X_add_number = 0; + } + return exp->X_add_number; +} + +offsetT +get_absolute_expression () +{ + expressionS exp; + + return get_absolute_expr (&exp); +} + +char /* Return terminator. */ +get_absolute_expression_and_terminator (val_pointer) + long *val_pointer; /* Return value of expression. */ +{ + /* FIXME: val_pointer should probably be offsetT *. */ + *val_pointer = (long) get_absolute_expression (); + return (*input_line_pointer++); +} + +/* Like demand_copy_string, but return NULL if the string contains any '\0's. + Give a warning if that happens. */ + +char * +demand_copy_C_string (len_pointer) + int *len_pointer; +{ + register char *s; + + if ((s = demand_copy_string (len_pointer)) != 0) + { + register int len; + + for (len = *len_pointer; len > 0; len--) + { + if (*s == 0) + { + s = 0; + len = 1; + *len_pointer = 0; + as_bad (_("this string may not contain \'\\0\'")); + } + } + } + + return s; +} + +/* Demand string, but return a safe (=private) copy of the string. + Return NULL if we can't read a string here. */ + +char * +demand_copy_string (lenP) + int *lenP; +{ + register unsigned int c; + register int len; + char *retval; + + len = 0; + SKIP_WHITESPACE (); + if (*input_line_pointer == '\"') + { + input_line_pointer++; /* Skip opening quote. */ + + while (is_a_char (c = next_char_of_string ())) + { + obstack_1grow (¬es, c); + len++; + } + /* JF this next line is so demand_copy_C_string will return a + null terminated string. */ + obstack_1grow (¬es, '\0'); + retval = obstack_finish (¬es); + } + else + { + as_warn (_("missing string")); + retval = NULL; + ignore_rest_of_line (); + } + *lenP = len; + return (retval); +} + +/* In: Input_line_pointer->next character. + + Do: Skip input_line_pointer over all whitespace. + + Out: 1 if input_line_pointer->end-of-line. */ + +int +is_it_end_of_statement () +{ + SKIP_WHITESPACE (); + return (is_end_of_line[(unsigned char) *input_line_pointer]); +} + +void +equals (sym_name, reassign) + char *sym_name; + int reassign; +{ + register symbolS *symbolP; /* Symbol we are working with. */ + char *stop = NULL; + char stopc; + + input_line_pointer++; + if (*input_line_pointer == '=') + input_line_pointer++; + + while (*input_line_pointer == ' ' || *input_line_pointer == '\t') + input_line_pointer++; + + if (flag_mri) + stop = mri_comment_field (&stopc); + + if (sym_name[0] == '.' && sym_name[1] == '\0') + { + /* Turn '. = mumble' into a .org mumble. */ + register segT segment; + expressionS exp; + + segment = get_known_segmented_expression (&exp); + if (!need_pass_2) + do_org (segment, &exp, 0); + } + else + { +#ifdef OBJ_COFF + int local; + + symbolP = symbol_find (sym_name); + local = symbolP == NULL; + if (local) +#endif /* OBJ_COFF */ + symbolP = symbol_find_or_make (sym_name); + /* Permit register names to be redefined. */ + if (!reassign + && S_IS_DEFINED (symbolP) + && S_GET_SEGMENT (symbolP) != reg_section) + as_bad (_("symbol `%s' is already defined"), S_GET_NAME (symbolP)); + +#ifdef OBJ_COFF + /* "set" symbols are local unless otherwise specified. */ + if (local) + SF_SET_LOCAL (symbolP); +#endif /* OBJ_COFF */ + + pseudo_set (symbolP); + } + + if (flag_mri) + { + /* Check garbage after the expression. */ + ignore_rest_of_line (); + mri_comment_end (stop, stopc); + } +} + +/* .incbin -- include a file verbatim at the current location. */ + +void +s_incbin (x) + int x ATTRIBUTE_UNUSED; +{ + FILE * binfile; + char * path; + char * filename; + char * binfrag; + long skip = 0; + long count = 0; + long bytes; + int len; + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + SKIP_WHITESPACE (); + filename = demand_copy_string (& len); + if (filename == NULL) + return; + + SKIP_WHITESPACE (); + + /* Look for optional skip and count. */ + if (* input_line_pointer == ',') + { + ++ input_line_pointer; + skip = get_absolute_expression (); + + SKIP_WHITESPACE (); + + if (* input_line_pointer == ',') + { + ++ input_line_pointer; + + count = get_absolute_expression (); + if (count == 0) + as_warn (_(".incbin count zero, ignoring `%s'"), filename); + + SKIP_WHITESPACE (); + } + } + + demand_empty_rest_of_line (); + + /* Try opening absolute path first, then try include dirs. */ + binfile = fopen (filename, FOPEN_RB); + if (binfile == NULL) + { + int i; + + path = xmalloc ((unsigned long) len + include_dir_maxlen + 5); + + for (i = 0; i < include_dir_count; i++) + { + sprintf (path, "%s/%s", include_dirs[i], filename); + + binfile = fopen (path, FOPEN_RB); + if (binfile != NULL) + break; + } + + if (binfile == NULL) + as_bad (_("file not found: %s"), filename); + } + else + path = xstrdup (filename); + + if (binfile) + { + long file_len; + + register_dependency (path); + + /* Compute the length of the file. */ + if (fseek (binfile, 0, SEEK_END) != 0) + { + as_bad (_("seek to end of .incbin file failed `%s'"), path); + goto done; + } + file_len = ftell (binfile); + + /* If a count was not specified use the size of the file. */ + if (count == 0) + count = file_len; + + if (skip + count > file_len) + { + as_bad (_("skip (%ld) + count (%ld) larger than file size (%ld)"), + skip, count, file_len); + goto done; + } + + if (fseek (binfile, skip, SEEK_SET) != 0) + { + as_bad (_("could not skip to %ld in file `%s'"), skip, path); + goto done; + } + + /* Allocate frag space and store file contents in it. */ + binfrag = frag_more (count); + + bytes = fread (binfrag, 1, count, binfile); + if (bytes < count) + as_warn (_("truncated file `%s', %ld of %ld bytes read"), + path, bytes, count); + } +done: + if (binfile != NULL) + fclose (binfile); + if (path) + free (path); +} + +/* .include -- include a file at this point. */ + +void +s_include (arg) + int arg ATTRIBUTE_UNUSED; +{ + char *filename; + int i; + FILE *try; + char *path; + + if (!flag_m68k_mri) + { + filename = demand_copy_string (&i); + if (filename == NULL) + { + /* demand_copy_string has already printed an error and + called ignore_rest_of_line. */ + return; + } + } + else + { + SKIP_WHITESPACE (); + i = 0; + while (!is_end_of_line[(unsigned char) *input_line_pointer] + && *input_line_pointer != ' ' + && *input_line_pointer != '\t') + { + obstack_1grow (¬es, *input_line_pointer); + ++input_line_pointer; + ++i; + } + + obstack_1grow (¬es, '\0'); + filename = obstack_finish (¬es); + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + ++input_line_pointer; + } + + demand_empty_rest_of_line (); + path = xmalloc ((unsigned long) i + include_dir_maxlen + 5 /* slop */ ); + + for (i = 0; i < include_dir_count; i++) + { + strcpy (path, include_dirs[i]); + strcat (path, "/"); + strcat (path, filename); + if (0 != (try = fopen (path, FOPEN_RT))) + { + fclose (try); + goto gotit; + } + } + + free (path); + path = filename; +gotit: + /* malloc Storage leak when file is found on path. FIXME-SOMEDAY. */ + register_dependency (path); + input_scrub_insert_file (path); +} + +void +add_include_dir (path) + char *path; +{ + int i; + + if (include_dir_count == 0) + { + include_dirs = (char **) xmalloc (2 * sizeof (*include_dirs)); + include_dirs[0] = "."; /* Current dir. */ + include_dir_count = 2; + } + else + { + include_dir_count++; + include_dirs = + (char **) realloc (include_dirs, + include_dir_count * sizeof (*include_dirs)); + } + + include_dirs[include_dir_count - 1] = path; /* New one. */ + + i = strlen (path); + if (i > include_dir_maxlen) + include_dir_maxlen = i; +} + +/* Output debugging information to denote the source file. */ + +static void +generate_file_debug () +{ + if (debug_type == DEBUG_STABS) + stabs_generate_asm_file (); +} + +/* Output line number debugging information for the current source line. */ + +void +generate_lineno_debug () +{ + switch (debug_type) + { + case DEBUG_UNSPECIFIED: + case DEBUG_NONE: + case DEBUG_DWARF: + break; + case DEBUG_STABS: + stabs_generate_asm_lineno (); + break; + case DEBUG_ECOFF: + ecoff_generate_asm_lineno (); + break; + case DEBUG_DWARF2: + /* ??? We could here indicate to dwarf2dbg.c that something + has changed. However, since there is additional backend + support that is required (calling dwarf2_emit_insn), we + let dwarf2dbg.c call as_where on its own. */ + break; + } +} + +/* Output debugging information to mark a function entry point or end point. + END_P is zero for .func, and non-zero for .endfunc. */ + +void +s_func (end_p) + int end_p; +{ + do_s_func (end_p, NULL); +} + +/* Subroutine of s_func so targets can choose a different default prefix. + If DEFAULT_PREFIX is NULL, use the target's "leading char". */ + +void +do_s_func (end_p, default_prefix) + int end_p; + const char *default_prefix; +{ + /* Record the current function so that we can issue an error message for + misplaced .func,.endfunc, and also so that .endfunc needs no + arguments. */ + static char *current_name; + static char *current_label; + + if (end_p) + { + if (current_name == NULL) + { + as_bad (_("missing .func")); + ignore_rest_of_line (); + return; + } + + if (debug_type == DEBUG_STABS) + stabs_generate_asm_endfunc (current_name, current_label); + + current_name = current_label = NULL; + } + else /* ! end_p */ + { + char *name, *label; + char delim1, delim2; + + if (current_name != NULL) + { + as_bad (_(".endfunc missing for previous .func")); + ignore_rest_of_line (); + return; + } + + name = input_line_pointer; + delim1 = get_symbol_end (); + name = xstrdup (name); + *input_line_pointer = delim1; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + if (default_prefix) + asprintf (&label, "%s%s", default_prefix, name); + else + { + char leading_char = 0; +#ifdef BFD_ASSEMBLER + leading_char = bfd_get_symbol_leading_char (stdoutput); +#endif + /* Missing entry point, use function's name with the leading + char prepended. */ + if (leading_char) + asprintf (&label, "%c%s", leading_char, name); + else + label = name; + } + } + else + { + ++input_line_pointer; + SKIP_WHITESPACE (); + label = input_line_pointer; + delim2 = get_symbol_end (); + label = xstrdup (label); + *input_line_pointer = delim2; + } + + if (debug_type == DEBUG_STABS) + stabs_generate_asm_func (name, label); + + current_name = name; + current_label = label; + } + + demand_empty_rest_of_line (); +} + +void +s_ignore (arg) + int arg ATTRIBUTE_UNUSED; +{ + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + ++input_line_pointer; + } + ++input_line_pointer; +} + +void +read_print_statistics (file) + FILE *file; +{ + hash_print_statistics (file, "pseudo-op table", po_hash); +} + +/* Inserts the given line into the input stream. + + This call avoids macro/conditionals nesting checking, since the contents of + the line are assumed to replace the contents of a line already scanned. + + An appropriate use of this function would be substition of input lines when + called by md_start_line_hook(). The given line is assumed to already be + properly scrubbed. */ + +void +input_scrub_insert_line (line) + const char *line; +{ + sb newline; + sb_new (&newline); + sb_add_string (&newline, line); + input_scrub_include_sb (&newline, input_line_pointer, 0); + sb_kill (&newline); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} + +/* Insert a file into the input stream; the path must resolve to an actual + file; no include path searching or dependency registering is performed. */ + +void +input_scrub_insert_file (path) + char *path; +{ + input_scrub_include_file (path, input_line_pointer); + buffer_limit = input_scrub_next_buffer (&input_line_pointer); +} diff --git a/contrib/binutils-2.14/gas/read.h b/contrib/binutils-2.14/gas/read.h new file mode 100644 index 0000000000..1e8ca7ab9c --- /dev/null +++ b/contrib/binutils-2.14/gas/read.h @@ -0,0 +1,187 @@ +/* read.h - of read.c + Copyright 1986, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +extern char *input_line_pointer; /* -> char we are parsing now. */ + +/* Define to make whitespace be allowed in many syntactically + unnecessary places. Normally undefined. For compatibility with + ancient GNU cc. */ +/* #undef PERMIT_WHITESPACE */ +#define PERMIT_WHITESPACE + +#ifdef PERMIT_WHITESPACE +#define SKIP_WHITESPACE() \ + { \ + if (* input_line_pointer == ' ') \ + ++ input_line_pointer; \ + } +#else +#define SKIP_WHITESPACE() know(*input_line_pointer != ' ' ) +#endif + +#define LEX_NAME (1) /* may continue a name */ +#define LEX_BEGIN_NAME (2) /* may begin a name */ +#define LEX_END_NAME (4) /* ends a name */ + +#define is_name_beginner(c) \ + ( lex_type[(unsigned char) (c)] & LEX_BEGIN_NAME ) +#define is_part_of_name(c) \ + ( lex_type[(unsigned char) (c)] & LEX_NAME ) +#define is_name_ender(c) \ + ( lex_type[(unsigned char) (c)] & LEX_END_NAME ) + +#ifndef is_a_char +#define CHAR_MASK (0xff) +#define NOT_A_CHAR (CHAR_MASK+1) +#define is_a_char(c) (((unsigned) (c)) <= CHAR_MASK) +#endif /* is_a_char() */ + +extern char lex_type[]; +extern char is_end_of_line[]; + +extern int is_it_end_of_statement PARAMS ((void)); + +extern int target_big_endian; + +/* These are initialized by the CPU specific target files (tc-*.c). */ +extern const char comment_chars[]; +extern const char line_comment_chars[]; +extern const char line_separator_chars[]; + +/* Table of -I directories. */ +extern char **include_dirs; +extern int include_dir_count; +extern int include_dir_maxlen; + +/* The offset in the absolute section. */ +extern addressT abs_section_offset; + +/* The label on a line, used by some of the pseudo-ops. */ +extern symbolS *line_label; + +/* This is used to support MRI common sections. */ +extern symbolS *mri_common_symbol; + +/* True if a stabs line debug statement is currently being emitted. */ +extern int outputting_stabs_line_debug; + +/* Possible arguments to .linkonce. */ +enum linkonce_type { + LINKONCE_UNSET = 0, + LINKONCE_DISCARD, + LINKONCE_ONE_ONLY, + LINKONCE_SAME_SIZE, + LINKONCE_SAME_CONTENTS +}; + +#define IGNORE_OPCODE_CASE +#ifdef IGNORE_OPCODE_CASE +extern char original_case_string[]; +#endif + +extern void pop_insert PARAMS ((const pseudo_typeS *)); +extern unsigned int get_stab_string_offset + PARAMS ((const char *string, const char *stabstr_secname)); +extern void aout_process_stab PARAMS ((int, const char *, int, int, int)); +extern char *demand_copy_C_string PARAMS ((int *len_pointer)); +extern char get_absolute_expression_and_terminator + PARAMS ((long *val_pointer)); +extern offsetT get_absolute_expr PARAMS ((expressionS *)); +extern offsetT get_absolute_expression PARAMS ((void)); +extern unsigned int next_char_of_string PARAMS ((void)); +extern void s_mri_sect PARAMS ((char *)); +extern char *mri_comment_field PARAMS ((char *)); +extern void mri_comment_end PARAMS ((char *, int)); +extern void add_include_dir PARAMS ((char *path)); +extern void cons PARAMS ((int nbytes)); +extern void demand_empty_rest_of_line PARAMS ((void)); +extern void emit_expr PARAMS ((expressionS *exp, unsigned int nbytes)); +extern void emit_leb128_expr PARAMS ((expressionS *, int)); +extern void equals PARAMS ((char *sym_name, int reassign)); +extern void float_cons PARAMS ((int float_type)); +extern void ignore_rest_of_line PARAMS ((void)); +extern void discard_rest_of_line PARAMS ((void)); +extern int output_leb128 PARAMS ((char *, valueT, int sign)); +extern void pseudo_set PARAMS ((symbolS * symbolP)); +extern void read_a_source_file PARAMS ((char *name)); +extern void read_begin PARAMS ((void)); +extern void read_print_statistics PARAMS ((FILE *)); +extern int sizeof_leb128 PARAMS ((valueT, int sign)); +extern void stabs_generate_asm_file PARAMS ((void)); +extern void stabs_generate_asm_lineno PARAMS ((void)); +extern void stabs_generate_asm_func PARAMS ((const char *, const char *)); +extern void stabs_generate_asm_endfunc PARAMS ((const char *, const char *)); +extern void do_repeat PARAMS((int,const char *,const char *)); +extern void end_repeat PARAMS((int)); + +extern void generate_lineno_debug PARAMS ((void)); + +extern void s_abort PARAMS ((int)) ATTRIBUTE_NORETURN; +extern void s_align_bytes PARAMS ((int arg)); +extern void s_align_ptwo PARAMS ((int)); +extern void s_app_file_string PARAMS ((char *)); +extern void s_app_file PARAMS ((int)); +extern void s_app_line PARAMS ((int)); +extern void s_bad_endr PARAMS ((int)); +extern void s_comm PARAMS ((int)); +extern void s_data PARAMS ((int)); +extern void s_desc PARAMS ((int)); +extern void s_else PARAMS ((int arg)); +extern void s_elseif PARAMS ((int arg)); +extern void s_end PARAMS ((int arg)); +extern void s_endif PARAMS ((int arg)); +extern void s_err PARAMS ((int)); +extern void s_fail PARAMS ((int)); +extern void s_fill PARAMS ((int)); +extern void s_float_space PARAMS ((int mult)); +extern void s_func PARAMS ((int)); +extern void do_s_func PARAMS ((int, const char *)); +extern void s_globl PARAMS ((int arg)); +extern void s_if PARAMS ((int arg)); +extern void s_ifc PARAMS ((int arg)); +extern void s_ifdef PARAMS ((int arg)); +extern void s_ifeqs PARAMS ((int arg)); +extern void s_ignore PARAMS ((int arg)); +extern void s_include PARAMS ((int arg)); +extern void s_irp PARAMS ((int arg)); +extern void s_lcomm PARAMS ((int needs_align)); +extern void s_lcomm_bytes PARAMS ((int needs_align)); +extern void s_leb128 PARAMS ((int sign)); +extern void s_linkonce PARAMS ((int)); +extern void s_lsym PARAMS ((int)); +extern void s_macro PARAMS ((int)); +extern void s_mexit PARAMS ((int)); +extern void s_mri PARAMS ((int)); +extern void s_mri_common PARAMS ((int)); +extern void s_org PARAMS ((int)); +extern void s_print PARAMS ((int)); +extern void s_purgem PARAMS ((int)); +extern void s_rept PARAMS ((int)); +extern void s_set PARAMS ((int)); +extern void s_space PARAMS ((int mult)); +extern void s_stab PARAMS ((int what)); +extern void s_struct PARAMS ((int)); +extern void s_text PARAMS ((int)); +extern void stringer PARAMS ((int append_zero)); +extern void s_xstab PARAMS ((int what)); +extern void s_rva PARAMS ((int)); +extern void s_incbin PARAMS ((int)); diff --git a/contrib/binutils-2.14/gas/sb.c b/contrib/binutils-2.14/gas/sb.c new file mode 100644 index 0000000000..93d2fcfb04 --- /dev/null +++ b/contrib/binutils-2.14/gas/sb.c @@ -0,0 +1,291 @@ +/* sb.c - string buffer manipulation routines + Copyright 1994, 1995, 2000 Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "config.h" +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#else +#include +#endif +#include "libiberty.h" +#include "sb.h" + +/* These routines are about manipulating strings. + + They are managed in things called `sb's which is an abbreviation + for string buffers. An sb has to be created, things can be glued + on to it, and at the end of it's life it should be freed. The + contents should never be pointed at whilst it is still growing, + since it could be moved at any time + + eg: + sb_new (&foo); + sb_grow... (&foo,...); + use foo->ptr[*]; + sb_kill (&foo); + +*/ + +#define dsize 5 + +static void sb_check PARAMS ((sb *, int)); + +/* Statistics of sb structures. */ + +int string_count[sb_max_power_two]; + +/* Free list of sb structures. */ + +static sb_list_vector free_list; + +/* initializes an sb. */ + +void +sb_build (ptr, size) + sb *ptr; + int size; +{ + /* see if we can find one to allocate */ + sb_element *e; + + if (size > sb_max_power_two) + abort (); + + e = free_list.size[size]; + if (!e) + { + /* nothing there, allocate one and stick into the free list */ + e = (sb_element *) xmalloc (sizeof (sb_element) + (1 << size)); + e->next = free_list.size[size]; + e->size = 1 << size; + free_list.size[size] = e; + string_count[size]++; + } + + /* remove from free list */ + + free_list.size[size] = e->next; + + /* copy into callers world */ + ptr->ptr = e->data; + ptr->pot = size; + ptr->len = 0; + ptr->item = e; +} + +void +sb_new (ptr) + sb *ptr; +{ + sb_build (ptr, dsize); +} + +/* deallocate the sb at ptr */ + +void +sb_kill (ptr) + sb *ptr; +{ + /* return item to free list */ + ptr->item->next = free_list.size[ptr->pot]; + free_list.size[ptr->pot] = ptr->item; +} + +/* add the sb at s to the end of the sb at ptr */ + +void +sb_add_sb (ptr, s) + sb *ptr; + sb *s; +{ + sb_check (ptr, s->len); + memcpy (ptr->ptr + ptr->len, s->ptr, s->len); + ptr->len += s->len; +} + +/* make sure that the sb at ptr has room for another len characters, + and grow it if it doesn't. */ + +static void +sb_check (ptr, len) + sb *ptr; + int len; +{ + if (ptr->len + len >= 1 << ptr->pot) + { + sb tmp; + int pot = ptr->pot; + while (ptr->len + len >= 1 << pot) + pot++; + sb_build (&tmp, pot); + sb_add_sb (&tmp, ptr); + sb_kill (ptr); + *ptr = tmp; + } +} + +/* make the sb at ptr point back to the beginning. */ + +void +sb_reset (ptr) + sb *ptr; +{ + ptr->len = 0; +} + +/* add character c to the end of the sb at ptr. */ + +void +sb_add_char (ptr, c) + sb *ptr; + int c; +{ + sb_check (ptr, 1); + ptr->ptr[ptr->len++] = c; +} + +/* add null terminated string s to the end of sb at ptr. */ + +void +sb_add_string (ptr, s) + sb *ptr; + const char *s; +{ + int len = strlen (s); + sb_check (ptr, len); + memcpy (ptr->ptr + ptr->len, s, len); + ptr->len += len; +} + +/* add string at s of length len to sb at ptr */ + +void +sb_add_buffer (ptr, s, len) + sb *ptr; + const char *s; + int len; +{ + sb_check (ptr, len); + memcpy (ptr->ptr + ptr->len, s, len); + ptr->len += len; +} + +/* print the sb at ptr to the output file */ + +void +sb_print (outfile, ptr) + FILE *outfile; + sb *ptr; +{ + int i; + int nc = 0; + + for (i = 0; i < ptr->len; i++) + { + if (nc) + { + fprintf (outfile, ","); + } + fprintf (outfile, "%d", ptr->ptr[i]); + nc = 1; + } +} + +void +sb_print_at (outfile, idx, ptr) + FILE *outfile; + int idx; + sb *ptr; +{ + int i; + for (i = idx; i < ptr->len; i++) + putc (ptr->ptr[i], outfile); +} + +/* put a null at the end of the sb at in and return the start of the + string, so that it can be used as an arg to printf %s. */ + +char * +sb_name (in) + sb *in; +{ + /* stick a null on the end of the string */ + sb_add_char (in, 0); + return in->ptr; +} + +/* like sb_name, but don't include the null byte in the string. */ + +char * +sb_terminate (in) + sb *in; +{ + sb_add_char (in, 0); + --in->len; + return in->ptr; +} + +/* start at the index idx into the string in sb at ptr and skip + whitespace. return the index of the first non whitespace character */ + +int +sb_skip_white (idx, ptr) + int idx; + sb *ptr; +{ + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + return idx; +} + +/* start at the index idx into the sb at ptr. skips whitespace, + a comma and any following whitespace. returnes the index of the + next character. */ + +int +sb_skip_comma (idx, ptr) + int idx; + sb *ptr; +{ + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + + if (idx < ptr->len + && ptr->ptr[idx] == ',') + idx++; + + while (idx < ptr->len + && (ptr->ptr[idx] == ' ' + || ptr->ptr[idx] == '\t')) + idx++; + + return idx; +} diff --git a/contrib/binutils-2.14/gas/sb.h b/contrib/binutils-2.14/gas/sb.h new file mode 100644 index 0000000000..dd01e0ddb7 --- /dev/null +++ b/contrib/binutils-2.14/gas/sb.h @@ -0,0 +1,99 @@ +/* sb.h - header file for string buffer manipulation routines + Copyright 1994, 1995, 2000 Free Software Foundation, Inc. + + Written by Steve and Judy Chamberlain of Cygnus Support, + sac@cygnus.com + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef SB_H + +#define SB_H + +#include +#include "ansidecl.h" + +/* string blocks + + I had a couple of choices when deciding upon this data structure. + gas uses null terminated strings for all its internal work. This + often means that parts of the program that want to examine + substrings have to manipulate the data in the string to do the + right thing (a common operation is to single out a bit of text by + saving away the character after it, nulling it out, operating on + the substring and then replacing the character which was under the + null). This is a pain and I remember a load of problems that I had with + code in gas which almost got this right. Also, it's harder to grow and + allocate null terminated strings efficiently. + + Obstacks provide all the functionality needed, but are too + complicated, hence the sb. + + An sb is allocated by the caller, and is initialzed to point to an + sb_element. sb_elements are kept on a free lists, and used when + needed, replaced onto the free list when unused. + */ + +#define sb_max_power_two 30 /* don't allow strings more than + 2^sb_max_power_two long */ +/* structure of an sb */ +typedef struct sb + { + char *ptr; /* points to the current block. */ + int len; /* how much is used. */ + int pot; /* the maximum length is 1<str section. + */ + +#ifndef SEPARATE_STAB_SECTIONS +#define SEPARATE_STAB_SECTIONS 0 +#endif + +unsigned int +get_stab_string_offset (string, stabstr_secname) + const char *string; + const char *stabstr_secname; +{ + unsigned int length; + unsigned int retval; + segT save_seg; + subsegT save_subseg; + segT seg; + char *p; + + if (! SEPARATE_STAB_SECTIONS) + abort (); + + length = strlen (string); + + save_seg = now_seg; + save_subseg = now_subseg; + + /* Create the stab string section. */ + seg = subseg_new (stabstr_secname, 0); + + retval = seg_info (seg)->stabu.stab_string_size; + if (retval <= 0) + { + /* Make sure the first string is empty. */ + p = frag_more (1); + *p = 0; + retval = seg_info (seg)->stabu.stab_string_size = 1; +#ifdef BFD_ASSEMBLER + bfd_set_section_flags (stdoutput, seg, SEC_READONLY | SEC_DEBUGGING); + if (seg->name == stabstr_secname) + seg->name = xstrdup (stabstr_secname); +#endif + } + + if (length > 0) + { /* Ordinary case. */ + p = frag_more (length + 1); + strcpy (p, string); + + seg_info (seg)->stabu.stab_string_size += length + 1; + } + else + retval = 0; + + subseg_set (save_seg, save_subseg); + + return retval; +} + +#ifdef AOUT_STABS +#ifndef OBJ_PROCESS_STAB +#define OBJ_PROCESS_STAB(SEG,W,S,T,O,D) aout_process_stab(W,S,T,O,D) +#endif + +/* Here instead of obj-aout.c because other formats use it too. */ +void +aout_process_stab (what, string, type, other, desc) + int what; + const char *string; + int type, other, desc; +{ + /* Put the stab information in the symbol table. */ + symbolS *symbol; + + /* Create the symbol now, but only insert it into the symbol chain + after any symbols mentioned in the value expression get into the + symbol chain. This is to avoid "continuation symbols" (where one + ends in "\" and the debug info is continued in the next .stabs + directive) from being separated by other random symbols. */ + symbol = symbol_create (string, undefined_section, 0, + (struct frag *) NULL); + if (what == 's' || what == 'n') + { + /* Pick up the value from the input line. */ + symbol_set_frag (symbol, &zero_address_frag); + pseudo_set (symbol); + } + else + { + /* .stabd sets the name to NULL. Why? */ + S_SET_NAME (symbol, NULL); + symbol_set_frag (symbol, frag_now); + S_SET_VALUE (symbol, (valueT) frag_now_fix ()); + } + + symbol_append (symbol, symbol_lastP, &symbol_rootP, &symbol_lastP); + + S_SET_TYPE (symbol, type); + S_SET_OTHER (symbol, other); + S_SET_DESC (symbol, desc); +} +#endif + +/* This can handle different kinds of stabs (s,n,d) and different + kinds of stab sections. */ + +static void +s_stab_generic (what, stab_secname, stabstr_secname) + int what; + char *stab_secname; + char *stabstr_secname; +{ + long longint; + char *string, *saved_string_obstack_end; + int type; + int other; + int desc; + + /* The general format is: + .stabs "STRING",TYPE,OTHER,DESC,VALUE + .stabn TYPE,OTHER,DESC,VALUE + .stabd TYPE,OTHER,DESC + At this point input_line_pointer points after the pseudo-op and + any trailing whitespace. The argument what is one of 's', 'n' or + 'd' indicating which type of .stab this is. */ + + if (what != 's') + { + string = ""; + saved_string_obstack_end = 0; + } + else + { + int length; + + string = demand_copy_C_string (&length); + /* FIXME: We should probably find some other temporary storage + for string, rather than leaking memory if someone else + happens to use the notes obstack. */ + saved_string_obstack_end = notes.next_free; + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + input_line_pointer++; + else + { + as_warn (_(".stab%c: missing comma"), what); + ignore_rest_of_line (); + return; + } + } + + if (get_absolute_expression_and_terminator (&longint) != ',') + { + as_warn (_(".stab%c: missing comma"), what); + ignore_rest_of_line (); + return; + } + type = longint; + + if (get_absolute_expression_and_terminator (&longint) != ',') + { + as_warn (_(".stab%c: missing comma"), what); + ignore_rest_of_line (); + return; + } + other = longint; + + desc = get_absolute_expression (); + + if ((desc > 0xffff) || (desc < -0x8000)) + /* This could happen for example with a source file with a huge + number of lines. The only cure is to use a different debug + format, probably DWARF. */ + as_warn (_(".stab%c: description field '%x' too big, try a different debug format"), + what, desc); + + if (what == 's' || what == 'n') + { + if (*input_line_pointer != ',') + { + as_warn (_(".stab%c: missing comma"), what); + ignore_rest_of_line (); + return; + } + input_line_pointer++; + SKIP_WHITESPACE (); + } + +#ifdef TC_PPC +#ifdef OBJ_ELF + /* Solaris on PowerPC has decided that .stabd can take 4 arguments, so if we were + given 4 arguments, make it a .stabn */ + else if (what == 'd') + { + char *save_location = input_line_pointer; + + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + { + input_line_pointer++; + what = 'n'; + } + else + input_line_pointer = save_location; + } +#endif /* OBJ_ELF */ +#endif /* TC_PPC */ + +#ifndef NO_LISTING + if (listing) + { + switch (type) + { + case N_SLINE: + listing_source_line ((unsigned int) desc); + break; + case N_SO: + case N_SOL: + listing_source_file (string); + break; + } + } +#endif /* ! NO_LISTING */ + + /* We have now gathered the type, other, and desc information. For + .stabs or .stabn, input_line_pointer is now pointing at the + value. */ + + if (SEPARATE_STAB_SECTIONS) + /* Output the stab information in a separate section. This is used + at least for COFF and ELF. */ + { + segT saved_seg = now_seg; + subsegT saved_subseg = now_subseg; + fragS *saved_frag = frag_now; + valueT dot; + segT seg; + unsigned int stroff; + char *p; + + static segT cached_sec; + static char *cached_secname; + + dot = frag_now_fix (); + +#ifdef md_flush_pending_output + md_flush_pending_output (); +#endif + + if (cached_secname && !strcmp (cached_secname, stab_secname)) + { + seg = cached_sec; + subseg_set (seg, 0); + } + else + { + seg = subseg_new (stab_secname, 0); + if (cached_secname) + free (cached_secname); + cached_secname = xstrdup (stab_secname); + cached_sec = seg; + } + + if (! seg_info (seg)->hadone) + { +#ifdef BFD_ASSEMBLER + bfd_set_section_flags (stdoutput, seg, + SEC_READONLY | SEC_RELOC | SEC_DEBUGGING); +#endif +#ifdef INIT_STAB_SECTION + INIT_STAB_SECTION (seg); +#endif + seg_info (seg)->hadone = 1; + } + + stroff = get_stab_string_offset (string, stabstr_secname); + if (what == 's') + { + /* Release the string, if nobody else has used the obstack. */ + if (saved_string_obstack_end == notes.next_free) + obstack_free (¬es, string); + } + + /* At least for now, stabs in a special stab section are always + output as 12 byte blocks of information. */ + p = frag_more (8); + md_number_to_chars (p, (valueT) stroff, 4); + md_number_to_chars (p + 4, (valueT) type, 1); + md_number_to_chars (p + 5, (valueT) other, 1); + md_number_to_chars (p + 6, (valueT) desc, 2); + + if (what == 's' || what == 'n') + { + /* Pick up the value from the input line. */ + cons (4); + input_line_pointer--; + } + else + { + const char *fake; + symbolS *symbol; + expressionS exp; + + /* Arrange for a value representing the current location. */ + fake = FAKE_LABEL_NAME; + symbol = symbol_new (fake, saved_seg, dot, saved_frag); + + exp.X_op = O_symbol; + exp.X_add_symbol = symbol; + exp.X_add_number = 0; + + emit_expr (&exp, 4); + } + +#ifdef OBJ_PROCESS_STAB + OBJ_PROCESS_STAB (seg, what, string, type, other, desc); +#endif + + subseg_set (saved_seg, saved_subseg); + } + else + { +#ifdef OBJ_PROCESS_STAB + OBJ_PROCESS_STAB (0, what, string, type, other, desc); +#else + abort (); +#endif + } + + demand_empty_rest_of_line (); +} + +/* Regular stab directive. */ + +void +s_stab (what) + int what; +{ + s_stab_generic (what, STAB_SECTION_NAME, STAB_STRING_SECTION_NAME); +} + +/* "Extended stabs", used in Solaris only now. */ + +void +s_xstab (what) + int what; +{ + int length; + char *stab_secname, *stabstr_secname; + static char *saved_secname, *saved_strsecname; + + /* @@ MEMORY LEAK: This allocates a copy of the string, but in most + cases it will be the same string, so we could release the storage + back to the obstack it came from. */ + stab_secname = demand_copy_C_string (&length); + SKIP_WHITESPACE (); + if (*input_line_pointer == ',') + input_line_pointer++; + else + { + as_bad (_("comma missing in .xstabs")); + ignore_rest_of_line (); + return; + } + + /* To get the name of the stab string section, simply add "str" to + the stab section name. */ + if (saved_secname == 0 || strcmp (saved_secname, stab_secname)) + { + stabstr_secname = (char *) xmalloc (strlen (stab_secname) + 4); + strcpy (stabstr_secname, stab_secname); + strcat (stabstr_secname, "str"); + if (saved_secname) + { + free (saved_secname); + free (saved_strsecname); + } + saved_secname = stab_secname; + saved_strsecname = stabstr_secname; + } + s_stab_generic (what, saved_secname, saved_strsecname); +} + +#ifdef S_SET_DESC + +/* Frob invented at RMS' request. Set the n_desc of a symbol. */ + +void +s_desc (ignore) + int ignore ATTRIBUTE_UNUSED; +{ + char *name; + char c; + char *p; + symbolS *symbolP; + int temp; + + name = input_line_pointer; + c = get_symbol_end (); + p = input_line_pointer; + *p = c; + SKIP_WHITESPACE (); + if (*input_line_pointer != ',') + { + *p = 0; + as_bad (_("expected comma after \"%s\""), name); + *p = c; + ignore_rest_of_line (); + } + else + { + input_line_pointer++; + temp = get_absolute_expression (); + *p = 0; + symbolP = symbol_find_or_make (name); + *p = c; + S_SET_DESC (symbolP, temp); + } + demand_empty_rest_of_line (); +} /* s_desc() */ + +#endif /* defined (S_SET_DESC) */ + +/* Generate stabs debugging information to denote the main source file. */ + +void +stabs_generate_asm_file () +{ + char *file; + unsigned int lineno; + + as_where (&file, &lineno); + generate_asm_file (N_SO, file); +} + +/* Generate stabs debugging information to denote the source file. + TYPE is one of N_SO, N_SOL. */ + +static void +generate_asm_file (type, file) + int type; + char *file; +{ + static char *last_file; + static int label_count; + char *hold; + char sym[30]; + char *buf; + char *tmp = file; + char *endp = file + strlen (file); + char *bufp = buf; + + if (last_file != NULL + && strcmp (last_file, file) == 0) + return; + + /* Rather than try to do this in some efficient fashion, we just + generate a string and then parse it again. That lets us use the + existing stabs hook, which expect to see a string, rather than + inventing new ones. */ + hold = input_line_pointer; + + sprintf (sym, "%sF%d", FAKE_LABEL_NAME, label_count); + ++label_count; + + /* Allocate enough space for the file name (possibly extended with + doubled up backslashes), the symbol name, and the other characters + that make up a stabs file directive. */ + bufp = buf = xmalloc (2 * strlen (file) + strlen (sym) + 12); + + *bufp++ = '"'; + + while (tmp < endp) + { + char *bslash = strchr (tmp, '\\'); + size_t len = (bslash) ? (size_t) (bslash - tmp + 1) : strlen (tmp); + + /* Double all backslashes, since demand_copy_C_string (used by + s_stab to extract the part in quotes) will try to replace them as + escape sequences. backslash may appear in a filespec. */ + strncpy (bufp, tmp, len); + + tmp += len; + bufp += len; + + if (bslash != NULL) + *bufp++ = '\\'; + } + + sprintf (bufp, "\",%d,0,0,%s\n", type, sym); + + input_line_pointer = buf; + s_stab ('s'); + colon (sym); + + if (last_file != NULL) + free (last_file); + last_file = xstrdup (file); + + free (buf); + + input_line_pointer = hold; +} + +/* Generate stabs debugging information for the current line. This is + used to produce debugging information for an assembler file. */ + +void +stabs_generate_asm_lineno () +{ + static int label_count; + char *hold; + char *file; + unsigned int lineno; + char *buf; + char sym[30]; + /* Remember the last file/line and avoid duplicates. */ + static unsigned int prev_lineno = -1; + static char *prev_file = NULL; + + /* Rather than try to do this in some efficient fashion, we just + generate a string and then parse it again. That lets us use the + existing stabs hook, which expect to see a string, rather than + inventing new ones. */ + + hold = input_line_pointer; + + as_where (&file, &lineno); + + /* Don't emit sequences of stabs for the same line. */ + if (prev_file == NULL) + { + /* First time thru. */ + prev_file = xstrdup (file); + prev_lineno = lineno; + } + else if (lineno == prev_lineno + && strcmp (file, prev_file) == 0) + { + /* Same file/line as last time. */ + return; + } + else + { + /* Remember file/line for next time. */ + prev_lineno = lineno; + if (strcmp (file, prev_file) != 0) + { + free (prev_file); + prev_file = xstrdup (file); + } + } + + /* Let the world know that we are in the middle of generating a + piece of stabs line debugging information. */ + outputting_stabs_line_debug = 1; + + generate_asm_file (N_SOL, file); + + sprintf (sym, "%sL%d", FAKE_LABEL_NAME, label_count); + ++label_count; + + if (in_dot_func_p) + { + buf = (char *) alloca (100 + strlen (current_function_label)); + sprintf (buf, "%d,0,%d,%s-%s\n", N_SLINE, lineno, + sym, current_function_label); + } + else + { + buf = (char *) alloca (100); + sprintf (buf, "%d,0,%d,%s\n", N_SLINE, lineno, sym); + } + input_line_pointer = buf; + s_stab ('n'); + colon (sym); + + input_line_pointer = hold; + outputting_stabs_line_debug = 0; +} + +/* Emit a function stab. + All assembler functions are assumed to have return type `void'. */ + +void +stabs_generate_asm_func (funcname, startlabname) + const char *funcname; + const char *startlabname; +{ + static int void_emitted_p; + char *hold = input_line_pointer; + char *buf; + char *file; + unsigned int lineno; + + if (! void_emitted_p) + { + input_line_pointer = "\"void:t1=1\",128,0,0,0"; + s_stab ('s'); + void_emitted_p = 1; + } + + as_where (&file, &lineno); + asprintf (&buf, "\"%s:F1\",%d,0,%d,%s", + funcname, N_FUN, lineno + 1, startlabname); + input_line_pointer = buf; + s_stab ('s'); + free (buf); + + input_line_pointer = hold; + current_function_label = xstrdup (startlabname); + in_dot_func_p = 1; +} + +/* Emit a stab to record the end of a function. */ + +void +stabs_generate_asm_endfunc (funcname, startlabname) + const char *funcname ATTRIBUTE_UNUSED; + const char *startlabname; +{ + static int label_count; + char *hold = input_line_pointer; + char *buf; + char sym[30]; + + sprintf (sym, "%sendfunc%d", FAKE_LABEL_NAME, label_count); + ++label_count; + colon (sym); + + asprintf (&buf, "\"\",%d,0,0,%s-%s", N_FUN, sym, startlabname); + input_line_pointer = buf; + s_stab ('s'); + free (buf); + + input_line_pointer = hold; + in_dot_func_p = 0; + current_function_label = NULL; +} diff --git a/contrib/binutils-2.14/gas/struc-symbol.h b/contrib/binutils-2.14/gas/struc-symbol.h new file mode 100644 index 0000000000..90945c433b --- /dev/null +++ b/contrib/binutils-2.14/gas/struc-symbol.h @@ -0,0 +1,159 @@ +/* struct_symbol.h - Internal symbol structure + Copyright 1987, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef __struc_symbol_h__ +#define __struc_symbol_h__ + +#ifdef BFD_ASSEMBLER +/* The BFD code wants to walk the list in both directions. */ +#undef SYMBOLS_NEED_BACKPOINTERS +#define SYMBOLS_NEED_BACKPOINTERS +#endif + +/* The information we keep for a symbol. Note that the symbol table + holds pointers both to this and to local_symbol structures. See + below. */ + +struct symbol +{ +#ifdef BFD_ASSEMBLER + /* BFD symbol */ + asymbol *bsym; +#else + /* The (4-origin) position of sy_name in the symbol table of the object + file. This will be 0 for (nameless) .stabd symbols. + + Not used until write_object_file() time. */ + unsigned long sy_name_offset; + + /* What we write in .o file (if permitted). */ + obj_symbol_type sy_symbol; + + /* The 24 bit symbol number. Symbol numbers start at 0 and are unsigned. */ + long sy_number; +#endif + + /* The value of the symbol. */ + expressionS sy_value; + + /* Forwards and (optionally) backwards chain pointers. */ + struct symbol *sy_next; +#ifdef SYMBOLS_NEED_BACKPOINTERS + struct symbol *sy_previous; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + + /* Pointer to the frag this symbol is attached to, if any. + Otherwise, NULL. */ + struct frag *sy_frag; + + unsigned int written : 1; + /* Whether symbol value has been completely resolved (used during + final pass over symbol table). */ + unsigned int sy_resolved : 1; + /* Whether the symbol value is currently being resolved (used to + detect loops in symbol dependencies). */ + unsigned int sy_resolving : 1; + /* Whether the symbol value is used in a reloc. This is used to + ensure that symbols used in relocs are written out, even if they + are local and would otherwise not be. */ + unsigned int sy_used_in_reloc : 1; + + /* Whether the symbol is used as an operand or in an expression. + NOTE: Not all the backends keep this information accurate; + backends which use this bit are responsible for setting it when + a symbol is used in backend routines. */ + unsigned int sy_used : 1; + + /* This is set if the symbol is defined in an MRI common section. + We handle such sections as single common symbols, so symbols + defined within them must be treated specially by the relocation + routines. */ + unsigned int sy_mri_common : 1; + +#ifdef OBJ_SYMFIELD_TYPE + OBJ_SYMFIELD_TYPE sy_obj; +#endif + +#ifdef TC_SYMFIELD_TYPE + TC_SYMFIELD_TYPE sy_tc; +#endif + +#ifdef TARGET_SYMBOL_FIELDS + TARGET_SYMBOL_FIELDS +#endif +}; + +#ifdef BFD_ASSEMBLER + +/* A pointer in the symbol may point to either a complete symbol + (struct symbol above) or to a local symbol (struct local_symbol + defined here). The symbol code can detect the case by examining + the first field. It is always NULL for a local symbol. + + We do this because we ordinarily only need a small amount of + information for a local symbol. The symbol table takes up a lot of + space, and storing less information for a local symbol can make a + big difference in assembler memory usage when assembling a large + file. */ + +struct local_symbol +{ + /* This pointer is always NULL to indicate that this is a local + symbol. */ + asymbol *lsy_marker; + + /* The symbol section. This also serves as a flag. If this is + reg_section, then this symbol has been converted into a regular + symbol, and lsy_sym points to it. */ + segT lsy_section; + + /* The symbol name. */ + const char *lsy_name; + + /* The symbol frag or the real symbol, depending upon the value in + lsy_section. If the symbol has been fully resolved, lsy_frag is + set to NULL. */ + union + { + fragS *lsy_frag; + symbolS *lsy_sym; + } u; + + /* The value of the symbol. */ + valueT lsy_value; + +#ifdef TC_LOCAL_SYMFIELD_TYPE + TC_LOCAL_SYMFIELD_TYPE lsy_tc; +#endif +}; + +#define local_symbol_converted_p(l) ((l)->lsy_section == reg_section) +#define local_symbol_mark_converted(l) ((l)->lsy_section = reg_section) +#define local_symbol_resolved_p(l) ((l)->u.lsy_frag == NULL) +#define local_symbol_mark_resolved(l) ((l)->u.lsy_frag = NULL) +#define local_symbol_get_frag(l) ((l)->u.lsy_frag) +#define local_symbol_set_frag(l, f) ((l)->u.lsy_frag = (f)) +#define local_symbol_get_real_symbol(l) ((l)->u.lsy_sym) +#define local_symbol_set_real_symbol(l, s) ((l)->u.lsy_sym = (s)) + +#endif /* BFD_ASSEMBLER */ + +#endif /* __struc_symbol_h__ */ diff --git a/contrib/binutils-2.14/gas/subsegs.c b/contrib/binutils-2.14/gas/subsegs.c new file mode 100644 index 0000000000..dfdb0009cb --- /dev/null +++ b/contrib/binutils-2.14/gas/subsegs.c @@ -0,0 +1,658 @@ +/* subsegs.c - subsegments - + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2002 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* Segments & sub-segments. */ + +#include "as.h" + +#include "subsegs.h" +#include "obstack.h" + +frchainS *frchain_root, *frchain_now; + +static struct obstack frchains; + +#ifndef BFD_ASSEMBLER +#ifdef MANY_SEGMENTS +segment_info_type segment_info[SEG_MAXIMUM_ORDINAL]; + +#else +/* Commented in "subsegs.h". */ +frchainS *data0_frchainP, *bss0_frchainP; + +#endif /* MANY_SEGMENTS */ +char const *const seg_name[] = { + "absolute", +#ifdef MANY_SEGMENTS + "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", + "e10", "e11", "e12", "e13", "e14", "e15", "e16", "e17", "e18", "e19", + "e20", "e21", "e22", "e23", "e24", "e25", "e26", "e27", "e28", "e29", + "e30", "e31", "e32", "e33", "e34", "e35", "e36", "e37", "e38", "e39", +#else + "text", + "data", + "bss", +#endif /* MANY_SEGMENTS */ + "unknown", + "ASSEMBLER-INTERNAL-LOGIC-ERROR!", + "expr", + "debug", + "transfert vector preload", + "transfert vector postload", + "register", + "", +}; /* Used by error reporters, dumpers etc. */ +#else /* BFD_ASSEMBLER */ + +/* Gas segment information for bfd_abs_section_ptr and + bfd_und_section_ptr. */ +static segment_info_type *abs_seg_info; +static segment_info_type *und_seg_info; + +#endif /* BFD_ASSEMBLER */ + +static void subseg_set_rest PARAMS ((segT, subsegT)); + +static fragS dummy_frag; + +static frchainS absolute_frchain; + +void +subsegs_begin () +{ + /* Check table(s) seg_name[], seg_N_TYPE[] is in correct order */ +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know (SEG_ABSOLUTE == 0); + know (SEG_TEXT == 1); + know (SEG_DATA == 2); + know (SEG_BSS == 3); + know (SEG_UNKNOWN == 4); + know (SEG_GOOF == 5); + know (SEG_EXPR == 6); + know (SEG_DEBUG == 7); + know (SEG_NTV == 8); + know (SEG_PTV == 9); + know (SEG_REGISTER == 10); + know (SEG_MAXIMUM_ORDINAL == SEG_REGISTER); +#endif + + obstack_begin (&frchains, chunksize); +#if __GNUC__ >= 2 + obstack_alignment_mask (&frchains) = __alignof__ (frchainS) - 1; +#endif + + frchain_root = NULL; + frchain_now = NULL; /* Warn new_subseg() that we are booting. */ + + frag_now = &dummy_frag; + +#ifndef BFD_ASSEMBLER + now_subseg = 42; /* Lie for 1st call to subseg_new. */ +#ifdef MANY_SEGMENTS + { + int i; + for (i = SEG_E0; i < SEG_UNKNOWN; i++) + { + subseg_set (i, 0); + segment_info[i].frchainP = frchain_now; + } + } +#else + subseg_set (SEG_DATA, 0); /* .data 0 */ + data0_frchainP = frchain_now; + + subseg_set (SEG_BSS, 0); + bss0_frchainP = frchain_now; + +#endif /* ! MANY_SEGMENTS */ +#endif /* ! BFD_ASSEMBLER */ + + absolute_frchain.frch_seg = absolute_section; + absolute_frchain.frch_subseg = 0; +#ifdef BFD_ASSEMBLER + absolute_frchain.fix_root = absolute_frchain.fix_tail = 0; +#endif + absolute_frchain.frch_frag_now = &zero_address_frag; + absolute_frchain.frch_root = absolute_frchain.frch_last = &zero_address_frag; +} + +/* + * subseg_change() + * + * Change the subsegment we are in, BUT DO NOT MAKE A NEW FRAG for the + * subsegment. If we are already in the correct subsegment, change nothing. + * This is used eg as a worker for subseg_set [which does make a new frag_now] + * and for changing segments after we have read the source. We construct eg + * fixSs even after the source file is read, so we do have to keep the + * segment context correct. + */ +void +subseg_change (seg, subseg) + register segT seg; + register int subseg; +{ + now_seg = seg; + now_subseg = subseg; + + if (now_seg == absolute_section) + return; + +#ifdef BFD_ASSEMBLER + { + segment_info_type *seginfo; + seginfo = (segment_info_type *) bfd_get_section_userdata (stdoutput, seg); + if (! seginfo) + { + seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); + memset ((PTR) seginfo, 0, sizeof (*seginfo)); + seginfo->fix_root = NULL; + seginfo->fix_tail = NULL; + seginfo->bfd_section = seg; + seginfo->sym = 0; + if (seg == bfd_abs_section_ptr) + abs_seg_info = seginfo; + else if (seg == bfd_und_section_ptr) + und_seg_info = seginfo; + else + bfd_set_section_userdata (stdoutput, seg, (PTR) seginfo); + } + } +#else +#ifdef MANY_SEGMENTS + seg_fix_rootP = &segment_info[seg].fix_root; + seg_fix_tailP = &segment_info[seg].fix_tail; +#else + if (seg == SEG_DATA) + { + seg_fix_rootP = &data_fix_root; + seg_fix_tailP = &data_fix_tail; + } + else if (seg == SEG_TEXT) + { + seg_fix_rootP = &text_fix_root; + seg_fix_tailP = &text_fix_tail; + } + else + { + know (seg == SEG_BSS); + seg_fix_rootP = &bss_fix_root; + seg_fix_tailP = &bss_fix_tail; + } + +#endif +#endif +} + +static void +subseg_set_rest (seg, subseg) + segT seg; + subsegT subseg; +{ + register frchainS *frcP; /* crawl frchain chain */ + register frchainS **lastPP; /* address of last pointer */ + frchainS *newP; /* address of new frchain */ + + mri_common_symbol = NULL; + + if (frag_now && frchain_now) + frchain_now->frch_frag_now = frag_now; + + assert (frchain_now == 0 + || now_seg == undefined_section + || now_seg == absolute_section + || frchain_now->frch_last == frag_now); + + subseg_change (seg, (int) subseg); + + if (seg == absolute_section) + { + frchain_now = &absolute_frchain; + frag_now = &zero_address_frag; + return; + } + + assert (frchain_now == 0 + || now_seg == undefined_section + || frchain_now->frch_last == frag_now); + + /* + * Attempt to find or make a frchain for that sub seg. + * Crawl along chain of frchainSs, begins @ frchain_root. + * If we need to make a frchainS, link it into correct + * position of chain rooted in frchain_root. + */ + for (frcP = *(lastPP = &frchain_root); + frcP && frcP->frch_seg <= seg; + frcP = *(lastPP = &frcP->frch_next)) + { + if (frcP->frch_seg == seg + && frcP->frch_subseg >= subseg) + { + break; + } + } + /* + * frcP: Address of the 1st frchainS in correct segment with + * frch_subseg >= subseg. + * We want to either use this frchainS, or we want + * to insert a new frchainS just before it. + * + * If frcP==NULL, then we are at the end of the chain + * of frchainS-s. A NULL frcP means we fell off the end + * of the chain looking for a + * frch_subseg >= subseg, so we + * must make a new frchainS. + * + * If we ever maintain a pointer to + * the last frchainS in the chain, we change that pointer + * ONLY when frcP==NULL. + * + * lastPP: Address of the pointer with value frcP; + * Never NULL. + * May point to frchain_root. + * + */ + if (!frcP + || (frcP->frch_seg > seg + || frcP->frch_subseg > subseg)) /* Kinky logic only works with 2 segments. */ + { + /* + * This should be the only code that creates a frchainS. + */ + newP = (frchainS *) obstack_alloc (&frchains, sizeof (frchainS)); + newP->frch_subseg = subseg; + newP->frch_seg = seg; +#ifdef BFD_ASSEMBLER + newP->fix_root = NULL; + newP->fix_tail = NULL; +#endif + obstack_begin (&newP->frch_obstack, chunksize); +#if __GNUC__ >= 2 + obstack_alignment_mask (&newP->frch_obstack) = __alignof__ (fragS) - 1; +#endif + newP->frch_frag_now = frag_alloc (&newP->frch_obstack); + newP->frch_frag_now->fr_type = rs_fill; + + newP->frch_root = newP->frch_last = newP->frch_frag_now; + + *lastPP = newP; + newP->frch_next = frcP; /* perhaps NULL */ + +#ifdef BFD_ASSEMBLER + { + segment_info_type *seginfo; + seginfo = seg_info (seg); + if (seginfo && seginfo->frchainP == frcP) + seginfo->frchainP = newP; + } +#endif + + frcP = newP; + } + /* + * Here with frcP pointing to the frchainS for subseg. + */ + frchain_now = frcP; + frag_now = frcP->frch_frag_now; + + assert (frchain_now->frch_last == frag_now); +} + +/* + * subseg_set(segT, subsegT) + * + * If you attempt to change to the current subsegment, nothing happens. + * + * In: segT, subsegT code for new subsegment. + * frag_now -> incomplete frag for current subsegment. + * If frag_now==NULL, then there is no old, incomplete frag, so + * the old frag is not closed off. + * + * Out: now_subseg, now_seg updated. + * Frchain_now points to the (possibly new) struct frchain for this + * sub-segment. + * Frchain_root updated if needed. + */ + +#ifndef BFD_ASSEMBLER + +segT +subseg_new (segname, subseg) + const char *segname; + subsegT subseg; +{ + int i; + + for (i = 0; i < (int) SEG_MAXIMUM_ORDINAL; i++) + { + const char *s; + + s = segment_name ((segT) i); + if (strcmp (segname, s) == 0 + || (segname[0] == '.' + && strcmp (segname + 1, s) == 0)) + { + subseg_set ((segT) i, subseg); + return (segT) i; + } +#ifdef obj_segment_name + s = obj_segment_name ((segT) i); + if (strcmp (segname, s) == 0 + || (segname[0] == '.' + && strcmp (segname + 1, s) == 0)) + { + subseg_set ((segT) i, subseg); + return (segT) i; + } +#endif + } + +#ifdef obj_add_segment + { + segT new_seg; + new_seg = obj_add_segment (segname); + subseg_set (new_seg, subseg); + return new_seg; + } +#else + as_bad (_("attempt to switch to nonexistent segment \"%s\""), segname); + return now_seg; +#endif +} + +void +subseg_set (seg, subseg) /* begin assembly for a new sub-segment */ + register segT seg; /* SEG_DATA or SEG_TEXT */ + register subsegT subseg; +{ +#ifndef MANY_SEGMENTS + know (seg == SEG_DATA + || seg == SEG_TEXT + || seg == SEG_BSS + || seg == SEG_ABSOLUTE); +#endif + + if (seg != now_seg || subseg != now_subseg) + { /* we just changed sub-segments */ + subseg_set_rest (seg, subseg); + } + mri_common_symbol = NULL; +} + +#else /* BFD_ASSEMBLER */ + +segT +subseg_get (segname, force_new) + const char *segname; + int force_new; +{ + segT secptr; + segment_info_type *seginfo; + const char *now_seg_name = (now_seg + ? bfd_get_section_name (stdoutput, now_seg) + : 0); + + if (!force_new + && now_seg_name + && (now_seg_name == segname + || !strcmp (now_seg_name, segname))) + return now_seg; + + if (!force_new) + secptr = bfd_make_section_old_way (stdoutput, segname); + else + secptr = bfd_make_section_anyway (stdoutput, segname); + + seginfo = seg_info (secptr); + if (! seginfo) + { + /* Check whether output_section is set first because secptr may + be bfd_abs_section_ptr. */ + if (secptr->output_section != secptr) + secptr->output_section = secptr; + seginfo = (segment_info_type *) xmalloc (sizeof (*seginfo)); + memset ((PTR) seginfo, 0, sizeof (*seginfo)); + seginfo->fix_root = NULL; + seginfo->fix_tail = NULL; + seginfo->bfd_section = secptr; + if (secptr == bfd_abs_section_ptr) + abs_seg_info = seginfo; + else if (secptr == bfd_und_section_ptr) + und_seg_info = seginfo; + else + bfd_set_section_userdata (stdoutput, secptr, (PTR) seginfo); + seginfo->frchainP = NULL; + seginfo->lineno_list_head = seginfo->lineno_list_tail = NULL; + seginfo->sym = NULL; + seginfo->dot = NULL; + } + return secptr; +} + +segT +subseg_new (segname, subseg) + const char *segname; + subsegT subseg; +{ + segT secptr; + segment_info_type *seginfo; + + secptr = subseg_get (segname, 0); + subseg_set_rest (secptr, subseg); + seginfo = seg_info (secptr); + if (! seginfo->frchainP) + seginfo->frchainP = frchain_now; + return secptr; +} + +/* Like subseg_new, except a new section is always created, even if + a section with that name already exists. */ +segT +subseg_force_new (segname, subseg) + const char *segname; + subsegT subseg; +{ + segT secptr; + segment_info_type *seginfo; + + secptr = subseg_get (segname, 1); + subseg_set_rest (secptr, subseg); + seginfo = seg_info (secptr); + if (! seginfo->frchainP) + seginfo->frchainP = frchain_now; + return secptr; +} + +void +subseg_set (secptr, subseg) + segT secptr; + subsegT subseg; +{ + if (! (secptr == now_seg && subseg == now_subseg)) + subseg_set_rest (secptr, subseg); + mri_common_symbol = NULL; +} + +#ifndef obj_sec_sym_ok_for_reloc +#define obj_sec_sym_ok_for_reloc(SEC) 0 +#endif + +/* Get the gas information we are storing for a section. */ + +segment_info_type * +seg_info (sec) + segT sec; +{ + if (sec == bfd_abs_section_ptr) + return abs_seg_info; + else if (sec == bfd_und_section_ptr) + return und_seg_info; + else + return (segment_info_type *) bfd_get_section_userdata (stdoutput, sec); +} + +symbolS * +section_symbol (sec) + segT sec; +{ + segment_info_type *seginfo = seg_info (sec); + symbolS *s; + + if (seginfo == 0) + abort (); + if (seginfo->sym) + return seginfo->sym; + +#ifndef EMIT_SECTION_SYMBOLS +#define EMIT_SECTION_SYMBOLS 1 +#endif + + if (! EMIT_SECTION_SYMBOLS || symbol_table_frozen) + { + /* Here we know it won't be going into the symbol table. */ + s = symbol_create (sec->symbol->name, sec, 0, &zero_address_frag); + } + else + { + s = symbol_find_base (sec->symbol->name, 0); + if (s == NULL) + s = symbol_new (sec->symbol->name, sec, 0, &zero_address_frag); + else + { + if (S_GET_SEGMENT (s) == undefined_section) + { + S_SET_SEGMENT (s, sec); + symbol_set_frag (s, &zero_address_frag); + } + } + } + + S_CLEAR_EXTERNAL (s); + + /* Use the BFD section symbol, if possible. */ + if (obj_sec_sym_ok_for_reloc (sec)) + symbol_set_bfdsym (s, sec->symbol); + else + symbol_get_bfdsym (s)->flags |= BSF_SECTION_SYM; + + seginfo->sym = s; + return s; +} + +#endif /* BFD_ASSEMBLER */ + +/* Return whether the specified segment is thought to hold text. */ + +#ifndef BFD_ASSEMBLER +const char * const nontext_section_names[] = { + ".eh_frame", + ".gcc_except_table", +#ifdef OBJ_COFF +#ifndef COFF_LONG_SECTION_NAMES + ".eh_fram", + ".gcc_exc", +#endif +#endif + NULL +}; +#endif /* ! BFD_ASSEMBLER */ + +int +subseg_text_p (sec) + segT sec; +{ +#ifdef BFD_ASSEMBLER + return (bfd_get_section_flags (stdoutput, sec) & SEC_CODE) != 0; +#else /* ! BFD_ASSEMBLER */ + const char * const *p; + + if (sec == data_section || sec == bss_section || sec == absolute_section) + return 0; + + for (p = nontext_section_names; *p != NULL; ++p) + { + if (strcmp (segment_name (sec), *p) == 0) + return 0; + +#ifdef obj_segment_name + if (strcmp (obj_segment_name (sec), *p) == 0) + return 0; +#endif + } + + return 1; + +#endif /* ! BFD_ASSEMBLER */ +} + +void +subsegs_print_statistics (file) + FILE *file; +{ + frchainS *frchp; + fprintf (file, "frag chains:\n"); + for (frchp = frchain_root; frchp; frchp = frchp->frch_next) + { + int count = 0; + fragS *fragp; + + /* If frch_subseg is non-zero, it's probably been chained onto + the end of a previous subsection. Don't count it again. */ + if (frchp->frch_subseg != 0) + continue; + + /* Skip gas-internal sections. */ + if (segment_name (frchp->frch_seg)[0] == '*') + continue; + + for (fragp = frchp->frch_root; fragp; fragp = fragp->fr_next) + { +#if 0 + switch (fragp->fr_type) + { + case rs_fill: + fprintf (file, "f"); break; + case rs_align: + fprintf (file, "a"); break; + case rs_align_code: + fprintf (file, "c"); break; + case rs_org: + fprintf (file, "o"); break; + case rs_machine_dependent: + fprintf (file, "m"); break; + case rs_space: + fprintf (file, "s"); break; + case 0: + fprintf (file, "0"); break; + default: + fprintf (file, "?"); break; + } +#endif + count++; + } + fprintf (file, "\n"); + fprintf (file, "\t%p %-10s\t%10d frags\n", (void *) frchp, + segment_name (frchp->frch_seg), count); + } +} + +/* end of subsegs.c */ diff --git a/contrib/binutils-2.14/gas/subsegs.h b/contrib/binutils-2.14/gas/subsegs.h new file mode 100644 index 0000000000..9a5abb019c --- /dev/null +++ b/contrib/binutils-2.14/gas/subsegs.h @@ -0,0 +1,155 @@ +/* subsegs.h -> subsegs.c + Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1998, 2000 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* + * For every sub-segment the user mentions in the ASsembler program, + * we make one struct frchain. Each sub-segment has exactly one struct frchain + * and vice versa. + * + * Struct frchain's are forward chained (in ascending order of sub-segment + * code number). The chain runs through frch_next of each subsegment. + * This makes it hard to find a subsegment's frags + * if programmer uses a lot of them. Most programs only use text0 and + * data0, so they don't suffer. At least this way: + * (1) There are no "arbitrary" restrictions on how many subsegments + * can be programmed; + * (2) Subsegments' frchain-s are (later) chained together in the order in + * which they are emitted for object file viz text then data. + * + * From each struct frchain dangles a chain of struct frags. The frags + * represent code fragments, for that sub-segment, forward chained. + */ + +#include "obstack.h" + +struct frchain /* control building of a frag chain */ +{ /* FRCH = FRagment CHain control */ + struct frag *frch_root; /* 1st struct frag in chain, or NULL */ + struct frag *frch_last; /* last struct frag in chain, or NULL */ + struct frchain *frch_next; /* next in chain of struct frchain-s */ + segT frch_seg; /* SEG_TEXT or SEG_DATA. */ + subsegT frch_subseg; /* subsegment number of this chain */ +#ifdef BFD_ASSEMBLER + fixS *fix_root; /* Root of fixups for this subsegment. */ + fixS *fix_tail; /* Last fixup for this subsegment. */ +#endif + struct obstack frch_obstack; /* for objects in this frag chain */ + fragS *frch_frag_now; /* frag_now for this subsegment */ +}; + +typedef struct frchain frchainS; + +/* All subsegments' chains hang off here. NULL means no frchains yet. */ +extern frchainS *frchain_root; + +/* Frchain we are assembling into now. That is, the current segment's + frag chain, even if it contains no (complete) frags. */ +extern frchainS *frchain_now; + +typedef struct segment_info_struct { + frchainS *frchainP; + unsigned int hadone : 1; + + /* This field is set if this is a .bss section which does not really + have any contents. Once upon a time a .bss section did not have + any frags, but that is no longer true. This field prevent the + SEC_HAS_CONTENTS flag from being set for the section even if + there are frags. */ + unsigned int bss : 1; + + int user_stuff; + + /* Fixups for this segment. If BFD_ASSEMBLER, this is only valid + after the frchains are run together. */ + fixS *fix_root; + fixS *fix_tail; + +#if defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + struct internal_scnhdr scnhdr; + enum linkonce_type linkonce; + const char *name; +#endif + + symbolS *dot; + + struct lineno_list *lineno_list_head; + struct lineno_list *lineno_list_tail; + +#ifdef BFD_ASSEMBLER + /* Which BFD section does this gas segment correspond to? */ + asection *bfd_section; + + /* NULL, or pointer to the gas symbol that is the section symbol for + this section. sym->bsym and bfd_section->symbol should be the same. */ + symbolS *sym; +#endif + + union { + /* Current size of section holding stabs strings. */ + unsigned long stab_string_size; + /* Initial frag for ELF. */ + char *p; + } + stabu; + +#ifdef NEED_LITERAL_POOL + unsigned long literal_pool_size; +#endif + +#ifdef TC_SEGMENT_INFO_TYPE + TC_SEGMENT_INFO_TYPE tc_segment_info_data; +#endif +} segment_info_type; + +#ifdef BFD_ASSEMBLER + +extern segment_info_type *seg_info PARAMS ((segT)); +extern symbolS *section_symbol PARAMS ((segT)); + +#else /* ! BFD_ASSEMBLER */ + +#ifdef MANY_SEGMENTS + +extern segment_info_type segment_info[]; + +#define seg_info(SEC) (&segment_info[SEC]) + +#else + +/* Sentinel for frchain crawling. Points to the 1st data-segment + frchain. (Which is pointed to by the last text-segment frchain.) */ +extern frchainS *data0_frchainP; +extern frchainS *bss0_frchainP; + +/* Dummy so stuff can compile. Should never be used. */ +struct seg_info_trash { + struct { + unsigned stab_string_size : 1; + } stabu; + unsigned hadone : 1; +}; +#define seg_info(S) (abort (), (struct seg_info_trash *) 0) + +#endif + +#endif /* ! BFD_ASSEMBLER */ + +extern void subsegs_print_statistics PARAMS ((FILE *)); diff --git a/contrib/binutils-2.14/gas/symbols.c b/contrib/binutils-2.14/gas/symbols.c new file mode 100644 index 0000000000..59658dff0d --- /dev/null +++ b/contrib/binutils-2.14/gas/symbols.c @@ -0,0 +1,2664 @@ +/* symbols.c -symbol table- + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, + 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* #define DEBUG_SYMS / * to debug symbol list maintenance. */ + +#include "as.h" + +#include "safe-ctype.h" +#include "obstack.h" /* For "symbols.h" */ +#include "subsegs.h" + +#include "struc-symbol.h" + +/* This is non-zero if symbols are case sensitive, which is the + default. */ +int symbols_case_sensitive = 1; + +#ifndef WORKING_DOT_WORD +extern int new_broken_words; +#endif + +/* symbol-name => struct symbol pointer */ +static struct hash_control *sy_hash; + +/* Table of local symbols. */ +static struct hash_control *local_hash; + +/* Below are commented in "symbols.h". */ +symbolS *symbol_rootP; +symbolS *symbol_lastP; +symbolS abs_symbol; + +#ifdef DEBUG_SYMS +#define debug_verify_symchain verify_symbol_chain +#else +#define debug_verify_symchain(root, last) ((void) 0) +#endif + +#define DOLLAR_LABEL_CHAR '\001' +#define LOCAL_LABEL_CHAR '\002' + +struct obstack notes; + +static char *save_symbol_name PARAMS ((const char *)); +static void fb_label_init PARAMS ((void)); +static long dollar_label_instance PARAMS ((long)); +static long fb_label_instance PARAMS ((long)); + +static void print_binary PARAMS ((FILE *, const char *, expressionS *)); +static void report_op_error PARAMS ((symbolS *, symbolS *, symbolS *)); + +/* Return a pointer to a new symbol. Die if we can't make a new + symbol. Fill in the symbol's values. Add symbol to end of symbol + chain. + + This function should be called in the general case of creating a + symbol. However, if the output file symbol table has already been + set, and you are certain that this symbol won't be wanted in the + output file, you can call symbol_create. */ + +symbolS * +symbol_new (name, segment, valu, frag) + const char *name; + segT segment; + valueT valu; + fragS *frag; +{ + symbolS *symbolP = symbol_create (name, segment, valu, frag); + + /* Link to end of symbol chain. */ +#ifdef BFD_ASSEMBLER + { + extern int symbol_table_frozen; + if (symbol_table_frozen) + abort (); + } +#endif + symbol_append (symbolP, symbol_lastP, &symbol_rootP, &symbol_lastP); + + return symbolP; +} + +/* Save a symbol name on a permanent obstack, and convert it according + to the object file format. */ + +static char * +save_symbol_name (name) + const char *name; +{ + unsigned int name_length; + char *ret; + + name_length = strlen (name) + 1; /* +1 for \0. */ + obstack_grow (¬es, name, name_length); + ret = obstack_finish (¬es); + +#ifdef STRIP_UNDERSCORE + if (ret[0] == '_') + ++ret; +#endif + +#ifdef tc_canonicalize_symbol_name + ret = tc_canonicalize_symbol_name (ret); +#endif + + if (! symbols_case_sensitive) + { + char *s; + + for (s = ret; *s != '\0'; s++) + *s = TOUPPER (*s); + } + + return ret; +} + +symbolS * +symbol_create (name, segment, valu, frag) + const char *name; /* It is copied, the caller can destroy/modify. */ + segT segment; /* Segment identifier (SEG_). */ + valueT valu; /* Symbol value. */ + fragS *frag; /* Associated fragment. */ +{ + char *preserved_copy_of_name; + symbolS *symbolP; + + preserved_copy_of_name = save_symbol_name (name); + + symbolP = (symbolS *) obstack_alloc (¬es, sizeof (symbolS)); + + /* symbol must be born in some fixed state. This seems as good as any. */ + memset (symbolP, 0, sizeof (symbolS)); + +#ifdef BFD_ASSEMBLER + symbolP->bsym = bfd_make_empty_symbol (stdoutput); + if (symbolP->bsym == NULL) + as_perror ("%s", "bfd_make_empty_symbol"); + symbolP->bsym->udata.p = (PTR) symbolP; +#endif + S_SET_NAME (symbolP, preserved_copy_of_name); + + S_SET_SEGMENT (symbolP, segment); + S_SET_VALUE (symbolP, valu); + symbol_clear_list_pointers (symbolP); + + symbolP->sy_frag = frag; +#ifndef BFD_ASSEMBLER + symbolP->sy_number = ~0; + symbolP->sy_name_offset = (unsigned int) ~0; +#endif + + obj_symbol_new_hook (symbolP); + +#ifdef tc_symbol_new_hook + tc_symbol_new_hook (symbolP); +#endif + + return symbolP; +} + +#ifdef BFD_ASSEMBLER + +/* Local symbol support. If we can get away with it, we keep only a + small amount of information for local symbols. */ + +static struct local_symbol *local_symbol_make PARAMS ((const char *, segT, + valueT, fragS *)); +static symbolS *local_symbol_convert PARAMS ((struct local_symbol *)); + +/* Used for statistics. */ + +static unsigned long local_symbol_count; +static unsigned long local_symbol_conversion_count; + +/* This macro is called with a symbol argument passed by reference. + It returns whether this is a local symbol. If necessary, it + changes its argument to the real symbol. */ + +#define LOCAL_SYMBOL_CHECK(s) \ + (s->bsym == NULL \ + ? (local_symbol_converted_p ((struct local_symbol *) s) \ + ? (s = local_symbol_get_real_symbol ((struct local_symbol *) s), \ + 0) \ + : 1) \ + : 0) + +/* Create a local symbol and insert it into the local hash table. */ + +static struct local_symbol * +local_symbol_make (name, section, value, frag) + const char *name; + segT section; + valueT value; + fragS *frag; +{ + char *name_copy; + struct local_symbol *ret; + + ++local_symbol_count; + + name_copy = save_symbol_name (name); + + ret = (struct local_symbol *) obstack_alloc (¬es, sizeof *ret); + ret->lsy_marker = NULL; + ret->lsy_name = name_copy; + ret->lsy_section = section; + local_symbol_set_frag (ret, frag); + ret->lsy_value = value; + + hash_jam (local_hash, name_copy, (PTR) ret); + + return ret; +} + +/* Convert a local symbol into a real symbol. Note that we do not + reclaim the space used by the local symbol. */ + +static symbolS * +local_symbol_convert (locsym) + struct local_symbol *locsym; +{ + symbolS *ret; + + assert (locsym->lsy_marker == NULL); + if (local_symbol_converted_p (locsym)) + return local_symbol_get_real_symbol (locsym); + + ++local_symbol_conversion_count; + + ret = symbol_new (locsym->lsy_name, locsym->lsy_section, locsym->lsy_value, + local_symbol_get_frag (locsym)); + + if (local_symbol_resolved_p (locsym)) + ret->sy_resolved = 1; + + /* Local symbols are always either defined or used. */ + ret->sy_used = 1; + +#ifdef TC_LOCAL_SYMFIELD_CONVERT + TC_LOCAL_SYMFIELD_CONVERT (locsym, ret); +#endif + + symbol_table_insert (ret); + + local_symbol_mark_converted (locsym); + local_symbol_set_real_symbol (locsym, ret); + + hash_jam (local_hash, locsym->lsy_name, NULL); + + return ret; +} + +#else /* ! BFD_ASSEMBLER */ + +#define LOCAL_SYMBOL_CHECK(s) 0 +#define local_symbol_convert(s) ((symbolS *) s) + +#endif /* ! BFD_ASSEMBLER */ + +/* We have just seen ":". + Creates a struct symbol unless it already exists. + + Gripes if we are redefining a symbol incompatibly (and ignores it). */ + +symbolS * +colon (sym_name) /* Just seen "x:" - rattle symbols & frags. */ + const char *sym_name; /* Symbol name, as a cannonical string. */ + /* We copy this string: OK to alter later. */ +{ + register symbolS *symbolP; /* Symbol we are working with. */ + + /* Sun local labels go out of scope whenever a non-local symbol is + defined. */ + if (LOCAL_LABELS_DOLLAR) + { + int local; + +#ifdef BFD_ASSEMBLER + local = bfd_is_local_label_name (stdoutput, sym_name); +#else + local = LOCAL_LABEL (sym_name); +#endif + + if (! local) + dollar_label_clear (); + } + +#ifndef WORKING_DOT_WORD + if (new_broken_words) + { + struct broken_word *a; + int possible_bytes; + fragS *frag_tmp; + char *frag_opcode; + + extern const int md_short_jump_size; + extern const int md_long_jump_size; + + if (now_seg == absolute_section) + { + as_bad (_("cannot define symbol `%s' in absolute section"), sym_name); + return NULL; + } + + possible_bytes = (md_short_jump_size + + new_broken_words * md_long_jump_size); + + frag_tmp = frag_now; + frag_opcode = frag_var (rs_broken_word, + possible_bytes, + possible_bytes, + (relax_substateT) 0, + (symbolS *) broken_words, + (offsetT) 0, + NULL); + + /* We want to store the pointer to where to insert the jump + table in the fr_opcode of the rs_broken_word frag. This + requires a little hackery. */ + while (frag_tmp + && (frag_tmp->fr_type != rs_broken_word + || frag_tmp->fr_opcode)) + frag_tmp = frag_tmp->fr_next; + know (frag_tmp); + frag_tmp->fr_opcode = frag_opcode; + new_broken_words = 0; + + for (a = broken_words; a && a->dispfrag == 0; a = a->next_broken_word) + a->dispfrag = frag_tmp; + } +#endif /* WORKING_DOT_WORD */ + + if ((symbolP = symbol_find (sym_name)) != 0) + { +#ifdef RESOLVE_SYMBOL_REDEFINITION + if (RESOLVE_SYMBOL_REDEFINITION (symbolP)) + return symbolP; +#endif + /* Now check for undefined symbols. */ + if (LOCAL_SYMBOL_CHECK (symbolP)) + { +#ifdef BFD_ASSEMBLER + struct local_symbol *locsym = (struct local_symbol *) symbolP; + + if (locsym->lsy_section != undefined_section + && (local_symbol_get_frag (locsym) != frag_now + || locsym->lsy_section != now_seg + || locsym->lsy_value != frag_now_fix ())) + { + as_bad (_("symbol `%s' is already defined"), sym_name); + return symbolP; + } + + locsym->lsy_section = now_seg; + local_symbol_set_frag (locsym, frag_now); + locsym->lsy_value = frag_now_fix (); +#endif + } + else if (!S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP)) + { + if (S_GET_VALUE (symbolP) == 0) + { + symbolP->sy_frag = frag_now; +#ifdef OBJ_VMS + S_SET_OTHER (symbolP, const_flag); +#endif + S_SET_VALUE (symbolP, (valueT) frag_now_fix ()); + S_SET_SEGMENT (symbolP, now_seg); +#ifdef N_UNDF + know (N_UNDF == 0); +#endif /* if we have one, it better be zero. */ + + } + else + { + /* There are still several cases to check: + + A .comm/.lcomm symbol being redefined as initialized + data is OK + + A .comm/.lcomm symbol being redefined with a larger + size is also OK + + This only used to be allowed on VMS gas, but Sun cc + on the sparc also depends on it. */ + + if (((!S_IS_DEBUG (symbolP) + && (!S_IS_DEFINED (symbolP) || S_IS_COMMON (symbolP)) + && S_IS_EXTERNAL (symbolP)) + || S_GET_SEGMENT (symbolP) == bss_section) + && (now_seg == data_section + || now_seg == S_GET_SEGMENT (symbolP))) + { + /* Select which of the 2 cases this is. */ + if (now_seg != data_section) + { + /* New .comm for prev .comm symbol. + + If the new size is larger we just change its + value. If the new size is smaller, we ignore + this symbol. */ + if (S_GET_VALUE (symbolP) + < ((unsigned) frag_now_fix ())) + { + S_SET_VALUE (symbolP, (valueT) frag_now_fix ()); + } + } + else + { + /* It is a .comm/.lcomm being converted to initialized + data. */ + symbolP->sy_frag = frag_now; +#ifdef OBJ_VMS + S_SET_OTHER (symbolP, const_flag); +#endif + S_SET_VALUE (symbolP, (valueT) frag_now_fix ()); + S_SET_SEGMENT (symbolP, now_seg); /* Keep N_EXT bit. */ + } + } + else + { +#if (!defined (OBJ_AOUT) && !defined (OBJ_MAYBE_AOUT) \ + && !defined (OBJ_BOUT) && !defined (OBJ_MAYBE_BOUT)) + static const char *od_buf = ""; +#else + char od_buf[100]; + od_buf[0] = '\0'; +#ifdef BFD_ASSEMBLER + if (OUTPUT_FLAVOR == bfd_target_aout_flavour) +#endif + sprintf (od_buf, "%d.%d.", + S_GET_OTHER (symbolP), + S_GET_DESC (symbolP)); +#endif + as_bad (_("symbol `%s' is already defined as \"%s\"/%s%ld"), + sym_name, + segment_name (S_GET_SEGMENT (symbolP)), + od_buf, + (long) S_GET_VALUE (symbolP)); + } + } /* if the undefined symbol has no value */ + } + else + { + /* Don't blow up if the definition is the same. */ + if (!(frag_now == symbolP->sy_frag + && S_GET_VALUE (symbolP) == frag_now_fix () + && S_GET_SEGMENT (symbolP) == now_seg)) + as_bad (_("symbol `%s' is already defined"), sym_name); + } + + } +#ifdef BFD_ASSEMBLER + else if (! flag_keep_locals && bfd_is_local_label_name (stdoutput, sym_name)) + { + symbolP = (symbolS *) local_symbol_make (sym_name, now_seg, + (valueT) frag_now_fix (), + frag_now); + } +#endif /* BFD_ASSEMBLER */ + else + { + symbolP = symbol_new (sym_name, now_seg, (valueT) frag_now_fix (), + frag_now); +#ifdef OBJ_VMS + S_SET_OTHER (symbolP, const_flag); +#endif /* OBJ_VMS */ + + symbol_table_insert (symbolP); + } + + if (mri_common_symbol != NULL) + { + /* This symbol is actually being defined within an MRI common + section. This requires special handling. */ + if (LOCAL_SYMBOL_CHECK (symbolP)) + symbolP = local_symbol_convert ((struct local_symbol *) symbolP); + symbolP->sy_value.X_op = O_symbol; + symbolP->sy_value.X_add_symbol = mri_common_symbol; + symbolP->sy_value.X_add_number = S_GET_VALUE (mri_common_symbol); + symbolP->sy_frag = &zero_address_frag; + S_SET_SEGMENT (symbolP, expr_section); + symbolP->sy_mri_common = 1; + } + +#ifdef tc_frob_label + tc_frob_label (symbolP); +#endif +#ifdef obj_frob_label + obj_frob_label (symbolP); +#endif + + return symbolP; +} + +/* Die if we can't insert the symbol. */ + +void +symbol_table_insert (symbolP) + symbolS *symbolP; +{ + register const char *error_string; + + know (symbolP); + know (S_GET_NAME (symbolP)); + + if (LOCAL_SYMBOL_CHECK (symbolP)) + { + error_string = hash_jam (local_hash, S_GET_NAME (symbolP), + (PTR) symbolP); + if (error_string != NULL) + as_fatal (_("inserting \"%s\" into symbol table failed: %s"), + S_GET_NAME (symbolP), error_string); + return; + } + + if ((error_string = hash_jam (sy_hash, S_GET_NAME (symbolP), (PTR) symbolP))) + { + as_fatal (_("inserting \"%s\" into symbol table failed: %s"), + S_GET_NAME (symbolP), error_string); + } /* on error */ +} + +/* If a symbol name does not exist, create it as undefined, and insert + it into the symbol table. Return a pointer to it. */ + +symbolS * +symbol_find_or_make (name) + const char *name; +{ + register symbolS *symbolP; + + symbolP = symbol_find (name); + + if (symbolP == NULL) + { +#ifdef BFD_ASSEMBLER + if (! flag_keep_locals && bfd_is_local_label_name (stdoutput, name)) + { + symbolP = md_undefined_symbol ((char *) name); + if (symbolP != NULL) + return symbolP; + + symbolP = (symbolS *) local_symbol_make (name, undefined_section, + (valueT) 0, + &zero_address_frag); + return symbolP; + } +#endif + + symbolP = symbol_make (name); + + symbol_table_insert (symbolP); + } /* if symbol wasn't found */ + + return (symbolP); +} + +symbolS * +symbol_make (name) + const char *name; +{ + symbolS *symbolP; + + /* Let the machine description default it, e.g. for register names. */ + symbolP = md_undefined_symbol ((char *) name); + + if (!symbolP) + symbolP = symbol_new (name, undefined_section, (valueT) 0, &zero_address_frag); + + return (symbolP); +} + +/* Implement symbol table lookup. + In: A symbol's name as a string: '\0' can't be part of a symbol name. + Out: NULL if the name was not in the symbol table, else the address + of a struct symbol associated with that name. */ + +symbolS * +symbol_find (name) + const char *name; +{ +#ifdef STRIP_UNDERSCORE + return (symbol_find_base (name, 1)); +#else /* STRIP_UNDERSCORE */ + return (symbol_find_base (name, 0)); +#endif /* STRIP_UNDERSCORE */ +} + +symbolS * +symbol_find_exact (name) + const char *name; +{ +#ifdef BFD_ASSEMBLER + { + struct local_symbol *locsym; + + locsym = (struct local_symbol *) hash_find (local_hash, name); + if (locsym != NULL) + return (symbolS *) locsym; + } +#endif + + return ((symbolS *) hash_find (sy_hash, name)); +} + +symbolS * +symbol_find_base (name, strip_underscore) + const char *name; + int strip_underscore; +{ + if (strip_underscore && *name == '_') + name++; + +#ifdef tc_canonicalize_symbol_name + { + char *copy; + size_t len = strlen (name) + 1; + + copy = (char *) alloca (len); + memcpy (copy, name, len); + name = tc_canonicalize_symbol_name (copy); + } +#endif + + if (! symbols_case_sensitive) + { + char *copy; + const char *orig; + unsigned char c; + + orig = name; + name = copy = (char *) alloca (strlen (name) + 1); + + while ((c = *orig++) != '\0') + { + *copy++ = TOUPPER (c); + } + *copy = '\0'; + } + + return symbol_find_exact (name); +} + +/* Once upon a time, symbols were kept in a singly linked list. At + least coff needs to be able to rearrange them from time to time, for + which a doubly linked list is much more convenient. Loic did these + as macros which seemed dangerous to me so they're now functions. + xoxorich. */ + +/* Link symbol ADDME after symbol TARGET in the chain. */ + +void +symbol_append (addme, target, rootPP, lastPP) + symbolS *addme; + symbolS *target; + symbolS **rootPP; + symbolS **lastPP; +{ + if (LOCAL_SYMBOL_CHECK (addme)) + abort (); + if (target != NULL && LOCAL_SYMBOL_CHECK (target)) + abort (); + + if (target == NULL) + { + know (*rootPP == NULL); + know (*lastPP == NULL); + addme->sy_next = NULL; +#ifdef SYMBOLS_NEED_BACKPOINTERS + addme->sy_previous = NULL; +#endif + *rootPP = addme; + *lastPP = addme; + return; + } /* if the list is empty */ + + if (target->sy_next != NULL) + { +#ifdef SYMBOLS_NEED_BACKPOINTERS + target->sy_next->sy_previous = addme; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + } + else + { + know (*lastPP == target); + *lastPP = addme; + } /* if we have a next */ + + addme->sy_next = target->sy_next; + target->sy_next = addme; + +#ifdef SYMBOLS_NEED_BACKPOINTERS + addme->sy_previous = target; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + + debug_verify_symchain (symbol_rootP, symbol_lastP); +} + +/* Set the chain pointers of SYMBOL to null. */ + +void +symbol_clear_list_pointers (symbolP) + symbolS *symbolP; +{ + if (LOCAL_SYMBOL_CHECK (symbolP)) + abort (); + symbolP->sy_next = NULL; +#ifdef SYMBOLS_NEED_BACKPOINTERS + symbolP->sy_previous = NULL; +#endif +} + +#ifdef SYMBOLS_NEED_BACKPOINTERS +/* Remove SYMBOLP from the list. */ + +void +symbol_remove (symbolP, rootPP, lastPP) + symbolS *symbolP; + symbolS **rootPP; + symbolS **lastPP; +{ + if (LOCAL_SYMBOL_CHECK (symbolP)) + abort (); + + if (symbolP == *rootPP) + { + *rootPP = symbolP->sy_next; + } /* if it was the root */ + + if (symbolP == *lastPP) + { + *lastPP = symbolP->sy_previous; + } /* if it was the tail */ + + if (symbolP->sy_next != NULL) + { + symbolP->sy_next->sy_previous = symbolP->sy_previous; + } /* if not last */ + + if (symbolP->sy_previous != NULL) + { + symbolP->sy_previous->sy_next = symbolP->sy_next; + } /* if not first */ + + debug_verify_symchain (*rootPP, *lastPP); +} + +/* Link symbol ADDME before symbol TARGET in the chain. */ + +void +symbol_insert (addme, target, rootPP, lastPP) + symbolS *addme; + symbolS *target; + symbolS **rootPP; + symbolS **lastPP ATTRIBUTE_UNUSED; +{ + if (LOCAL_SYMBOL_CHECK (addme)) + abort (); + if (LOCAL_SYMBOL_CHECK (target)) + abort (); + + if (target->sy_previous != NULL) + { + target->sy_previous->sy_next = addme; + } + else + { + know (*rootPP == target); + *rootPP = addme; + } /* if not first */ + + addme->sy_previous = target->sy_previous; + target->sy_previous = addme; + addme->sy_next = target; + + debug_verify_symchain (*rootPP, *lastPP); +} + +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +void +verify_symbol_chain (rootP, lastP) + symbolS *rootP; + symbolS *lastP; +{ + symbolS *symbolP = rootP; + + if (symbolP == NULL) + return; + + for (; symbol_next (symbolP) != NULL; symbolP = symbol_next (symbolP)) + { +#ifdef BFD_ASSEMBLER + assert (symbolP->bsym != NULL); +#endif +#ifdef SYMBOLS_NEED_BACKPOINTERS + assert (symbolP->sy_next->sy_previous == symbolP); +#else + /* Walk the list anyways, to make sure pointers are still good. */ + ; +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + } + + assert (lastP == symbolP); +} + +void +verify_symbol_chain_2 (sym) + symbolS *sym; +{ + symbolS *p = sym, *n = sym; +#ifdef SYMBOLS_NEED_BACKPOINTERS + while (symbol_previous (p)) + p = symbol_previous (p); +#endif + while (symbol_next (n)) + n = symbol_next (n); + verify_symbol_chain (p, n); +} + +static void +report_op_error (symp, left, right) + symbolS *symp; + symbolS *left, *right; +{ + char *file; + unsigned int line; + segT seg_left = S_GET_SEGMENT (left); + segT seg_right = right ? S_GET_SEGMENT (right) : 0; + + if (expr_symbol_where (symp, &file, &line)) + { + if (seg_left == undefined_section) + as_bad_where (file, line, + _("undefined symbol `%s' in operation"), + S_GET_NAME (left)); + if (seg_right == undefined_section) + as_bad_where (file, line, + _("undefined symbol `%s' in operation"), + S_GET_NAME (right)); + if (seg_left != undefined_section + && seg_right != undefined_section) + { + if (right) + as_bad_where (file, line, + _("invalid sections for operation on `%s' and `%s'"), + S_GET_NAME (left), S_GET_NAME (right)); + else + as_bad_where (file, line, + _("invalid section for operation on `%s'"), + S_GET_NAME (left)); + } + + } + else + { + if (seg_left == undefined_section) + as_bad (_("undefined symbol `%s' in operation setting `%s'"), + S_GET_NAME (left), S_GET_NAME (symp)); + if (seg_right == undefined_section) + as_bad (_("undefined symbol `%s' in operation setting `%s'"), + S_GET_NAME (right), S_GET_NAME (symp)); + if (seg_left != undefined_section + && seg_right != undefined_section) + { + if (right) + as_bad_where (file, line, + _("invalid sections for operation on `%s' and `%s' setting `%s'"), + S_GET_NAME (left), S_GET_NAME (right), S_GET_NAME (symp)); + else + as_bad_where (file, line, + _("invalid section for operation on `%s' setting `%s'"), + S_GET_NAME (left), S_GET_NAME (symp)); + } + } +} + +/* Resolve the value of a symbol. This is called during the final + pass over the symbol table to resolve any symbols with complex + values. */ + +valueT +resolve_symbol_value (symp) + symbolS *symp; +{ + int resolved; + valueT final_val = 0; + segT final_seg; + +#ifdef BFD_ASSEMBLER + if (LOCAL_SYMBOL_CHECK (symp)) + { + struct local_symbol *locsym = (struct local_symbol *) symp; + + final_val = locsym->lsy_value; + if (local_symbol_resolved_p (locsym)) + return final_val; + + final_val += local_symbol_get_frag (locsym)->fr_address / OCTETS_PER_BYTE; + + if (finalize_syms) + { + locsym->lsy_value = final_val; + local_symbol_mark_resolved (locsym); + } + + return final_val; + } +#endif + + if (symp->sy_resolved) + { + if (symp->sy_value.X_op == O_constant) + return (valueT) symp->sy_value.X_add_number; + else + return 0; + } + + resolved = 0; + final_seg = S_GET_SEGMENT (symp); + + if (symp->sy_resolving) + { + if (finalize_syms) + as_bad (_("symbol definition loop encountered at `%s'"), + S_GET_NAME (symp)); + final_val = 0; + resolved = 1; + } + else + { + symbolS *add_symbol, *op_symbol; + offsetT left, right; + segT seg_left, seg_right; + operatorT op; + + symp->sy_resolving = 1; + + /* Help out with CSE. */ + add_symbol = symp->sy_value.X_add_symbol; + op_symbol = symp->sy_value.X_op_symbol; + final_val = symp->sy_value.X_add_number; + op = symp->sy_value.X_op; + + switch (op) + { + default: + BAD_CASE (op); + break; + + case O_absent: + final_val = 0; + /* Fall through. */ + + case O_constant: + final_val += symp->sy_frag->fr_address / OCTETS_PER_BYTE; + if (final_seg == expr_section) + final_seg = absolute_section; + resolved = 1; + break; + + case O_symbol: + case O_symbol_rva: + left = resolve_symbol_value (add_symbol); + seg_left = S_GET_SEGMENT (add_symbol); + if (finalize_syms) + symp->sy_value.X_op_symbol = NULL; + + do_symbol: + if (symp->sy_mri_common) + { + /* This is a symbol inside an MRI common section. The + relocation routines are going to handle it specially. + Don't change the value. */ + resolved = symbol_resolved_p (add_symbol); + break; + } + + if (finalize_syms && final_val == 0) + { + if (LOCAL_SYMBOL_CHECK (add_symbol)) + add_symbol = local_symbol_convert ((struct local_symbol *) + add_symbol); + copy_symbol_attributes (symp, add_symbol); + } + + /* If we have equated this symbol to an undefined or common + symbol, keep X_op set to O_symbol, and don't change + X_add_number. This permits the routine which writes out + relocation to detect this case, and convert the + relocation to be against the symbol to which this symbol + is equated. */ + if (! S_IS_DEFINED (add_symbol) || S_IS_COMMON (add_symbol)) + { + if (finalize_syms) + { + symp->sy_value.X_op = O_symbol; + symp->sy_value.X_add_symbol = add_symbol; + symp->sy_value.X_add_number = final_val; + /* Use X_op_symbol as a flag. */ + symp->sy_value.X_op_symbol = add_symbol; + final_seg = seg_left; + } + final_val = 0; + resolved = symbol_resolved_p (add_symbol); + symp->sy_resolving = 0; + goto exit_dont_set_value; + } + else if (finalize_syms && final_seg == expr_section + && seg_left != expr_section) + { + /* If the symbol is an expression symbol, do similarly + as for undefined and common syms above. Handles + "sym +/- expr" where "expr" cannot be evaluated + immediately, and we want relocations to be against + "sym", eg. because it is weak. */ + symp->sy_value.X_op = O_symbol; + symp->sy_value.X_add_symbol = add_symbol; + symp->sy_value.X_add_number = final_val; + symp->sy_value.X_op_symbol = add_symbol; + final_seg = seg_left; + final_val += symp->sy_frag->fr_address + left; + resolved = symbol_resolved_p (add_symbol); + symp->sy_resolving = 0; + goto exit_dont_set_value; + } + else + { + final_val += symp->sy_frag->fr_address + left; + if (final_seg == expr_section || final_seg == undefined_section) + final_seg = seg_left; + } + + resolved = symbol_resolved_p (add_symbol); + break; + + case O_uminus: + case O_bit_not: + case O_logical_not: + left = resolve_symbol_value (add_symbol); + seg_left = S_GET_SEGMENT (add_symbol); + + /* By reducing these to the relevant dyadic operator, we get + !S -> S == 0 permitted on anything, + -S -> 0 - S only permitted on absolute + ~S -> S ^ ~0 only permitted on absolute */ + if (op != O_logical_not && seg_left != absolute_section + && finalize_syms) + report_op_error (symp, add_symbol, NULL); + + if (final_seg == expr_section || final_seg == undefined_section) + final_seg = absolute_section; + + if (op == O_uminus) + left = -left; + else if (op == O_logical_not) + left = !left; + else + left = ~left; + + final_val += left + symp->sy_frag->fr_address; + + resolved = symbol_resolved_p (add_symbol); + break; + + case O_multiply: + case O_divide: + case O_modulus: + case O_left_shift: + case O_right_shift: + case O_bit_inclusive_or: + case O_bit_or_not: + case O_bit_exclusive_or: + case O_bit_and: + case O_add: + case O_subtract: + case O_eq: + case O_ne: + case O_lt: + case O_le: + case O_ge: + case O_gt: + case O_logical_and: + case O_logical_or: + left = resolve_symbol_value (add_symbol); + right = resolve_symbol_value (op_symbol); + seg_left = S_GET_SEGMENT (add_symbol); + seg_right = S_GET_SEGMENT (op_symbol); + + /* Simplify addition or subtraction of a constant by folding the + constant into X_add_number. */ + if (op == O_add) + { + if (seg_right == absolute_section) + { + final_val += right; + goto do_symbol; + } + else if (seg_left == absolute_section) + { + final_val += left; + add_symbol = op_symbol; + left = right; + seg_left = seg_right; + goto do_symbol; + } + } + else if (op == O_subtract) + { + if (seg_right == absolute_section) + { + final_val -= right; + goto do_symbol; + } + } + + /* Equality and non-equality tests are permitted on anything. + Subtraction, and other comparison operators are permitted if + both operands are in the same section. Otherwise, both + operands must be absolute. We already handled the case of + addition or subtraction of a constant above. This will + probably need to be changed for an object file format which + supports arbitrary expressions, such as IEEE-695. + + Don't emit messages unless we're finalizing the symbol value, + otherwise we may get the same message multiple times. */ + if (finalize_syms + && !(seg_left == absolute_section + && seg_right == absolute_section) + && !(op == O_eq || op == O_ne) + && !((op == O_subtract + || op == O_lt || op == O_le || op == O_ge || op == O_gt) + && seg_left == seg_right + && (seg_left != undefined_section + || add_symbol == op_symbol))) + report_op_error (symp, add_symbol, op_symbol); + + if (final_seg == expr_section || final_seg == undefined_section) + final_seg = absolute_section; + + /* Check for division by zero. */ + if ((op == O_divide || op == O_modulus) && right == 0) + { + /* If seg_right is not absolute_section, then we've + already issued a warning about using a bad symbol. */ + if (seg_right == absolute_section && finalize_syms) + { + char *file; + unsigned int line; + + if (expr_symbol_where (symp, &file, &line)) + as_bad_where (file, line, _("division by zero")); + else + as_bad (_("division by zero when setting `%s'"), + S_GET_NAME (symp)); + } + + right = 1; + } + + switch (symp->sy_value.X_op) + { + case O_multiply: left *= right; break; + case O_divide: left /= right; break; + case O_modulus: left %= right; break; + case O_left_shift: left <<= right; break; + case O_right_shift: left >>= right; break; + case O_bit_inclusive_or: left |= right; break; + case O_bit_or_not: left |= ~right; break; + case O_bit_exclusive_or: left ^= right; break; + case O_bit_and: left &= right; break; + case O_add: left += right; break; + case O_subtract: left -= right; break; + case O_eq: + case O_ne: + left = (left == right && seg_left == seg_right + && (seg_left != undefined_section + || add_symbol == op_symbol) + ? ~ (offsetT) 0 : 0); + if (symp->sy_value.X_op == O_ne) + left = ~left; + break; + case O_lt: left = left < right ? ~ (offsetT) 0 : 0; break; + case O_le: left = left <= right ? ~ (offsetT) 0 : 0; break; + case O_ge: left = left >= right ? ~ (offsetT) 0 : 0; break; + case O_gt: left = left > right ? ~ (offsetT) 0 : 0; break; + case O_logical_and: left = left && right; break; + case O_logical_or: left = left || right; break; + default: abort (); + } + + final_val += symp->sy_frag->fr_address + left; + if (final_seg == expr_section || final_seg == undefined_section) + { + if (seg_left == undefined_section + || seg_right == undefined_section) + final_seg = undefined_section; + else if (seg_left == absolute_section) + final_seg = seg_right; + else + final_seg = seg_left; + } + resolved = (symbol_resolved_p (add_symbol) + && symbol_resolved_p (op_symbol)); + break; + + case O_register: + case O_big: + case O_illegal: + /* Give an error (below) if not in expr_section. We don't + want to worry about expr_section symbols, because they + are fictional (they are created as part of expression + resolution), and any problems may not actually mean + anything. */ + break; + } + + symp->sy_resolving = 0; + } + + if (finalize_syms) + S_SET_VALUE (symp, final_val); + +exit_dont_set_value: + /* Always set the segment, even if not finalizing the value. + The segment is used to determine whether a symbol is defined. */ +#if defined (OBJ_AOUT) && ! defined (BFD_ASSEMBLER) + /* The old a.out backend does not handle S_SET_SEGMENT correctly + for a stab symbol, so we use this bad hack. */ + if (final_seg != S_GET_SEGMENT (symp)) +#endif + S_SET_SEGMENT (symp, final_seg); + + /* Don't worry if we can't resolve an expr_section symbol. */ + if (finalize_syms) + { + if (resolved) + symp->sy_resolved = 1; + else if (S_GET_SEGMENT (symp) != expr_section) + { + as_bad (_("can't resolve value for symbol `%s'"), + S_GET_NAME (symp)); + symp->sy_resolved = 1; + } + } + + return final_val; +} + +#ifdef BFD_ASSEMBLER + +static void resolve_local_symbol PARAMS ((const char *, PTR)); + +/* A static function passed to hash_traverse. */ + +static void +resolve_local_symbol (key, value) + const char *key ATTRIBUTE_UNUSED; + PTR value; +{ + if (value != NULL) + resolve_symbol_value (value); +} + +#endif + +/* Resolve all local symbols. */ + +void +resolve_local_symbol_values () +{ +#ifdef BFD_ASSEMBLER + hash_traverse (local_hash, resolve_local_symbol); +#endif +} + +/* Dollar labels look like a number followed by a dollar sign. Eg, "42$". + They are *really* local. That is, they go out of scope whenever we see a + label that isn't local. Also, like fb labels, there can be multiple + instances of a dollar label. Therefor, we name encode each instance with + the instance number, keep a list of defined symbols separate from the real + symbol table, and we treat these buggers as a sparse array. */ + +static long *dollar_labels; +static long *dollar_label_instances; +static char *dollar_label_defines; +static unsigned long dollar_label_count; +static unsigned long dollar_label_max; + +int +dollar_label_defined (label) + long label; +{ + long *i; + + know ((dollar_labels != NULL) || (dollar_label_count == 0)); + + for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) + if (*i == label) + return dollar_label_defines[i - dollar_labels]; + + /* If we get here, label isn't defined. */ + return 0; +} + +static long +dollar_label_instance (label) + long label; +{ + long *i; + + know ((dollar_labels != NULL) || (dollar_label_count == 0)); + + for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) + if (*i == label) + return (dollar_label_instances[i - dollar_labels]); + + /* If we get here, we haven't seen the label before. + Therefore its instance count is zero. */ + return 0; +} + +void +dollar_label_clear () +{ + memset (dollar_label_defines, '\0', (unsigned int) dollar_label_count); +} + +#define DOLLAR_LABEL_BUMP_BY 10 + +void +define_dollar_label (label) + long label; +{ + long *i; + + for (i = dollar_labels; i < dollar_labels + dollar_label_count; ++i) + if (*i == label) + { + ++dollar_label_instances[i - dollar_labels]; + dollar_label_defines[i - dollar_labels] = 1; + return; + } + + /* If we get to here, we don't have label listed yet. */ + + if (dollar_labels == NULL) + { + dollar_labels = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long)); + dollar_label_instances = (long *) xmalloc (DOLLAR_LABEL_BUMP_BY * sizeof (long)); + dollar_label_defines = xmalloc (DOLLAR_LABEL_BUMP_BY); + dollar_label_max = DOLLAR_LABEL_BUMP_BY; + dollar_label_count = 0; + } + else if (dollar_label_count == dollar_label_max) + { + dollar_label_max += DOLLAR_LABEL_BUMP_BY; + dollar_labels = (long *) xrealloc ((char *) dollar_labels, + dollar_label_max * sizeof (long)); + dollar_label_instances = (long *) xrealloc ((char *) dollar_label_instances, + dollar_label_max * sizeof (long)); + dollar_label_defines = xrealloc (dollar_label_defines, dollar_label_max); + } /* if we needed to grow */ + + dollar_labels[dollar_label_count] = label; + dollar_label_instances[dollar_label_count] = 1; + dollar_label_defines[dollar_label_count] = 1; + ++dollar_label_count; +} + +/* Caller must copy returned name: we re-use the area for the next name. + + The mth occurence of label n: is turned into the symbol "Ln^Am" + where n is the label number and m is the instance number. "L" makes + it a label discarded unless debugging and "^A"('\1') ensures no + ordinary symbol SHOULD get the same name as a local label + symbol. The first "4:" is "L4^A1" - the m numbers begin at 1. + + fb labels get the same treatment, except that ^B is used in place + of ^A. */ + +char * /* Return local label name. */ +dollar_label_name (n, augend) + register long n; /* we just saw "n$:" : n a number. */ + register int augend; /* 0 for current instance, 1 for new instance. */ +{ + long i; + /* Returned to caller, then copied. Used for created names ("4f"). */ + static char symbol_name_build[24]; + register char *p; + register char *q; + char symbol_name_temporary[20]; /* Build up a number, BACKWARDS. */ + + know (n >= 0); + know (augend == 0 || augend == 1); + p = symbol_name_build; +#ifdef LOCAL_LABEL_PREFIX + *p++ = LOCAL_LABEL_PREFIX; +#endif + *p++ = 'L'; + + /* Next code just does sprintf( {}, "%d", n); */ + /* Label number. */ + q = symbol_name_temporary; + for (*q++ = 0, i = n; i; ++q) + { + *q = i % 10 + '0'; + i /= 10; + } + while ((*p = *--q) != '\0') + ++p; + + *p++ = DOLLAR_LABEL_CHAR; /* ^A */ + + /* Instance number. */ + q = symbol_name_temporary; + for (*q++ = 0, i = dollar_label_instance (n) + augend; i; ++q) + { + *q = i % 10 + '0'; + i /= 10; + } + while ((*p++ = *--q) != '\0');; + + /* The label, as a '\0' ended string, starts at symbol_name_build. */ + return symbol_name_build; +} + +/* Sombody else's idea of local labels. They are made by "n:" where n + is any decimal digit. Refer to them with + "nb" for previous (backward) n: + or "nf" for next (forward) n:. + + We do a little better and let n be any number, not just a single digit, but + since the other guy's assembler only does ten, we treat the first ten + specially. + + Like someone else's assembler, we have one set of local label counters for + entire assembly, not one set per (sub)segment like in most assemblers. This + implies that one can refer to a label in another segment, and indeed some + crufty compilers have done just that. + + Since there could be a LOT of these things, treat them as a sparse + array. */ + +#define FB_LABEL_SPECIAL (10) + +static long fb_low_counter[FB_LABEL_SPECIAL]; +static long *fb_labels; +static long *fb_label_instances; +static long fb_label_count; +static long fb_label_max; + +/* This must be more than FB_LABEL_SPECIAL. */ +#define FB_LABEL_BUMP_BY (FB_LABEL_SPECIAL + 6) + +static void +fb_label_init () +{ + memset ((void *) fb_low_counter, '\0', sizeof (fb_low_counter)); +} + +/* Add one to the instance number of this fb label. */ + +void +fb_label_instance_inc (label) + long label; +{ + long *i; + + if (label < FB_LABEL_SPECIAL) + { + ++fb_low_counter[label]; + return; + } + + if (fb_labels != NULL) + { + for (i = fb_labels + FB_LABEL_SPECIAL; + i < fb_labels + fb_label_count; ++i) + { + if (*i == label) + { + ++fb_label_instances[i - fb_labels]; + return; + } /* if we find it */ + } /* for each existing label */ + } + + /* If we get to here, we don't have label listed yet. */ + + if (fb_labels == NULL) + { + fb_labels = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long)); + fb_label_instances = (long *) xmalloc (FB_LABEL_BUMP_BY * sizeof (long)); + fb_label_max = FB_LABEL_BUMP_BY; + fb_label_count = FB_LABEL_SPECIAL; + + } + else if (fb_label_count == fb_label_max) + { + fb_label_max += FB_LABEL_BUMP_BY; + fb_labels = (long *) xrealloc ((char *) fb_labels, + fb_label_max * sizeof (long)); + fb_label_instances = (long *) xrealloc ((char *) fb_label_instances, + fb_label_max * sizeof (long)); + } /* if we needed to grow */ + + fb_labels[fb_label_count] = label; + fb_label_instances[fb_label_count] = 1; + ++fb_label_count; +} + +static long +fb_label_instance (label) + long label; +{ + long *i; + + if (label < FB_LABEL_SPECIAL) + { + return (fb_low_counter[label]); + } + + if (fb_labels != NULL) + { + for (i = fb_labels + FB_LABEL_SPECIAL; + i < fb_labels + fb_label_count; ++i) + { + if (*i == label) + { + return (fb_label_instances[i - fb_labels]); + } /* if we find it */ + } /* for each existing label */ + } + + /* We didn't find the label, so this must be a reference to the + first instance. */ + return 0; +} + +/* Caller must copy returned name: we re-use the area for the next name. + + The mth occurence of label n: is turned into the symbol "Ln^Bm" + where n is the label number and m is the instance number. "L" makes + it a label discarded unless debugging and "^B"('\2') ensures no + ordinary symbol SHOULD get the same name as a local label + symbol. The first "4:" is "L4^B1" - the m numbers begin at 1. + + dollar labels get the same treatment, except that ^A is used in + place of ^B. */ + +char * /* Return local label name. */ +fb_label_name (n, augend) + long n; /* We just saw "n:", "nf" or "nb" : n a number. */ + long augend; /* 0 for nb, 1 for n:, nf. */ +{ + long i; + /* Returned to caller, then copied. Used for created names ("4f"). */ + static char symbol_name_build[24]; + register char *p; + register char *q; + char symbol_name_temporary[20]; /* Build up a number, BACKWARDS. */ + + know (n >= 0); + know (augend == 0 || augend == 1); + p = symbol_name_build; +#ifdef LOCAL_LABEL_PREFIX + *p++ = LOCAL_LABEL_PREFIX; +#endif + *p++ = 'L'; + + /* Next code just does sprintf( {}, "%d", n); */ + /* Label number. */ + q = symbol_name_temporary; + for (*q++ = 0, i = n; i; ++q) + { + *q = i % 10 + '0'; + i /= 10; + } + while ((*p = *--q) != '\0') + ++p; + + *p++ = LOCAL_LABEL_CHAR; /* ^B */ + + /* Instance number. */ + q = symbol_name_temporary; + for (*q++ = 0, i = fb_label_instance (n) + augend; i; ++q) + { + *q = i % 10 + '0'; + i /= 10; + } + while ((*p++ = *--q) != '\0');; + + /* The label, as a '\0' ended string, starts at symbol_name_build. */ + return (symbol_name_build); +} + +/* Decode name that may have been generated by foo_label_name() above. + If the name wasn't generated by foo_label_name(), then return it + unaltered. This is used for error messages. */ + +char * +decode_local_label_name (s) + char *s; +{ + char *p; + char *symbol_decode; + int label_number; + int instance_number; + char *type; + const char *message_format; + int index = 0; + +#ifdef LOCAL_LABEL_PREFIX + if (s[index] == LOCAL_LABEL_PREFIX) + ++index; +#endif + + if (s[index] != 'L') + return s; + + for (label_number = 0, p = s + index + 1; ISDIGIT (*p); ++p) + label_number = (10 * label_number) + *p - '0'; + + if (*p == DOLLAR_LABEL_CHAR) + type = "dollar"; + else if (*p == LOCAL_LABEL_CHAR) + type = "fb"; + else + return s; + + for (instance_number = 0, p++; ISDIGIT (*p); ++p) + instance_number = (10 * instance_number) + *p - '0'; + + message_format = _("\"%d\" (instance number %d of a %s label)"); + symbol_decode = obstack_alloc (¬es, strlen (message_format) + 30); + sprintf (symbol_decode, message_format, label_number, instance_number, type); + + return symbol_decode; +} + +/* Get the value of a symbol. */ + +valueT +S_GET_VALUE (s) + symbolS *s; +{ +#ifdef BFD_ASSEMBLER + if (LOCAL_SYMBOL_CHECK (s)) + return resolve_symbol_value (s); +#endif + + if (!s->sy_resolved) + { + valueT val = resolve_symbol_value (s); + if (!finalize_syms) + return val; + } + if (s->sy_value.X_op != O_constant) + { + static symbolS *recur; + + /* FIXME: In non BFD assemblers, S_IS_DEFINED and S_IS_COMMON + may call S_GET_VALUE. We use a static symbol to avoid the + immediate recursion. */ + if (recur == s) + return (valueT) s->sy_value.X_add_number; + recur = s; + if (! s->sy_resolved + || s->sy_value.X_op != O_symbol + || (S_IS_DEFINED (s) && ! S_IS_COMMON (s))) + as_bad (_("attempt to get value of unresolved symbol `%s'"), + S_GET_NAME (s)); + recur = NULL; + } + return (valueT) s->sy_value.X_add_number; +} + +/* Set the value of a symbol. */ + +void +S_SET_VALUE (s, val) + symbolS *s; + valueT val; +{ +#ifdef BFD_ASSEMBLER + if (LOCAL_SYMBOL_CHECK (s)) + { + ((struct local_symbol *) s)->lsy_value = val; + return; + } +#endif + + s->sy_value.X_op = O_constant; + s->sy_value.X_add_number = (offsetT) val; + s->sy_value.X_unsigned = 0; +} + +void +copy_symbol_attributes (dest, src) + symbolS *dest, *src; +{ + if (LOCAL_SYMBOL_CHECK (dest)) + dest = local_symbol_convert ((struct local_symbol *) dest); + if (LOCAL_SYMBOL_CHECK (src)) + src = local_symbol_convert ((struct local_symbol *) src); + +#ifdef BFD_ASSEMBLER + /* In an expression, transfer the settings of these flags. + The user can override later, of course. */ +#define COPIED_SYMFLAGS (BSF_FUNCTION | BSF_OBJECT) + dest->bsym->flags |= src->bsym->flags & COPIED_SYMFLAGS; +#endif + +#ifdef OBJ_COPY_SYMBOL_ATTRIBUTES + OBJ_COPY_SYMBOL_ATTRIBUTES (dest, src); +#endif +} + +#ifdef BFD_ASSEMBLER + +int +S_IS_FUNCTION (s) + symbolS *s; +{ + flagword flags; + + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + + flags = s->bsym->flags; + + return (flags & BSF_FUNCTION) != 0; +} + +int +S_IS_EXTERNAL (s) + symbolS *s; +{ + flagword flags; + + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + + flags = s->bsym->flags; + + /* Sanity check. */ + if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL)) + abort (); + + return (flags & BSF_GLOBAL) != 0; +} + +int +S_IS_WEAK (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return (s->bsym->flags & BSF_WEAK) != 0; +} + +int +S_IS_COMMON (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return bfd_is_com_section (s->bsym->section); +} + +int +S_IS_DEFINED (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return ((struct local_symbol *) s)->lsy_section != undefined_section; + return s->bsym->section != undefined_section; +} + + +#ifndef EXTERN_FORCE_RELOC +#define EXTERN_FORCE_RELOC IS_ELF +#endif + +/* Return true for symbols that should not be reduced to section + symbols or eliminated from expressions, because they may be + overridden by the linker. */ +int +S_FORCE_RELOC (s, strict) + symbolS *s; + int strict; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return ((struct local_symbol *) s)->lsy_section == undefined_section; + + return ((strict + && ((s->bsym->flags & BSF_WEAK) != 0 + || (EXTERN_FORCE_RELOC + && (s->bsym->flags & BSF_GLOBAL) != 0))) + || s->bsym->section == undefined_section + || bfd_is_com_section (s->bsym->section)); +} + +int +S_IS_DEBUG (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + if (s->bsym->flags & BSF_DEBUGGING) + return 1; + return 0; +} + +int +S_IS_LOCAL (s) + symbolS *s; +{ + flagword flags; + const char *name; + + if (LOCAL_SYMBOL_CHECK (s)) + return 1; + + flags = s->bsym->flags; + + /* Sanity check. */ + if ((flags & BSF_LOCAL) && (flags & BSF_GLOBAL)) + abort (); + + if (bfd_get_section (s->bsym) == reg_section) + return 1; + + if (flag_strip_local_absolute + && (flags & BSF_GLOBAL) == 0 + && bfd_get_section (s->bsym) == absolute_section) + return 1; + + name = S_GET_NAME (s); + return (name != NULL + && ! S_IS_DEBUG (s) + && (strchr (name, DOLLAR_LABEL_CHAR) + || strchr (name, LOCAL_LABEL_CHAR) + || (! flag_keep_locals + && (bfd_is_local_label (stdoutput, s->bsym) + || (flag_mri + && name[0] == '?' + && name[1] == '?'))))); +} + +int +S_IS_EXTERN (s) + symbolS *s; +{ + return S_IS_EXTERNAL (s); +} + +int +S_IS_STABD (s) + symbolS *s; +{ + return S_GET_NAME (s) == 0; +} + +const char * +S_GET_NAME (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return ((struct local_symbol *) s)->lsy_name; + return s->bsym->name; +} + +segT +S_GET_SEGMENT (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return ((struct local_symbol *) s)->lsy_section; + return s->bsym->section; +} + +void +S_SET_SEGMENT (s, seg) + symbolS *s; + segT seg; +{ + /* Don't reassign section symbols. The direct reason is to prevent seg + faults assigning back to const global symbols such as *ABS*, but it + shouldn't happen anyway. */ + + if (LOCAL_SYMBOL_CHECK (s)) + { + if (seg == reg_section) + s = local_symbol_convert ((struct local_symbol *) s); + else + { + ((struct local_symbol *) s)->lsy_section = seg; + return; + } + } + + if (s->bsym->flags & BSF_SECTION_SYM) + { + if (s->bsym->section != seg) + abort (); + } + else + s->bsym->section = seg; +} + +void +S_SET_EXTERNAL (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + if ((s->bsym->flags & BSF_WEAK) != 0) + { + /* Let .weak override .global. */ + return; + } + if (s->bsym->flags & BSF_SECTION_SYM) + { + char * file; + unsigned int line; + + /* Do not reassign section symbols. */ + as_where (& file, & line); + as_warn_where (file, line, + _("section symbols are already global")); + return; + } + s->bsym->flags |= BSF_GLOBAL; + s->bsym->flags &= ~(BSF_LOCAL | BSF_WEAK); +} + +void +S_CLEAR_EXTERNAL (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return; + if ((s->bsym->flags & BSF_WEAK) != 0) + { + /* Let .weak override. */ + return; + } + s->bsym->flags |= BSF_LOCAL; + s->bsym->flags &= ~(BSF_GLOBAL | BSF_WEAK); +} + +void +S_SET_WEAK (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->bsym->flags |= BSF_WEAK; + s->bsym->flags &= ~(BSF_GLOBAL | BSF_LOCAL); +} + +void +S_SET_THREAD_LOCAL (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + if (bfd_is_com_section (s->bsym->section) + && (s->bsym->flags & BSF_THREAD_LOCAL) != 0) + return; + s->bsym->flags |= BSF_THREAD_LOCAL; + if ((s->bsym->flags & BSF_FUNCTION) != 0) + as_bad (_("Accessing function `%s' as thread-local object"), + S_GET_NAME (s)); + else if (! bfd_is_und_section (s->bsym->section) + && (s->bsym->section->flags & SEC_THREAD_LOCAL) == 0) + as_bad (_("Accessing `%s' as thread-local object"), + S_GET_NAME (s)); +} + +void +S_SET_NAME (s, name) + symbolS *s; + char *name; +{ + if (LOCAL_SYMBOL_CHECK (s)) + { + ((struct local_symbol *) s)->lsy_name = name; + return; + } + s->bsym->name = name; +} +#endif /* BFD_ASSEMBLER */ + +#ifdef SYMBOLS_NEED_BACKPOINTERS + +/* Return the previous symbol in a chain. */ + +symbolS * +symbol_previous (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + abort (); + return s->sy_previous; +} + +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +/* Return the next symbol in a chain. */ + +symbolS * +symbol_next (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + abort (); + return s->sy_next; +} + +/* Return a pointer to the value of a symbol as an expression. */ + +expressionS * +symbol_get_value_expression (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + return &s->sy_value; +} + +/* Set the value of a symbol to an expression. */ + +void +symbol_set_value_expression (s, exp) + symbolS *s; + const expressionS *exp; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->sy_value = *exp; +} + +/* Set the frag of a symbol. */ + +void +symbol_set_frag (s, f) + symbolS *s; + fragS *f; +{ +#ifdef BFD_ASSEMBLER + if (LOCAL_SYMBOL_CHECK (s)) + { + local_symbol_set_frag ((struct local_symbol *) s, f); + return; + } +#endif + s->sy_frag = f; +} + +/* Return the frag of a symbol. */ + +fragS * +symbol_get_frag (s) + symbolS *s; +{ +#ifdef BFD_ASSEMBLER + if (LOCAL_SYMBOL_CHECK (s)) + return local_symbol_get_frag ((struct local_symbol *) s); +#endif + return s->sy_frag; +} + +/* Mark a symbol as having been used. */ + +void +symbol_mark_used (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return; + s->sy_used = 1; +} + +/* Clear the mark of whether a symbol has been used. */ + +void +symbol_clear_used (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->sy_used = 0; +} + +/* Return whether a symbol has been used. */ + +int +symbol_used_p (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 1; + return s->sy_used; +} + +/* Mark a symbol as having been used in a reloc. */ + +void +symbol_mark_used_in_reloc (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->sy_used_in_reloc = 1; +} + +/* Clear the mark of whether a symbol has been used in a reloc. */ + +void +symbol_clear_used_in_reloc (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return; + s->sy_used_in_reloc = 0; +} + +/* Return whether a symbol has been used in a reloc. */ + +int +symbol_used_in_reloc_p (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return s->sy_used_in_reloc; +} + +/* Mark a symbol as an MRI common symbol. */ + +void +symbol_mark_mri_common (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->sy_mri_common = 1; +} + +/* Clear the mark of whether a symbol is an MRI common symbol. */ + +void +symbol_clear_mri_common (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return; + s->sy_mri_common = 0; +} + +/* Return whether a symbol is an MRI common symbol. */ + +int +symbol_mri_common_p (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return s->sy_mri_common; +} + +/* Mark a symbol as having been written. */ + +void +symbol_mark_written (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return; + s->written = 1; +} + +/* Clear the mark of whether a symbol has been written. */ + +void +symbol_clear_written (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return; + s->written = 0; +} + +/* Return whether a symbol has been written. */ + +int +symbol_written_p (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return s->written; +} + +/* Mark a symbol has having been resolved. */ + +void +symbol_mark_resolved (s) + symbolS *s; +{ +#ifdef BFD_ASSEMBLER + if (LOCAL_SYMBOL_CHECK (s)) + { + local_symbol_mark_resolved ((struct local_symbol *) s); + return; + } +#endif + s->sy_resolved = 1; +} + +/* Return whether a symbol has been resolved. */ + +int +symbol_resolved_p (s) + symbolS *s; +{ +#ifdef BFD_ASSEMBLER + if (LOCAL_SYMBOL_CHECK (s)) + return local_symbol_resolved_p ((struct local_symbol *) s); +#endif + return s->sy_resolved; +} + +/* Return whether a symbol is a section symbol. */ + +int +symbol_section_p (s) + symbolS *s ATTRIBUTE_UNUSED; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; +#ifdef BFD_ASSEMBLER + return (s->bsym->flags & BSF_SECTION_SYM) != 0; +#else + /* FIXME. */ + return 0; +#endif +} + +/* Return whether a symbol is equated to another symbol. */ + +int +symbol_equated_p (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + return s->sy_value.X_op == O_symbol; +} + +/* Return whether a symbol is equated to another symbol, and should be + treated specially when writing out relocs. */ + +int +symbol_equated_reloc_p (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 0; + /* X_op_symbol, normally not used for O_symbol, is set by + resolve_symbol_value to flag expression syms that have been + equated. */ + return (s->sy_value.X_op == O_symbol + && ((s->sy_resolved && s->sy_value.X_op_symbol != NULL) + || ! S_IS_DEFINED (s) + || S_IS_COMMON (s))); +} + +/* Return whether a symbol has a constant value. */ + +int +symbol_constant_p (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + return 1; + return s->sy_value.X_op == O_constant; +} + +#ifdef BFD_ASSEMBLER + +/* Return the BFD symbol for a symbol. */ + +asymbol * +symbol_get_bfdsym (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + return s->bsym; +} + +/* Set the BFD symbol for a symbol. */ + +void +symbol_set_bfdsym (s, bsym) + symbolS *s; + asymbol *bsym; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->bsym = bsym; +} + +#endif /* BFD_ASSEMBLER */ + +#ifdef OBJ_SYMFIELD_TYPE + +/* Get a pointer to the object format information for a symbol. */ + +OBJ_SYMFIELD_TYPE * +symbol_get_obj (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + return &s->sy_obj; +} + +/* Set the object format information for a symbol. */ + +void +symbol_set_obj (s, o) + symbolS *s; + OBJ_SYMFIELD_TYPE *o; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->sy_obj = *o; +} + +#endif /* OBJ_SYMFIELD_TYPE */ + +#ifdef TC_SYMFIELD_TYPE + +/* Get a pointer to the processor information for a symbol. */ + +TC_SYMFIELD_TYPE * +symbol_get_tc (s) + symbolS *s; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + return &s->sy_tc; +} + +/* Set the processor information for a symbol. */ + +void +symbol_set_tc (s, o) + symbolS *s; + TC_SYMFIELD_TYPE *o; +{ + if (LOCAL_SYMBOL_CHECK (s)) + s = local_symbol_convert ((struct local_symbol *) s); + s->sy_tc = *o; +} + +#endif /* TC_SYMFIELD_TYPE */ + +void +symbol_begin () +{ + symbol_lastP = NULL; + symbol_rootP = NULL; /* In case we have 0 symbols (!!) */ + sy_hash = hash_new (); +#ifdef BFD_ASSEMBLER + local_hash = hash_new (); +#endif + + memset ((char *) (&abs_symbol), '\0', sizeof (abs_symbol)); +#ifdef BFD_ASSEMBLER +#if defined (EMIT_SECTION_SYMBOLS) || !defined (RELOC_REQUIRES_SYMBOL) + abs_symbol.bsym = bfd_abs_section.symbol; +#endif +#else + /* Can't initialise a union. Sigh. */ + S_SET_SEGMENT (&abs_symbol, absolute_section); +#endif + abs_symbol.sy_value.X_op = O_constant; + abs_symbol.sy_frag = &zero_address_frag; + + if (LOCAL_LABELS_FB) + fb_label_init (); +} + +int indent_level; + +/* Maximum indent level. + Available for modification inside a gdb session. */ +int max_indent_level = 8; + +#if 0 + +static void +indent () +{ + printf ("%*s", indent_level * 4, ""); +} + +#endif + +void +print_symbol_value_1 (file, sym) + FILE *file; + symbolS *sym; +{ + const char *name = S_GET_NAME (sym); + if (!name || !name[0]) + name = "(unnamed)"; + fprintf (file, "sym %lx %s", (unsigned long) sym, name); + + if (LOCAL_SYMBOL_CHECK (sym)) + { +#ifdef BFD_ASSEMBLER + struct local_symbol *locsym = (struct local_symbol *) sym; + if (local_symbol_get_frag (locsym) != &zero_address_frag + && local_symbol_get_frag (locsym) != NULL) + fprintf (file, " frag %lx", (long) local_symbol_get_frag (locsym)); + if (local_symbol_resolved_p (locsym)) + fprintf (file, " resolved"); + fprintf (file, " local"); +#endif + } + else + { + if (sym->sy_frag != &zero_address_frag) + fprintf (file, " frag %lx", (long) sym->sy_frag); + if (sym->written) + fprintf (file, " written"); + if (sym->sy_resolved) + fprintf (file, " resolved"); + else if (sym->sy_resolving) + fprintf (file, " resolving"); + if (sym->sy_used_in_reloc) + fprintf (file, " used-in-reloc"); + if (sym->sy_used) + fprintf (file, " used"); + if (S_IS_LOCAL (sym)) + fprintf (file, " local"); + if (S_IS_EXTERN (sym)) + fprintf (file, " extern"); + if (S_IS_DEBUG (sym)) + fprintf (file, " debug"); + if (S_IS_DEFINED (sym)) + fprintf (file, " defined"); + } + fprintf (file, " %s", segment_name (S_GET_SEGMENT (sym))); + if (symbol_resolved_p (sym)) + { + segT s = S_GET_SEGMENT (sym); + + if (s != undefined_section + && s != expr_section) + fprintf (file, " %lx", (long) S_GET_VALUE (sym)); + } + else if (indent_level < max_indent_level + && S_GET_SEGMENT (sym) != undefined_section) + { + indent_level++; + fprintf (file, "\n%*s<", indent_level * 4, ""); +#ifdef BFD_ASSEMBLER + if (LOCAL_SYMBOL_CHECK (sym)) + fprintf (file, "constant %lx", + (long) ((struct local_symbol *) sym)->lsy_value); + else +#endif + print_expr_1 (file, &sym->sy_value); + fprintf (file, ">"); + indent_level--; + } + fflush (file); +} + +void +print_symbol_value (sym) + symbolS *sym; +{ + indent_level = 0; + print_symbol_value_1 (stderr, sym); + fprintf (stderr, "\n"); +} + +static void +print_binary (file, name, exp) + FILE *file; + const char *name; + expressionS *exp; +{ + indent_level++; + fprintf (file, "%s\n%*s<", name, indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_op_symbol); + fprintf (file, ">"); + indent_level--; +} + +void +print_expr_1 (file, exp) + FILE *file; + expressionS *exp; +{ + fprintf (file, "expr %lx ", (long) exp); + switch (exp->X_op) + { + case O_illegal: + fprintf (file, "illegal"); + break; + case O_absent: + fprintf (file, "absent"); + break; + case O_constant: + fprintf (file, "constant %lx", (long) exp->X_add_number); + break; + case O_symbol: + indent_level++; + fprintf (file, "symbol\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">"); + maybe_print_addnum: + if (exp->X_add_number) + fprintf (file, "\n%*s%lx", indent_level * 4, "", + (long) exp->X_add_number); + indent_level--; + break; + case O_register: + fprintf (file, "register #%d", (int) exp->X_add_number); + break; + case O_big: + fprintf (file, "big"); + break; + case O_uminus: + fprintf (file, "uminus -<"); + indent_level++; + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">"); + goto maybe_print_addnum; + case O_bit_not: + fprintf (file, "bit_not"); + break; + case O_multiply: + print_binary (file, "multiply", exp); + break; + case O_divide: + print_binary (file, "divide", exp); + break; + case O_modulus: + print_binary (file, "modulus", exp); + break; + case O_left_shift: + print_binary (file, "lshift", exp); + break; + case O_right_shift: + print_binary (file, "rshift", exp); + break; + case O_bit_inclusive_or: + print_binary (file, "bit_ior", exp); + break; + case O_bit_exclusive_or: + print_binary (file, "bit_xor", exp); + break; + case O_bit_and: + print_binary (file, "bit_and", exp); + break; + case O_eq: + print_binary (file, "eq", exp); + break; + case O_ne: + print_binary (file, "ne", exp); + break; + case O_lt: + print_binary (file, "lt", exp); + break; + case O_le: + print_binary (file, "le", exp); + break; + case O_ge: + print_binary (file, "ge", exp); + break; + case O_gt: + print_binary (file, "gt", exp); + break; + case O_logical_and: + print_binary (file, "logical_and", exp); + break; + case O_logical_or: + print_binary (file, "logical_or", exp); + break; + case O_add: + indent_level++; + fprintf (file, "add\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_op_symbol); + fprintf (file, ">"); + goto maybe_print_addnum; + case O_subtract: + indent_level++; + fprintf (file, "subtract\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_add_symbol); + fprintf (file, ">\n%*s<", indent_level * 4, ""); + print_symbol_value_1 (file, exp->X_op_symbol); + fprintf (file, ">"); + goto maybe_print_addnum; + default: + fprintf (file, "{unknown opcode %d}", (int) exp->X_op); + break; + } + fflush (stdout); +} + +void +print_expr (exp) + expressionS *exp; +{ + print_expr_1 (stderr, exp); + fprintf (stderr, "\n"); +} + +void +symbol_print_statistics (file) + FILE *file; +{ + hash_print_statistics (file, "symbol table", sy_hash); +#ifdef BFD_ASSEMBLER + hash_print_statistics (file, "mini local symbol table", local_hash); + fprintf (file, "%lu mini local symbols created, %lu converted\n", + local_symbol_count, local_symbol_conversion_count); +#endif +} diff --git a/contrib/binutils-2.14/gas/symbols.h b/contrib/binutils-2.14/gas/symbols.h new file mode 100644 index 0000000000..65fb8492fd --- /dev/null +++ b/contrib/binutils-2.14/gas/symbols.h @@ -0,0 +1,207 @@ +/* symbols.h - + Copyright 1987, 1990, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001, + 2002, 2003 Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifdef BFD_ASSEMBLER +/* The BFD code wants to walk the list in both directions. */ +#undef SYMBOLS_NEED_BACKPOINTERS +#define SYMBOLS_NEED_BACKPOINTERS +#endif + +#ifndef BFD_ASSEMBLER +/* The non-BFD code expects to be able to manipulate the symbol fields + directly. */ +#include "struc-symbol.h" +#endif + +extern struct obstack notes; /* eg FixS live here. */ + +extern struct obstack cond_obstack; /* this is where we track .ifdef/.endif + (if we do that at all). */ + +extern symbolS *symbol_rootP; /* all the symbol nodes */ +extern symbolS *symbol_lastP; /* last struct symbol we made, or NULL */ + +extern symbolS abs_symbol; + +extern int symbol_table_frozen; + +/* This is non-zero if symbols are case sensitive, which is the + default. */ +extern int symbols_case_sensitive; + +char *decode_local_label_name PARAMS ((char *s)); +symbolS *symbol_find PARAMS ((const char *name)); +symbolS *symbol_find_exact PARAMS ((const char *name)); +symbolS *symbol_find_base PARAMS ((const char *name, int strip_underscore)); +symbolS *symbol_find_or_make PARAMS ((const char *name)); +symbolS *symbol_make PARAMS ((const char *name)); +symbolS *symbol_new PARAMS ((const char *name, segT segment, valueT value, + fragS * frag)); +symbolS *symbol_create PARAMS ((const char *name, segT segment, valueT value, + fragS * frag)); +symbolS *colon PARAMS ((const char *sym_name)); +void local_colon PARAMS ((int n)); +void symbol_begin PARAMS ((void)); +void symbol_print_statistics PARAMS ((FILE *)); +void symbol_table_insert PARAMS ((symbolS * symbolP)); +valueT resolve_symbol_value PARAMS ((symbolS *)); +void resolve_local_symbol_values PARAMS ((void)); + +void print_symbol_value PARAMS ((symbolS *)); +void print_expr PARAMS ((expressionS *)); +void print_expr_1 PARAMS ((FILE *, expressionS *)); +void print_symbol_value_1 PARAMS ((FILE *, symbolS *)); + +int dollar_label_defined PARAMS ((long l)); +void dollar_label_clear PARAMS ((void)); +void define_dollar_label PARAMS ((long l)); +char *dollar_label_name PARAMS ((long l, int augend)); + +void fb_label_instance_inc PARAMS ((long label)); +char *fb_label_name PARAMS ((long n, long augend)); + +extern void copy_symbol_attributes PARAMS ((symbolS *, symbolS *)); + +/* Get and set the values of symbols. These used to be macros. */ +extern valueT S_GET_VALUE PARAMS ((symbolS *)); +extern void S_SET_VALUE PARAMS ((symbolS *, valueT)); + +#ifdef BFD_ASSEMBLER +extern int S_IS_FUNCTION PARAMS ((symbolS *)); +extern int S_IS_EXTERNAL PARAMS ((symbolS *)); +extern int S_IS_WEAK PARAMS ((symbolS *)); +extern int S_IS_COMMON PARAMS ((symbolS *)); +extern int S_IS_DEFINED PARAMS ((symbolS *)); +extern int S_FORCE_RELOC PARAMS ((symbolS *, int)); +extern int S_IS_DEBUG PARAMS ((symbolS *)); +extern int S_IS_LOCAL PARAMS ((symbolS *)); +extern int S_IS_EXTERN PARAMS ((symbolS *)); +extern int S_IS_STABD PARAMS ((symbolS *)); +extern const char *S_GET_NAME PARAMS ((symbolS *)); +extern segT S_GET_SEGMENT PARAMS ((symbolS *)); +extern void S_SET_SEGMENT PARAMS ((symbolS *, segT)); +extern void S_SET_EXTERNAL PARAMS ((symbolS *)); +extern void S_SET_NAME PARAMS ((symbolS *, char *)); +extern void S_CLEAR_EXTERNAL PARAMS ((symbolS *)); +extern void S_SET_WEAK PARAMS ((symbolS *)); +extern void S_SET_THREAD_LOCAL PARAMS ((symbolS *)); +#endif + +#ifndef WORKING_DOT_WORD +struct broken_word + { + /* Linked list -- one of these structures per ".word x-y+C" + expression. */ + struct broken_word *next_broken_word; + /* Segment and subsegment for broken word. */ + segT seg; + subsegT subseg; + /* Which frag is this broken word in? */ + fragS *frag; + /* Where in the frag is it? */ + char *word_goes_here; + /* Where to add the break. */ + fragS *dispfrag; /* where to add the break */ + /* Operands of expression. */ + symbolS *add; + symbolS *sub; + offsetT addnum; + + int added; /* nasty thing happend yet? */ + /* 1: added and has a long-jump */ + /* 2: added but uses someone elses long-jump */ + + /* Pointer to broken_word with a similar long-jump. */ + struct broken_word *use_jump; + }; +extern struct broken_word *broken_words; +#endif /* ndef WORKING_DOT_WORD */ + +/* + * Current means for getting from symbols to segments and vice verse. + * This will change for infinite-segments support (e.g. COFF). + */ +extern const segT N_TYPE_seg[]; /* subseg.c */ + +#define SEGMENT_TO_SYMBOL_TYPE(seg) ( seg_N_TYPE [(int) (seg)] ) +extern const short seg_N_TYPE[];/* subseg.c */ + +#define N_REGISTER 30 /* Fake N_TYPE value for SEG_REGISTER */ + +void symbol_clear_list_pointers PARAMS ((symbolS * symbolP)); + +#ifdef SYMBOLS_NEED_BACKPOINTERS + +void symbol_insert PARAMS ((symbolS * addme, symbolS * target, + symbolS ** rootP, symbolS ** lastP)); +void symbol_remove PARAMS ((symbolS * symbolP, symbolS ** rootP, + symbolS ** lastP)); + +extern symbolS *symbol_previous PARAMS ((symbolS *)); + +#endif /* SYMBOLS_NEED_BACKPOINTERS */ + +void verify_symbol_chain PARAMS ((symbolS * rootP, symbolS * lastP)); +void verify_symbol_chain_2 PARAMS ((symbolS * symP)); + +void symbol_append PARAMS ((symbolS * addme, symbolS * target, + symbolS ** rootP, symbolS ** lastP)); + +extern symbolS *symbol_next PARAMS ((symbolS *)); + +extern expressionS *symbol_get_value_expression PARAMS ((symbolS *)); +extern void symbol_set_value_expression PARAMS ((symbolS *, + const expressionS *)); +extern void symbol_set_frag PARAMS ((symbolS *, fragS *)); +extern fragS *symbol_get_frag PARAMS ((symbolS *)); +extern void symbol_mark_used PARAMS ((symbolS *)); +extern void symbol_clear_used PARAMS ((symbolS *)); +extern int symbol_used_p PARAMS ((symbolS *)); +extern void symbol_mark_used_in_reloc PARAMS ((symbolS *)); +extern void symbol_clear_used_in_reloc PARAMS ((symbolS *)); +extern int symbol_used_in_reloc_p PARAMS ((symbolS *)); +extern void symbol_mark_mri_common PARAMS ((symbolS *)); +extern void symbol_clear_mri_common PARAMS ((symbolS *)); +extern int symbol_mri_common_p PARAMS ((symbolS *)); +extern void symbol_mark_written PARAMS ((symbolS *)); +extern void symbol_clear_written PARAMS ((symbolS *)); +extern int symbol_written_p PARAMS ((symbolS *)); +extern void symbol_mark_resolved PARAMS ((symbolS *)); +extern int symbol_resolved_p PARAMS ((symbolS *)); +extern int symbol_section_p PARAMS ((symbolS *)); +extern int symbol_equated_p PARAMS ((symbolS *)); +extern int symbol_equated_reloc_p PARAMS ((symbolS *)); +extern int symbol_constant_p PARAMS ((symbolS *)); + +#ifdef BFD_ASSEMBLER +extern asymbol *symbol_get_bfdsym PARAMS ((symbolS *)); +extern void symbol_set_bfdsym PARAMS ((symbolS *, asymbol *)); +#endif + +#ifdef OBJ_SYMFIELD_TYPE +OBJ_SYMFIELD_TYPE *symbol_get_obj PARAMS ((symbolS *)); +void symbol_set_obj PARAMS ((symbolS *, OBJ_SYMFIELD_TYPE *)); +#endif + +#ifdef TC_SYMFIELD_TYPE +TC_SYMFIELD_TYPE *symbol_get_tc PARAMS ((symbolS *)); +void symbol_set_tc PARAMS ((symbolS *, TC_SYMFIELD_TYPE *)); +#endif diff --git a/contrib/binutils-2.14/gas/tc.h b/contrib/binutils-2.14/gas/tc.h new file mode 100644 index 0000000000..c8cb13c392 --- /dev/null +++ b/contrib/binutils-2.14/gas/tc.h @@ -0,0 +1,110 @@ +/* tc.h - target cpu dependent + + Copyright 1987, 1990, 1991, 1992, 1993, 1994, 1995, 2000 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* In theory (mine, at least!) the machine dependent part of the assembler + should only have to include one file. This one. -- JF */ + +extern const pseudo_typeS md_pseudo_table[]; + +/* JF moved this here from as.h under the theory that nobody except MACHINE.c + and write.c care about it anyway. */ + +struct relax_type +{ + /* Forward reach. Signed number. > 0. */ + long rlx_forward; + /* Backward reach. Signed number. < 0. */ + long rlx_backward; + + /* Bytes length of this address. */ + unsigned char rlx_length; + + /* Next longer relax-state. 0 means there is no 'next' relax-state. */ + relax_substateT rlx_more; +}; + +typedef struct relax_type relax_typeS; + +extern const int md_reloc_size; /* Size of a relocation record */ + +char *md_atof PARAMS ((int what_statement_type, char *literalP, int *sizeP)); +#ifndef md_estimate_size_before_relax +int md_estimate_size_before_relax PARAMS ((fragS * fragP, segT segment)); +#endif +int md_parse_option PARAMS ((int c, char *arg)); +void md_show_usage PARAMS ((FILE *)); +long md_pcrel_from PARAMS ((fixS * fixP)); +short tc_coff_fix2rtype PARAMS ((fixS * fixP)); +void md_assemble PARAMS ((char *str)); +void md_begin PARAMS ((void)); +#ifndef md_create_long_jump +void md_create_long_jump PARAMS ((char *ptr, addressT from_addr, + addressT to_addr, fragS * frag, + symbolS * to_symbol)); +#endif +#ifndef md_create_short_jump +void md_create_short_jump PARAMS ((char *ptr, addressT from_addr, + addressT to_addr, fragS * frag, + symbolS * to_symbol)); +#endif +void md_number_to_chars PARAMS ((char *buf, valueT val, int n)); + +#ifndef md_operand +void md_operand PARAMS ((expressionS * expressionP)); +#endif + +void md_apply_fix3 PARAMS ((fixS *, valueT *, segT)); + +#ifdef BFD_ASSEMBLER +#ifndef md_convert_frag +void md_convert_frag PARAMS ((bfd * headers, segT sec, fragS * fragP)); +#endif +#ifndef tc_headers_hook +void tc_headers_hook PARAMS ((segT *, fixS *)); +#endif +#ifndef RELOC_EXPANSION_POSSIBLE +extern arelent *tc_gen_reloc PARAMS ((asection *, fixS *)); +#else +extern arelent **tc_gen_reloc PARAMS ((asection *, fixS *)); +#endif +#else /* not BFD_ASSEMBLER */ +#ifndef md_convert_frag +void md_convert_frag PARAMS ((object_headers * headers, segT, fragS * fragP)); +#endif + +#ifndef tc_crawl_symbol_chain +void tc_crawl_symbol_chain PARAMS ((object_headers * headers)); +#endif /* tc_crawl_symbol_chain */ + +#ifndef tc_headers_hook +void tc_headers_hook PARAMS ((object_headers * headers)); +#endif /* tc_headers_hook */ +#endif /* BFD_ASSEMBLER */ + +#ifndef md_section_align +valueT md_section_align PARAMS ((segT seg, valueT size)); +#endif + +#ifndef md_undefined_symbol +symbolS *md_undefined_symbol PARAMS ((char *name)); +#endif + +/* end of tc.h */ diff --git a/contrib/binutils-2.14/gas/write.c b/contrib/binutils-2.14/gas/write.c new file mode 100644 index 0000000000..ce40572749 --- /dev/null +++ b/contrib/binutils-2.14/gas/write.c @@ -0,0 +1,2897 @@ +/* write.c - emit .o file + Copyright 1986, 1987, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, + 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This thing should be set up to do byteordering correctly. But... */ + +#include "as.h" +#include "subsegs.h" +#include "obstack.h" +#include "output-file.h" +#include "dwarf2dbg.h" + +#ifndef TC_ADJUST_RELOC_COUNT +#define TC_ADJUST_RELOC_COUNT(FIX, COUNT) +#endif + +#ifndef TC_FORCE_RELOCATION +#define TC_FORCE_RELOCATION(FIX) \ + (generic_force_reloc (FIX)) +#endif + +#ifndef TC_FORCE_RELOCATION_ABS +#define TC_FORCE_RELOCATION_ABS(FIX) \ + (TC_FORCE_RELOCATION (FIX)) +#endif + +#ifndef TC_FORCE_RELOCATION_LOCAL +#define TC_FORCE_RELOCATION_LOCAL(FIX) \ + (!(FIX)->fx_pcrel \ + || (FIX)->fx_plt \ + || TC_FORCE_RELOCATION (FIX)) +#endif + +#ifndef TC_FORCE_RELOCATION_SUB_SAME +#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \ + (! SEG_NORMAL (SEG)) +#endif + +#ifndef TC_FORCE_RELOCATION_SUB_ABS +#define TC_FORCE_RELOCATION_SUB_ABS(FIX) 0 +#endif + +#ifndef TC_FORCE_RELOCATION_SUB_LOCAL +#ifdef DIFF_EXPR_OK +#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX) 0 +#else +#define TC_FORCE_RELOCATION_SUB_LOCAL(FIX) 1 +#endif +#endif + +#ifndef TC_VALIDATE_FIX_SUB +#ifdef UNDEFINED_DIFFERENCE_OK +/* The PA needs this for PIC code generation. */ +#define TC_VALIDATE_FIX_SUB(FIX) 1 +#else +#ifdef BFD_ASSEMBLER +#define TC_VALIDATE_FIX_SUB(FIX) \ + ((FIX)->fx_r_type == BFD_RELOC_GPREL32 \ + || (FIX)->fx_r_type == BFD_RELOC_GPREL16) +#else +#define TC_VALIDATE_FIX_SUB(FIX) 0 +#endif +#endif +#endif + +#ifndef TC_LINKRELAX_FIXUP +#define TC_LINKRELAX_FIXUP(SEG) 1 +#endif + +#ifndef MD_APPLY_SYM_VALUE +#define MD_APPLY_SYM_VALUE(FIX) 1 +#endif + +#ifndef TC_FINALIZE_SYMS_BEFORE_SIZE_SEG +#define TC_FINALIZE_SYMS_BEFORE_SIZE_SEG 1 +#endif + +#ifndef MD_PCREL_FROM_SECTION +#define MD_PCREL_FROM_SECTION(FIX, SEC) md_pcrel_from (FIX) +#endif + +#ifndef WORKING_DOT_WORD +extern const int md_short_jump_size; +extern const int md_long_jump_size; +#endif + +/* Used to control final evaluation of expressions. */ +int finalize_syms = 0; + +int symbol_table_frozen; + +symbolS *abs_section_sym; + +/* Remember the value of dot when parsing expressions. */ +addressT dot_value; + +void print_fixup PARAMS ((fixS *)); + +#ifdef BFD_ASSEMBLER +static void renumber_sections PARAMS ((bfd *, asection *, PTR)); + +/* We generally attach relocs to frag chains. However, after we have + chained these all together into a segment, any relocs we add after + that must be attached to a segment. This will include relocs added + in md_estimate_size_for_relax, for example. */ +static int frags_chained = 0; +#endif + +#ifndef BFD_ASSEMBLER + +#ifndef MANY_SEGMENTS +struct frag *text_frag_root; +struct frag *data_frag_root; +struct frag *bss_frag_root; + +struct frag *text_last_frag; /* Last frag in segment. */ +struct frag *data_last_frag; /* Last frag in segment. */ +static struct frag *bss_last_frag; /* Last frag in segment. */ +#endif + +#ifndef BFD +static object_headers headers; +#endif + +long string_byte_count; +char *next_object_file_charP; /* Tracks object file bytes. */ + +#ifndef OBJ_VMS +int magic_number_for_object_file = DEFAULT_MAGIC_NUMBER_FOR_OBJECT_FILE; +#endif + +#endif /* BFD_ASSEMBLER */ + +static int n_fixups; + +#ifdef BFD_ASSEMBLER +#define RELOC_ENUM enum bfd_reloc_code_real +#else +#define RELOC_ENUM int +#endif + +static fixS *fix_new_internal PARAMS ((fragS *, int where, int size, + symbolS *add, symbolS *sub, + offsetT offset, int pcrel, + RELOC_ENUM r_type)); +#if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS)) +static long fixup_segment PARAMS ((fixS *, segT)); +#endif +static relax_addressT relax_align PARAMS ((relax_addressT addr, int align)); +#if defined (BFD_ASSEMBLER) || ! defined (BFD) +static fragS *chain_frchains_together_1 PARAMS ((segT, struct frchain *)); +#endif +#ifdef BFD_ASSEMBLER +static void chain_frchains_together PARAMS ((bfd *, segT, PTR)); +static void cvt_frag_to_fill PARAMS ((segT, fragS *)); +static void adjust_reloc_syms PARAMS ((bfd *, asection *, PTR)); +static void fix_segment PARAMS ((bfd *, asection *, PTR)); +static void write_relocs PARAMS ((bfd *, asection *, PTR)); +static void write_contents PARAMS ((bfd *, asection *, PTR)); +static void set_symtab PARAMS ((void)); +#endif +#if defined (BFD_ASSEMBLER) || (! defined (BFD) && ! defined (OBJ_AOUT)) +static void merge_data_into_text PARAMS ((void)); +#endif +#if ! defined (BFD_ASSEMBLER) && ! defined (BFD) +static void cvt_frag_to_fill PARAMS ((object_headers *, segT, fragS *)); +static void remove_subsegs PARAMS ((frchainS *, int, fragS **, fragS **)); +static void relax_and_size_all_segments PARAMS ((void)); +#endif + +/* Create a fixS in obstack 'notes'. */ + +static fixS * +fix_new_internal (frag, where, size, add_symbol, sub_symbol, offset, pcrel, + r_type) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + int size; /* 1, 2, or 4 usually. */ + symbolS *add_symbol; /* X_add_symbol. */ + symbolS *sub_symbol; /* X_op_symbol. */ + offsetT offset; /* X_add_number. */ + int pcrel; /* TRUE if PC-relative relocation. */ + RELOC_ENUM r_type ATTRIBUTE_UNUSED; /* Relocation type. */ +{ + fixS *fixP; + + n_fixups++; + + fixP = (fixS *) obstack_alloc (¬es, sizeof (fixS)); + + fixP->fx_frag = frag; + fixP->fx_where = where; + fixP->fx_size = size; + /* We've made fx_size a narrow field; check that it's wide enough. */ + if (fixP->fx_size != size) + { + as_bad (_("field fx_size too small to hold %d"), size); + abort (); + } + fixP->fx_addsy = add_symbol; + fixP->fx_subsy = sub_symbol; + fixP->fx_offset = offset; + fixP->fx_dot_value = dot_value; + fixP->fx_pcrel = pcrel; + fixP->fx_plt = 0; +#if defined(NEED_FX_R_TYPE) || defined (BFD_ASSEMBLER) + fixP->fx_r_type = r_type; +#endif + fixP->fx_im_disp = 0; + fixP->fx_pcrel_adjust = 0; + fixP->fx_bit_fixP = 0; + fixP->fx_addnumber = 0; + fixP->fx_tcbit = 0; + fixP->fx_done = 0; + fixP->fx_no_overflow = 0; + fixP->fx_signed = 0; + +#ifdef USING_CGEN + fixP->fx_cgen.insn = NULL; + fixP->fx_cgen.opinfo = 0; +#endif + +#ifdef TC_FIX_TYPE + TC_INIT_FIX_DATA (fixP); +#endif + + as_where (&fixP->fx_file, &fixP->fx_line); + + /* Usually, we want relocs sorted numerically, but while + comparing to older versions of gas that have relocs + reverse sorted, it is convenient to have this compile + time option. xoxorich. */ + { + +#ifdef BFD_ASSEMBLER + fixS **seg_fix_rootP = (frags_chained + ? &seg_info (now_seg)->fix_root + : &frchain_now->fix_root); + fixS **seg_fix_tailP = (frags_chained + ? &seg_info (now_seg)->fix_tail + : &frchain_now->fix_tail); +#endif + +#ifdef REVERSE_SORT_RELOCS + + fixP->fx_next = *seg_fix_rootP; + *seg_fix_rootP = fixP; + +#else /* REVERSE_SORT_RELOCS */ + + fixP->fx_next = NULL; + + if (*seg_fix_tailP) + (*seg_fix_tailP)->fx_next = fixP; + else + *seg_fix_rootP = fixP; + *seg_fix_tailP = fixP; + +#endif /* REVERSE_SORT_RELOCS */ + } + + return fixP; +} + +/* Create a fixup relative to a symbol (plus a constant). */ + +fixS * +fix_new (frag, where, size, add_symbol, offset, pcrel, r_type) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + int size; /* 1, 2, or 4 usually. */ + symbolS *add_symbol; /* X_add_symbol. */ + offsetT offset; /* X_add_number. */ + int pcrel; /* TRUE if PC-relative relocation. */ + RELOC_ENUM r_type; /* Relocation type. */ +{ + return fix_new_internal (frag, where, size, add_symbol, + (symbolS *) NULL, offset, pcrel, r_type); +} + +/* Create a fixup for an expression. Currently we only support fixups + for difference expressions. That is itself more than most object + file formats support anyhow. */ + +fixS * +fix_new_exp (frag, where, size, exp, pcrel, r_type) + fragS *frag; /* Which frag? */ + int where; /* Where in that frag? */ + int size; /* 1, 2, or 4 usually. */ + expressionS *exp; /* Expression. */ + int pcrel; /* TRUE if PC-relative relocation. */ + RELOC_ENUM r_type; /* Relocation type. */ +{ + symbolS *add = NULL; + symbolS *sub = NULL; + offsetT off = 0; + + switch (exp->X_op) + { + case O_absent: + break; + + case O_register: + as_bad (_("register value used as expression")); + break; + + case O_add: + /* This comes up when _GLOBAL_OFFSET_TABLE_+(.-L0) is read, if + the difference expression cannot immediately be reduced. */ + { + symbolS *stmp = make_expr_symbol (exp); + + exp->X_op = O_symbol; + exp->X_op_symbol = 0; + exp->X_add_symbol = stmp; + exp->X_add_number = 0; + + return fix_new_exp (frag, where, size, exp, pcrel, r_type); + } + + case O_symbol_rva: + add = exp->X_add_symbol; + off = exp->X_add_number; + +#if defined(BFD_ASSEMBLER) + r_type = BFD_RELOC_RVA; +#else +#if defined(TC_RVA_RELOC) + r_type = TC_RVA_RELOC; +#else + as_fatal (_("rva not supported")); +#endif +#endif + break; + + case O_uminus: + sub = exp->X_add_symbol; + off = exp->X_add_number; + break; + + case O_subtract: + sub = exp->X_op_symbol; + /* Fall through. */ + case O_symbol: + add = exp->X_add_symbol; + /* Fall through. */ + case O_constant: + off = exp->X_add_number; + break; + + default: + add = make_expr_symbol (exp); + break; + } + + return fix_new_internal (frag, where, size, add, sub, off, pcrel, r_type); +} + +/* Generic function to determine whether a fixup requires a relocation. */ +int +generic_force_reloc (fix) + fixS *fix; +{ +#ifdef BFD_ASSEMBLER + if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT + || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + return 1; +#endif + return S_FORCE_RELOC (fix->fx_addsy, fix->fx_subsy == NULL); +} + +/* Append a string onto another string, bumping the pointer along. */ +void +append (charPP, fromP, length) + char **charPP; + char *fromP; + unsigned long length; +{ + /* Don't trust memcpy() of 0 chars. */ + if (length == 0) + return; + + memcpy (*charPP, fromP, length); + *charPP += length; +} + +#ifndef BFD_ASSEMBLER +int section_alignment[SEG_MAXIMUM_ORDINAL]; +#endif + +/* This routine records the largest alignment seen for each segment. + If the beginning of the segment is aligned on the worst-case + boundary, all of the other alignments within it will work. At + least one object format really uses this info. */ + +void +record_alignment (seg, align) + /* Segment to which alignment pertains. */ + segT seg; + /* Alignment, as a power of 2 (e.g., 1 => 2-byte boundary, 2 => 4-byte + boundary, etc.) */ + int align; +{ + if (seg == absolute_section) + return; +#ifdef BFD_ASSEMBLER + if ((unsigned int) align > bfd_get_section_alignment (stdoutput, seg)) + bfd_set_section_alignment (stdoutput, seg, align); +#else + if (align > section_alignment[(int) seg]) + section_alignment[(int) seg] = align; +#endif +} + +int +get_recorded_alignment (seg) + segT seg; +{ + if (seg == absolute_section) + return 0; +#ifdef BFD_ASSEMBLER + return bfd_get_section_alignment (stdoutput, seg); +#else + return section_alignment[(int) seg]; +#endif +} + +#ifdef BFD_ASSEMBLER + +/* Reset the section indices after removing the gas created sections. */ + +static void +renumber_sections (abfd, sec, countparg) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR countparg; +{ + int *countp = (int *) countparg; + + sec->index = *countp; + ++*countp; +} + +#endif /* defined (BFD_ASSEMBLER) */ + +#if defined (BFD_ASSEMBLER) || ! defined (BFD) + +static fragS * +chain_frchains_together_1 (section, frchp) + segT section; + struct frchain *frchp; +{ + fragS dummy, *prev_frag = &dummy; +#ifdef BFD_ASSEMBLER + fixS fix_dummy, *prev_fix = &fix_dummy; +#endif + + for (; frchp && frchp->frch_seg == section; frchp = frchp->frch_next) + { + prev_frag->fr_next = frchp->frch_root; + prev_frag = frchp->frch_last; + assert (prev_frag->fr_type != 0); +#ifdef BFD_ASSEMBLER + if (frchp->fix_root != (fixS *) NULL) + { + if (seg_info (section)->fix_root == (fixS *) NULL) + seg_info (section)->fix_root = frchp->fix_root; + prev_fix->fx_next = frchp->fix_root; + seg_info (section)->fix_tail = frchp->fix_tail; + prev_fix = frchp->fix_tail; + } +#endif + } + assert (prev_frag->fr_type != 0); + prev_frag->fr_next = 0; + return prev_frag; +} + +#endif + +#ifdef BFD_ASSEMBLER + +static void +chain_frchains_together (abfd, section, xxx) + bfd *abfd ATTRIBUTE_UNUSED; + segT section; + PTR xxx ATTRIBUTE_UNUSED; +{ + segment_info_type *info; + + /* BFD may have introduced its own sections without using + subseg_new, so it is possible that seg_info is NULL. */ + info = seg_info (section); + if (info != (segment_info_type *) NULL) + info->frchainP->frch_last + = chain_frchains_together_1 (section, info->frchainP); + + /* Now that we've chained the frags together, we must add new fixups + to the segment, not to the frag chain. */ + frags_chained = 1; +} + +#endif + +#if !defined (BFD) && !defined (BFD_ASSEMBLER) + +static void +remove_subsegs (head, seg, root, last) + frchainS *head; + int seg; + fragS **root; + fragS **last; +{ + *root = head->frch_root; + *last = chain_frchains_together_1 (seg, head); +} + +#endif /* BFD */ + +#if defined (BFD_ASSEMBLER) || !defined (BFD) + +#ifdef BFD_ASSEMBLER +static void +cvt_frag_to_fill (sec, fragP) + segT sec ATTRIBUTE_UNUSED; + fragS *fragP; +#else +static void +cvt_frag_to_fill (headersP, sec, fragP) + object_headers *headersP; + segT sec; + fragS *fragP; +#endif +{ + switch (fragP->fr_type) + { + case rs_align: + case rs_align_code: + case rs_align_test: + case rs_org: + case rs_space: +#ifdef HANDLE_ALIGN + HANDLE_ALIGN (fragP); +#endif + know (fragP->fr_next != NULL); + fragP->fr_offset = (fragP->fr_next->fr_address + - fragP->fr_address + - fragP->fr_fix) / fragP->fr_var; + if (fragP->fr_offset < 0) + { + as_bad_where (fragP->fr_file, fragP->fr_line, + _("attempt to .org/.space backwards? (%ld)"), + (long) fragP->fr_offset); + fragP->fr_offset = 0; + } + fragP->fr_type = rs_fill; + break; + + case rs_fill: + break; + + case rs_leb128: + { + valueT value = S_GET_VALUE (fragP->fr_symbol); + int size; + + size = output_leb128 (fragP->fr_literal + fragP->fr_fix, value, + fragP->fr_subtype); + + fragP->fr_fix += size; + fragP->fr_type = rs_fill; + fragP->fr_var = 0; + fragP->fr_offset = 0; + fragP->fr_symbol = NULL; + } + break; + + case rs_cfa: + eh_frame_convert_frag (fragP); + break; + + case rs_dwarf2dbg: + dwarf2dbg_convert_frag (fragP); + break; + + case rs_machine_dependent: +#ifdef BFD_ASSEMBLER + md_convert_frag (stdoutput, sec, fragP); +#else + md_convert_frag (headersP, sec, fragP); +#endif + + assert (fragP->fr_next == NULL + || ((offsetT) (fragP->fr_next->fr_address - fragP->fr_address) + == fragP->fr_fix)); + + /* After md_convert_frag, we make the frag into a ".space 0". + md_convert_frag() should set up any fixSs and constants + required. */ + frag_wane (fragP); + break; + +#ifndef WORKING_DOT_WORD + case rs_broken_word: + { + struct broken_word *lie; + + if (fragP->fr_subtype) + { + fragP->fr_fix += md_short_jump_size; + for (lie = (struct broken_word *) (fragP->fr_symbol); + lie && lie->dispfrag == fragP; + lie = lie->next_broken_word) + if (lie->added == 1) + fragP->fr_fix += md_long_jump_size; + } + frag_wane (fragP); + } + break; +#endif + + default: + BAD_CASE (fragP->fr_type); + break; + } +} + +#endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */ + +#ifdef BFD_ASSEMBLER +static void relax_seg PARAMS ((bfd *, asection *, PTR)); +static void +relax_seg (abfd, sec, xxx) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR xxx; +{ + segment_info_type *seginfo = seg_info (sec); + + if (seginfo && seginfo->frchainP + && relax_segment (seginfo->frchainP->frch_root, sec)) + { + int *result = (int *) xxx; + *result = 1; + } +} + +static void size_seg PARAMS ((bfd *, asection *, PTR)); +static void +size_seg (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx ATTRIBUTE_UNUSED; +{ + flagword flags; + fragS *fragp; + segment_info_type *seginfo; + int x; + valueT size, newsize; + + subseg_change (sec, 0); + + seginfo = seg_info (sec); + if (seginfo && seginfo->frchainP) + { + for (fragp = seginfo->frchainP->frch_root; fragp; fragp = fragp->fr_next) + cvt_frag_to_fill (sec, fragp); + for (fragp = seginfo->frchainP->frch_root; + fragp->fr_next; + fragp = fragp->fr_next) + /* Walk to last elt. */ + ; + size = fragp->fr_address + fragp->fr_fix; + } + else + size = 0; + + flags = bfd_get_section_flags (abfd, sec); + + if (size > 0 && ! seginfo->bss) + flags |= SEC_HAS_CONTENTS; + + /* @@ This is just an approximation. */ + if (seginfo && seginfo->fix_root) + flags |= SEC_RELOC; + else + flags &= ~SEC_RELOC; + x = bfd_set_section_flags (abfd, sec, flags); + assert (x); + + newsize = md_section_align (sec, size); + x = bfd_set_section_size (abfd, sec, newsize); + assert (x); + + /* If the size had to be rounded up, add some padding in the last + non-empty frag. */ + assert (newsize >= size); + if (size != newsize) + { + fragS *last = seginfo->frchainP->frch_last; + fragp = seginfo->frchainP->frch_root; + while (fragp->fr_next != last) + fragp = fragp->fr_next; + last->fr_address = size; + if ((newsize - size) % fragp->fr_var == 0) + fragp->fr_offset += (newsize - size) / fragp->fr_var; + else + /* If we hit this abort, it's likely due to subsegs_finish not + providing sufficient alignment on the last frag, and the + machine dependent code using alignment frags with fr_var + greater than 1. */ + abort (); + } + +#ifdef tc_frob_section + tc_frob_section (sec); +#endif +#ifdef obj_frob_section + obj_frob_section (sec); +#endif +} + +#ifdef DEBUG2 +static void +dump_section_relocs (abfd, sec, stream_) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + char *stream_; +{ + FILE *stream = (FILE *) stream_; + segment_info_type *seginfo = seg_info (sec); + fixS *fixp = seginfo->fix_root; + + if (!fixp) + return; + + fprintf (stream, "sec %s relocs:\n", sec->name); + while (fixp) + { + symbolS *s = fixp->fx_addsy; + + fprintf (stream, " %08lx: type %d ", (unsigned long) fixp, + (int) fixp->fx_r_type); + if (s == NULL) + fprintf (stream, "no sym\n"); + else + { + print_symbol_value_1 (stream, s); + fprintf (stream, "\n"); + } + fixp = fixp->fx_next; + } +} +#else +#define dump_section_relocs(ABFD,SEC,STREAM) ((void) 0) +#endif + +#ifndef EMIT_SECTION_SYMBOLS +#define EMIT_SECTION_SYMBOLS 1 +#endif + +/* This pass over fixups decides whether symbols can be replaced with + section symbols. */ + +static void +adjust_reloc_syms (abfd, sec, xxx) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR xxx ATTRIBUTE_UNUSED; +{ + segment_info_type *seginfo = seg_info (sec); + fixS *fixp; + + if (seginfo == NULL) + return; + + dump_section_relocs (abfd, sec, stderr); + + for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) + if (fixp->fx_done) + /* Ignore it. */ + ; + else if (fixp->fx_addsy) + { + symbolS *sym; + asection *symsec; + +#ifdef DEBUG5 + fprintf (stderr, "\n\nadjusting fixup:\n"); + print_fixup (fixp); +#endif + + sym = fixp->fx_addsy; + + /* All symbols should have already been resolved at this + point. It is possible to see unresolved expression + symbols, though, since they are not in the regular symbol + table. */ + resolve_symbol_value (sym); + + if (fixp->fx_subsy != NULL) + resolve_symbol_value (fixp->fx_subsy); + + /* If this symbol is equated to an undefined symbol, convert + the fixup to being against that symbol. */ + if (symbol_equated_reloc_p (sym)) + { + fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number; + sym = symbol_get_value_expression (sym)->X_add_symbol; + fixp->fx_addsy = sym; + } + + if (symbol_mri_common_p (sym)) + { + /* These symbols are handled specially in fixup_segment. */ + continue; + } + + /* If the symbol is undefined, common, weak, or global (ELF + shared libs), we can't replace it with the section symbol. */ + if (S_FORCE_RELOC (fixp->fx_addsy, 1)) + continue; + + /* Is there some other (target cpu dependent) reason we can't adjust + this one? (E.g. relocations involving function addresses on + the PA. */ +#ifdef tc_fix_adjustable + if (! tc_fix_adjustable (fixp)) + continue; +#endif + + /* Since we're reducing to section symbols, don't attempt to reduce + anything that's already using one. */ + if (symbol_section_p (sym)) + continue; + + symsec = S_GET_SEGMENT (sym); + if (symsec == NULL) + abort (); + + if (bfd_is_abs_section (symsec)) + { + /* The fixup_segment routine normally will not use this + symbol in a relocation. */ + continue; + } + + /* Don't try to reduce relocs which refer to non-local symbols + in .linkonce sections. It can lead to confusion when a + debugging section refers to a .linkonce section. I hope + this will always be correct. */ + if (symsec != sec && ! S_IS_LOCAL (sym)) + { + if ((symsec->flags & SEC_LINK_ONCE) != 0 + || (IS_ELF + /* The GNU toolchain uses an extension for ELF: a + section beginning with the magic string + .gnu.linkonce is a linkonce section. */ + && strncmp (segment_name (symsec), ".gnu.linkonce", + sizeof ".gnu.linkonce" - 1) == 0)) + continue; + } + + /* Never adjust a reloc against local symbol in a merge section + with non-zero addend. */ + if ((symsec->flags & SEC_MERGE) != 0 + && (fixp->fx_offset != 0 || fixp->fx_subsy != NULL)) + continue; + + /* Never adjust a reloc against TLS local symbol. */ + if ((symsec->flags & SEC_THREAD_LOCAL) != 0) + continue; + + /* We refetch the segment when calling section_symbol, rather + than using symsec, because S_GET_VALUE may wind up changing + the section when it calls resolve_symbol_value. */ + fixp->fx_offset += S_GET_VALUE (sym); + fixp->fx_addsy = section_symbol (S_GET_SEGMENT (sym)); +#ifdef DEBUG5 + fprintf (stderr, "\nadjusted fixup:\n"); + print_fixup (fixp); +#endif + } + + dump_section_relocs (abfd, sec, stderr); +} + +static void +fix_segment (abfd, sec, xxx) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR xxx ATTRIBUTE_UNUSED; +{ + segment_info_type *seginfo = seg_info (sec); + + fixup_segment (seginfo->fix_root, sec); +} + +static void +write_relocs (abfd, sec, xxx) + bfd *abfd; + asection *sec; + PTR xxx ATTRIBUTE_UNUSED; +{ + segment_info_type *seginfo = seg_info (sec); + unsigned int i; + unsigned int n; + arelent **relocs; + fixS *fixp; + char *err; + + /* If seginfo is NULL, we did not create this section; don't do + anything with it. */ + if (seginfo == NULL) + return; + + n = 0; + for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) + n++; + +#ifndef RELOC_EXPANSION_POSSIBLE + /* Set up reloc information as well. */ + relocs = (arelent **) xmalloc (n * sizeof (arelent *)); + memset ((char *) relocs, 0, n * sizeof (arelent *)); + + i = 0; + for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next) + { + arelent *reloc; + bfd_reloc_status_type s; + symbolS *sym; + + if (fixp->fx_done) + { + n--; + continue; + } + + /* If this is an undefined symbol which was equated to another + symbol, then generate the reloc against the latter symbol + rather than the former. */ + sym = fixp->fx_addsy; + while (symbol_equated_reloc_p (sym)) + { + symbolS *n; + + /* We must avoid looping, as that can occur with a badly + written program. */ + n = symbol_get_value_expression (sym)->X_add_symbol; + if (n == sym) + break; + fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number; + sym = n; + } + fixp->fx_addsy = sym; + + reloc = tc_gen_reloc (sec, fixp); + if (!reloc) + { + n--; + continue; + } + +#if 0 + /* This test is triggered inappropriately for the SH. */ + if (fixp->fx_where + fixp->fx_size + > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset) + abort (); +#endif + + s = bfd_install_relocation (stdoutput, reloc, + fixp->fx_frag->fr_literal, + fixp->fx_frag->fr_address, + sec, &err); + switch (s) + { + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("relocation overflow")); + break; + case bfd_reloc_outofrange: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("relocation out of range")); + break; + default: + as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"), + fixp->fx_file, fixp->fx_line, s); + } + relocs[i++] = reloc; + } +#else + n = n * MAX_RELOC_EXPANSION; + /* Set up reloc information as well. */ + relocs = (arelent **) xmalloc (n * sizeof (arelent *)); + + i = 0; + for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next) + { + arelent **reloc; + bfd_reloc_status_type s; + symbolS *sym; + int j; + + if (fixp->fx_done) + { + n--; + continue; + } + + /* If this is an undefined symbol which was equated to another + symbol, then generate the reloc against the latter symbol + rather than the former. */ + sym = fixp->fx_addsy; + while (symbol_equated_reloc_p (sym)) + { + symbolS *n; + + /* We must avoid looping, as that can occur with a badly + written program. */ + n = symbol_get_value_expression (sym)->X_add_symbol; + if (n == sym) + break; + fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number; + sym = n; + } + fixp->fx_addsy = sym; + + reloc = tc_gen_reloc (sec, fixp); + + for (j = 0; reloc[j]; j++) + { + relocs[i++] = reloc[j]; + assert (i <= n); + } + if (fixp->fx_where + fixp->fx_size + > fixp->fx_frag->fr_fix + fixp->fx_frag->fr_offset) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("internal error: fixup not contained within frag")); + for (j = 0; reloc[j]; j++) + { + s = bfd_install_relocation (stdoutput, reloc[j], + fixp->fx_frag->fr_literal, + fixp->fx_frag->fr_address, + sec, &err); + switch (s) + { + case bfd_reloc_ok: + break; + case bfd_reloc_overflow: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("relocation overflow")); + break; + case bfd_reloc_outofrange: + as_bad_where (fixp->fx_file, fixp->fx_line, + _("relocation out of range")); + break; + default: + as_fatal (_("%s:%u: bad return from bfd_install_relocation: %x"), + fixp->fx_file, fixp->fx_line, s); + } + } + } + n = i; +#endif + +#ifdef DEBUG4 + { + int i, j, nsyms; + asymbol **sympp; + sympp = bfd_get_outsymbols (stdoutput); + nsyms = bfd_get_symcount (stdoutput); + for (i = 0; i < n; i++) + if (((*relocs[i]->sym_ptr_ptr)->flags & BSF_SECTION_SYM) == 0) + { + for (j = 0; j < nsyms; j++) + if (sympp[j] == *relocs[i]->sym_ptr_ptr) + break; + if (j == nsyms) + abort (); + } + } +#endif + + if (n) + bfd_set_reloc (stdoutput, sec, relocs, n); + else + bfd_set_section_flags (abfd, sec, + (bfd_get_section_flags (abfd, sec) + & (flagword) ~SEC_RELOC)); + +#ifdef SET_SECTION_RELOCS + SET_SECTION_RELOCS (sec, relocs, n); +#endif + +#ifdef DEBUG3 + { + int i; + arelent *r; + asymbol *s; + fprintf (stderr, "relocs for sec %s\n", sec->name); + for (i = 0; i < n; i++) + { + r = relocs[i]; + s = *r->sym_ptr_ptr; + fprintf (stderr, " reloc %2d @%08x off %4x : sym %-10s addend %x\n", + i, r, r->address, s->name, r->addend); + } + } +#endif +} + +static void +write_contents (abfd, sec, xxx) + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec; + PTR xxx ATTRIBUTE_UNUSED; +{ + segment_info_type *seginfo = seg_info (sec); + unsigned long offset = 0; + fragS *f; + + /* Write out the frags. */ + if (seginfo == NULL + || !(bfd_get_section_flags (abfd, sec) & SEC_HAS_CONTENTS)) + return; + + for (f = seginfo->frchainP->frch_root; + f; + f = f->fr_next) + { + int x; + unsigned long fill_size; + char *fill_literal; + long count; + + assert (f->fr_type == rs_fill); + if (f->fr_fix) + { + x = bfd_set_section_contents (stdoutput, sec, + f->fr_literal, (file_ptr) offset, + (bfd_size_type) f->fr_fix); + if (!x) + { + bfd_perror (stdoutput->filename); + as_perror (_("FATAL: Can't write %s"), stdoutput->filename); + exit (EXIT_FAILURE); + } + offset += f->fr_fix; + } + fill_literal = f->fr_literal + f->fr_fix; + fill_size = f->fr_var; + count = f->fr_offset; + assert (count >= 0); + if (fill_size && count) + { + char buf[256]; + if (fill_size > sizeof (buf)) + { + /* Do it the old way. Can this ever happen? */ + while (count--) + { + x = bfd_set_section_contents (stdoutput, sec, + fill_literal, + (file_ptr) offset, + (bfd_size_type) fill_size); + if (!x) + { + bfd_perror (stdoutput->filename); + as_perror (_("FATAL: Can't write %s"), + stdoutput->filename); + exit (EXIT_FAILURE); + } + offset += fill_size; + } + } + else + { + /* Build a buffer full of fill objects and output it as + often as necessary. This saves on the overhead of + potentially lots of bfd_set_section_contents calls. */ + int n_per_buf, i; + if (fill_size == 1) + { + n_per_buf = sizeof (buf); + memset (buf, *fill_literal, n_per_buf); + } + else + { + char *bufp; + n_per_buf = sizeof (buf) / fill_size; + for (i = n_per_buf, bufp = buf; i; i--, bufp += fill_size) + memcpy (bufp, fill_literal, fill_size); + } + for (; count > 0; count -= n_per_buf) + { + n_per_buf = n_per_buf > count ? count : n_per_buf; + x = bfd_set_section_contents + (stdoutput, sec, buf, (file_ptr) offset, + (bfd_size_type) n_per_buf * fill_size); + if (!x) + as_fatal (_("cannot write to output file")); + offset += n_per_buf * fill_size; + } + } + } + } +} +#endif + +#if defined(BFD_ASSEMBLER) || (!defined (BFD) && !defined(OBJ_AOUT)) +static void +merge_data_into_text () +{ +#if defined(BFD_ASSEMBLER) || defined(MANY_SEGMENTS) + seg_info (text_section)->frchainP->frch_last->fr_next = + seg_info (data_section)->frchainP->frch_root; + seg_info (text_section)->frchainP->frch_last = + seg_info (data_section)->frchainP->frch_last; + seg_info (data_section)->frchainP = 0; +#else + fixS *tmp; + + text_last_frag->fr_next = data_frag_root; + text_last_frag = data_last_frag; + data_last_frag = NULL; + data_frag_root = NULL; + if (text_fix_root) + { + for (tmp = text_fix_root; tmp->fx_next; tmp = tmp->fx_next);; + tmp->fx_next = data_fix_root; + text_fix_tail = data_fix_tail; + } + else + text_fix_root = data_fix_root; + data_fix_root = NULL; +#endif +} +#endif /* BFD_ASSEMBLER || (! BFD && ! OBJ_AOUT) */ + +#if !defined (BFD_ASSEMBLER) && !defined (BFD) +static void +relax_and_size_all_segments () +{ + fragS *fragP; + + relax_segment (text_frag_root, SEG_TEXT); + relax_segment (data_frag_root, SEG_DATA); + relax_segment (bss_frag_root, SEG_BSS); + + /* Now the addresses of frags are correct within the segment. */ + know (text_last_frag->fr_type == rs_fill && text_last_frag->fr_offset == 0); + H_SET_TEXT_SIZE (&headers, text_last_frag->fr_address); + text_last_frag->fr_address = H_GET_TEXT_SIZE (&headers); + + /* Join the 2 segments into 1 huge segment. + To do this, re-compute every rn_address in the SEG_DATA frags. + Then join the data frags after the text frags. + + Determine a_data [length of data segment]. */ + if (data_frag_root) + { + register relax_addressT slide; + + know ((text_last_frag->fr_type == rs_fill) + && (text_last_frag->fr_offset == 0)); + + H_SET_DATA_SIZE (&headers, data_last_frag->fr_address); + data_last_frag->fr_address = H_GET_DATA_SIZE (&headers); + slide = H_GET_TEXT_SIZE (&headers); /* & in file of the data segment. */ +#ifdef OBJ_BOUT +#define RoundUp(N,S) (((N)+(S)-1)&-(S)) + /* For b.out: If the data section has a strict alignment + requirement, its load address in the .o file will be + rounded up from the size of the text section. These + two values are *not* the same! Similarly for the bss + section.... */ + slide = RoundUp (slide, 1 << section_alignment[SEG_DATA]); +#endif + + for (fragP = data_frag_root; fragP; fragP = fragP->fr_next) + fragP->fr_address += slide; + + know (text_last_frag != 0); + text_last_frag->fr_next = data_frag_root; + } + else + { + H_SET_DATA_SIZE (&headers, 0); + } + +#ifdef OBJ_BOUT + /* See above comments on b.out data section address. */ + { + long bss_vma; + if (data_last_frag == 0) + bss_vma = H_GET_TEXT_SIZE (&headers); + else + bss_vma = data_last_frag->fr_address; + bss_vma = RoundUp (bss_vma, 1 << section_alignment[SEG_BSS]); + bss_address_frag.fr_address = bss_vma; + } +#else /* ! OBJ_BOUT */ + bss_address_frag.fr_address = (H_GET_TEXT_SIZE (&headers) + + H_GET_DATA_SIZE (&headers)); + +#endif /* ! OBJ_BOUT */ + + /* Slide all the frags. */ + if (bss_frag_root) + { + relax_addressT slide = bss_address_frag.fr_address; + + for (fragP = bss_frag_root; fragP; fragP = fragP->fr_next) + fragP->fr_address += slide; + } + + if (bss_last_frag) + H_SET_BSS_SIZE (&headers, + bss_last_frag->fr_address - bss_frag_root->fr_address); + else + H_SET_BSS_SIZE (&headers, 0); +} +#endif /* ! BFD_ASSEMBLER && ! BFD */ + +#if defined (BFD_ASSEMBLER) || !defined (BFD) + +#ifdef BFD_ASSEMBLER +static void +set_symtab () +{ + int nsyms; + asymbol **asympp; + symbolS *symp; + bfd_boolean result; + extern PTR bfd_alloc PARAMS ((bfd *, bfd_size_type)); + + /* Count symbols. We can't rely on a count made by the loop in + write_object_file, because *_frob_file may add a new symbol or + two. */ + nsyms = 0; + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + nsyms++; + + if (nsyms) + { + int i; + bfd_size_type amt = (bfd_size_type) nsyms * sizeof (asymbol *); + + asympp = (asymbol **) bfd_alloc (stdoutput, amt); + symp = symbol_rootP; + for (i = 0; i < nsyms; i++, symp = symbol_next (symp)) + { + asympp[i] = symbol_get_bfdsym (symp); + symbol_mark_written (symp); + } + } + else + asympp = 0; + result = bfd_set_symtab (stdoutput, asympp, nsyms); + assert (result); + symbol_table_frozen = 1; +} +#endif + +/* Finish the subsegments. After every sub-segment, we fake an + ".align ...". This conforms to BSD4.2 brane-damage. We then fake + ".fill 0" because that is the kind of frag that requires least + thought. ".align" frags like to have a following frag since that + makes calculating their intended length trivial. */ + +#ifndef SUB_SEGMENT_ALIGN +#ifdef HANDLE_ALIGN +/* The last subsegment gets an aligment corresponding to the alignment + of the section. This allows proper nop-filling at the end of + code-bearing sections. */ +#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) \ + (!(FRCHAIN)->frch_next || (FRCHAIN)->frch_next->frch_seg != (SEG) \ + ? get_recorded_alignment (SEG) : 0) +#else +#ifdef BFD_ASSEMBLER +#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 0 +#else +#define SUB_SEGMENT_ALIGN(SEG, FRCHAIN) 2 +#endif +#endif +#endif + +void +subsegs_finish () +{ + struct frchain *frchainP; + + for (frchainP = frchain_root; frchainP; frchainP = frchainP->frch_next) + { + int alignment = 0; + + subseg_set (frchainP->frch_seg, frchainP->frch_subseg); + + /* This now gets called even if we had errors. In that case, + any alignment is meaningless, and, moreover, will look weird + if we are generating a listing. */ + if (!had_errors ()) + { + alignment = SUB_SEGMENT_ALIGN (now_seg, frchainP); +#ifdef BFD_ASSEMBLER + if ((bfd_get_section_flags (now_seg->owner, now_seg) & SEC_MERGE) + && now_seg->entsize) + { + unsigned int entsize = now_seg->entsize; + int entalign = 0; + + while ((entsize & 1) == 0) + { + ++entalign; + entsize >>= 1; + } + if (entalign > alignment) + alignment = entalign; + } +#endif + } + + if (subseg_text_p (now_seg)) + frag_align_code (alignment, 0); + else + frag_align (alignment, 0, 0); + + /* frag_align will have left a new frag. + Use this last frag for an empty ".fill". + + For this segment ... + Create a last frag. Do not leave a "being filled in frag". */ + frag_wane (frag_now); + frag_now->fr_fix = 0; + know (frag_now->fr_next == NULL); + } +} + +/* Write the object file. */ + +void +write_object_file () +{ +#if ! defined (BFD_ASSEMBLER) || ! defined (WORKING_DOT_WORD) + fragS *fragP; /* Track along all frags. */ +#endif + + /* Do we really want to write it? */ + { + int n_warns, n_errs; + n_warns = had_warnings (); + n_errs = had_errors (); + /* The -Z flag indicates that an object file should be generated, + regardless of warnings and errors. */ + if (flag_always_generate_output) + { + if (n_warns || n_errs) + as_warn (_("%d error%s, %d warning%s, generating bad object file"), + n_errs, n_errs == 1 ? "" : "s", + n_warns, n_warns == 1 ? "" : "s"); + } + else + { + if (n_errs) + as_fatal (_("%d error%s, %d warning%s, no object file generated"), + n_errs, n_errs == 1 ? "" : "s", + n_warns, n_warns == 1 ? "" : "s"); + } + } + +#ifdef OBJ_VMS + /* Under VMS we try to be compatible with VAX-11 "C". Thus, we call + a routine to check for the definition of the procedure "_main", + and if so -- fix it up so that it can be program entry point. */ + vms_check_for_main (); +#endif /* OBJ_VMS */ + + /* From now on, we don't care about sub-segments. Build one frag chain + for each segment. Linked thru fr_next. */ + +#ifdef BFD_ASSEMBLER + /* Remove the sections created by gas for its own purposes. */ + { + asection **seclist; + int i; + + seclist = &stdoutput->sections; + while (*seclist) + { + if (*seclist == reg_section || *seclist == expr_section) + { + bfd_section_list_remove (stdoutput, seclist); + stdoutput->section_count--; + } + else + seclist = &(*seclist)->next; + } + i = 0; + bfd_map_over_sections (stdoutput, renumber_sections, &i); + } + + bfd_map_over_sections (stdoutput, chain_frchains_together, (char *) 0); +#else + remove_subsegs (frchain_root, SEG_TEXT, &text_frag_root, &text_last_frag); + remove_subsegs (data0_frchainP, SEG_DATA, &data_frag_root, &data_last_frag); + remove_subsegs (bss0_frchainP, SEG_BSS, &bss_frag_root, &bss_last_frag); +#endif + + /* We have two segments. If user gave -R flag, then we must put the + data frags into the text segment. Do this before relaxing so + we know to take advantage of -R and make shorter addresses. */ +#if !defined (OBJ_AOUT) || defined (BFD_ASSEMBLER) + if (flag_readonly_data_in_text) + { + merge_data_into_text (); + } +#endif + +#ifdef BFD_ASSEMBLER + while (1) + { + int changed; + +#ifndef WORKING_DOT_WORD + /* We need to reset the markers in the broken word list and + associated frags between calls to relax_segment (via + relax_seg). Since the broken word list is global, we do it + once per round, rather than locally in relax_segment for each + segment. */ + struct broken_word *brokp; + + for (brokp = broken_words; + brokp != (struct broken_word *) NULL; + brokp = brokp->next_broken_word) + { + brokp->added = 0; + + if (brokp->dispfrag != (fragS *) NULL + && brokp->dispfrag->fr_type == rs_broken_word) + brokp->dispfrag->fr_subtype = 0; + } +#endif + + changed = 0; + bfd_map_over_sections (stdoutput, relax_seg, &changed); + if (!changed) + break; + } + + /* Note - Most ports will use the default value of + TC_FINALIZE_SYMS_BEFORE_SIZE_SEG, which 1. This will force + local symbols to be resolved, removing their frag information. + Some ports however, will not have finished relaxing all of + their frags and will still need the local symbol frag + information. These ports can set + TC_FINALIZE_SYMS_BEFORE_SIZE_SEG to 0. */ + finalize_syms = TC_FINALIZE_SYMS_BEFORE_SIZE_SEG; + + bfd_map_over_sections (stdoutput, size_seg, (char *) 0); +#else + relax_and_size_all_segments (); +#endif /* BFD_ASSEMBLER */ + + /* Relaxation has completed. Freeze all syms. */ + finalize_syms = 1; + +#ifdef md_post_relax_hook + md_post_relax_hook; +#endif + +#ifndef BFD_ASSEMBLER + /* Crawl the symbol chain. + + For each symbol whose value depends on a frag, take the address of + that frag and subsume it into the value of the symbol. + After this, there is just one way to lookup a symbol value. + Values are left in their final state for object file emission. + We adjust the values of 'L' local symbols, even if we do + not intend to emit them to the object file, because their values + are needed for fix-ups. + + Unless we saw a -L flag, remove all symbols that begin with 'L' + from the symbol chain. (They are still pointed to by the fixes.) + + Count the remaining symbols. + Assign a symbol number to each symbol. + Count the number of string-table chars we will emit. + Put this info into the headers as appropriate. */ + know (zero_address_frag.fr_address == 0); + string_byte_count = sizeof (string_byte_count); + + obj_crawl_symbol_chain (&headers); + + if (string_byte_count == sizeof (string_byte_count)) + string_byte_count = 0; + + H_SET_STRING_SIZE (&headers, string_byte_count); + + /* Addresses of frags now reflect addresses we use in the object file. + Symbol values are correct. + Scan the frags, converting any ".org"s and ".align"s to ".fill"s. + Also converting any machine-dependent frags using md_convert_frag(); */ + subseg_change (SEG_TEXT, 0); + + for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) + { + /* At this point we have linked all the frags into a single + chain. However, cvt_frag_to_fill may call md_convert_frag + which may call fix_new. We need to ensure that fix_new adds + the fixup to the right section. */ + if (fragP == data_frag_root) + subseg_change (SEG_DATA, 0); + + cvt_frag_to_fill (&headers, SEG_TEXT, fragP); + + /* Some assert macros don't work with # directives mixed in. */ +#ifndef NDEBUG + if (!(fragP->fr_next == NULL +#ifdef OBJ_BOUT + || fragP->fr_next == data_frag_root +#endif + || ((offsetT) (fragP->fr_next->fr_address - fragP->fr_address) + == (fragP->fr_fix + fragP->fr_offset * fragP->fr_var)))) + abort (); +#endif + } +#endif /* ! BFD_ASSEMBLER */ + +#ifndef WORKING_DOT_WORD + { + struct broken_word *lie; + struct broken_word **prevP; + + prevP = &broken_words; + for (lie = broken_words; lie; lie = lie->next_broken_word) + if (!lie->added) + { + expressionS exp; + + subseg_change (lie->seg, lie->subseg); + exp.X_op = O_subtract; + exp.X_add_symbol = lie->add; + exp.X_op_symbol = lie->sub; + exp.X_add_number = lie->addnum; +#ifdef BFD_ASSEMBLER +#ifdef TC_CONS_FIX_NEW + TC_CONS_FIX_NEW (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp); +#else + fix_new_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp, 0, BFD_RELOC_16); +#endif +#else +#if defined(TC_SPARC) || defined(TC_A29K) || defined(NEED_FX_R_TYPE) + fix_new_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp, 0, NO_RELOC); +#else +#ifdef TC_NS32K + fix_new_ns32k_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp, 0, 0, 2, 0, 0); +#else + fix_new_exp (lie->frag, + lie->word_goes_here - lie->frag->fr_literal, + 2, &exp, 0, 0); +#endif /* TC_NS32K */ +#endif /* TC_SPARC|TC_A29K|NEED_FX_R_TYPE */ +#endif /* BFD_ASSEMBLER */ + *prevP = lie->next_broken_word; + } + else + prevP = &(lie->next_broken_word); + + for (lie = broken_words; lie;) + { + struct broken_word *untruth; + char *table_ptr; + addressT table_addr; + addressT from_addr, to_addr; + int n, m; + + subseg_change (lie->seg, lie->subseg); + fragP = lie->dispfrag; + + /* Find out how many broken_words go here. */ + n = 0; + for (untruth = lie; + untruth && untruth->dispfrag == fragP; + untruth = untruth->next_broken_word) + if (untruth->added == 1) + n++; + + table_ptr = lie->dispfrag->fr_opcode; + table_addr = (lie->dispfrag->fr_address + + (table_ptr - lie->dispfrag->fr_literal)); + /* Create the jump around the long jumps. This is a short + jump from table_ptr+0 to table_ptr+n*long_jump_size. */ + from_addr = table_addr; + to_addr = table_addr + md_short_jump_size + n * md_long_jump_size; + md_create_short_jump (table_ptr, from_addr, to_addr, lie->dispfrag, + lie->add); + table_ptr += md_short_jump_size; + table_addr += md_short_jump_size; + + for (m = 0; + lie && lie->dispfrag == fragP; + m++, lie = lie->next_broken_word) + { + if (lie->added == 2) + continue; + /* Patch the jump table. */ + /* This is the offset from ??? to table_ptr+0. */ + to_addr = table_addr - S_GET_VALUE (lie->sub); +#ifdef TC_CHECK_ADJUSTED_BROKEN_DOT_WORD + TC_CHECK_ADJUSTED_BROKEN_DOT_WORD (to_addr, lie); +#endif + md_number_to_chars (lie->word_goes_here, to_addr, 2); + for (untruth = lie->next_broken_word; + untruth && untruth->dispfrag == fragP; + untruth = untruth->next_broken_word) + { + if (untruth->use_jump == lie) + md_number_to_chars (untruth->word_goes_here, to_addr, 2); + } + + /* Install the long jump. */ + /* This is a long jump from table_ptr+0 to the final target. */ + from_addr = table_addr; + to_addr = S_GET_VALUE (lie->add) + lie->addnum; + md_create_long_jump (table_ptr, from_addr, to_addr, lie->dispfrag, + lie->add); + table_ptr += md_long_jump_size; + table_addr += md_long_jump_size; + } + } + } +#endif /* not WORKING_DOT_WORD */ + +#ifndef BFD_ASSEMBLER +#ifndef OBJ_VMS + { /* not vms */ + char *the_object_file; + long object_file_size; + /* Scan every FixS performing fixups. We had to wait until now to + do this because md_convert_frag() may have made some fixSs. */ + int trsize, drsize; + + subseg_change (SEG_TEXT, 0); + trsize = md_reloc_size * fixup_segment (text_fix_root, SEG_TEXT); + subseg_change (SEG_DATA, 0); + drsize = md_reloc_size * fixup_segment (data_fix_root, SEG_DATA); + H_SET_RELOCATION_SIZE (&headers, trsize, drsize); + + /* FIXME: Move this stuff into the pre-write-hook. */ + H_SET_MAGIC_NUMBER (&headers, magic_number_for_object_file); + H_SET_ENTRY_POINT (&headers, 0); + + obj_pre_write_hook (&headers); /* Extra coff stuff. */ + + object_file_size = H_GET_FILE_SIZE (&headers); + next_object_file_charP = the_object_file = xmalloc (object_file_size); + + output_file_create (out_file_name); + + obj_header_append (&next_object_file_charP, &headers); + + know ((next_object_file_charP - the_object_file) + == H_GET_HEADER_SIZE (&headers)); + + /* Emit code. */ + for (fragP = text_frag_root; fragP; fragP = fragP->fr_next) + { + register long count; + register char *fill_literal; + register long fill_size; + + PROGRESS (1); + know (fragP->fr_type == rs_fill); + append (&next_object_file_charP, fragP->fr_literal, + (unsigned long) fragP->fr_fix); + fill_literal = fragP->fr_literal + fragP->fr_fix; + fill_size = fragP->fr_var; + know (fragP->fr_offset >= 0); + + for (count = fragP->fr_offset; count; count--) + append (&next_object_file_charP, fill_literal, + (unsigned long) fill_size); + } + + know ((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE (&headers) + + H_GET_TEXT_SIZE (&headers) + + H_GET_DATA_SIZE (&headers))); + + /* Emit relocations. */ + obj_emit_relocations (&next_object_file_charP, text_fix_root, + (relax_addressT) 0); + know ((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE (&headers) + + H_GET_TEXT_SIZE (&headers) + + H_GET_DATA_SIZE (&headers) + + H_GET_TEXT_RELOCATION_SIZE (&headers))); +#ifdef TC_I960 + /* Make addresses in data relocation directives relative to beginning of + first data fragment, not end of last text fragment: alignment of the + start of the data segment may place a gap between the segments. */ + obj_emit_relocations (&next_object_file_charP, data_fix_root, + data0_frchainP->frch_root->fr_address); +#else /* TC_I960 */ + obj_emit_relocations (&next_object_file_charP, data_fix_root, + text_last_frag->fr_address); +#endif /* TC_I960 */ + + know ((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE (&headers) + + H_GET_TEXT_SIZE (&headers) + + H_GET_DATA_SIZE (&headers) + + H_GET_TEXT_RELOCATION_SIZE (&headers) + + H_GET_DATA_RELOCATION_SIZE (&headers))); + + /* Emit line number entries. */ + OBJ_EMIT_LINENO (&next_object_file_charP, lineno_rootP, the_object_file); + know ((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE (&headers) + + H_GET_TEXT_SIZE (&headers) + + H_GET_DATA_SIZE (&headers) + + H_GET_TEXT_RELOCATION_SIZE (&headers) + + H_GET_DATA_RELOCATION_SIZE (&headers) + + H_GET_LINENO_SIZE (&headers))); + + /* Emit symbols. */ + obj_emit_symbols (&next_object_file_charP, symbol_rootP); + know ((next_object_file_charP - the_object_file) + == (H_GET_HEADER_SIZE (&headers) + + H_GET_TEXT_SIZE (&headers) + + H_GET_DATA_SIZE (&headers) + + H_GET_TEXT_RELOCATION_SIZE (&headers) + + H_GET_DATA_RELOCATION_SIZE (&headers) + + H_GET_LINENO_SIZE (&headers) + + H_GET_SYMBOL_TABLE_SIZE (&headers))); + + /* Emit strings. */ + if (string_byte_count > 0) + obj_emit_strings (&next_object_file_charP); + +#ifdef BFD_HEADERS + bfd_seek (stdoutput, (file_ptr) 0, 0); + bfd_bwrite (the_object_file, (bfd_size_type) object_file_size, stdoutput); +#else + + /* Write the data to the file. */ + output_file_append (the_object_file, object_file_size, out_file_name); + free (the_object_file); +#endif + } +#else /* OBJ_VMS */ + /* Now do the VMS-dependent part of writing the object file. */ + vms_write_object_file (H_GET_TEXT_SIZE (&headers), + H_GET_DATA_SIZE (&headers), + H_GET_BSS_SIZE (&headers), + text_frag_root, data_frag_root); +#endif /* OBJ_VMS */ +#else /* BFD_ASSEMBLER */ + + /* Resolve symbol values. This needs to be done before processing + the relocations. */ + if (symbol_rootP) + { + symbolS *symp; + + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + resolve_symbol_value (symp); + } + resolve_local_symbol_values (); + + PROGRESS (1); + +#ifdef tc_frob_file_before_adjust + tc_frob_file_before_adjust (); +#endif +#ifdef obj_frob_file_before_adjust + obj_frob_file_before_adjust (); +#endif + + bfd_map_over_sections (stdoutput, adjust_reloc_syms, (char *) 0); + +#ifdef tc_frob_file_before_fix + tc_frob_file_before_fix (); +#endif +#ifdef obj_frob_file_before_fix + obj_frob_file_before_fix (); +#endif + + bfd_map_over_sections (stdoutput, fix_segment, (char *) 0); + + /* Set up symbol table, and write it out. */ + if (symbol_rootP) + { + symbolS *symp; + + for (symp = symbol_rootP; symp; symp = symbol_next (symp)) + { + int punt = 0; + const char *name; + + if (symbol_mri_common_p (symp)) + { + if (S_IS_EXTERNAL (symp)) + as_bad (_("%s: global symbols not supported in common sections"), + S_GET_NAME (symp)); + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + continue; + } + + name = S_GET_NAME (symp); + if (name) + { + const char *name2 = + decode_local_label_name ((char *) S_GET_NAME (symp)); + /* They only differ if `name' is a fb or dollar local + label name. */ + if (name2 != name && ! S_IS_DEFINED (symp)) + as_bad (_("local label `%s' is not defined"), name2); + } + + /* Do it again, because adjust_reloc_syms might introduce + more symbols. They'll probably only be section symbols, + but they'll still need to have the values computed. */ + resolve_symbol_value (symp); + + /* Skip symbols which were equated to undefined or common + symbols. */ + if (symbol_equated_reloc_p (symp)) + { + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + continue; + } + + /* So far, common symbols have been treated like undefined symbols. + Put them in the common section now. */ + if (S_IS_DEFINED (symp) == 0 + && S_GET_VALUE (symp) != 0) + S_SET_SEGMENT (symp, bfd_com_section_ptr); +#if 0 + printf ("symbol `%s'\n\t@%x: value=%d flags=%x seg=%s\n", + S_GET_NAME (symp), symp, + S_GET_VALUE (symp), + symbol_get_bfdsym (symp)->flags, + segment_name (S_GET_SEGMENT (symp))); +#endif + +#ifdef obj_frob_symbol + obj_frob_symbol (symp, punt); +#endif +#ifdef tc_frob_symbol + if (! punt || symbol_used_in_reloc_p (symp)) + tc_frob_symbol (symp, punt); +#endif + + /* If we don't want to keep this symbol, splice it out of + the chain now. If EMIT_SECTION_SYMBOLS is 0, we never + want section symbols. Otherwise, we skip local symbols + and symbols that the frob_symbol macros told us to punt, + but we keep such symbols if they are used in relocs. */ + if (symp == abs_section_sym + || (! EMIT_SECTION_SYMBOLS + && symbol_section_p (symp)) + /* Note that S_IS_EXTERN and S_IS_LOCAL are not always + opposites. Sometimes the former checks flags and the + latter examines the name... */ + || (!S_IS_EXTERN (symp) + && (punt || S_IS_LOCAL (symp)) + && ! symbol_used_in_reloc_p (symp))) + { + symbol_remove (symp, &symbol_rootP, &symbol_lastP); + + /* After symbol_remove, symbol_next(symp) still returns + the one that came after it in the chain. So we don't + need to do any extra cleanup work here. */ + continue; + } + + /* Make sure we really got a value for the symbol. */ + if (! symbol_resolved_p (symp)) + { + as_bad (_("can't resolve value for symbol `%s'"), + S_GET_NAME (symp)); + symbol_mark_resolved (symp); + } + + /* Set the value into the BFD symbol. Up til now the value + has only been kept in the gas symbolS struct. */ + symbol_get_bfdsym (symp)->value = S_GET_VALUE (symp); + } + } + + PROGRESS (1); + + /* Now do any format-specific adjustments to the symbol table, such + as adding file symbols. */ +#ifdef tc_adjust_symtab + tc_adjust_symtab (); +#endif +#ifdef obj_adjust_symtab + obj_adjust_symtab (); +#endif + + /* Now that all the sizes are known, and contents correct, we can + start writing to the file. */ + set_symtab (); + + /* If *_frob_file changes the symbol value at this point, it is + responsible for moving the changed value into symp->bsym->value + as well. Hopefully all symbol value changing can be done in + *_frob_symbol. */ +#ifdef tc_frob_file + tc_frob_file (); +#endif +#ifdef obj_frob_file + obj_frob_file (); +#endif + + bfd_map_over_sections (stdoutput, write_relocs, (char *) 0); + +#ifdef tc_frob_file_after_relocs + tc_frob_file_after_relocs (); +#endif +#ifdef obj_frob_file_after_relocs + obj_frob_file_after_relocs (); +#endif + + bfd_map_over_sections (stdoutput, write_contents, (char *) 0); +#endif /* BFD_ASSEMBLER */ +} +#endif /* ! BFD */ + +#ifdef TC_GENERIC_RELAX_TABLE + +/* Relax a fragment by scanning TC_GENERIC_RELAX_TABLE. */ + +long +relax_frag (segment, fragP, stretch) + segT segment; + fragS *fragP; + long stretch; +{ + const relax_typeS *this_type; + const relax_typeS *start_type; + relax_substateT next_state; + relax_substateT this_state; + long growth; + offsetT aim; + addressT target; + addressT address; + symbolS *symbolP; + const relax_typeS *table; + + target = fragP->fr_offset; + address = fragP->fr_address; + table = TC_GENERIC_RELAX_TABLE; + this_state = fragP->fr_subtype; + start_type = this_type = table + this_state; + symbolP = fragP->fr_symbol; + + if (symbolP) + { + fragS *sym_frag; + + sym_frag = symbol_get_frag (symbolP); + +#ifndef DIFF_EXPR_OK +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (S_GET_SEGMENT (symbolP) == SEG_DATA) + || (S_GET_SEGMENT (symbolP) == SEG_BSS) + || (S_GET_SEGMENT (symbolP) == SEG_TEXT)); +#endif + know (sym_frag != NULL); +#endif + know (S_GET_SEGMENT (symbolP) != absolute_section + || sym_frag == &zero_address_frag); + target += S_GET_VALUE (symbolP); + + /* If frag has yet to be reached on this pass, + assume it will move by STRETCH just as we did. + If this is not so, it will be because some frag + between grows, and that will force another pass. */ + + if (stretch != 0 + && sym_frag->relax_marker != fragP->relax_marker + && S_GET_SEGMENT (symbolP) == segment) + { + target += stretch; + } + } + + aim = target - address - fragP->fr_fix; +#ifdef TC_PCREL_ADJUST + /* Currently only the ns32k family needs this. */ + aim += TC_PCREL_ADJUST (fragP); +/* #else */ + /* This machine doesn't want to use pcrel_adjust. + In that case, pcrel_adjust should be zero. */ +#if 0 + assert (fragP->fr_targ.ns32k.pcrel_adjust == 0); +#endif +#endif +#ifdef md_prepare_relax_scan /* formerly called M68K_AIM_KLUDGE */ + md_prepare_relax_scan (fragP, address, aim, this_state, this_type); +#endif + + if (aim < 0) + { + /* Look backwards. */ + for (next_state = this_type->rlx_more; next_state;) + if (aim >= this_type->rlx_backward) + next_state = 0; + else + { + /* Grow to next state. */ + this_state = next_state; + this_type = table + this_state; + next_state = this_type->rlx_more; + } + } + else + { + /* Look forwards. */ + for (next_state = this_type->rlx_more; next_state;) + if (aim <= this_type->rlx_forward) + next_state = 0; + else + { + /* Grow to next state. */ + this_state = next_state; + this_type = table + this_state; + next_state = this_type->rlx_more; + } + } + + growth = this_type->rlx_length - start_type->rlx_length; + if (growth != 0) + fragP->fr_subtype = this_state; + return growth; +} + +#endif /* defined (TC_GENERIC_RELAX_TABLE) */ + +/* Relax_align. Advance location counter to next address that has 'alignment' + lowest order bits all 0s, return size of adjustment made. */ +static relax_addressT +relax_align (address, alignment) + register relax_addressT address; /* Address now. */ + register int alignment; /* Alignment (binary). */ +{ + relax_addressT mask; + relax_addressT new_address; + + mask = ~((~0) << alignment); + new_address = (address + mask) & (~mask); +#ifdef LINKER_RELAXING_SHRINKS_ONLY + if (linkrelax) + /* We must provide lots of padding, so the linker can discard it + when needed. The linker will not add extra space, ever. */ + new_address += (1 << alignment); +#endif + return (new_address - address); +} + +/* Now we have a segment, not a crowd of sub-segments, we can make + fr_address values. + + Relax the frags. + + After this, all frags in this segment have addresses that are correct + within the segment. Since segments live in different file addresses, + these frag addresses may not be the same as final object-file + addresses. */ + +int +relax_segment (segment_frag_root, segment) + struct frag *segment_frag_root; + segT segment; +{ + register struct frag *fragP; + register relax_addressT address; + int ret; + +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know (segment == SEG_DATA || segment == SEG_TEXT || segment == SEG_BSS); +#endif + /* In case md_estimate_size_before_relax() wants to make fixSs. */ + subseg_change (segment, 0); + + /* For each frag in segment: count and store (a 1st guess of) + fr_address. */ + address = 0; + for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) + { + fragP->relax_marker = 0; + fragP->fr_address = address; + address += fragP->fr_fix; + + switch (fragP->fr_type) + { + case rs_fill: + address += fragP->fr_offset * fragP->fr_var; + break; + + case rs_align: + case rs_align_code: + case rs_align_test: + { + addressT offset = relax_align (address, (int) fragP->fr_offset); + + if (fragP->fr_subtype != 0 && offset > fragP->fr_subtype) + offset = 0; + + if (offset % fragP->fr_var != 0) + { + as_bad_where (fragP->fr_file, fragP->fr_line, + _("alignment padding (%lu bytes) not a multiple of %ld"), + (unsigned long) offset, (long) fragP->fr_var); + offset -= (offset % fragP->fr_var); + } + + address += offset; + } + break; + + case rs_org: + case rs_space: + /* Assume .org is nugatory. It will grow with 1st relax. */ + break; + + case rs_machine_dependent: + /* If fr_symbol is an expression, this call to + resolve_symbol_value sets up the correct segment, which will + likely be needed in md_estimate_size_before_relax. */ + if (fragP->fr_symbol) + resolve_symbol_value (fragP->fr_symbol); + + address += md_estimate_size_before_relax (fragP, segment); + break; + +#ifndef WORKING_DOT_WORD + /* Broken words don't concern us yet. */ + case rs_broken_word: + break; +#endif + + case rs_leb128: + /* Initial guess is always 1; doing otherwise can result in + stable solutions that are larger than the minimum. */ + address += fragP->fr_offset = 1; + break; + + case rs_cfa: + address += eh_frame_estimate_size_before_relax (fragP); + break; + + case rs_dwarf2dbg: + address += dwarf2dbg_estimate_size_before_relax (fragP); + break; + + default: + BAD_CASE (fragP->fr_type); + break; + } + } + + /* Do relax(). */ + { + long stretch; /* May be any size, 0 or negative. */ + /* Cumulative number of addresses we have relaxed this pass. + We may have relaxed more than one address. */ + int stretched; /* Have we stretched on this pass? */ + /* This is 'cuz stretch may be zero, when, in fact some piece of code + grew, and another shrank. If a branch instruction doesn't fit anymore, + we could be scrod. */ + + do + { + stretch = 0; + stretched = 0; + + for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) + { + long growth = 0; + addressT was_address; + offsetT offset; + symbolS *symbolP; + + fragP->relax_marker ^= 1; + was_address = fragP->fr_address; + address = fragP->fr_address += stretch; + symbolP = fragP->fr_symbol; + offset = fragP->fr_offset; + + switch (fragP->fr_type) + { + case rs_fill: /* .fill never relaxes. */ + growth = 0; + break; + +#ifndef WORKING_DOT_WORD + /* JF: This is RMS's idea. I do *NOT* want to be blamed + for it I do not want to write it. I do not want to have + anything to do with it. This is not the proper way to + implement this misfeature. */ + case rs_broken_word: + { + struct broken_word *lie; + struct broken_word *untruth; + + /* Yes this is ugly (storing the broken_word pointer + in the symbol slot). Still, this whole chunk of + code is ugly, and I don't feel like doing anything + about it. Think of it as stubbornness in action. */ + growth = 0; + for (lie = (struct broken_word *) (fragP->fr_symbol); + lie && lie->dispfrag == fragP; + lie = lie->next_broken_word) + { + + if (lie->added) + continue; + + offset = (S_GET_VALUE (lie->add) + + lie->addnum + - S_GET_VALUE (lie->sub)); + if (offset <= -32768 || offset >= 32767) + { + if (flag_warn_displacement) + { + char buf[50]; + sprint_value (buf, (addressT) lie->addnum); + as_warn_where (fragP->fr_file, fragP->fr_line, + _(".word %s-%s+%s didn't fit"), + S_GET_NAME (lie->add), + S_GET_NAME (lie->sub), + buf); + } + lie->added = 1; + if (fragP->fr_subtype == 0) + { + fragP->fr_subtype++; + growth += md_short_jump_size; + } + for (untruth = lie->next_broken_word; + untruth && untruth->dispfrag == lie->dispfrag; + untruth = untruth->next_broken_word) + if ((symbol_get_frag (untruth->add) + == symbol_get_frag (lie->add)) + && (S_GET_VALUE (untruth->add) + == S_GET_VALUE (lie->add))) + { + untruth->added = 2; + untruth->use_jump = lie; + } + growth += md_long_jump_size; + } + } + + break; + } /* case rs_broken_word */ +#endif + case rs_align: + case rs_align_code: + case rs_align_test: + { + addressT oldoff, newoff; + + oldoff = relax_align (was_address + fragP->fr_fix, + (int) offset); + newoff = relax_align (address + fragP->fr_fix, + (int) offset); + + if (fragP->fr_subtype != 0) + { + if (oldoff > fragP->fr_subtype) + oldoff = 0; + if (newoff > fragP->fr_subtype) + newoff = 0; + } + + growth = newoff - oldoff; + } + break; + + case rs_org: + { + addressT target = offset; + addressT after; + + if (symbolP) + { +#if !defined (MANY_SEGMENTS) && !defined (BFD_ASSEMBLER) + know ((S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (S_GET_SEGMENT (symbolP) == SEG_DATA) + || (S_GET_SEGMENT (symbolP) == SEG_TEXT) + || S_GET_SEGMENT (symbolP) == SEG_BSS); + know (symbolP->sy_frag); + know (!(S_GET_SEGMENT (symbolP) == SEG_ABSOLUTE) + || (symbolP->sy_frag == &zero_address_frag)); +#endif + /* Convert from an actual address to an octet offset + into the section. Here it is assumed that the + section's VMA is zero, and can omit subtracting it + from the symbol's value to get the address offset. */ + know (S_GET_SECTION (symbolP)->vma == 0); + target += S_GET_VALUE (symbolP) * OCTETS_PER_BYTE; + } + + know (fragP->fr_next); + after = fragP->fr_next->fr_address; + growth = target - after; + if (growth < 0) + { + /* Growth may be negative, but variable part of frag + cannot have fewer than 0 chars. That is, we can't + .org backwards. */ + as_bad_where (fragP->fr_file, fragP->fr_line, + _("attempt to .org backwards")); + + /* We've issued an error message. Change the + frag to avoid cascading errors. */ + fragP->fr_type = rs_align; + fragP->fr_subtype = 0; + fragP->fr_offset = 0; + fragP->fr_fix = after - address; + growth = stretch; + } + + /* This is an absolute growth factor */ + growth -= stretch; + break; + } + + case rs_space: + growth = 0; + if (symbolP) + { + offsetT amount; + + amount = S_GET_VALUE (symbolP); + if (S_GET_SEGMENT (symbolP) != absolute_section + || S_IS_COMMON (symbolP) + || ! S_IS_DEFINED (symbolP)) + { + as_bad_where (fragP->fr_file, fragP->fr_line, + _(".space specifies non-absolute value")); + /* Prevent repeat of this error message. */ + fragP->fr_symbol = 0; + } + else if (amount < 0) + { + as_warn_where (fragP->fr_file, fragP->fr_line, + _(".space or .fill with negative value, ignored")); + fragP->fr_symbol = 0; + } + else + growth = (was_address + fragP->fr_fix + amount + - fragP->fr_next->fr_address); + } + break; + + case rs_machine_dependent: +#ifdef md_relax_frag + growth = md_relax_frag (segment, fragP, stretch); +#else +#ifdef TC_GENERIC_RELAX_TABLE + /* The default way to relax a frag is to look through + TC_GENERIC_RELAX_TABLE. */ + growth = relax_frag (segment, fragP, stretch); +#endif /* TC_GENERIC_RELAX_TABLE */ +#endif + break; + + case rs_leb128: + { + valueT value; + int size; + + value = resolve_symbol_value (fragP->fr_symbol); + size = sizeof_leb128 (value, fragP->fr_subtype); + growth = size - fragP->fr_offset; + fragP->fr_offset = size; + } + break; + + case rs_cfa: + growth = eh_frame_relax_frag (fragP); + break; + + case rs_dwarf2dbg: + growth = dwarf2dbg_relax_frag (fragP); + break; + + default: + BAD_CASE (fragP->fr_type); + break; + } + if (growth) + { + stretch += growth; + stretched = 1; + } + } /* For each frag in the segment. */ + } + while (stretched); /* Until nothing further to relax. */ + } /* do_relax */ + + ret = 0; + for (fragP = segment_frag_root; fragP; fragP = fragP->fr_next) + if (fragP->last_fr_address != fragP->fr_address) + { + fragP->last_fr_address = fragP->fr_address; + ret = 1; + } + return ret; +} + +#if defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS)) + +/* fixup_segment() + + Go through all the fixS's in a segment and see which ones can be + handled now. (These consist of fixS where we have since discovered + the value of a symbol, or the address of the frag involved.) + For each one, call md_apply_fix3 to put the fix into the frag data. + + Result is a count of how many relocation structs will be needed to + handle the remaining fixS's that we couldn't completely handle here. + These will be output later by emit_relocations(). */ + +static long +fixup_segment (fixP, this_segment) + fixS *fixP; + segT this_segment; +{ + long seg_reloc_count = 0; + valueT add_number; + fragS *fragP; + segT add_symbol_segment = absolute_section; + + if (fixP != NULL && abs_section_sym == NULL) + { +#ifndef BFD_ASSEMBLER + abs_section_sym = &abs_symbol; +#else + abs_section_sym = section_symbol (absolute_section); +#endif + } + + /* If the linker is doing the relaxing, we must not do any fixups. + + Well, strictly speaking that's not true -- we could do any that + are PC-relative and don't cross regions that could change size. + And for the i960 we might be able to turn callx/callj into bal + anyways in cases where we know the maximum displacement. */ + if (linkrelax && TC_LINKRELAX_FIXUP (this_segment)) + { + for (; fixP; fixP = fixP->fx_next) + if (!fixP->fx_done) + { + if (fixP->fx_addsy == NULL) + { + /* There was no symbol required by this relocation. + However, BFD doesn't really handle relocations + without symbols well. So fake up a local symbol in + the absolute section. */ + fixP->fx_addsy = abs_section_sym; + } + symbol_mark_used_in_reloc (fixP->fx_addsy); + if (fixP->fx_subsy != NULL) + symbol_mark_used_in_reloc (fixP->fx_subsy); + seg_reloc_count++; + } + TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count); + return seg_reloc_count; + } + + for (; fixP; fixP = fixP->fx_next) + { +#ifdef DEBUG5 + fprintf (stderr, "\nprocessing fixup:\n"); + print_fixup (fixP); +#endif + + fragP = fixP->fx_frag; + know (fragP); +#ifdef TC_VALIDATE_FIX + TC_VALIDATE_FIX (fixP, this_segment, skip); +#endif + add_number = fixP->fx_offset; + + if (fixP->fx_addsy != NULL + && symbol_mri_common_p (fixP->fx_addsy)) + { + know (fixP->fx_addsy->sy_value.X_op == O_symbol); + add_number += S_GET_VALUE (fixP->fx_addsy); + fixP->fx_offset = add_number; + fixP->fx_addsy + = symbol_get_value_expression (fixP->fx_addsy)->X_add_symbol; + } + + if (fixP->fx_addsy != NULL) + add_symbol_segment = S_GET_SEGMENT (fixP->fx_addsy); + + if (fixP->fx_subsy != NULL) + { + segT sub_symbol_segment; + resolve_symbol_value (fixP->fx_subsy); + sub_symbol_segment = S_GET_SEGMENT (fixP->fx_subsy); + if (fixP->fx_addsy != NULL + && sub_symbol_segment == add_symbol_segment + && !TC_FORCE_RELOCATION_SUB_SAME (fixP, add_symbol_segment)) + { + add_number += S_GET_VALUE (fixP->fx_addsy); + add_number -= S_GET_VALUE (fixP->fx_subsy); + fixP->fx_offset = add_number; + /* If the back-end code has selected a pc-relative + reloc, adjust the value to be pc-relative. */ + if (1 +#ifdef TC_M68K + /* See the comment below about 68k weirdness. */ + && 0 +#endif + && fixP->fx_pcrel) + add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment); + fixP->fx_addsy = NULL; + fixP->fx_subsy = NULL; + fixP->fx_pcrel = 0; + } + else if (sub_symbol_segment == absolute_section + && !TC_FORCE_RELOCATION_SUB_ABS (fixP)) + { + add_number -= S_GET_VALUE (fixP->fx_subsy); + fixP->fx_offset = add_number; + fixP->fx_subsy = NULL; + } + else if (sub_symbol_segment == this_segment + && !TC_FORCE_RELOCATION_SUB_LOCAL (fixP)) + { + add_number -= S_GET_VALUE (fixP->fx_subsy); + fixP->fx_offset = (add_number + fixP->fx_dot_value + + fixP->fx_frag->fr_address); + + /* Make it pc-relative. If the back-end code has not + selected a pc-relative reloc, cancel the adjustment + we do later on all pc-relative relocs. */ + if (0 +#ifdef TC_M68K + /* Do this for m68k even if it's already described + as pc-relative. On the m68k, an operand of + "pc@(foo-.-2)" should address "foo" in a + pc-relative mode. */ + || 1 +#endif + || !fixP->fx_pcrel) + add_number += MD_PCREL_FROM_SECTION (fixP, this_segment); + fixP->fx_subsy = NULL; + fixP->fx_pcrel = 1; + } + else if (!TC_VALIDATE_FIX_SUB (fixP)) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("can't resolve `%s' {%s section} - `%s' {%s section}"), + fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "0", + segment_name (add_symbol_segment), + S_GET_NAME (fixP->fx_subsy), + segment_name (sub_symbol_segment)); + } + } + + if (fixP->fx_addsy) + { + if (add_symbol_segment == this_segment + && !TC_FORCE_RELOCATION_LOCAL (fixP)) + { + /* This fixup was made when the symbol's segment was + SEG_UNKNOWN, but it is now in the local segment. + So we know how to do the address without relocation. */ + add_number += S_GET_VALUE (fixP->fx_addsy); + fixP->fx_offset = add_number; + if (fixP->fx_pcrel) + add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment); + fixP->fx_addsy = NULL; + fixP->fx_pcrel = 0; + } + else if (add_symbol_segment == absolute_section + && !TC_FORCE_RELOCATION_ABS (fixP)) + { + add_number += S_GET_VALUE (fixP->fx_addsy); + fixP->fx_offset = add_number; + fixP->fx_addsy = NULL; + } + else if (add_symbol_segment != undefined_section +#ifdef BFD_ASSEMBLER + && ! bfd_is_com_section (add_symbol_segment) +#endif + && MD_APPLY_SYM_VALUE (fixP)) + add_number += S_GET_VALUE (fixP->fx_addsy); + } + + if (fixP->fx_pcrel) + { + add_number -= MD_PCREL_FROM_SECTION (fixP, this_segment); + if (!fixP->fx_done && fixP->fx_addsy == NULL) + { + /* There was no symbol required by this relocation. + However, BFD doesn't really handle relocations + without symbols well. So fake up a local symbol in + the absolute section. */ + fixP->fx_addsy = abs_section_sym; + } + } + + if (!fixP->fx_done) + md_apply_fix3 (fixP, &add_number, this_segment); + + if (!fixP->fx_done) + { + ++seg_reloc_count; + if (fixP->fx_addsy == NULL) + fixP->fx_addsy = abs_section_sym; + symbol_mark_used_in_reloc (fixP->fx_addsy); + if (fixP->fx_subsy != NULL) + symbol_mark_used_in_reloc (fixP->fx_subsy); + } + + if (!fixP->fx_bit_fixP && !fixP->fx_no_overflow && fixP->fx_size != 0) + { + if (fixP->fx_size < sizeof (valueT)) + { + valueT mask; + + mask = 0; + mask--; /* Set all bits to one. */ + mask <<= fixP->fx_size * 8 - (fixP->fx_signed ? 1 : 0); + if ((add_number & mask) != 0 && (add_number & mask) != mask) + { + char buf[50], buf2[50]; + sprint_value (buf, fragP->fr_address + fixP->fx_where); + if (add_number > 1000) + sprint_value (buf2, add_number); + else + sprintf (buf2, "%ld", (long) add_number); + as_bad_where (fixP->fx_file, fixP->fx_line, + _("value of %s too large for field of %d bytes at %s"), + buf2, fixP->fx_size, buf); + } /* Generic error checking. */ + } +#ifdef WARN_SIGNED_OVERFLOW_WORD + /* Warn if a .word value is too large when treated as a signed + number. We already know it is not too negative. This is to + catch over-large switches generated by gcc on the 68k. */ + if (!flag_signed_overflow_ok + && fixP->fx_size == 2 + && add_number > 0x7fff) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("signed .word overflow; switch may be too large; %ld at 0x%lx"), + (long) add_number, + (long) (fragP->fr_address + fixP->fx_where)); +#endif + } /* Not a bit fix. */ + +#ifdef TC_VALIDATE_FIX + skip: ATTRIBUTE_UNUSED_LABEL + ; +#endif +#ifdef DEBUG5 + fprintf (stderr, "result:\n"); + print_fixup (fixP); +#endif + } /* For each fixS in this segment. */ + + TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count); + return seg_reloc_count; +} + +#endif /* defined (BFD_ASSEMBLER) || (!defined (BFD) && !defined (OBJ_VMS)) */ + +void +number_to_chars_bigendian (buf, val, n) + char *buf; + valueT val; + int n; +{ + if (n <= 0) + abort (); + while (n--) + { + buf[n] = val & 0xff; + val >>= 8; + } +} + +void +number_to_chars_littleendian (buf, val, n) + char *buf; + valueT val; + int n; +{ + if (n <= 0) + abort (); + while (n--) + { + *buf++ = val & 0xff; + val >>= 8; + } +} + +void +write_print_statistics (file) + FILE *file; +{ + fprintf (file, "fixups: %d\n", n_fixups); +} + +/* For debugging. */ +extern int indent_level; + +void +print_fixup (fixp) + fixS *fixp; +{ + indent_level = 1; + fprintf (stderr, "fix %lx %s:%d", (long) fixp, fixp->fx_file, fixp->fx_line); + if (fixp->fx_pcrel) + fprintf (stderr, " pcrel"); + if (fixp->fx_pcrel_adjust) + fprintf (stderr, " pcrel_adjust=%d", fixp->fx_pcrel_adjust); + if (fixp->fx_im_disp) + { +#ifdef TC_NS32K + fprintf (stderr, " im_disp=%d", fixp->fx_im_disp); +#else + fprintf (stderr, " im_disp"); +#endif + } + if (fixp->fx_tcbit) + fprintf (stderr, " tcbit"); + if (fixp->fx_done) + fprintf (stderr, " done"); + fprintf (stderr, "\n size=%d frag=%lx where=%ld offset=%lx addnumber=%lx", + fixp->fx_size, (long) fixp->fx_frag, (long) fixp->fx_where, + (long) fixp->fx_offset, (long) fixp->fx_addnumber); +#ifdef BFD_ASSEMBLER + fprintf (stderr, "\n %s (%d)", bfd_get_reloc_code_name (fixp->fx_r_type), + fixp->fx_r_type); +#else +#ifdef NEED_FX_R_TYPE + fprintf (stderr, " r_type=%d", fixp->fx_r_type); +#endif +#endif + if (fixp->fx_addsy) + { + fprintf (stderr, "\n +<"); + print_symbol_value_1 (stderr, fixp->fx_addsy); + fprintf (stderr, ">"); + } + if (fixp->fx_subsy) + { + fprintf (stderr, "\n -<"); + print_symbol_value_1 (stderr, fixp->fx_subsy); + fprintf (stderr, ">"); + } + fprintf (stderr, "\n"); +#ifdef TC_FIX_DATA_PRINT + TC_FIX_DATA_PRINT (stderr, fixp); +#endif +} diff --git a/contrib/binutils-2.14/gas/write.h b/contrib/binutils-2.14/gas/write.h new file mode 100644 index 0000000000..962ccd0fb1 --- /dev/null +++ b/contrib/binutils-2.14/gas/write.h @@ -0,0 +1,216 @@ +/* write.h + Copyright 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2000, 2001 + Free Software Foundation, Inc. + + This file is part of GAS, the GNU Assembler. + + GAS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GAS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GAS; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef __write_h__ +#define __write_h__ + +#ifndef TC_I960 +#ifdef hpux +#define EXEC_MACHINE_TYPE HP9000S200_ID +#endif +#endif /* TC_I960 */ + +#ifndef BFD_ASSEMBLER + +#ifndef LOCAL_LABEL +#define LOCAL_LABEL(name) (name [0] == 'L' ) +#endif + +#define S_LOCAL_NAME(s) (LOCAL_LABEL (S_GET_NAME (s))) + +#endif /* ! BFD_ASSEMBLER */ + +/* This is the name of a fake symbol which will never appear in the + assembler output. S_IS_LOCAL detects it because of the \001. */ +#define FAKE_LABEL_NAME "L0\001" + +#include "bit_fix.h" + +/* + * FixSs may be built up in any order. + */ + +struct fix +{ + /* These small fields are grouped together for compactness of + this structure, and efficiency of access on some architectures. */ + + /* pc-relative offset adjust (only used by m68k) */ + char fx_pcrel_adjust; + + /* How many bytes are involved? */ + unsigned char fx_size; + + /* Is this a pc-relative relocation? */ + unsigned fx_pcrel : 1; + + /* Is this a relocation to a procedure linkage table entry? If so, + some of the reductions we try to apply are invalid. A better way + might be to represent PLT entries with different kinds of + symbols, and use normal relocations (with undefined symbols); + look into it for version 2.6. */ + unsigned fx_plt : 1; + + /* Is this value an immediate displacement? */ + /* Only used on i960 and ns32k; merge it into TC_FIX_TYPE sometime. */ + unsigned fx_im_disp : 2; + + /* A bit for the CPU specific code. + This probably can be folded into tc_fix_data, below. */ + unsigned fx_tcbit : 1; + + /* Has this relocation already been applied? */ + unsigned fx_done : 1; + + /* Suppress overflow complaints on large addends. This is used + in the PowerPC ELF config to allow large addends on the + BFD_RELOC_{LO16,HI16,HI16_S} relocations. + + @@ Can this be determined from BFD? */ + unsigned fx_no_overflow : 1; + + /* The value is signed when checking for overflow. */ + unsigned fx_signed : 1; + + /* Which frag does this fix apply to? */ + fragS *fx_frag; + + /* Where is the first byte to fix up? */ + long fx_where; + + /* NULL or Symbol whose value we add in. */ + symbolS *fx_addsy; + + /* NULL or Symbol whose value we subtract. */ + symbolS *fx_subsy; + + /* Absolute number we add in. */ + valueT fx_offset; + + /* The value of dot when the fixup expression was parsed. */ + addressT fx_dot_value; + + /* Next fixS in linked list, or NULL. */ + struct fix *fx_next; + + /* If NULL, no bitfix's to do. */ + /* Only i960-coff and ns32k use this, and i960-coff stores an + integer. This can probably be folded into tc_fix_data, below. + @@ Alpha also uses it, but only to disable certain relocation + processing. */ + bit_fixS *fx_bit_fixP; + +#ifdef BFD_ASSEMBLER + bfd_reloc_code_real_type fx_r_type; +#else +#ifdef NEED_FX_R_TYPE + /* Hack for machines where the type of reloc can't be + worked out by looking at how big it is. */ + int fx_r_type; +#endif +#endif + + /* This field is sort of misnamed. It appears to be a sort of random + scratch field, for use by the back ends. The main gas code doesn't + do anything but initialize it to zero. The use of it does need to + be coordinated between the cpu and format files, though. E.g., some + coff targets pass the `addend' field from the cpu file via this + field. I don't know why the `fx_offset' field above can't be used + for that; investigate later and document. KR */ + valueT fx_addnumber; + + /* The location of the instruction which created the reloc, used + in error messages. */ + char *fx_file; + unsigned fx_line; + +#ifdef USING_CGEN + struct { + /* CGEN_INSN entry for this instruction. */ + const struct cgen_insn *insn; + /* Target specific data, usually reloc number. */ + int opinfo; + } fx_cgen; +#endif + +#ifdef TC_FIX_TYPE + /* Location where a backend can attach additional data + needed to perform fixups. */ + TC_FIX_TYPE tc_fix_data; +#endif +}; + +typedef struct fix fixS; + +extern int finalize_syms; +extern symbolS *abs_section_sym; +extern addressT dot_value; + +#ifndef BFD_ASSEMBLER +extern char *next_object_file_charP; + +#ifndef MANY_SEGMENTS +COMMON fixS *text_fix_root, *text_fix_tail; /* Chains fixSs. */ +COMMON fixS *data_fix_root, *data_fix_tail; /* Chains fixSs. */ +COMMON fixS *bss_fix_root, *bss_fix_tail; /* Chains fixSs. */ +extern struct frag *text_last_frag; /* Last frag in segment. */ +extern struct frag *data_last_frag; /* Last frag in segment. */ +#endif +COMMON fixS **seg_fix_rootP, **seg_fix_tailP; /* -> one of above. */ +#endif + +extern long string_byte_count; +extern int section_alignment[]; + +extern bit_fixS *bit_fix_new + PARAMS ((int size, int offset, long base_type, long base_adj, long min, + long max, long add)); +extern void append PARAMS ((char **charPP, char *fromP, unsigned long length)); +extern void record_alignment PARAMS ((segT seg, int align)); +extern int get_recorded_alignment PARAMS ((segT seg)); +extern void subsegs_finish PARAMS ((void)); +extern void write_object_file PARAMS ((void)); +extern long relax_frag PARAMS ((segT, fragS *, long)); +extern int relax_segment + PARAMS ((struct frag * seg_frag_root, segT seg_type)); + +extern void number_to_chars_littleendian PARAMS ((char *, valueT, int)); +extern void number_to_chars_bigendian PARAMS ((char *, valueT, int)); + +#ifdef BFD_ASSEMBLER +extern fixS *fix_new + PARAMS ((fragS * frag, int where, int size, symbolS * add_symbol, + offsetT offset, int pcrel, bfd_reloc_code_real_type r_type)); +extern fixS *fix_new_exp + PARAMS ((fragS * frag, int where, int size, expressionS *exp, int pcrel, + bfd_reloc_code_real_type r_type)); +#else +extern fixS *fix_new + PARAMS ((fragS * frag, int where, int size, symbolS * add_symbol, + offsetT offset, int pcrel, int r_type)); +extern fixS *fix_new_exp + PARAMS ((fragS * frag, int where, int size, expressionS *exp, int pcrel, + int r_type)); +#endif + +extern void write_print_statistics PARAMS ((FILE *)); + +#endif /* __write_h__ */ diff --git a/contrib/binutils-2.14/gprof/MAINTAINERS b/contrib/binutils-2.14/gprof/MAINTAINERS new file mode 100644 index 0000000000..d59a3bd7f8 --- /dev/null +++ b/contrib/binutils-2.14/gprof/MAINTAINERS @@ -0,0 +1 @@ +See ../binutils/MAINTAINERS diff --git a/contrib/binutils-2.14/gprof/README b/contrib/binutils-2.14/gprof/README new file mode 100644 index 0000000000..8fe2da8a5a --- /dev/null +++ b/contrib/binutils-2.14/gprof/README @@ -0,0 +1,442 @@ + README for GPROF + +This is the GNU profiler. It is distributed with other "binary +utilities" which should be in ../binutils. See ../binutils/README for +more general notes, including where to send bug reports. + +This file documents the changes and new features available with this +version of GNU gprof. + +* New Features + + o Long options + + o Supports generalized file format, without breaking backward compatibility: + new file format supports basic-block execution counts and non-realtime + histograms (see below) + + o Supports profiling at the line level: flat profiles, call-graph profiles, + and execution-counts can all be displayed at a level that identifies + individual lines rather than just functions + + o Test-coverage support (similar to Sun tcov program): source files + can be annotated with the number of times a function was invoked + or with the number of times each basic-block in a function was + executed + + o Generalized histograms: not just execution-time, but arbitrary + histograms are support (for example, performance counter based + profiles) + + o Powerful mechanism to select data to be included/excluded from + analysis and/or output + + o Support for DEC OSF/1 v3.0 + + o Full cross-platform profiling support: gprof uses BFD to support + arbitrary, non-native object file formats and non-native byte-orders + (this feature has not been tested yet) + + o In the call-graph function index, static function names are now + printed together with the filename in which the function was defined + (required bfd_find_nearest_line() support and symbolic debugging + information to be present in the executable file) + + o Major overhaul of source code (compiles cleanly with -Wall, etc.) + +* Supported Platforms + +The current version is known to work on: + + o DEC OSF/1 v3.0 + All features supported. + + o SunOS 4.1.x + All features supported. + + o Solaris 2.3 + Line-level profiling unsupported because bfd_find_nearest_line() + is not fully implemented for Elf binaries. + + o HP-UX 9.01 + Line-level profiling unsupported because bfd_find_nearest_line() + is not fully implemented for SOM binaries. + +* Detailed Description + +** User Interface Changes + +The command-line interface is backwards compatible with earlier +versions of GNU gprof and Berkeley gprof. The only exception is +the option to delete arcs from the call graph. The old syntax +was: + + -k fromname toname + +while the new syntax is: + + -k fromname/toname + +This change was necessary to be compatible with long-option parsing. +Also, "fromname" and "toname" can now be arbitrary symspecs rather +than just function names (see below for an explanation of symspecs). +For example, option "-k gprof.c/" suppresses all arcs due to calls out +of file "gprof.c". + +*** Sym Specs + +It is often necessary to apply gprof only to specific parts of a +program. GNU gprof has a simple but powerful mechanism to achieve +this. So called {\em symspecs\/} provide the foundation for this +mechanism. A symspec selects the parts of a profiled program to which +an operation should be applied to. The syntax of a symspec is +simple: + + filename_containing_a_dot + | funcname_not_containing_a_dot + | linenumber + | ( [ any_filename ] `:' ( any_funcname | linenumber ) ) + +Here are some examples: + + main.c Selects everything in file "main.c"---the + dot in the string tells gprof to interpret + the string as a filename, rather than as + a function name. To select a file whose + name does contain a dot, a trailing colon + should be specified. For example, "odd:" is + interpreted as the file named "odd". + + main Selects all functions named "main". Notice + that there may be multiple instances of the + same function name because some of the + definitions may be local (i.e., static). + Unless a function name is unique in a program, + you must use the colon notation explained + below to specify a function from a specific + source file. Sometimes, functionnames contain + dots. In such cases, it is necessary to + add a leading colon to the name. For example, + ":.mul" selects function ".mul". + + main.c:main Selects function "main" in file "main.c". + + main.c:134 Selects line 134 in file "main.c". + +IMPLEMENTATION NOTE: The source code uses the type sym_id for symspecs. +At some point, this probably ought to be changed to "sym_spec" to make +reading the code easier. + +*** Long options + +GNU gprof now supports long options. The following is a list of all +supported options. Options that are listed without description +operate in the same manner as the corresponding option in older +versions of gprof. + +Short Form: Long Form: +----------- ---------- +-l --line + Request profiling at the line-level rather + than just at the function level. Source + lines are identified by symbols of the form: + + func (file:line) + + where "func" is the function name, "file" is the + file name and "line" is the line-number that + corresponds to the line. + + To work properly, the binary must contain symbolic + debugging information. This means that the source + have to be translated with option "-g" specified. + Functions for which there is no symbolic debugging + information available are treated as if "--line" + had not been specified. However, the line number + printed with such symbols is usually incorrect + and should be ignored. + +-a --no-static +-A[symspec] --annotated-source[=symspec] + Request output in the form of annotated source + files. If "symspec" is specified, print output only + for symbols selected by "symspec". If the option + is specified multiple times, annotated output is + generated for the union of all symspecs. + + Examples: + + -A Prints annotated source for all + source files. + -Agprof.c Prints annotated source for file + gprof.c. + -Afoobar Prints annotated source for files + containing a function named "foobar". + The entire file will be printed, but + only the function itself will be + annotated with profile data. + +-J[symspec] --no-annotated-source[=symspec] + Suppress annotated source output. If specified + without argument, annotated output is suppressed + completely. With an argument, annotated output + is suppressed only for the symbols selected by + "symspec". If the option is specified multiple + times, annotated output is suppressed for the + union of all symspecs. This option has lower + precedence than --annotated-source + +-p[symspec] --flat-profile[=symspec] + Request output in the form of a flat profile + (unless any other output-style option is specified, + this option is turned on by default). If + "symspec" is specified, include only symbols + selected by "symspec" in flat profile. If the + option is specified multiple times, the flat + profile includes symbols selected by the union + of all symspecs. + +-P[symspec] --no-flat-profile[=symspec] + Suppress output in the flat profile. If given + without an argument, the flat profile is suppressed + completely. If "symspec" is specified, suppress + the selected symbols in the flat profile. If the + option is specified multiple times, the union of + the selected symbols is suppressed. This option + has lower precedence than --flat-profile. + +-q[symspec] --graph[=symspec] + Request output in the form of a call-graph + (unless any other output-style option is specified, + this option is turned on by default). If "symspec" + is specified, include only symbols selected by + "symspec" in the call-graph. If the option is + specified multiple times, the call-graph includes + symbols selected by the union of all symspecs. + +-Q[symspec] --no-graph[=symspec] + Suppress output in the call-graph. If given without + an argument, the call-graph is suppressed completely. + With a "symspec", suppress the selected symbols + from the call-graph. If the option is specified + multiple times, the union of the selected symbols + is suppressed. This option has lower precedence + than --graph. + +-C[symspec] --exec-counts[=symspec] + Request output in the form of execution counts. + If "symspec" is present, include only symbols + selected by "symspec" in the execution count + listing. If the option is specified multiple + times, the execution count listing includes + symbols selected by the union of all symspecs. + +-Z[symspec] --no-exec-counts[=symspec] + Suppress output in the execution count listing. + If given without an argument, the listing is + suppressed completely. With a "symspec", suppress + the selected symbols from the call-graph. If the + option is specified multiple times, the union of + the selected symbols is suppressed. This option + has lower precedence than --exec-counts. + +-i --file-info + Print information about the profile files that + are read. The information consists of the + number and types of records present in the + profile file. Currently, a profile file can + contain any number and any combination of histogram, + call-graph, or basic-block count records. + +-s --sum + +-x --all-lines + This option affects annotated source output only. + By default, only the lines at the beginning of + a basic-block are annotated. If this option is + specified, every line in a basic-block is annotated + by repeating the annotation for the first line. + This option is identical to tcov's "-a". + +-I dirs --directory-path=dirs + This option affects annotated source output only. + Specifies the list of directories to be searched + for source files. The argument "dirs" is a colon + separated list of directories. By default, gprof + searches for source files relative to the current + working directory only. + +-z --display-unused-functions + +-m num --min-count=num + This option affects annotated source and execution + count output only. Symbols that are executed + less than "num" times are suppressed. For annotated + source output, suppressed symbols are marked + by five hash-marks (#####). In an execution count + output, suppressed symbols do not appear at all. + +-L --print-path + Normally, source filenames are printed with the path + component suppressed. With this option, gprof + can be forced to print the full pathname of + source filenames. The full pathname is determined + from symbolic debugging information in the image file + and is relative to the directory in which the compiler + was invoked. + +-y --separate-files + This option affects annotated source output only. + Normally, gprof prints annotated source files + to standard-output. If this option is specified, + annotated source for a file named "path/filename" + is generated in the file "filename-ann". That is, + annotated output is {\em always\/} generated in + gprof's current working directory. Care has to + be taken if a program consists of files that have + identical filenames, but distinct paths. + +-c --static-call-graph + +-t num --table-length=num + This option affects annotated source output only. + After annotating a source file, gprof generates + an execution count summary consisting of a table + of lines with the top execution counts. By + default, this table is ten entries long. + This option can be used to change the table length + or, by specifying an argument value of 0, it can be + suppressed completely. + +-n symspec --time=symspec + Only symbols selected by "symspec" are considered + in total and percentage time computations. + However, this option does not affect percentage time + computation for the flat profile. + If the option is specified multiple times, the union + of all selected symbols is used in time computations. + +-N --no-time=symspec + Exclude the symbols selected by "symspec" from + total and percentage time computations. + However, this option does not affect percentage time + computation for the flat profile. + This option is ignored if any --time options are + specified. + +-w num --width=num + Sets the output line width. Currently, this option + affects the printing of the call-graph function index + only. + +-e +-E +-f +-F +-k +-b --brief +-dnum --debug[=num] + +-h --help + Prints a usage message. + +-O name --file-format=name + Selects the format of the profile data files. + Recognized formats are "auto", "bsd", "magic", + and "prof". The last one is not yet supported. + Format "auto" attempts to detect the file format + automatically (this is the default behavior). + It attempts to read the profile data files as + "magic" files and if this fails, falls back to + the "bsd" format. "bsd" forces gprof to read + the data files in the BSD format. "magic" forces + gprof to read the data files in the "magic" format. + +-T --traditional +-v --version + +** File Format Changes + +The old BSD-derived format used for profile data does not contain a +magic cookie that allows to check whether a data file really is a +gprof file. Furthermore, it does not provide a version number, thus +rendering changes to the file format almost impossible. GNU gprof +uses a new file format that provides these features. For backward +compatibility, GNU gprof continues to support the old BSD-derived +format, but not all features are supported with it. For example, +basic-block execution counts cannot be accommodated by the old file +format. + +The new file format is defined in header file \file{gmon_out.h}. It +consists of a header containing the magic cookie and a version number, +as well as some spare bytes available for future extensions. All data +in a profile data file is in the native format of the host on which +the profile was collected. GNU gprof adapts automatically to the +byte-order in use. + +In the new file format, the header is followed by a sequence of +records. Currently, there are three different record types: histogram +records, call-graph arc records, and basic-block execution count +records. Each file can contain any number of each record type. When +reading a file, GNU gprof will ensure records of the same type are +compatible with each other and compute the union of all records. For +example, for basic-block execution counts, the union is simply the sum +of all execution counts for each basic-block. + +*** Histogram Records + +Histogram records consist of a header that is followed by an array of +bins. The header contains the text-segment range that the histogram +spans, the size of the histogram in bytes (unlike in the old BSD +format, this does not include the size of the header), the rate of the +profiling clock, and the physical dimension that the bin counts +represent after being scaled by the profiling clock rate. The +physical dimension is specified in two parts: a long name of up to 15 +characters and a single character abbreviation. For example, a +histogram representing real-time would specify the long name as +"seconds" and the abbreviation as "s". This feature is useful for +architectures that support performance monitor hardware (which, +fortunately, is becoming increasingly common). For example, under DEC +OSF/1, the "uprofile" command can be used to produce a histogram of, +say, instruction cache misses. In this case, the dimension in the +histogram header could be set to "i-cache misses" and the abbreviation +could be set to "1" (because it is simply a count, not a physical +dimension). Also, the profiling rate would have to be set to 1 in +this case. + +Histogram bins are 16-bit numbers and each bin represent an equal +amount of text-space. For example, if the text-segment is one +thousand bytes long and if there are ten bins in the histogram, each +bin represents one hundred bytes. + + +*** Call-Graph Records + +Call-graph records have a format that is identical to the one used in +the BSD-derived file format. It consists of an arc in the call graph +and a count indicating the number of times the arc was traversed +during program execution. Arcs are specified by a pair of addresses: +the first must be within caller's function and the second must be +within the callee's function. When performing profiling at the +function level, these addresses can point anywhere within the +respective function. However, when profiling at the line-level, it is +better if the addresses are as close to the call-site/entry-point as +possible. This will ensure that the line-level call-graph is able to +identify exactly which line of source code performed calls to a +function. + +*** Basic-Block Execution Count Records + +Basic-block execution count records consist of a header followed by a +sequence of address/count pairs. The header simply specifies the +length of the sequence. In an address/count pair, the address +identifies a basic-block and the count specifies the number of times +that basic-block was executed. Any address within the basic-address can +be used. + +IMPLEMENTATION NOTE: gcc -a can be used to instrument a program to +record basic-block execution counts. However, the __bb_exit_func() +that is currently present in libgcc2.c does not generate a gmon.out +file in a suitable format. This should be fixed for future releases +of gcc. In the meantime, contact davidm@cs.arizona.edu for a version +of __bb_exit_func() to is appropriate. diff --git a/contrib/binutils-2.14/gprof/TEST b/contrib/binutils-2.14/gprof/TEST new file mode 100644 index 0000000000..78a90300ca --- /dev/null +++ b/contrib/binutils-2.14/gprof/TEST @@ -0,0 +1,7 @@ +- check whether old file format is properly read when input comes from + stdin + +- check whether underscores are properly dealt with (both, on systems + that prepend them to each C name and on systems that don't) + +- ensure gprof fails gracefully when no debugging info available diff --git a/contrib/binutils-2.14/gprof/TODO b/contrib/binutils-2.14/gprof/TODO new file mode 100644 index 0000000000..324983861c --- /dev/null +++ b/contrib/binutils-2.14/gprof/TODO @@ -0,0 +1,69 @@ + +- add support for prof file format so that prof files can be displayed + at the line-level (this is useful for the uprofile tool under DEC's + OSF/1) +- take a hard look at --file-ordering (broken) and --function-ordering + ++ documentation ++ optimize bfd_find_nearest_line_num() (or replace by different interface) ++ cleanup _bfd_ecoff_find_nearest_line_num() fixes & description ++ ensure "cc -pg" produces good files under OSF/1 v3.0 ++ make sure gprof works together with OSF/1 v3.0's profiling libraries ++ implement symtab_parse(); modify sym_lookup() to consider addr_high ++ change gprof.c to collect lists, then invoke symtab_parse() for + each list ++ Questions: + o is -c (--static-call-graph) useful at all? i can't see + how; if it were deleted, gprof would be completely machine + independent => yup, it is + o are (long) option names appropriate? + o -k (--exclude-arc) cannot be implemented with getopt(); + is new syntax (-k from/to) acceptable? If not, how to + fix it? + o in the FSF output, the call-graph index now prints + the filename of static functions in parentheses; e.g., + static function foo() that is defined in file bar.c + would be printed as: + + [4] foo (bar.c) + + is this acceptable? should it be done only optionally? + o symbols with addresses that map back to a different + name are suppressed (happens with labels, for example); + is this acceptable? should it be done only optionally? ++ generalize to allow arbitrary histograms (not just time histograms) ++ basic-block information currently replaces all symbols created from + the core because of an ugly ordering conflict---for now, the current + solution works, but something cleaner is desirable ==> cleaned up, + but it's slower now ++ convert to very new file format (back to trivial format, that is :) ++ replace "dummy.h" for Alpha (if there is any use to it) ++ add support for execution time profiling at a basic-block level ++ fix filename-off-by-one bug for Alpha (see ~/tmp/d.[ch])---no longer + relevant ++ "-pg -a" doesn't work as expected because mcleanup() will overwrite + the file generated by __bb_exit_func() (or vice versa) ++ first basic-block of fac() seems to get credited to last basic-block + of previous function => bug in basic_blocks.c ++ flat profile should provide automatic scaling for per-call times because + otherwise they'll always be zero on a fast machine with tons of small + functions ++ make "-a" imply to retain line number info (without actually generating + the debugging information (unless -g is specified)---no, this is a + bad idea, because it is not clear what level of debugging info should + be requested (e.g., -g vs. -g3); leaving it up to the user seems best ++ add long options support (or at least use getopt instead of ad-hoc + implementation) ++ split into files according to abstract objects that are manipulated ++ replace sccsid by rcsid & add "end of ..." to every .c file ++ use DBG() everywhere ++ fix spacing (" ," -> "," etc.) ++ use DEFUNs everywhere ++ make compile cleanly with -Wall ++ "gcc -pg -O2" doesn't work on tecc.c unless -fno-omit-frame-pointer is + specified; find out why ++ make things portable (prototypes, const, etc.) ++ if NEW_GMON_OUT is not defined, have a flag that will allow to + read new gmon.out style files. The idea being that everyone + will use the new format for basic-block style profiling but + the old format for regular gpprofiling diff --git a/contrib/binutils-2.14/include/COPYING b/contrib/binutils-2.14/include/COPYING new file mode 100644 index 0000000000..d60c31a97a --- /dev/null +++ b/contrib/binutils-2.14/include/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/contrib/binutils-2.14/include/MAINTAINERS b/contrib/binutils-2.14/include/MAINTAINERS new file mode 100644 index 0000000000..d59a3bd7f8 --- /dev/null +++ b/contrib/binutils-2.14/include/MAINTAINERS @@ -0,0 +1 @@ +See ../binutils/MAINTAINERS diff --git a/contrib/binutils-2.14/include/ansidecl.h b/contrib/binutils-2.14/include/ansidecl.h new file mode 100644 index 0000000000..f8f2d737bf --- /dev/null +++ b/contrib/binutils-2.14/include/ansidecl.h @@ -0,0 +1,326 @@ +/* ANSI and traditional C compatability macros + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + This file is part of the GNU C 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* ANSI and traditional C compatibility macros + + ANSI C is assumed if __STDC__ is #defined. + + Macro ANSI C definition Traditional C definition + ----- ---- - ---------- ----------- - ---------- + ANSI_PROTOTYPES 1 not defined + PTR `void *' `char *' + PTRCONST `void *const' `char *' + LONG_DOUBLE `long double' `double' + const not defined `' + volatile not defined `' + signed not defined `' + VA_START(ap, var) va_start(ap, var) va_start(ap) + + Note that it is safe to write "void foo();" indicating a function + with no return value, in all K+R compilers we have been able to test. + + For declaring functions with prototypes, we also provide these: + + PARAMS ((prototype)) + -- for functions which take a fixed number of arguments. Use this + when declaring the function. When defining the function, write a + K+R style argument list. For example: + + char *strcpy PARAMS ((char *dest, char *source)); + ... + char * + strcpy (dest, source) + char *dest; + char *source; + { ... } + + + VPARAMS ((prototype, ...)) + -- for functions which take a variable number of arguments. Use + PARAMS to declare the function, VPARAMS to define it. For example: + + int printf PARAMS ((const char *format, ...)); + ... + int + printf VPARAMS ((const char *format, ...)) + { + ... + } + + For writing functions which take variable numbers of arguments, we + also provide the VA_OPEN, VA_CLOSE, and VA_FIXEDARG macros. These + hide the differences between K+R and C89 more + thoroughly than the simple VA_START() macro mentioned above. + + VA_OPEN and VA_CLOSE are used *instead of* va_start and va_end. + Immediately after VA_OPEN, put a sequence of VA_FIXEDARG calls + corresponding to the list of fixed arguments. Then use va_arg + normally to get the variable arguments, or pass your va_list object + around. You do not declare the va_list yourself; VA_OPEN does it + for you. + + Here is a complete example: + + int + printf VPARAMS ((const char *format, ...)) + { + int result; + + VA_OPEN (ap, format); + VA_FIXEDARG (ap, const char *, format); + + result = vfprintf (stdout, format, ap); + VA_CLOSE (ap); + + return result; + } + + + You can declare variables either before or after the VA_OPEN, + VA_FIXEDARG sequence. Also, VA_OPEN and VA_CLOSE are the beginning + and end of a block. They must appear at the same nesting level, + and any variables declared after VA_OPEN go out of scope at + VA_CLOSE. Unfortunately, with a K+R compiler, that includes the + argument list. You can have multiple instances of VA_OPEN/VA_CLOSE + pairs in a single function in case you need to traverse the + argument list more than once. + + For ease of writing code which uses GCC extensions but needs to be + portable to other compilers, we provide the GCC_VERSION macro that + simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various + wrappers around __attribute__. Also, __extension__ will be #defined + to nothing if it doesn't work. See below. + + This header also defines a lot of obsolete macros: + CONST, VOLATILE, SIGNED, PROTO, EXFUN, DEFUN, DEFUN_VOID, + AND, DOTS, NOARGS. Don't use them. */ + +#ifndef _ANSIDECL_H +#define _ANSIDECL_H 1 + +/* Every source file includes this file, + so they will all get the switch for lint. */ +/* LINTLIBRARY */ + +/* Using MACRO(x,y) in cpp #if conditionals does not work with some + older preprocessors. Thus we can't define something like this: + +#define HAVE_GCC_VERSION(MAJOR, MINOR) \ + (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) + +and then test "#if HAVE_GCC_VERSION(2,7)". + +So instead we use the macro below and test it against specific values. */ + +/* This macro simplifies testing whether we are using gcc, and if it + is of a particular minimum version. (Both major & minor numbers are + significant.) This macro will evaluate to 0 if we are not using + gcc at all. */ +#ifndef GCC_VERSION +#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) +#endif /* GCC_VERSION */ + +#if defined (__STDC__) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) || (defined(__alpha) && defined(__cplusplus)) +/* All known AIX compilers implement these things (but don't always + define __STDC__). The RISC/OS MIPS compiler defines these things + in SVR4 mode, but does not define __STDC__. */ +/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other + C++ compilers, does not define __STDC__, though it acts as if this + was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ + +#define ANSI_PROTOTYPES 1 +#define PTR void * +#define PTRCONST void *const +#define LONG_DOUBLE long double + +#define PARAMS(ARGS) ARGS +#define VPARAMS(ARGS) ARGS +#define VA_START(VA_LIST, VAR) va_start(VA_LIST, VAR) + +/* variadic function helper macros */ +/* "struct Qdmy" swallows the semicolon after VA_OPEN/VA_FIXEDARG's + use without inhibiting further decls and without declaring an + actual variable. */ +#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP, VAR); { struct Qdmy +#define VA_CLOSE(AP) } va_end(AP); } +#define VA_FIXEDARG(AP, T, N) struct Qdmy + +#undef const +#undef volatile +#undef signed + +/* inline requires special treatment; it's in C99, and GCC >=2.7 supports + it too, but it's not in C89. */ +#undef inline +#if __STDC_VERSION__ > 199901L +/* it's a keyword */ +#else +# if GCC_VERSION >= 2007 +# define inline __inline__ /* __inline__ prevents -pedantic warnings */ +# else +# define inline /* nothing */ +# endif +#endif + +/* These are obsolete. Do not use. */ +#ifndef IN_GCC +#define CONST const +#define VOLATILE volatile +#define SIGNED signed + +#define PROTO(type, name, arglist) type name arglist +#define EXFUN(name, proto) name proto +#define DEFUN(name, arglist, args) name(args) +#define DEFUN_VOID(name) name(void) +#define AND , +#define DOTS , ... +#define NOARGS void +#endif /* ! IN_GCC */ + +#else /* Not ANSI C. */ + +#undef ANSI_PROTOTYPES +#define PTR char * +#define PTRCONST PTR +#define LONG_DOUBLE double + +#define PARAMS(args) () +#define VPARAMS(args) (va_alist) va_dcl +#define VA_START(va_list, var) va_start(va_list) + +#define VA_OPEN(AP, VAR) { va_list AP; va_start(AP); { struct Qdmy +#define VA_CLOSE(AP) } va_end(AP); } +#define VA_FIXEDARG(AP, TYPE, NAME) TYPE NAME = va_arg(AP, TYPE) + +/* some systems define these in header files for non-ansi mode */ +#undef const +#undef volatile +#undef signed +#undef inline +#define const +#define volatile +#define signed +#define inline + +#ifndef IN_GCC +#define CONST +#define VOLATILE +#define SIGNED + +#define PROTO(type, name, arglist) type name () +#define EXFUN(name, proto) name() +#define DEFUN(name, arglist, args) name arglist args; +#define DEFUN_VOID(name) name() +#define AND ; +#define DOTS +#define NOARGS +#endif /* ! IN_GCC */ + +#endif /* ANSI C. */ + +/* Define macros for some gcc attributes. This permits us to use the + macros freely, and know that they will come into play for the + version of gcc in which they are supported. */ + +#if (GCC_VERSION < 2007) +# define __attribute__(x) +#endif + +/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ +#ifndef ATTRIBUTE_MALLOC +# if (GCC_VERSION >= 2096) +# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) +# else +# define ATTRIBUTE_MALLOC +# endif /* GNUC >= 2.96 */ +#endif /* ATTRIBUTE_MALLOC */ + +/* Attributes on labels were valid as of gcc 2.93. */ +#ifndef ATTRIBUTE_UNUSED_LABEL +# if (GCC_VERSION >= 2093) +# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED +# else +# define ATTRIBUTE_UNUSED_LABEL +# endif /* GNUC >= 2.93 */ +#endif /* ATTRIBUTE_UNUSED_LABEL */ + +#ifndef ATTRIBUTE_UNUSED +#define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +#endif /* ATTRIBUTE_UNUSED */ + +#ifndef ATTRIBUTE_NORETURN +#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) +#endif /* ATTRIBUTE_NORETURN */ + +/* Attribute `nonnull' was valid as of gcc 3.3. */ +#ifndef ATTRIBUTE_NONNULL +# if (GCC_VERSION >= 3003) +# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) +# else +# define ATTRIBUTE_NONNULL(m) +# endif /* GNUC >= 3.3 */ +#endif /* ATTRIBUTE_NONNULL */ + +/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. + This was the case for the `printf' format attribute by itself + before GCC 3.3, but as of 3.3 we need to add the `nonnull' + attribute to retain this behavior. */ +#ifndef ATTRIBUTE_PRINTF +#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) +#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) +#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) +#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) +#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) +#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) +#endif /* ATTRIBUTE_PRINTF */ + +/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A + NULL format specifier was allowed as of gcc 3.3. */ +#ifndef ATTRIBUTE_NULL_PRINTF +# if (GCC_VERSION >= 3003) +# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) +# else +# define ATTRIBUTE_NULL_PRINTF(m, n) +# endif /* GNUC >= 3.3 */ +# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) +# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) +# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) +# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) +# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) +#endif /* ATTRIBUTE_NULL_PRINTF */ + +/* We use __extension__ in some places to suppress -pedantic warnings + about GCC extensions. This feature didn't work properly before + gcc 2.8. */ +#if GCC_VERSION < 2008 +#define __extension__ +#endif + +/* Bootstrap support: Adjust certain macros defined by Autoconf, + which are only valid for the stage1 compiler. If we detect + a modern version of GCC, we are probably in stage2 or beyond, + so unconditionally reset the values. Note that const, inline, + etc. have been dealt with above. */ +#if (GCC_VERSION >= 2007) +# ifndef HAVE_LONG_DOUBLE +# define HAVE_LONG_DOUBLE 1 +# endif +#endif /* GCC >= 2.7 */ + +#endif /* ansidecl.h */ diff --git a/contrib/binutils-2.14/include/aout/aout64.h b/contrib/binutils-2.14/include/aout/aout64.h new file mode 100644 index 0000000000..4843410d27 --- /dev/null +++ b/contrib/binutils-2.14/include/aout/aout64.h @@ -0,0 +1,519 @@ +/* `a.out' object-file definitions, including extensions to 64-bit fields + + Copyright 2001, 2003 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef __A_OUT_64_H__ +#define __A_OUT_64_H__ + +#ifndef BYTES_IN_WORD +#define BYTES_IN_WORD 4 +#endif + +/* This is the layout on disk of the 32-bit or 64-bit exec header. */ + +#ifndef external_exec +struct external_exec +{ + bfd_byte e_info[4]; /* Magic number and stuff. */ + bfd_byte e_text[BYTES_IN_WORD]; /* Length of text section in bytes. */ + bfd_byte e_data[BYTES_IN_WORD]; /* Length of data section in bytes. */ + bfd_byte e_bss[BYTES_IN_WORD]; /* Length of bss area in bytes. */ + bfd_byte e_syms[BYTES_IN_WORD]; /* Length of symbol table in bytes. */ + bfd_byte e_entry[BYTES_IN_WORD]; /* Start address. */ + bfd_byte e_trsize[BYTES_IN_WORD]; /* Length of text relocation info. */ + bfd_byte e_drsize[BYTES_IN_WORD]; /* Length of data relocation info. */ +}; + +#define EXEC_BYTES_SIZE (4 + BYTES_IN_WORD * 7) + +/* Magic numbers for a.out files. */ + +#if ARCH_SIZE==64 +#define OMAGIC 0x1001 /* Code indicating object file. */ +#define ZMAGIC 0x1002 /* Code indicating demand-paged executable. */ +#define NMAGIC 0x1003 /* Code indicating pure executable. */ + +/* There is no 64-bit QMAGIC as far as I know. */ + +#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC) +#else +#define OMAGIC 0407 /* Object file or impure executable. */ +#define NMAGIC 0410 /* Code indicating pure executable. */ +#define ZMAGIC 0413 /* Code indicating demand-paged executable. */ +#define BMAGIC 0415 /* Used by a b.out object. */ + +/* This indicates a demand-paged executable with the header in the text. + It is used by 386BSD (and variants) and Linux, at least. */ +#ifndef QMAGIC +#define QMAGIC 0314 +#endif +# ifndef N_BADMAG +# define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC \ + && N_MAGIC(x) != QMAGIC) +# endif /* N_BADMAG */ +#endif + +#endif + +#ifdef QMAGIC +#define N_IS_QMAGIC(x) (N_MAGIC (x) == QMAGIC) +#else +#define N_IS_QMAGIC(x) (0) +#endif + +/* The difference between TARGET_PAGE_SIZE and N_SEGSIZE is that TARGET_PAGE_SIZE is + the finest granularity at which you can page something, thus it + controls the padding (if any) before the text segment of a ZMAGIC + file. N_SEGSIZE is the resolution at which things can be marked as + read-only versus read/write, so it controls the padding between the + text segment and the data segment (in memory; on disk the padding + between them is TARGET_PAGE_SIZE). TARGET_PAGE_SIZE and N_SEGSIZE are the same + for most machines, but different for sun3. */ + +/* By default, segment size is constant. But some machines override this + to be a function of the a.out header (e.g. machine type). */ + +#ifndef N_SEGSIZE +#define N_SEGSIZE(x) SEGMENT_SIZE +#endif + +/* Virtual memory address of the text section. + This is getting very complicated. A good reason to discard a.out format + for something that specifies these fields explicitly. But til then... + + * OMAGIC and NMAGIC files: + (object files: text for "relocatable addr 0" right after the header) + start at 0, offset is EXEC_BYTES_SIZE, size as stated. + * The text address, offset, and size of ZMAGIC files depend + on the entry point of the file: + * entry point below TEXT_START_ADDR: + (hack for SunOS shared libraries) + start at 0, offset is 0, size as stated. + * If N_HEADER_IN_TEXT(x) is true (which defaults to being the + case when the entry point is EXEC_BYTES_SIZE or further into a page): + no padding is needed; text can start after exec header. Sun + considers the text segment of such files to include the exec header; + for BFD's purposes, we don't, which makes more work for us. + start at TEXT_START_ADDR + EXEC_BYTES_SIZE, offset is EXEC_BYTES_SIZE, + size as stated minus EXEC_BYTES_SIZE. + * If N_HEADER_IN_TEXT(x) is false (which defaults to being the case when + the entry point is less than EXEC_BYTES_SIZE into a page (e.g. page + aligned)): (padding is needed so that text can start at a page boundary) + start at TEXT_START_ADDR, offset TARGET_PAGE_SIZE, size as stated. + + Specific configurations may want to hardwire N_HEADER_IN_TEXT, + for efficiency or to allow people to play games with the entry point. + In that case, you would #define N_HEADER_IN_TEXT(x) as 1 for sunos, + and as 0 for most other hosts (Sony News, Vax Ultrix, etc). + (Do this in the appropriate bfd target file.) + (The default is a heuristic that will break if people try changing + the entry point, perhaps with the ld -e flag.) + + * QMAGIC is always like a ZMAGIC for which N_HEADER_IN_TEXT is true, + and for which the starting address is TARGET_PAGE_SIZE (or should this be + SEGMENT_SIZE?) (TEXT_START_ADDR only applies to ZMAGIC, not to QMAGIC). */ + +/* This macro is only relevant for ZMAGIC files; QMAGIC always has the header + in the text. */ +#ifndef N_HEADER_IN_TEXT +#define N_HEADER_IN_TEXT(x) \ + (((x).a_entry & (TARGET_PAGE_SIZE-1)) >= EXEC_BYTES_SIZE) +#endif + +/* Sun shared libraries, not linux. This macro is only relevant for ZMAGIC + files. */ +#ifndef N_SHARED_LIB +#if defined (TEXT_START_ADDR) && TEXT_START_ADDR == 0 +#define N_SHARED_LIB(x) (0) +#else +#define N_SHARED_LIB(x) ((x).a_entry < TEXT_START_ADDR) +#endif +#endif + +/* Returning 0 not TEXT_START_ADDR for OMAGIC and NMAGIC is based on + the assumption that we are dealing with a .o file, not an + executable. This is necessary for OMAGIC (but means we don't work + right on the output from ld -N); more questionable for NMAGIC. */ + +#ifndef N_TXTADDR +#define N_TXTADDR(x) \ + (/* The address of a QMAGIC file is always one page in, \ + with the header in the text. */ \ + N_IS_QMAGIC (x) \ + ? (bfd_vma) TARGET_PAGE_SIZE + EXEC_BYTES_SIZE \ + : (N_MAGIC (x) != ZMAGIC \ + ? (bfd_vma) 0 /* Object file or NMAGIC. */ \ + : (N_SHARED_LIB (x) \ + ? (bfd_vma) 0 \ + : (N_HEADER_IN_TEXT (x) \ + ? (bfd_vma) TEXT_START_ADDR + EXEC_BYTES_SIZE \ + : (bfd_vma) TEXT_START_ADDR)))) +#endif + +/* If N_HEADER_IN_TEXT is not true for ZMAGIC, there is some padding + to make the text segment start at a certain boundary. For most + systems, this boundary is TARGET_PAGE_SIZE. But for Linux, in the + time-honored tradition of crazy ZMAGIC hacks, it is 1024 which is + not what TARGET_PAGE_SIZE needs to be for QMAGIC. */ + +#ifndef ZMAGIC_DISK_BLOCK_SIZE +#define ZMAGIC_DISK_BLOCK_SIZE TARGET_PAGE_SIZE +#endif + +#define N_DISK_BLOCK_SIZE(x) \ + (N_MAGIC(x) == ZMAGIC ? ZMAGIC_DISK_BLOCK_SIZE : TARGET_PAGE_SIZE) + +/* Offset in an a.out of the start of the text section. */ +#ifndef N_TXTOFF +#define N_TXTOFF(x) \ + (/* For {O,N,Q}MAGIC, no padding. */ \ + N_MAGIC (x) != ZMAGIC \ + ? EXEC_BYTES_SIZE \ + : (N_SHARED_LIB (x) \ + ? 0 \ + : (N_HEADER_IN_TEXT (x) \ + ? EXEC_BYTES_SIZE /* No padding. */ \ + : ZMAGIC_DISK_BLOCK_SIZE /* A page of padding. */))) +#endif +/* Size of the text section. It's always as stated, except that we + offset it to `undo' the adjustment to N_TXTADDR and N_TXTOFF + for ZMAGIC files that nominally include the exec header + as part of the first page of text. (BFD doesn't consider the + exec header to be part of the text segment.) */ +#ifndef N_TXTSIZE +#define N_TXTSIZE(x) \ + (/* For QMAGIC, we don't consider the header part of the text section. */\ + N_IS_QMAGIC (x) \ + ? (x).a_text - EXEC_BYTES_SIZE \ + : ((N_MAGIC (x) != ZMAGIC || N_SHARED_LIB (x)) \ + ? (x).a_text \ + : (N_HEADER_IN_TEXT (x) \ + ? (x).a_text - EXEC_BYTES_SIZE /* No padding. */ \ + : (x).a_text /* A page of padding. */ ))) +#endif +/* The address of the data segment in virtual memory. + It is the text segment address, plus text segment size, rounded + up to a N_SEGSIZE boundary for pure or pageable files. */ +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC (x) == OMAGIC \ + ? (N_TXTADDR (x) + N_TXTSIZE (x)) \ + : (N_SEGSIZE (x) + ((N_TXTADDR (x) + N_TXTSIZE (x) - 1) \ + & ~ (bfd_vma) (N_SEGSIZE (x) - 1)))) +#endif +/* The address of the BSS segment -- immediately after the data segment. */ + +#define N_BSSADDR(x) (N_DATADDR (x) + (x).a_data) + +/* Offsets of the various portions of the file after the text segment. */ + +/* For {Q,Z}MAGIC, there is padding to make the data segment start on + a page boundary. Most of the time the a_text field (and thus + N_TXTSIZE) already contains this padding. It is possible that for + BSDI and/or 386BSD it sometimes doesn't contain the padding, and + perhaps we should be adding it here. But this seems kind of + questionable and probably should be BSDI/386BSD-specific if we do + do it. + + For NMAGIC (at least for hp300 BSD, probably others), there is + padding in memory only, not on disk, so we must *not* ever pad here + for NMAGIC. */ + +#ifndef N_DATOFF +#define N_DATOFF(x) (N_TXTOFF (x) + N_TXTSIZE (x)) +#endif +#ifndef N_TRELOFF +#define N_TRELOFF(x) (N_DATOFF (x) + (x).a_data) +#endif +#ifndef N_DRELOFF +#define N_DRELOFF(x) (N_TRELOFF (x) + (x).a_trsize) +#endif +#ifndef N_SYMOFF +#define N_SYMOFF(x) (N_DRELOFF (x) + (x).a_drsize) +#endif +#ifndef N_STROFF +#define N_STROFF(x) (N_SYMOFF (x) + (x).a_syms) +#endif + +/* Symbols */ +#ifndef external_nlist +struct external_nlist +{ + bfd_byte e_strx[BYTES_IN_WORD]; /* Index into string table of name. */ + bfd_byte e_type[1]; /* Type of symbol. */ + bfd_byte e_other[1]; /* Misc info (usually empty). */ + bfd_byte e_desc[2]; /* Description field. */ + bfd_byte e_value[BYTES_IN_WORD]; /* Value of symbol. */ +}; +#define EXTERNAL_NLIST_SIZE (BYTES_IN_WORD+4+BYTES_IN_WORD) +#endif + +struct internal_nlist +{ + unsigned long n_strx; /* Index into string table of name. */ + unsigned char n_type; /* Type of symbol. */ + unsigned char n_other; /* Misc info (usually empty). */ + unsigned short n_desc; /* Description field. */ + bfd_vma n_value; /* Value of symbol. */ +}; + +/* The n_type field is the symbol type, containing: */ + +#define N_UNDF 0 /* Undefined symbol. */ +#define N_ABS 2 /* Absolute symbol -- defined at particular addr. */ +#define N_TEXT 4 /* Text sym -- defined at offset in text seg. */ +#define N_DATA 6 /* Data sym -- defined at offset in data seg. */ +#define N_BSS 8 /* BSS sym -- defined at offset in zero'd seg. */ +#define N_COMM 0x12 /* Common symbol (visible after shared lib dynlink). */ +#define N_FN 0x1f /* File name of .o file. */ +#define N_FN_SEQ 0x0C /* N_FN from Sequent compilers (sigh). */ +/* Note: N_EXT can only be usefully OR-ed with N_UNDF, N_ABS, N_TEXT, + N_DATA, or N_BSS. When the low-order bit of other types is set, + (e.g. N_WARNING versus N_FN), they are two different types. */ +#define N_EXT 1 /* External symbol (as opposed to local-to-this-file). */ +#define N_TYPE 0x1e +#define N_STAB 0xe0 /* If any of these bits are on, it's a debug symbol. */ + +#define N_INDR 0x0a + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + elements value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol. */ +#define N_SETT 0x16 /* Text set element symbol. */ +#define N_SETD 0x18 /* Data set element symbol. */ +#define N_SETB 0x1A /* Bss set element symbol. */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +/* Warning symbol. The text gives a warning message, the next symbol + in the table will be undefined. When the symbol is referenced, the + message is printed. */ + +#define N_WARNING 0x1e + +/* Weak symbols. These are a GNU extension to the a.out format. The + semantics are those of ELF weak symbols. Weak symbols are always + externally visible. The N_WEAK? values are squeezed into the + available slots. The value of a N_WEAKU symbol is 0. The values + of the other types are the definitions. */ +#define N_WEAKU 0x0d /* Weak undefined symbol. */ +#define N_WEAKA 0x0e /* Weak absolute symbol. */ +#define N_WEAKT 0x0f /* Weak text symbol. */ +#define N_WEAKD 0x10 /* Weak data symbol. */ +#define N_WEAKB 0x11 /* Weak bss symbol. */ + +/* Relocations + + There are two types of relocation flavours for a.out systems, + standard and extended. The standard form is used on systems where the + instruction has room for all the bits of an offset to the operand, whilst + the extended form is used when an address operand has to be split over n + instructions. Eg, on the 68k, each move instruction can reference + the target with a displacement of 16 or 32 bits. On the sparc, move + instructions use an offset of 14 bits, so the offset is stored in + the reloc field, and the data in the section is ignored. */ + +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct reloc_std_external +{ + bfd_byte r_address[BYTES_IN_WORD]; /* Offset of of data to relocate. */ + bfd_byte r_index[3]; /* Symbol table index of symbol. */ + bfd_byte r_type[1]; /* Relocation type. */ +}; + +#define RELOC_STD_BITS_PCREL_BIG ((unsigned int) 0x80) +#define RELOC_STD_BITS_PCREL_LITTLE ((unsigned int) 0x01) + +#define RELOC_STD_BITS_LENGTH_BIG ((unsigned int) 0x60) +#define RELOC_STD_BITS_LENGTH_SH_BIG 5 +#define RELOC_STD_BITS_LENGTH_LITTLE ((unsigned int) 0x06) +#define RELOC_STD_BITS_LENGTH_SH_LITTLE 1 + +#define RELOC_STD_BITS_EXTERN_BIG ((unsigned int) 0x10) +#define RELOC_STD_BITS_EXTERN_LITTLE ((unsigned int) 0x08) + +#define RELOC_STD_BITS_BASEREL_BIG ((unsigned int) 0x08) +#define RELOC_STD_BITS_BASEREL_LITTLE ((unsigned int) 0x10) + +#define RELOC_STD_BITS_JMPTABLE_BIG ((unsigned int) 0x04) +#define RELOC_STD_BITS_JMPTABLE_LITTLE ((unsigned int) 0x20) + +#define RELOC_STD_BITS_RELATIVE_BIG ((unsigned int) 0x02) +#define RELOC_STD_BITS_RELATIVE_LITTLE ((unsigned int) 0x40) + +#define RELOC_STD_SIZE (BYTES_IN_WORD + 3 + 1) /* Bytes per relocation entry. */ + +struct reloc_std_internal +{ + bfd_vma r_address; /* Address (within segment) to be relocated. */ + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in files the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* The next three bits are for SunOS shared libraries, and seem to + be undocumented. */ + unsigned int r_baserel:1; /* Linkage table relative. */ + unsigned int r_jmptable:1; /* pc-relative to jump table. */ + unsigned int r_relative:1; /* "relative relocation". */ + /* unused */ + unsigned int r_pad:1; /* Padding -- set to zero. */ +}; + + +/* EXTENDED RELOCS. */ + +struct reloc_ext_external +{ + bfd_byte r_address[BYTES_IN_WORD]; /* Offset of of data to relocate. */ + bfd_byte r_index[3]; /* Symbol table index of symbol. */ + bfd_byte r_type[1]; /* Relocation type. */ + bfd_byte r_addend[BYTES_IN_WORD]; /* Datum addend. */ +}; + +#ifndef RELOC_EXT_BITS_EXTERN_BIG +#define RELOC_EXT_BITS_EXTERN_BIG ((unsigned int) 0x80) +#endif + +#ifndef RELOC_EXT_BITS_EXTERN_LITTLE +#define RELOC_EXT_BITS_EXTERN_LITTLE ((unsigned int) 0x01) +#endif + +#ifndef RELOC_EXT_BITS_TYPE_BIG +#define RELOC_EXT_BITS_TYPE_BIG ((unsigned int) 0x1F) +#endif + +#ifndef RELOC_EXT_BITS_TYPE_SH_BIG +#define RELOC_EXT_BITS_TYPE_SH_BIG 0 +#endif + +#ifndef RELOC_EXT_BITS_TYPE_LITTLE +#define RELOC_EXT_BITS_TYPE_LITTLE ((unsigned int) 0xF8) +#endif + +#ifndef RELOC_EXT_BITS_TYPE_SH_LITTLE +#define RELOC_EXT_BITS_TYPE_SH_LITTLE 3 +#endif + +/* Bytes per relocation entry. */ +#define RELOC_EXT_SIZE (BYTES_IN_WORD + 3 + 1 + BYTES_IN_WORD) + +enum reloc_type +{ + /* Simple relocations. */ + RELOC_8, /* data[0:7] = addend + sv */ + RELOC_16, /* data[0:15] = addend + sv */ + RELOC_32, /* data[0:31] = addend + sv */ + /* PC-rel displacement. */ + RELOC_DISP8, /* data[0:7] = addend - pc + sv */ + RELOC_DISP16, /* data[0:15] = addend - pc + sv */ + RELOC_DISP32, /* data[0:31] = addend - pc + sv */ + /* Special. */ + RELOC_WDISP30, /* data[0:29] = (addend + sv - pc)>>2 */ + RELOC_WDISP22, /* data[0:21] = (addend + sv - pc)>>2 */ + RELOC_HI22, /* data[0:21] = (addend + sv)>>10 */ + RELOC_22, /* data[0:21] = (addend + sv) */ + RELOC_13, /* data[0:12] = (addend + sv) */ + RELOC_LO10, /* data[0:9] = (addend + sv) */ + RELOC_SFA_BASE, + RELOC_SFA_OFF13, + /* P.I.C. (base-relative). */ + RELOC_BASE10, /* Not sure - maybe we can do this the */ + RELOC_BASE13, /* right way now */ + RELOC_BASE22, + /* For some sort of pc-rel P.I.C. (?) */ + RELOC_PC10, + RELOC_PC22, + /* P.I.C. jump table. */ + RELOC_JMP_TBL, + /* Reputedly for shared libraries somehow. */ + RELOC_SEGOFF16, + RELOC_GLOB_DAT, + RELOC_JMP_SLOT, + RELOC_RELATIVE, + + RELOC_11, + RELOC_WDISP2_14, + RELOC_WDISP19, + RELOC_HHI22, /* data[0:21] = (addend + sv) >> 42 */ + RELOC_HLO10, /* data[0:9] = (addend + sv) >> 32 */ + + /* 29K relocation types. */ + RELOC_JUMPTARG, + RELOC_CONST, + RELOC_CONSTH, + + /* All the new ones I can think of, for sparc v9. */ + RELOC_64, /* data[0:63] = addend + sv */ + RELOC_DISP64, /* data[0:63] = addend - pc + sv */ + RELOC_WDISP21, /* data[0:20] = (addend + sv - pc)>>2 */ + RELOC_DISP21, /* data[0:20] = addend - pc + sv */ + RELOC_DISP14, /* data[0:13] = addend - pc + sv */ + /* Q . + What are the other ones, + Since this is a clean slate, can we throw away the ones we dont + understand ? Should we sort the values ? What about using a + microcode format like the 68k ? */ + NO_RELOC + }; + + +struct reloc_internal +{ + bfd_vma r_address; /* Offset of of data to relocate. */ + long r_index; /* Symbol table index of symbol. */ + enum reloc_type r_type; /* Relocation type. */ + bfd_vma r_addend; /* Datum addend. */ +}; + +/* Q. + Should the length of the string table be 4 bytes or 8 bytes ? + + Q. + What about archive indexes ? */ + +#endif /* __A_OUT_64_H__ */ diff --git a/contrib/binutils-2.14/include/aout/ar.h b/contrib/binutils-2.14/include/aout/ar.h new file mode 100644 index 0000000000..15d534c578 --- /dev/null +++ b/contrib/binutils-2.14/include/aout/ar.h @@ -0,0 +1,52 @@ +/* archive file definition for GNU software + + Copyright 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* So far this is correct for BSDish archives. Don't forget that + files must begin on an even byte boundary. */ + +#ifndef __GNU_AR_H__ +#define __GNU_AR_H__ + +/* Note that the usual '\n' in magic strings may translate to different + characters, as allowed by ANSI. '\012' has a fixed value, and remains + compatible with existing BSDish archives. */ + +#define ARMAG "!\012" /* For COFF and a.out archives */ +#define ARMAGB "!\012" /* For b.out archives */ +#define SARMAG 8 +#define ARFMAG "`\012" + +/* The ar_date field of the armap (__.SYMDEF) member of an archive + must be greater than the modified date of the entire file, or + BSD-derived linkers complain. We originally write the ar_date with + this offset from the real file's mod-time. After finishing the + file, we rewrite ar_date if it's not still greater than the mod date. */ + +#define ARMAP_TIME_OFFSET 60 + +struct ar_hdr { + char ar_name[16]; /* name of this member */ + char ar_date[12]; /* file mtime */ + char ar_uid[6]; /* owner uid; printed as decimal */ + char ar_gid[6]; /* owner gid; printed as decimal */ + char ar_mode[8]; /* file mode, printed as octal */ + char ar_size[10]; /* file size, printed as decimal */ + char ar_fmag[2]; /* should contain ARFMAG */ +}; + +#endif /* __GNU_AR_H__ */ diff --git a/contrib/binutils-2.14/include/aout/ranlib.h b/contrib/binutils-2.14/include/aout/ranlib.h new file mode 100644 index 0000000000..e4603edf66 --- /dev/null +++ b/contrib/binutils-2.14/include/aout/ranlib.h @@ -0,0 +1,62 @@ +/* ranlib.h -- archive library index member definition for GNU. + Copyright 1990, 1991 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The Symdef member of an archive contains two things: + a table that maps symbol-string offsets to file offsets, + and a symbol-string table. All the symbol names are + run together (each with trailing null) in the symbol-string + table. There is a single longword bytecount on the front + of each of these tables. Thus if we have two symbols, + "foo" and "_bar", that are in archive members at offsets + 200 and 900, it would look like this: + 16 ; byte count of index table + 0 ; offset of "foo" in string table + 200 ; offset of foo-module in file + 4 ; offset of "bar" in string table + 900 ; offset of bar-module in file + 9 ; byte count of string table + "foo\0_bar\0" ; string table */ + +#define RANLIBMAG "__.SYMDEF" /* Archive file name containing index */ +#define RANLIBSKEW 3 /* Creation time offset */ + +/* Format of __.SYMDEF: + First, a longword containing the size of the 'symdef' data that follows. + Second, zero or more 'symdef' structures. + Third, a longword containing the length of symbol name strings. + Fourth, zero or more symbol name strings (each followed by a null). */ + +struct symdef + { + union + { + unsigned long string_offset; /* In the file */ + char *name; /* In memory, sometimes */ + } s; + /* this points to the front of the file header (AKA member header -- + a struct ar_hdr), not to the front of the file or into the file). + in other words it only tells you which file to read */ + unsigned long file_offset; + }; + +/* Compatability with BSD code */ + +#define ranlib symdef +#define ran_un s +#define ran_strx string_offset +#define ran_name name +#define ran_off file_offset diff --git a/contrib/binutils-2.14/include/aout/stab.def b/contrib/binutils-2.14/include/aout/stab.def new file mode 100644 index 0000000000..67bde35f10 --- /dev/null +++ b/contrib/binutils-2.14/include/aout/stab.def @@ -0,0 +1,268 @@ +/* Table of DBX symbol codes for the GNU system. + Copyright 1988, 1991, 1992, 1993, 1994, 1996, 1998 + Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* New stab from Solaris 2. This uses an n_type of 0, which in a.out files + overlaps the N_UNDF used for ordinary symbols. In ELF files, the + debug information is in a different file section, so there is no conflict. + This symbol's n_value gives the size of the string section associated + with this file. The symbol's n_strx (relative to the just-updated + string section start address) gives the name of the source file, + e.g. "foo.c", without any path information. The symbol's n_desc gives + the count of upcoming symbols associated with this file (not including + this one). */ +/* __define_stab (N_UNDF, 0x00, "UNDF") */ + +/* Global variable. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_GSYM, 0x20, "GSYM") + +/* Function name for BSD Fortran. Only the name is significant. + To find the address, look in the corresponding external symbol. */ +__define_stab (N_FNAME, 0x22, "FNAME") + +/* Function name or text-segment variable for C. Value is its address. + Desc is supposedly starting line number, but GCC doesn't set it + and DBX seems not to miss it. */ +__define_stab (N_FUN, 0x24, "FUN") + +/* Data-segment variable with internal linkage. Value is its address. + "Static Sym". */ +__define_stab (N_STSYM, 0x26, "STSYM") + +/* BSS-segment variable with internal linkage. Value is its address. */ +__define_stab (N_LCSYM, 0x28, "LCSYM") + +/* Name of main routine. Only the name is significant. */ +__define_stab (N_MAIN, 0x2a, "MAIN") + +/* Solaris2: Read-only data symbols. */ +__define_stab (N_ROSYM, 0x2c, "ROSYM") + +/* Global symbol in Pascal. + Supposedly the value is its line number; I'm skeptical. */ +__define_stab (N_PC, 0x30, "PC") + +/* Number of symbols: 0, files,,funcs,lines according to Ultrix V4.0. */ +__define_stab (N_NSYMS, 0x32, "NSYMS") + +/* "No DST map for sym: name, ,0,type,ignored" according to Ultrix V4.0. */ +__define_stab (N_NOMAP, 0x34, "NOMAP") + +/* New stab from Solaris 2. Like N_SO, but for the object file. Two in + a row provide the build directory and the relative path of the .o from it. + Solaris2 uses this to avoid putting the stabs info into the linked + executable; this stab goes into the ".stab.index" section, and the debugger + reads the real stabs directly from the .o files instead. */ +__define_stab (N_OBJ, 0x38, "OBJ") + +/* New stab from Solaris 2. Options for the debugger, related to the + source language for this module. E.g. whether to use ANSI + integral promotions or traditional integral promotions. */ +__define_stab (N_OPT, 0x3c, "OPT") + +/* Register variable. Value is number of register. */ +__define_stab (N_RSYM, 0x40, "RSYM") + +/* Modula-2 compilation unit. Can someone say what info it contains? */ +__define_stab (N_M2C, 0x42, "M2C") + +/* Line number in text segment. Desc is the line number; + value is corresponding address. On Solaris2, the line number is + relative to the start of the current function. */ +__define_stab (N_SLINE, 0x44, "SLINE") + +/* Similar, for data segment. */ +__define_stab (N_DSLINE, 0x46, "DSLINE") + +/* Similar, for bss segment. */ +__define_stab (N_BSLINE, 0x48, "BSLINE") + +/* Sun's source-code browser stabs. ?? Don't know what the fields are. + Supposedly the field is "path to associated .cb file". THIS VALUE + OVERLAPS WITH N_BSLINE! */ +__define_stab_duplicate (N_BROWS, 0x48, "BROWS") + +/* GNU Modula-2 definition module dependency. Value is the modification time + of the definition file. Other is non-zero if it is imported with the + GNU M2 keyword %INITIALIZE. Perhaps N_M2C can be used if there + are enough empty fields? */ +__define_stab(N_DEFD, 0x4a, "DEFD") + +/* New in Solaris2. Function start/body/end line numbers. */ +__define_stab(N_FLINE, 0x4C, "FLINE") + +/* THE FOLLOWING TWO STAB VALUES CONFLICT. Happily, one is for Modula-2 + and one is for C++. Still,... */ +/* GNU C++ exception variable. Name is variable name. */ +__define_stab (N_EHDECL, 0x50, "EHDECL") +/* Modula2 info "for imc": name,,0,0,0 according to Ultrix V4.0. */ +__define_stab_duplicate (N_MOD2, 0x50, "MOD2") + +/* GNU C++ `catch' clause. Value is its address. Desc is nonzero if + this entry is immediately followed by a CAUGHT stab saying what exception + was caught. Multiple CAUGHT stabs means that multiple exceptions + can be caught here. If Desc is 0, it means all exceptions are caught + here. */ +__define_stab (N_CATCH, 0x54, "CATCH") + +/* Structure or union element. Value is offset in the structure. */ +__define_stab (N_SSYM, 0x60, "SSYM") + +/* Solaris2: Last stab emitted for module. */ +__define_stab (N_ENDM, 0x62, "ENDM") + +/* Name of main source file. + Value is starting text address of the compilation. + If multiple N_SO's appear, the first to contain a trailing / is the + compilation directory. The first to not contain a trailing / is the + source file name, relative to the compilation directory. Others (perhaps + resulting from cfront) are ignored. + On Solaris2, value is undefined, but desc is a source-language code. */ + +__define_stab (N_SO, 0x64, "SO") + +/* SunPro F77: Name of alias. */ +__define_stab (N_ALIAS, 0x6c, "ALIAS") + +/* Automatic variable in the stack. Value is offset from frame pointer. + Also used for type descriptions. */ +__define_stab (N_LSYM, 0x80, "LSYM") + +/* Beginning of an include file. Only Sun uses this. + In an object file, only the name is significant. + The Sun linker puts data into some of the other fields. */ +__define_stab (N_BINCL, 0x82, "BINCL") + +/* Name of sub-source file (#include file). + Value is starting text address of the compilation. */ +__define_stab (N_SOL, 0x84, "SOL") + +/* Parameter variable. Value is offset from argument pointer. + (On most machines the argument pointer is the same as the frame pointer. */ +__define_stab (N_PSYM, 0xa0, "PSYM") + +/* End of an include file. No name. + This and N_BINCL act as brackets around the file's output. + In an object file, there is no significant data in this entry. + The Sun linker puts data into some of the fields. */ +__define_stab (N_EINCL, 0xa2, "EINCL") + +/* Alternate entry point. Value is its address. */ +__define_stab (N_ENTRY, 0xa4, "ENTRY") + +/* Beginning of lexical block. + The desc is the nesting level in lexical blocks. + The value is the address of the start of the text for the block. + The variables declared inside the block *precede* the N_LBRAC symbol. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_LBRAC, 0xc0, "LBRAC") + +/* Place holder for deleted include file. Replaces a N_BINCL and everything + up to the corresponding N_EINCL. The Sun linker generates these when + it finds multiple identical copies of the symbols from an include file. + This appears only in output from the Sun linker. */ +__define_stab (N_EXCL, 0xc2, "EXCL") + +/* Modula-2 scope information. Can someone say what info it contains? */ +__define_stab (N_SCOPE, 0xc4, "SCOPE") + +/* End of a lexical block. Desc matches the N_LBRAC's desc. + The value is the address of the end of the text for the block. + On Solaris2, the value is relative to the start of the current function. */ +__define_stab (N_RBRAC, 0xe0, "RBRAC") + +/* Begin named common block. Only the name is significant. */ +__define_stab (N_BCOMM, 0xe2, "BCOMM") + +/* End named common block. Only the name is significant + (and it should match the N_BCOMM). */ +__define_stab (N_ECOMM, 0xe4, "ECOMM") + +/* Member of a common block; value is offset within the common block. + This should occur within a BCOMM/ECOMM pair. */ +__define_stab (N_ECOML, 0xe8, "ECOML") + +/* Solaris2: Pascal "with" statement: type,,0,0,offset */ +__define_stab (N_WITH, 0xea, "WITH") + +/* These STAB's are used on Gould systems for Non-Base register symbols + or something like that. FIXME. I have assigned the values at random + since I don't have a Gould here. Fixups from Gould folk welcome... */ +__define_stab (N_NBTEXT, 0xF0, "NBTEXT") +__define_stab (N_NBDATA, 0xF2, "NBDATA") +__define_stab (N_NBBSS, 0xF4, "NBBSS") +__define_stab (N_NBSTS, 0xF6, "NBSTS") +__define_stab (N_NBLCS, 0xF8, "NBLCS") + +/* Second symbol entry containing a length-value for the preceding entry. + The value is the length. */ +__define_stab (N_LENG, 0xfe, "LENG") + +/* The above information, in matrix format. + + STAB MATRIX + _________________________________________________ + | 00 - 1F are not dbx stab symbols | + | In most cases, the low bit is the EXTernal bit| + + | 00 UNDEF | 02 ABS | 04 TEXT | 06 DATA | + | 01 |EXT | 03 |EXT | 05 |EXT | 07 |EXT | + + | 08 BSS | 0A INDR | 0C FN_SEQ | 0E WEAKA | + | 09 |EXT | 0B | 0D WEAKU | 0F WEAKT | + + | 10 WEAKD | 12 COMM | 14 SETA | 16 SETT | + | 11 WEAKB | 13 | 15 | 17 | + + | 18 SETD | 1A SETB | 1C SETV | 1E WARNING| + | 19 | 1B | 1D | 1F FN | + + |_______________________________________________| + | Debug entries with bit 01 set are unused. | + | 20 GSYM | 22 FNAME | 24 FUN | 26 STSYM | + | 28 LCSYM | 2A MAIN | 2C ROSYM | 2E | + | 30 PC | 32 NSYMS | 34 NOMAP | 36 | + | 38 OBJ | 3A | 3C OPT | 3E | + | 40 RSYM | 42 M2C | 44 SLINE | 46 DSLINE | + | 48 BSLINE*| 4A DEFD | 4C FLINE | 4E | + | 50 EHDECL*| 52 | 54 CATCH | 56 | + | 58 | 5A | 5C | 5E | + | 60 SSYM | 62 ENDM | 64 SO | 66 | + | 68 | 6A | 6C ALIAS | 6E | + | 70 | 72 | 74 | 76 | + | 78 | 7A | 7C | 7E | + | 80 LSYM | 82 BINCL | 84 SOL | 86 | + | 88 | 8A | 8C | 8E | + | 90 | 92 | 94 | 96 | + | 98 | 9A | 9C | 9E | + | A0 PSYM | A2 EINCL | A4 ENTRY | A6 | + | A8 | AA | AC | AE | + | B0 | B2 | B4 | B6 | + | B8 | BA | BC | BE | + | C0 LBRAC | C2 EXCL | C4 SCOPE | C6 | + | C8 | CA | CC | CE | + | D0 | D2 | D4 | D6 | + | D8 | DA | DC | DE | + | E0 RBRAC | E2 BCOMM | E4 ECOMM | E6 | + | E8 ECOML | EA WITH | EC | EE | + | F0 | F2 | F4 | F6 | + | F8 | FA | FC | FE LENG | + +-----------------------------------------------+ + * 50 EHDECL is also MOD2. + * 48 BSLINE is also BROWS. + */ diff --git a/contrib/binutils-2.14/include/aout/stab_gnu.h b/contrib/binutils-2.14/include/aout/stab_gnu.h new file mode 100644 index 0000000000..c62ac6ed46 --- /dev/null +++ b/contrib/binutils-2.14/include/aout/stab_gnu.h @@ -0,0 +1,54 @@ +/* gnu_stab.h Definitions for GNU extensions to STABS + + Copyright 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef __GNU_STAB__ + +/* Indicate the GNU stab.h is in use. */ + +#define __GNU_STAB__ + +#define __define_stab(NAME, CODE, STRING) NAME=CODE, +#define __define_stab_duplicate(NAME, CODE, STRING) NAME=CODE, + +enum __stab_debug_code +{ +#include "aout/stab.def" +LAST_UNUSED_STAB_CODE +}; + +#undef __define_stab + +/* Definitions of "desc" field for N_SO stabs in Solaris2. */ + +#define N_SO_AS 1 +#define N_SO_C 2 +#define N_SO_ANSI_C 3 +#define N_SO_CC 4 /* C++ */ +#define N_SO_FORTRAN 5 +#define N_SO_PASCAL 6 + +/* Solaris2: Floating point type values in basic types. */ + +#define NF_NONE 0 +#define NF_SINGLE 1 /* IEEE 32-bit */ +#define NF_DOUBLE 2 /* IEEE 64-bit */ +#define NF_COMPLEX 3 /* Fortran complex */ +#define NF_COMPLEX16 4 /* Fortran double complex */ +#define NF_COMPLEX32 5 /* Fortran complex*16 */ +#define NF_LDOUBLE 6 /* Long double (whatever that is) */ + +#endif /* __GNU_STAB_ */ diff --git a/contrib/binutils-2.14/include/bfdlink.h b/contrib/binutils-2.14/include/bfdlink.h new file mode 100644 index 0000000000..89d916ee83 --- /dev/null +++ b/contrib/binutils-2.14/include/bfdlink.h @@ -0,0 +1,646 @@ +/* bfdlink.h -- header file for BFD link routines + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002 + Free Software Foundation, Inc. + Written by Steve Chamberlain and Ian Lance Taylor, 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef BFDLINK_H +#define BFDLINK_H + +/* Which symbols to strip during a link. */ +enum bfd_link_strip +{ + strip_none, /* Don't strip any symbols. */ + strip_debugger, /* Strip debugging symbols. */ + strip_some, /* keep_hash is the list of symbols to keep. */ + strip_all /* Strip all symbols. */ +}; + +/* Which local symbols to discard during a link. This is irrelevant + if strip_all is used. */ +enum bfd_link_discard +{ + discard_sec_merge, /* Discard local temporary symbols in SEC_MERGE + sections. */ + discard_none, /* Don't discard any locals. */ + discard_l, /* Discard local temporary symbols. */ + discard_all /* Discard all locals. */ +}; + +/* Describes the type of hash table entry structure being used. + Different hash table structure have different fields and so + support different linking features. */ +enum bfd_link_hash_table_type + { + bfd_link_generic_hash_table, + bfd_link_elf_hash_table + }; + +/* These are the possible types of an entry in the BFD link hash + table. */ + +enum bfd_link_hash_type +{ + bfd_link_hash_new, /* Symbol is new. */ + bfd_link_hash_undefined, /* Symbol seen before, but undefined. */ + bfd_link_hash_undefweak, /* Symbol is weak and undefined. */ + bfd_link_hash_defined, /* Symbol is defined. */ + bfd_link_hash_defweak, /* Symbol is weak and defined. */ + bfd_link_hash_common, /* Symbol is common. */ + bfd_link_hash_indirect, /* Symbol is an indirect link. */ + bfd_link_hash_warning /* Like indirect, but warn if referenced. */ +}; + +enum bfd_link_common_skip_ar_aymbols +{ + bfd_link_common_skip_none, + bfd_link_common_skip_text, + bfd_link_common_skip_data, + bfd_link_common_skip_all +}; + +/* The linking routines use a hash table which uses this structure for + its elements. */ + +struct bfd_link_hash_entry +{ + /* Base hash table entry structure. */ + struct bfd_hash_entry root; + /* Type of this entry. */ + enum bfd_link_hash_type type; + + /* Undefined and common symbols are kept in a linked list through + this field. This field is not in the union because that would + force us to remove entries from the list when we changed their + type, which would force the list to be doubly linked, which would + waste more memory. When an undefined or common symbol is + created, it should be added to this list, the head of which is in + the link hash table itself. As symbols are defined, they need + not be removed from the list; anything which reads the list must + doublecheck the symbol type. + + Weak symbols are not kept on this list. + + Defined and defweak symbols use this field as a reference marker. + If the field is not NULL, or this structure is the tail of the + undefined symbol list, the symbol has been referenced. If the + symbol is undefined and becomes defined, this field will + automatically be non-NULL since the symbol will have been on the + undefined symbol list. */ + struct bfd_link_hash_entry *next; + /* A union of information depending upon the type. */ + union + { + /* Nothing is kept for bfd_hash_new. */ + /* bfd_link_hash_undefined, bfd_link_hash_undefweak. */ + struct + { + bfd *abfd; /* BFD symbol was found in. */ + } undef; + /* bfd_link_hash_defined, bfd_link_hash_defweak. */ + struct + { + bfd_vma value; /* Symbol value. */ + asection *section; /* Symbol section. */ + } def; + /* bfd_link_hash_indirect, bfd_link_hash_warning. */ + struct + { + struct bfd_link_hash_entry *link; /* Real symbol. */ + const char *warning; /* Warning (bfd_link_hash_warning only). */ + } i; + /* bfd_link_hash_common. */ + struct + { + /* The linker needs to know three things about common + symbols: the size, the alignment, and the section in + which the symbol should be placed. We store the size + here, and we allocate a small structure to hold the + section and the alignment. The alignment is stored as a + power of two. We don't store all the information + directly because we don't want to increase the size of + the union; this structure is a major space user in the + linker. */ + bfd_size_type size; /* Common symbol size. */ + struct bfd_link_hash_common_entry + { + unsigned int alignment_power; /* Alignment. */ + asection *section; /* Symbol section. */ + } *p; + } c; + } u; +}; + +/* This is the link hash table. It is a derived class of + bfd_hash_table. */ + +struct bfd_link_hash_table +{ + /* The hash table itself. */ + struct bfd_hash_table table; + /* The back end which created this hash table. This indicates the + type of the entries in the hash table, which is sometimes + important information when linking object files of different + types together. */ + const bfd_target *creator; + /* A linked list of undefined and common symbols, linked through the + next field in the bfd_link_hash_entry structure. */ + struct bfd_link_hash_entry *undefs; + /* Entries are added to the tail of the undefs list. */ + struct bfd_link_hash_entry *undefs_tail; + /* The type of the link hash table. */ + enum bfd_link_hash_table_type type; +}; + +/* Look up an entry in a link hash table. If FOLLOW is TRUE, this + follows bfd_link_hash_indirect and bfd_link_hash_warning links to + the real symbol. */ +extern struct bfd_link_hash_entry *bfd_link_hash_lookup + PARAMS ((struct bfd_link_hash_table *, const char *, bfd_boolean create, + bfd_boolean copy, bfd_boolean follow)); + +/* Look up an entry in the main linker hash table if the symbol might + be wrapped. This should only be used for references to an + undefined symbol, not for definitions of a symbol. */ + +extern struct bfd_link_hash_entry *bfd_wrapped_link_hash_lookup + PARAMS ((bfd *, struct bfd_link_info *, const char *, bfd_boolean, + bfd_boolean, bfd_boolean)); + +/* Traverse a link hash table. */ +extern void bfd_link_hash_traverse + PARAMS ((struct bfd_link_hash_table *, + bfd_boolean (*) (struct bfd_link_hash_entry *, PTR), + PTR)); + +/* Add an entry to the undefs list. */ +extern void bfd_link_add_undef + PARAMS ((struct bfd_link_hash_table *, struct bfd_link_hash_entry *)); + +struct bfd_sym_chain +{ + struct bfd_sym_chain *next; + const char *name; +}; + +/* This structure holds all the information needed to communicate + between BFD and the linker when doing a link. */ + +struct bfd_link_info +{ + /* TRUE if BFD should generate a relocatable object file. */ + unsigned int relocateable: 1; + + /* TRUE if BFD should generate relocation information in the final + executable. */ + unsigned int emitrelocations: 1; + + /* TRUE if BFD should generate a "task linked" object file, + similar to relocatable but also with globals converted to + statics. */ + unsigned int task_link: 1; + + /* TRUE if BFD should generate a shared object. */ + unsigned int shared: 1; + + /* TRUE if BFD should pre-bind symbols in a shared object. */ + unsigned int symbolic: 1; + + /* TRUE if BFD should export all symbols in the dynamic symbol table + of an executable, rather than only those used. */ + unsigned int export_dynamic: 1; + + /* TRUE if shared objects should be linked directly, not shared. */ + unsigned int static_link: 1; + + /* TRUE if the output file should be in a traditional format. This + is equivalent to the setting of the BFD_TRADITIONAL_FORMAT flag + on the output file, but may be checked when reading the input + files. */ + unsigned int traditional_format: 1; + + /* TRUE if we want to produced optimized output files. This might + need much more time and therefore must be explicitly selected. */ + unsigned int optimize: 1; + + /* TRUE if BFD should generate errors for undefined symbols + even if generating a shared object. */ + unsigned int no_undefined: 1; + + /* TRUE if BFD should allow undefined symbols in shared objects even + when no_undefined is set to disallow undefined symbols. The net + result will be that undefined symbols in regular objects will + still trigger an error, but undefined symbols in shared objects + will be ignored. The implementation of no_undefined makes the + assumption that the runtime linker will choke on undefined + symbols. However there is at least one system (BeOS) where + undefined symbols in shared libraries is normal since the kernel + patches them at load time to select which function is most + appropriate for the current architecture. I.E. dynamically + select an appropriate memset function. Apparently it is also + normal for HPPA shared libraries to have undefined symbols. */ + unsigned int allow_shlib_undefined: 1; + + /* TRUE if ok to have multiple definition. */ + unsigned int allow_multiple_definition: 1; + + /* TRUE if ok to have version with no definition. */ + unsigned int allow_undefined_version: 1; + + /* TRUE if symbols should be retained in memory, FALSE if they + should be freed and reread. */ + unsigned int keep_memory: 1; + + /* TRUE if every symbol should be reported back via the notice + callback. */ + unsigned int notice_all: 1; + + /* TRUE if executable should not contain copy relocs. + Setting this true may result in a non-sharable text segment. */ + unsigned int nocopyreloc: 1; + + /* TRUE if the new ELF dynamic tags are enabled. */ + unsigned int new_dtags: 1; + + /* TRUE if non-PLT relocs should be merged into one reloc section + and sorted so that relocs against the same symbol come together. */ + unsigned int combreloc: 1; + + /* TRUE if .eh_frame_hdr section and PT_GNU_EH_FRAME ELF segment + should be created. */ + unsigned int eh_frame_hdr: 1; + + /* TRUE if global symbols in discarded sections should be stripped. */ + unsigned int strip_discarded: 1; + + /* TRUE if relaxation is being finalized. */ + unsigned int relax_finalizing: 1; + + /* Which symbols to strip. */ + enum bfd_link_strip strip; + + /* Which local symbols to discard. */ + enum bfd_link_discard discard; + + /* Criteria for skipping symbols when detemining + whether to include an object from an archive. */ + enum bfd_link_common_skip_ar_aymbols common_skip_ar_aymbols; + + /* Function callbacks. */ + const struct bfd_link_callbacks *callbacks; + + /* Hash table handled by BFD. */ + struct bfd_link_hash_table *hash; + + /* Hash table of symbols to keep. This is NULL unless strip is + strip_some. */ + struct bfd_hash_table *keep_hash; + + /* Hash table of symbols to report back via the notice callback. If + this is NULL, and notice_all is FALSE, then no symbols are + reported back. */ + struct bfd_hash_table *notice_hash; + + /* Hash table of symbols which are being wrapped (the --wrap linker + option). If this is NULL, no symbols are being wrapped. */ + struct bfd_hash_table *wrap_hash; + + /* The list of input BFD's involved in the link. These are chained + together via the link_next field. */ + bfd *input_bfds; + + /* If a symbol should be created for each input BFD, this is section + where those symbols should be placed. It must be a section in + the output BFD. It may be NULL, in which case no such symbols + will be created. This is to support CREATE_OBJECT_SYMBOLS in the + linker command language. */ + asection *create_object_symbols_section; + + /* List of global symbol names that are starting points for marking + sections against garbage collection. */ + struct bfd_sym_chain *gc_sym_list; + + /* If a base output file is wanted, then this points to it */ + PTR base_file; + + /* The function to call when the executable or shared object is + loaded. */ + const char *init_function; + + /* The function to call when the executable or shared object is + unloaded. */ + const char *fini_function; + + /* If non-zero, specifies that branches which are problematic for the + MPC860 C0 (or earlier) should be checked for and modified. It gives the + number of bytes that should be checked at the end of each text page. */ + int mpc860c0; + + /* Non-zero if auto-import thunks for DATA items in pei386 DLLs + should be generated/linked against. Set to 1 if this feature + is explicitly requested by the user, -1 if enabled by default. */ + int pei386_auto_import; + + /* Non-zero if runtime relocs for DATA items with non-zero addends + in pei386 DLLs should be generated. Set to 1 if this feature + is explicitly requested by the user, -1 if enabled by default. */ + int pei386_runtime_pseudo_reloc; + + /* How many spare .dynamic DT_NULL entries should be added? */ + unsigned int spare_dynamic_tags; + + /* May be used to set DT_FLAGS for ELF. */ + bfd_vma flags; + + /* May be used to set DT_FLAGS_1 for ELF. */ + bfd_vma flags_1; +}; + +/* This structures holds a set of callback functions. These are + called by the BFD linker routines. The first argument to each + callback function is the bfd_link_info structure being used. Each + function returns a boolean value. If the function returns FALSE, + then the BFD function which called it will return with a failure + indication. */ + +struct bfd_link_callbacks +{ + /* A function which is called when an object is added from an + archive. ABFD is the archive element being added. NAME is the + name of the symbol which caused the archive element to be pulled + in. */ + bfd_boolean (*add_archive_element) + PARAMS ((struct bfd_link_info *, bfd *abfd, const char *name)); + /* A function which is called when a symbol is found with multiple + definitions. NAME is the symbol which is defined multiple times. + OBFD is the old BFD, OSEC is the old section, OVAL is the old + value, NBFD is the new BFD, NSEC is the new section, and NVAL is + the new value. OBFD may be NULL. OSEC and NSEC may be + bfd_com_section or bfd_ind_section. */ + bfd_boolean (*multiple_definition) + PARAMS ((struct bfd_link_info *, const char *name, + bfd *obfd, asection *osec, bfd_vma oval, + bfd *nbfd, asection *nsec, bfd_vma nval)); + /* A function which is called when a common symbol is defined + multiple times. NAME is the symbol appearing multiple times. + OBFD is the BFD of the existing symbol; it may be NULL if this is + not known. OTYPE is the type of the existing symbol, which may + be bfd_link_hash_defined, bfd_link_hash_defweak, + bfd_link_hash_common, or bfd_link_hash_indirect. If OTYPE is + bfd_link_hash_common, OSIZE is the size of the existing symbol. + NBFD is the BFD of the new symbol. NTYPE is the type of the new + symbol, one of bfd_link_hash_defined, bfd_link_hash_common, or + bfd_link_hash_indirect. If NTYPE is bfd_link_hash_common, NSIZE + is the size of the new symbol. */ + bfd_boolean (*multiple_common) + PARAMS ((struct bfd_link_info *, const char *name, + bfd *obfd, enum bfd_link_hash_type otype, bfd_vma osize, + bfd *nbfd, enum bfd_link_hash_type ntype, bfd_vma nsize)); + /* A function which is called to add a symbol to a set. ENTRY is + the link hash table entry for the set itself (e.g., + __CTOR_LIST__). RELOC is the relocation to use for an entry in + the set when generating a relocateable file, and is also used to + get the size of the entry when generating an executable file. + ABFD, SEC and VALUE identify the value to add to the set. */ + bfd_boolean (*add_to_set) + PARAMS ((struct bfd_link_info *, struct bfd_link_hash_entry *entry, + bfd_reloc_code_real_type reloc, bfd *abfd, asection *sec, + bfd_vma value)); + /* A function which is called when the name of a g++ constructor or + destructor is found. This is only called by some object file + formats. CONSTRUCTOR is TRUE for a constructor, FALSE for a + destructor. This will use BFD_RELOC_CTOR when generating a + relocateable file. NAME is the name of the symbol found. ABFD, + SECTION and VALUE are the value of the symbol. */ + bfd_boolean (*constructor) + PARAMS ((struct bfd_link_info *, bfd_boolean constructor, + const char *name, bfd *abfd, asection *sec, bfd_vma value)); + /* A function which is called to issue a linker warning. For + example, this is called when there is a reference to a warning + symbol. WARNING is the warning to be issued. SYMBOL is the name + of the symbol which triggered the warning; it may be NULL if + there is none. ABFD, SECTION and ADDRESS identify the location + which trigerred the warning; either ABFD or SECTION or both may + be NULL if the location is not known. */ + bfd_boolean (*warning) + PARAMS ((struct bfd_link_info *, const char *warning, const char *symbol, + bfd *abfd, asection *section, bfd_vma address)); + /* A function which is called when a relocation is attempted against + an undefined symbol. NAME is the symbol which is undefined. + ABFD, SECTION and ADDRESS identify the location from which the + reference is made. FATAL indicates whether an undefined symbol is + a fatal error or not. In some cases SECTION may be NULL. */ + bfd_boolean (*undefined_symbol) + PARAMS ((struct bfd_link_info *, const char *name, bfd *abfd, + asection *section, bfd_vma address, bfd_boolean fatal)); + /* A function which is called when a reloc overflow occurs. NAME is + the name of the symbol or section the reloc is against, + RELOC_NAME is the name of the relocation, and ADDEND is any + addend that is used. ABFD, SECTION and ADDRESS identify the + location at which the overflow occurs; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + bfd_boolean (*reloc_overflow) + PARAMS ((struct bfd_link_info *, const char *name, const char *reloc_name, + bfd_vma addend, bfd *abfd, asection *section, bfd_vma address)); + /* A function which is called when a dangerous reloc is performed. + The canonical example is an a29k IHCONST reloc which does not + follow an IHIHALF reloc. MESSAGE is an appropriate message. + ABFD, SECTION and ADDRESS identify the location at which the + problem occurred; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + bfd_boolean (*reloc_dangerous) + PARAMS ((struct bfd_link_info *, const char *message, + bfd *abfd, asection *section, bfd_vma address)); + /* A function which is called when a reloc is found to be attached + to a symbol which is not being written out. NAME is the name of + the symbol. ABFD, SECTION and ADDRESS identify the location of + the reloc; if this is the result of a + bfd_section_reloc_link_order or bfd_symbol_reloc_link_order, then + ABFD will be NULL. */ + bfd_boolean (*unattached_reloc) + PARAMS ((struct bfd_link_info *, const char *name, + bfd *abfd, asection *section, bfd_vma address)); + /* A function which is called when a symbol in notice_hash is + defined or referenced. NAME is the symbol. ABFD, SECTION and + ADDRESS are the value of the symbol. If SECTION is + bfd_und_section, this is a reference. */ + bfd_boolean (*notice) + PARAMS ((struct bfd_link_info *, const char *name, + bfd *abfd, asection *section, bfd_vma address)); + /* A function which is called for reporting a linker error. ID is the + error identifier. The remaining input is the same as einfo () in + ld. */ + bfd_boolean (*error_handler) + PARAMS ((int id, const char * fmt, ...)); +}; + +/* The linker builds link_order structures which tell the code how to + include input data in the output file. */ + +/* These are the types of link_order structures. */ + +enum bfd_link_order_type +{ + bfd_undefined_link_order, /* Undefined. */ + bfd_indirect_link_order, /* Built from a section. */ + bfd_data_link_order, /* Set to explicit data. */ + bfd_section_reloc_link_order, /* Relocate against a section. */ + bfd_symbol_reloc_link_order /* Relocate against a symbol. */ +}; + +/* This is the link_order structure itself. These form a chain + attached to the section whose contents they are describing. */ + +struct bfd_link_order +{ + /* Next link_order in chain. */ + struct bfd_link_order *next; + /* Type of link_order. */ + enum bfd_link_order_type type; + /* Offset within output section. */ + bfd_vma offset; + /* Size within output section. */ + bfd_size_type size; + /* Type specific information. */ + union + { + struct + { + /* Section to include. If this is used, then + section->output_section must be the section the + link_order is attached to, section->output_offset must + equal the link_order offset field, and section->_raw_size + must equal the link_order size field. Maybe these + restrictions should be relaxed someday. */ + asection *section; + } indirect; + struct + { + /* Size of contents, or zero when contents size == size + within output section. + A non-zero value allows filling of the output section + with an arbitrary repeated pattern. */ + unsigned int size; + /* Data to put into file. */ + bfd_byte *contents; + } data; + struct + { + /* Description of reloc to generate. Used for + bfd_section_reloc_link_order and + bfd_symbol_reloc_link_order. */ + struct bfd_link_order_reloc *p; + } reloc; + } u; +}; + +/* A linker order of type bfd_section_reloc_link_order or + bfd_symbol_reloc_link_order means to create a reloc against a + section or symbol, respectively. This is used to implement -Ur to + generate relocs for the constructor tables. The + bfd_link_order_reloc structure describes the reloc that BFD should + create. It is similar to a arelent, but I didn't use arelent + because the linker does not know anything about most symbols, and + any asymbol structure it creates will be partially meaningless. + This information could logically be in the bfd_link_order struct, + but I didn't want to waste the space since these types of relocs + are relatively rare. */ + +struct bfd_link_order_reloc +{ + /* Reloc type. */ + bfd_reloc_code_real_type reloc; + + union + { + /* For type bfd_section_reloc_link_order, this is the section + the reloc should be against. This must be a section in the + output BFD, not any of the input BFDs. */ + asection *section; + /* For type bfd_symbol_reloc_link_order, this is the name of the + symbol the reloc should be against. */ + const char *name; + } u; + + /* Addend to use. The object file should contain zero. The BFD + backend is responsible for filling in the contents of the object + file correctly. For some object file formats (e.g., COFF) the + addend must be stored into in the object file, and for some + (e.g., SPARC a.out) it is kept in the reloc. */ + bfd_vma addend; +}; + +/* Allocate a new link_order for a section. */ +extern struct bfd_link_order *bfd_new_link_order PARAMS ((bfd *, asection *)); + +/* These structures are used to describe version information for the + ELF linker. These structures could be manipulated entirely inside + BFD, but it would be a pain. Instead, the regular linker sets up + these structures, and then passes them into BFD. */ + +/* Regular expressions for a version. */ + +struct bfd_elf_version_expr +{ + /* Next regular expression for this version. */ + struct bfd_elf_version_expr *next; + /* Regular expression. */ + const char *pattern; + /* Matching function. */ + int (*match) PARAMS ((struct bfd_elf_version_expr *, const char *)); + /* Defined by ".symver". */ + unsigned int symver: 1; + /* Defined by version script. */ + unsigned int script : 1; +}; + +/* Version dependencies. */ + +struct bfd_elf_version_deps +{ + /* Next dependency for this version. */ + struct bfd_elf_version_deps *next; + /* The version which this version depends upon. */ + struct bfd_elf_version_tree *version_needed; +}; + +/* A node in the version tree. */ + +struct bfd_elf_version_tree +{ + /* Next version. */ + struct bfd_elf_version_tree *next; + /* Name of this version. */ + const char *name; + /* Version number. */ + unsigned int vernum; + /* Regular expressions for global symbols in this version. */ + struct bfd_elf_version_expr *globals; + /* Regular expressions for local symbols in this version. */ + struct bfd_elf_version_expr *locals; + /* List of versions which this version depends upon. */ + struct bfd_elf_version_deps *deps; + /* Index of the version name. This is used within BFD. */ + unsigned int name_indx; + /* Whether this version tree was used. This is used within BFD. */ + int used; +}; + +#endif diff --git a/contrib/binutils-2.14/include/bin-bugs.h b/contrib/binutils-2.14/include/bin-bugs.h new file mode 100644 index 0000000000..3c97715add --- /dev/null +++ b/contrib/binutils-2.14/include/bin-bugs.h @@ -0,0 +1,3 @@ +#ifndef REPORT_BUGS_TO +#define REPORT_BUGS_TO "bug-binutils@gnu.org" +#endif diff --git a/contrib/binutils-2.14/include/coff/ecoff.h b/contrib/binutils-2.14/include/coff/ecoff.h new file mode 100644 index 0000000000..00d2f24008 --- /dev/null +++ b/contrib/binutils-2.14/include/coff/ecoff.h @@ -0,0 +1,437 @@ +/* Generic ECOFF support. + This does not include symbol information, found in sym.h and + symconst.h. + + Copyright 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef ECOFF_H +#define ECOFF_H + +/* Mips magic numbers used in filehdr. MIPS_MAGIC_LITTLE is used on + little endian machines. MIPS_MAGIC_BIG is used on big endian + machines. Where is MIPS_MAGIC_1 from? */ +#define MIPS_MAGIC_1 0x0180 +#define MIPS_MAGIC_LITTLE 0x0162 +#define MIPS_MAGIC_BIG 0x0160 + +/* These are the magic numbers used for MIPS code compiled at ISA + level 2. */ +#define MIPS_MAGIC_LITTLE2 0x0166 +#define MIPS_MAGIC_BIG2 0x0163 + +/* These are the magic numbers used for MIPS code compiled at ISA + level 3. */ +#define MIPS_MAGIC_LITTLE3 0x142 +#define MIPS_MAGIC_BIG3 0x140 + +/* Alpha magic numbers used in filehdr. */ +#define ALPHA_MAGIC 0x183 +#define ALPHA_MAGIC_BSD 0x185 + +/* Magic numbers used in a.out header. */ +#define ECOFF_AOUT_OMAGIC 0407 /* not demand paged (ld -N). */ +#define ECOFF_AOUT_ZMAGIC 0413 /* demand load format, eg normal ld output */ + +/* Names of special sections. */ +#define _TEXT ".text" +#define _DATA ".data" +#define _BSS ".bss" +#define _RDATA ".rdata" +#define _SDATA ".sdata" +#define _SBSS ".sbss" +#define _LITA ".lita" +#define _LIT4 ".lit4" +#define _LIT8 ".lit8" +#define _LIB ".lib" +#define _INIT ".init" +#define _FINI ".fini" +#define _PDATA ".pdata" +#define _XDATA ".xdata" +#define _GOT ".got" +#define _HASH ".hash" +#define _DYNSYM ".dynsym" +#define _DYNSTR ".dynstr" +#define _RELDYN ".rel.dyn" +#define _CONFLIC ".conflic" +#define _COMMENT ".comment" +#define _LIBLIST ".liblist" +#define _DYNAMIC ".dynamic" +#define _RCONST ".rconst" + +/* ECOFF uses some additional section flags. */ +#define STYP_RDATA 0x100 +#define STYP_SDATA 0x200 +#define STYP_SBSS 0x400 +#define STYP_GOT 0x1000 +#define STYP_DYNAMIC 0x2000 +#define STYP_DYNSYM 0x4000 +#define STYP_RELDYN 0x8000 +#define STYP_DYNSTR 0x10000 +#define STYP_HASH 0x20000 +#define STYP_LIBLIST 0x40000 +#define STYP_CONFLIC 0x100000 +#define STYP_ECOFF_FINI 0x1000000 +#define STYP_EXTENDESC 0x2000000 /* 0x02FFF000 bits => scn type, rest clr */ +#define STYP_LITA 0x4000000 +#define STYP_LIT8 0x8000000 +#define STYP_LIT4 0x10000000 +#define STYP_ECOFF_LIB 0x40000000 +#define STYP_ECOFF_INIT 0x80000000 +#define STYP_OTHER_LOAD (STYP_ECOFF_INIT | STYP_ECOFF_FINI) + +/* extended section types */ +#define STYP_COMMENT 0x2100000 +#define STYP_RCONST 0x2200000 +#define STYP_XDATA 0x2400000 +#define STYP_PDATA 0x2800000 + +/* The linker needs a section to hold small common variables while + linking. There is no convenient way to create it when the linker + needs it, so we always create one for each BFD. We then avoid + writing it out. */ +#define SCOMMON ".scommon" + +/* If the extern bit in a reloc is 1, then r_symndx is an index into + the external symbol table. If the extern bit is 0, then r_symndx + indicates a section, and is one of the following values. */ +#define RELOC_SECTION_NONE 0 +#define RELOC_SECTION_TEXT 1 +#define RELOC_SECTION_RDATA 2 +#define RELOC_SECTION_DATA 3 +#define RELOC_SECTION_SDATA 4 +#define RELOC_SECTION_SBSS 5 +#define RELOC_SECTION_BSS 6 +#define RELOC_SECTION_INIT 7 +#define RELOC_SECTION_LIT8 8 +#define RELOC_SECTION_LIT4 9 +#define RELOC_SECTION_XDATA 10 +#define RELOC_SECTION_PDATA 11 +#define RELOC_SECTION_FINI 12 +#define RELOC_SECTION_LITA 13 +#define RELOC_SECTION_ABS 14 +#define RELOC_SECTION_RCONST 15 + +#define NUM_RELOC_SECTIONS 16 + +/********************** STABS **********************/ + +/* gcc uses mips-tfile to output type information in special stabs + entries. These must match the corresponding definition in + gcc/config/mips.h. At some point, these should probably go into a + shared include file, but currently gcc and gdb do not share any + directories. */ +#define CODE_MASK 0x8F300 +#define ECOFF_IS_STAB(sym) (((sym)->index & 0xFFF00) == CODE_MASK) +#define ECOFF_MARK_STAB(code) ((code)+CODE_MASK) +#define ECOFF_UNMARK_STAB(code) ((code)-CODE_MASK) +#define STABS_SYMBOL "@stabs" + +/********************** COFF **********************/ + +/* gcc also uses mips-tfile to output COFF debugging information. + These are the values it uses when outputting the .type directive. + These should also be in a shared include file. */ +#define N_BTMASK (017) +#define N_TMASK (060) +#define N_BTSHFT (4) +#define N_TSHIFT (2) + +/********************** AUX **********************/ + +/* The auxiliary type information is the same on all known ECOFF + targets. I can't see any reason that it would ever change, so I am + going to gamble and define the external structures here, in the + target independent ECOFF header file. The internal forms are + defined in coff/sym.h, which was originally donated by MIPS + Computer Systems. */ + +/* Type information external record */ + +struct tir_ext { + unsigned char t_bits1[1]; + unsigned char t_tq45[1]; + unsigned char t_tq01[1]; + unsigned char t_tq23[1]; +}; + +#define TIR_BITS1_FBITFIELD_BIG ((unsigned int) 0x80) +#define TIR_BITS1_FBITFIELD_LITTLE ((unsigned int) 0x01) + +#define TIR_BITS1_CONTINUED_BIG ((unsigned int) 0x40) +#define TIR_BITS1_CONTINUED_LITTLE ((unsigned int) 0x02) + +#define TIR_BITS1_BT_BIG ((unsigned int) 0x3F) +#define TIR_BITS1_BT_SH_BIG 0 +#define TIR_BITS1_BT_LITTLE ((unsigned int) 0xFC) +#define TIR_BITS1_BT_SH_LITTLE 2 + +#define TIR_BITS_TQ4_BIG ((unsigned int) 0xF0) +#define TIR_BITS_TQ4_SH_BIG 4 +#define TIR_BITS_TQ5_BIG ((unsigned int) 0x0F) +#define TIR_BITS_TQ5_SH_BIG 0 +#define TIR_BITS_TQ4_LITTLE ((unsigned int) 0x0F) +#define TIR_BITS_TQ4_SH_LITTLE 0 +#define TIR_BITS_TQ5_LITTLE ((unsigned int) 0xF0) +#define TIR_BITS_TQ5_SH_LITTLE 4 + +#define TIR_BITS_TQ0_BIG ((unsigned int) 0xF0) +#define TIR_BITS_TQ0_SH_BIG 4 +#define TIR_BITS_TQ1_BIG ((unsigned int) 0x0F) +#define TIR_BITS_TQ1_SH_BIG 0 +#define TIR_BITS_TQ0_LITTLE ((unsigned int) 0x0F) +#define TIR_BITS_TQ0_SH_LITTLE 0 +#define TIR_BITS_TQ1_LITTLE ((unsigned int) 0xF0) +#define TIR_BITS_TQ1_SH_LITTLE 4 + +#define TIR_BITS_TQ2_BIG ((unsigned int) 0xF0) +#define TIR_BITS_TQ2_SH_BIG 4 +#define TIR_BITS_TQ3_BIG ((unsigned int) 0x0F) +#define TIR_BITS_TQ3_SH_BIG 0 +#define TIR_BITS_TQ2_LITTLE ((unsigned int) 0x0F) +#define TIR_BITS_TQ2_SH_LITTLE 0 +#define TIR_BITS_TQ3_LITTLE ((unsigned int) 0xF0) +#define TIR_BITS_TQ3_SH_LITTLE 4 + +/* Relative symbol external record */ + +struct rndx_ext { + unsigned char r_bits[4]; +}; + +#define RNDX_BITS0_RFD_SH_LEFT_BIG 4 +#define RNDX_BITS1_RFD_BIG ((unsigned int) 0xF0) +#define RNDX_BITS1_RFD_SH_BIG 4 + +#define RNDX_BITS0_RFD_SH_LEFT_LITTLE 0 +#define RNDX_BITS1_RFD_LITTLE ((unsigned int) 0x0F) +#define RNDX_BITS1_RFD_SH_LEFT_LITTLE 8 + +#define RNDX_BITS1_INDEX_BIG ((unsigned int) 0x0F) +#define RNDX_BITS1_INDEX_SH_LEFT_BIG 16 +#define RNDX_BITS2_INDEX_SH_LEFT_BIG 8 +#define RNDX_BITS3_INDEX_SH_LEFT_BIG 0 + +#define RNDX_BITS1_INDEX_LITTLE ((unsigned int) 0xF0) +#define RNDX_BITS1_INDEX_SH_LITTLE 4 +#define RNDX_BITS2_INDEX_SH_LEFT_LITTLE 4 +#define RNDX_BITS3_INDEX_SH_LEFT_LITTLE 12 + +/* Auxiliary symbol information external record */ + +union aux_ext { + struct tir_ext a_ti; + struct rndx_ext a_rndx; + unsigned char a_dnLow[4]; + unsigned char a_dnHigh[4]; + unsigned char a_isym[4]; + unsigned char a_iss[4]; + unsigned char a_width[4]; + unsigned char a_count[4]; +}; + +#define AUX_GET_ANY(bigend, ax, field) \ + ((bigend) ? bfd_getb32 ((ax)->field) : bfd_getl32 ((ax)->field)) + +#define AUX_GET_DNLOW(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnLow) +#define AUX_GET_DNHIGH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_dnHigh) +#define AUX_GET_ISYM(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_isym) +#define AUX_GET_ISS(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_iss) +#define AUX_GET_WIDTH(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_width) +#define AUX_GET_COUNT(bigend, ax) AUX_GET_ANY ((bigend), (ax), a_count) + +#define AUX_PUT_ANY(bigend, val, ax, field) \ + ((bigend) \ + ? (bfd_putb32 ((bfd_vma) (val), (ax)->field), 0) \ + : (bfd_putl32 ((bfd_vma) (val), (ax)->field), 0)) + +#define AUX_PUT_DNLOW(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_dnLow) +#define AUX_PUT_DNHIGH(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_dnHigh) +#define AUX_PUT_ISYM(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_isym) +#define AUX_PUT_ISS(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_iss) +#define AUX_PUT_WIDTH(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_width) +#define AUX_PUT_COUNT(bigend, val, ax) \ + AUX_PUT_ANY ((bigend), (val), (ax), a_count) + +/********************** SYMBOLS **********************/ + +/* For efficiency, gdb deals directly with the unswapped symbolic + information (that way it only takes the time to swap information + that it really needs to read). gdb originally retrieved the + information directly from the BFD backend information, but that + strategy, besides being sort of ugly, does not work for MIPS ELF, + which also uses ECOFF debugging information. This structure holds + pointers to the (mostly) unswapped symbolic information. */ + +struct ecoff_debug_info +{ + /* The swapped ECOFF symbolic header. */ + HDRR symbolic_header; + + /* Pointers to the unswapped symbolic information. Note that the + pointers to external structures point to different sorts of + information on different ECOFF targets. The ecoff_debug_swap + structure provides the sizes of the structures and the functions + needed to swap the information in and out. These pointers are + all pointers to arrays, not single structures. They will be NULL + if there are no instances of the relevant structure. These + fields are also used by the assembler to output ECOFF debugging + information. */ + unsigned char *line; + PTR external_dnr; /* struct dnr_ext */ + PTR external_pdr; /* struct pdr_ext */ + PTR external_sym; /* struct sym_ext */ + PTR external_opt; /* struct opt_ext */ + union aux_ext *external_aux; + char *ss; + char *ssext; + PTR external_fdr; /* struct fdr_ext */ + PTR external_rfd; /* struct rfd_ext */ + PTR external_ext; /* struct ext_ext */ + + /* These fields are used when linking. They may disappear at some + point. */ + char *ssext_end; + PTR external_ext_end; + + /* When linking, this field holds a mapping from the input FDR + numbers to the output numbers, and is used when writing out the + external symbols. It is NULL if no mapping is required. */ + RFDT *ifdmap; + + /* The swapped FDR information. Currently this is never NULL, but + code using this structure should probably double-check in case + this changes in the future. This is a pointer to an array, not a + single structure. */ + FDR *fdr; + + /* When relaxing MIPS embedded PIC code, we may need to adjust + symbol values when they are output. This is a linked list of + structures indicating how values should be adjusted. There is no + requirement that the entries be in any order, or that they not + overlap. This field is normally NULL, in which case no + adjustments need to be made. */ + struct ecoff_value_adjust *adjust; +}; + +/* This structure describes how to adjust symbol values when + outputting MIPS embedded PIC code. These adjustments only apply to + the internal symbols, as the external symbol values will come from + the hash table and have already been adjusted. */ + +struct ecoff_value_adjust +{ + /* Next entry on adjustment list. */ + struct ecoff_value_adjust *next; + /* Starting VMA of adjustment. This is the VMA in the ECOFF file, + not the offset from the start of the section. Thus it should + indicate a particular section. */ + bfd_vma start; + /* Ending VMA of adjustment. */ + bfd_vma end; + /* Adjustment. This should be added to the value of the symbol, or + FDR. This is zero for the last entry in the array. */ + long adjust; +}; + +/* These structures are used by the ECOFF find_nearest_line function. */ + +struct ecoff_fdrtab_entry +{ + /* Base address in .text of this FDR. */ + bfd_vma base_addr; + FDR *fdr; +}; + +struct ecoff_find_line +{ + /* Allocated memory to hold function and file names. */ + char *find_buffer; + + /* FDR table, sorted by address: */ + long fdrtab_len; + struct ecoff_fdrtab_entry *fdrtab; + + /* Cache entry for most recently found line information. The sect + field is NULL if this cache does not contain valid information. */ + struct + { + asection *sect; + bfd_vma start; + bfd_vma stop; + const char *filename; + const char *functionname; + unsigned int line_num; + } cache; +}; + +/********************** SWAPPING **********************/ + +/* The generic ECOFF code needs to be able to swap debugging + information in and out in the specific format used by a particular + ECOFF implementation. This structure provides the information + needed to do this. */ + +struct ecoff_debug_swap +{ + /* Symbol table magic number. */ + int sym_magic; + /* Alignment of debugging information. E.g., 4. */ + bfd_size_type debug_align; + /* Sizes of external symbolic information. */ + bfd_size_type external_hdr_size; + bfd_size_type external_dnr_size; + bfd_size_type external_pdr_size; + bfd_size_type external_sym_size; + bfd_size_type external_opt_size; + bfd_size_type external_fdr_size; + bfd_size_type external_rfd_size; + bfd_size_type external_ext_size; + /* Functions to swap in external symbolic data. */ + void (*swap_hdr_in) PARAMS ((bfd *, PTR, HDRR *)); + void (*swap_dnr_in) PARAMS ((bfd *, PTR, DNR *)); + void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *)); + void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *)); + void (*swap_opt_in) PARAMS ((bfd *, PTR, OPTR *)); + void (*swap_fdr_in) PARAMS ((bfd *, PTR, FDR *)); + void (*swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *)); + void (*swap_ext_in) PARAMS ((bfd *, PTR, EXTR *)); + void (*swap_tir_in) PARAMS ((int, const struct tir_ext *, TIR *)); + void (*swap_rndx_in) PARAMS ((int, const struct rndx_ext *, RNDXR *)); + /* Functions to swap out external symbolic data. */ + void (*swap_hdr_out) PARAMS ((bfd *, const HDRR *, PTR)); + void (*swap_dnr_out) PARAMS ((bfd *, const DNR *, PTR)); + void (*swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR)); + void (*swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR)); + void (*swap_opt_out) PARAMS ((bfd *, const OPTR *, PTR)); + void (*swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR)); + void (*swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR)); + void (*swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR)); + void (*swap_tir_out) PARAMS ((int, const TIR *, struct tir_ext *)); + void (*swap_rndx_out) PARAMS ((int, const RNDXR *, struct rndx_ext *)); + /* Function to read symbol data and set up pointers in + ecoff_debug_info structure. The section argument is used for + ELF, not straight ECOFF. */ + bfd_boolean (*read_debug_info) + PARAMS ((bfd *, asection *, struct ecoff_debug_info *)); +}; + +#endif /* ! defined (ECOFF_H) */ diff --git a/contrib/binutils-2.14/include/coff/internal.h b/contrib/binutils-2.14/include/coff/internal.h new file mode 100644 index 0000000000..b9b6368f03 --- /dev/null +++ b/contrib/binutils-2.14/include/coff/internal.h @@ -0,0 +1,741 @@ +/* Internal format of COFF object file data structures, for GNU BFD. + This file is part of BFD, the Binary File Descriptor library. + + Copyright 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef GNU_COFF_INTERNAL_H +#define GNU_COFF_INTERNAL_H 1 + +/* First, make "signed char" work, even on old compilers. */ +#ifndef signed +#ifndef __STDC__ +#define signed /**/ +#endif +#endif + +/********************** FILE HEADER **********************/ + +/* extra stuff in a PE header. */ + +struct internal_extra_pe_filehdr +{ + /* DOS header data follows for PE stuff */ + unsigned short e_magic; /* Magic number, 0x5a4d */ + unsigned short e_cblp; /* Bytes on last page of file, 0x90 */ + unsigned short e_cp; /* Pages in file, 0x3 */ + unsigned short e_crlc; /* Relocations, 0x0 */ + unsigned short e_cparhdr; /* Size of header in paragraphs, 0x4 */ + unsigned short e_minalloc; /* Minimum extra paragraphs needed, 0x0 */ + unsigned short e_maxalloc; /* Maximum extra paragraphs needed, 0xFFFF */ + unsigned short e_ss; /* Initial (relative) SS value, 0x0 */ + unsigned short e_sp; /* Initial SP value, 0xb8 */ + unsigned short e_csum; /* Checksum, 0x0 */ + unsigned short e_ip; /* Initial IP value, 0x0 */ + unsigned short e_cs; /* Initial (relative) CS value, 0x0 */ + unsigned short e_lfarlc; /* File address of relocation table, 0x40 */ + unsigned short e_ovno; /* Overlay number, 0x0 */ + unsigned short e_res[4]; /* Reserved words, all 0x0 */ + unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */ + unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */ + unsigned short e_res2[10]; /* Reserved words, all 0x0 */ + bfd_vma e_lfanew; /* File address of new exe header, 0x80 */ + unsigned long dos_message[16]; /* text which always follows dos header */ + bfd_vma nt_signature; /* required NT signature, 0x4550 */ +}; + +struct internal_filehdr +{ + struct internal_extra_pe_filehdr pe; + + /* Standard coff internal info. */ + unsigned short f_magic; /* magic number */ + unsigned short f_nscns; /* number of sections */ + long f_timdat; /* time & date stamp */ + bfd_vma f_symptr; /* file pointer to symtab */ + long f_nsyms; /* number of symtab entries */ + unsigned short f_opthdr; /* sizeof(optional hdr) */ + unsigned short f_flags; /* flags */ + unsigned short f_target_id; /* (TI COFF specific) */ +}; + + +/* Bits for f_flags: + F_RELFLG relocation info stripped from file + F_EXEC file is executable (no unresolved external references) + F_LNNO line numbers stripped from file + F_LSYMS local symbols stripped from file + F_AR16WR file is 16-bit little-endian + F_AR32WR file is 32-bit little-endian + F_AR32W file is 32-bit big-endian + F_DYNLOAD rs/6000 aix: dynamically loadable w/imports & exports + F_SHROBJ rs/6000 aix: file is a shared object + F_DLL PE format DLL. */ + +#define F_RELFLG (0x0001) +#define F_EXEC (0x0002) +#define F_LNNO (0x0004) +#define F_LSYMS (0x0008) +#define F_AR16WR (0x0080) +#define F_AR32WR (0x0100) +#define F_AR32W (0x0200) +#define F_DYNLOAD (0x1000) +#define F_SHROBJ (0x2000) +#define F_DLL (0x2000) + +/* Extra structure which is used in the optional header. */ +typedef struct _IMAGE_DATA_DIRECTORY +{ + bfd_vma VirtualAddress; + long Size; +} IMAGE_DATA_DIRECTORY; +#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 + +/* Default image base for NT. */ +#define NT_EXE_IMAGE_BASE 0x400000 +#define NT_DLL_IMAGE_BASE 0x10000000 + +/* Default image base for BeOS. */ +#define BEOS_EXE_IMAGE_BASE 0x80000000 +#define BEOS_DLL_IMAGE_BASE 0x10000000 + +/* Extra stuff in a PE aouthdr */ + +#define PE_DEF_SECTION_ALIGNMENT 0x1000 +#ifndef PE_DEF_FILE_ALIGNMENT +# define PE_DEF_FILE_ALIGNMENT 0x200 +#endif + +struct internal_extra_pe_aouthdr +{ + /* PE stuff */ + bfd_vma ImageBase; /* address of specific location in memory that + file is located, NT default 0x10000 */ + + bfd_vma SectionAlignment; /* section alignment default 0x1000 */ + bfd_vma FileAlignment; /* file alignment default 0x200 */ + short MajorOperatingSystemVersion; /* minimum version of the operating */ + short MinorOperatingSystemVersion; /* system req'd for exe, default to 1*/ + short MajorImageVersion; /* user defineable field to store version of */ + short MinorImageVersion; /* exe or dll being created, default to 0 */ + short MajorSubsystemVersion; /* minimum subsystem version required to */ + short MinorSubsystemVersion; /* run exe; default to 3.1 */ + long Reserved1; /* seems to be 0 */ + long SizeOfImage; /* size of memory to allocate for prog */ + long SizeOfHeaders; /* size of PE header and section table */ + long CheckSum; /* set to 0 */ + short Subsystem; + + /* type of subsystem exe uses for user interface, + possible values: + 1 - NATIVE Doesn't require a subsystem + 2 - WINDOWS_GUI runs in Windows GUI subsystem + 3 - WINDOWS_CUI runs in Windows char sub. (console app) + 5 - OS2_CUI runs in OS/2 character subsystem + 7 - POSIX_CUI runs in Posix character subsystem */ + short DllCharacteristics; /* flags for DLL init, use 0 */ + bfd_vma SizeOfStackReserve; /* amount of memory to reserve */ + bfd_vma SizeOfStackCommit; /* amount of memory initially committed for + initial thread's stack, default is 0x1000 */ + bfd_vma SizeOfHeapReserve; /* amount of virtual memory to reserve and */ + bfd_vma SizeOfHeapCommit; /* commit, don't know what to defaut it to */ + long LoaderFlags; /* can probably set to 0 */ + long NumberOfRvaAndSizes; /* number of entries in next entry, 16 */ + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +}; + +/********************** AOUT "OPTIONAL HEADER" **********************/ +struct internal_aouthdr +{ + short magic; /* type of file */ + short vstamp; /* version stamp */ + bfd_vma tsize; /* text size in bytes, padded to FW bdry*/ + bfd_vma dsize; /* initialized data " " */ + bfd_vma bsize; /* uninitialized data " " */ + bfd_vma entry; /* entry pt. */ + bfd_vma text_start; /* base of text used for this file */ + bfd_vma data_start; /* base of data used for this file */ + + /* i960 stuff */ + unsigned long tagentries; /* number of tag entries to follow */ + + /* RS/6000 stuff */ + bfd_vma o_toc; /* address of TOC */ + short o_snentry; /* section number for entry point */ + short o_sntext; /* section number for text */ + short o_sndata; /* section number for data */ + short o_sntoc; /* section number for toc */ + short o_snloader; /* section number for loader section */ + short o_snbss; /* section number for bss */ + short o_algntext; /* max alignment for text */ + short o_algndata; /* max alignment for data */ + short o_modtype; /* Module type field, 1R,RE,RO */ + short o_cputype; /* Encoded CPU type */ + bfd_vma o_maxstack; /* max stack size allowed. */ + bfd_vma o_maxdata; /* max data size allowed. */ + + /* ECOFF stuff */ + bfd_vma bss_start; /* Base of bss section. */ + bfd_vma gp_value; /* GP register value. */ + unsigned long gprmask; /* General registers used. */ + unsigned long cprmask[4]; /* Coprocessor registers used. */ + unsigned long fprmask; /* Floating pointer registers used. */ + + /* Apollo stuff */ + long o_inlib; /* inlib data */ + long o_sri; /* Static Resource Information */ + long vid[2]; /* Version id */ + + struct internal_extra_pe_aouthdr pe; +}; + +/********************** STORAGE CLASSES **********************/ + +/* This used to be defined as -1, but now n_sclass is unsigned. */ +#define C_EFCN 0xff /* physical end of function */ +#define C_NULL 0 +#define C_AUTO 1 /* automatic variable */ +#define C_EXT 2 /* external symbol */ +#define C_STAT 3 /* static */ +#define C_REG 4 /* register variable */ +#define C_EXTDEF 5 /* external definition */ +#define C_LABEL 6 /* label */ +#define C_ULABEL 7 /* undefined label */ +#define C_MOS 8 /* member of structure */ +#define C_ARG 9 /* function argument */ +#define C_STRTAG 10 /* structure tag */ +#define C_MOU 11 /* member of union */ +#define C_UNTAG 12 /* union tag */ +#define C_TPDEF 13 /* type definition */ +#define C_USTATIC 14 /* undefined static */ +#define C_ENTAG 15 /* enumeration tag */ +#define C_MOE 16 /* member of enumeration */ +#define C_REGPARM 17 /* register parameter */ +#define C_FIELD 18 /* bit field */ +#define C_AUTOARG 19 /* auto argument */ +#define C_LASTENT 20 /* dummy entry (end of block) */ +#define C_BLOCK 100 /* ".bb" or ".eb" */ +#define C_FCN 101 /* ".bf" or ".ef" */ +#define C_EOS 102 /* end of structure */ +#define C_FILE 103 /* file name */ +#define C_LINE 104 /* line # reformatted as symbol table entry */ +#define C_ALIAS 105 /* duplicate tag */ +#define C_HIDDEN 106 /* ext symbol in dmert public lib */ + +#define C_WEAKEXT 127 /* weak symbol -- GNU extension */ + +/* New storage classes for TI COFF */ +#define C_UEXT 19 /* Tentative external definition */ +#define C_STATLAB 20 /* Static load time label */ +#define C_EXTLAB 21 /* External load time label */ +#define C_SYSTEM 23 /* System Wide variable */ + +/* New storage classes for WINDOWS_NT */ +#define C_SECTION 104 /* section name */ +#define C_NT_WEAK 105 /* weak external */ + + /* New storage classes for 80960 */ + +/* C_LEAFPROC is obsolete. Use C_LEAFEXT or C_LEAFSTAT */ +#define C_LEAFPROC 108 /* Leaf procedure, "call" via BAL */ + +#define C_SCALL 107 /* Procedure reachable via system call */ +#define C_LEAFEXT 108 /* External leaf */ +#define C_LEAFSTAT 113 /* Static leaf */ +#define C_OPTVAR 109 /* Optimized variable */ +#define C_DEFINE 110 /* Preprocessor #define */ +#define C_PRAGMA 111 /* Advice to compiler or linker */ +#define C_SEGMENT 112 /* 80960 segment name */ + + /* Storage classes for m88k */ +#define C_SHADOW 107 /* shadow symbol */ +#define C_VERSION 108 /* coff version symbol */ + + /* New storage classes for RS/6000 */ +#define C_HIDEXT 107 /* Un-named external symbol */ +#define C_BINCL 108 /* Marks beginning of include file */ +#define C_EINCL 109 /* Marks ending of include file */ + + /* storage classes for stab symbols for RS/6000 */ +#define C_GSYM (0x80) +#define C_LSYM (0x81) +#define C_PSYM (0x82) +#define C_RSYM (0x83) +#define C_RPSYM (0x84) +#define C_STSYM (0x85) +#define C_TCSYM (0x86) +#define C_BCOMM (0x87) +#define C_ECOML (0x88) +#define C_ECOMM (0x89) +#define C_DECL (0x8c) +#define C_ENTRY (0x8d) +#define C_FUN (0x8e) +#define C_BSTAT (0x8f) +#define C_ESTAT (0x90) + +/* Storage classes for Thumb symbols */ +#define C_THUMBEXT (128 + C_EXT) /* 130 */ +#define C_THUMBSTAT (128 + C_STAT) /* 131 */ +#define C_THUMBLABEL (128 + C_LABEL) /* 134 */ +#define C_THUMBEXTFUNC (C_THUMBEXT + 20) /* 150 */ +#define C_THUMBSTATFUNC (C_THUMBSTAT + 20) /* 151 */ + +/********************** SECTION HEADER **********************/ + +#define SCNNMLEN (8) + +struct internal_scnhdr +{ + char s_name[SCNNMLEN]; /* section name */ + + /* Physical address, aliased s_nlib. + In the pei format, this field is the virtual section size + (the size of the section after being loaded int memory), + NOT the physical address. */ + bfd_vma s_paddr; + + bfd_vma s_vaddr; /* virtual address */ + bfd_vma s_size; /* section size */ + bfd_vma s_scnptr; /* file ptr to raw data for section */ + bfd_vma s_relptr; /* file ptr to relocation */ + bfd_vma s_lnnoptr; /* file ptr to line numbers */ + unsigned long s_nreloc; /* number of relocation entries */ + unsigned long s_nlnno; /* number of line number entries*/ + long s_flags; /* flags */ + long s_align; /* used on I960 */ + unsigned char s_page; /* TI COFF load page */ +}; + +/* s_flags "type". */ +#define STYP_REG (0x0000) /* "regular": allocated, relocated, loaded */ +#define STYP_DSECT (0x0001) /* "dummy": relocated only*/ +#define STYP_NOLOAD (0x0002) /* "noload": allocated, relocated, not loaded */ +#define STYP_GROUP (0x0004) /* "grouped": formed of input sections */ +#define STYP_PAD (0x0008) /* "padding": not allocated, not relocated, loaded */ +#define STYP_COPY (0x0010) /* "copy": for decision function used by field update; not allocated, not relocated, + loaded; reloc & lineno entries processed normally */ +#define STYP_TEXT (0x0020) /* section contains text only */ +#define S_SHRSEG (0x0020) /* In 3b Update files (output of ogen), sections which appear in SHARED segments of the Pfile + will have the S_SHRSEG flag set by ogen, to inform dufr that updating 1 copy of the proc. will + update all process invocations. */ +#define STYP_DATA (0x0040) /* section contains data only */ +#define STYP_BSS (0x0080) /* section contains bss only */ +#define S_NEWFCN (0x0100) /* In a minimal file or an update file, a new function (as compared with a replaced function) */ +#define STYP_INFO (0x0200) /* comment: not allocated not relocated, not loaded */ +#define STYP_OVER (0x0400) /* overlay: relocated not allocated or loaded */ +#define STYP_LIB (0x0800) /* for .lib: same as INFO */ +#define STYP_MERGE (0x2000) /* merge section -- combines with text, data or bss sections only */ +#define STYP_REVERSE_PAD (0x4000) /* section will be padded with no-op instructions + wherever padding is necessary and there is a + word of contiguous bytes beginning on a word + boundary. */ + +#define STYP_LIT 0x8020 /* Literal data (like STYP_TEXT) */ + + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + Line numbers are grouped on a per function basis; first entry in a function + grouping will have l_lnno = 0 and in place of physical address will be the + symbol table index of the function name. */ + +struct internal_lineno +{ + union + { + bfd_signed_vma l_symndx; /* function name symbol index, iff l_lnno == 0*/ + bfd_signed_vma l_paddr; /* (physical) address of line number */ + } l_addr; + unsigned long l_lnno; /* line number */ +}; + +/********************** SYMBOLS **********************/ + +#define SYMNMLEN 8 /* # characters in a symbol name */ +#define FILNMLEN 14 /* # characters in a file name */ +#define DIMNUM 4 /* # array dimensions in auxiliary entry */ + +struct internal_syment +{ + union + { + char _n_name[SYMNMLEN]; /* old COFF version */ + struct + { + long _n_zeroes; /* new == 0 */ + long _n_offset; /* offset into string table */ + } _n_n; + char *_n_nptr[2]; /* allows for overlaying */ + } _n; + bfd_vma n_value; /* value of symbol */ + short n_scnum; /* section number */ + unsigned short n_flags; /* copy of flags from filhdr */ + unsigned short n_type; /* type and derived type */ + unsigned char n_sclass; /* storage class */ + unsigned char n_numaux; /* number of aux. entries */ +}; + +#define n_name _n._n_name +#define n_zeroes _n._n_n._n_zeroes +#define n_offset _n._n_n._n_offset + +/* Relocatable symbols have number of the section in which they are defined, + or one of the following: */ + +#define N_UNDEF ((short)0) /* undefined symbol */ +#define N_ABS ((short)-1) /* value of symbol is absolute */ +#define N_DEBUG ((short)-2) /* debugging symbol -- value is meaningless */ +#define N_TV ((short)-3) /* indicates symbol needs preload transfer vector */ +#define P_TV ((short)-4) /* indicates symbol needs postload transfer vector*/ + +/* Type of a symbol, in low N bits of the word. */ + +#define T_NULL 0 +#define T_VOID 1 /* function argument (only used by compiler) */ +#define T_CHAR 2 /* character */ +#define T_SHORT 3 /* short integer */ +#define T_INT 4 /* integer */ +#define T_LONG 5 /* long integer */ +#define T_FLOAT 6 /* floating point */ +#define T_DOUBLE 7 /* double word */ +#define T_STRUCT 8 /* structure */ +#define T_UNION 9 /* union */ +#define T_ENUM 10 /* enumeration */ +#define T_MOE 11 /* member of enumeration*/ +#define T_UCHAR 12 /* unsigned character */ +#define T_USHORT 13 /* unsigned short */ +#define T_UINT 14 /* unsigned integer */ +#define T_ULONG 15 /* unsigned long */ +#define T_LNGDBL 16 /* long double */ + +/* Derived types, in n_type. */ + +#define DT_NON (0) /* no derived type */ +#define DT_PTR (1) /* pointer */ +#define DT_FCN (2) /* function */ +#define DT_ARY (3) /* array */ + +#define BTYPE(x) ((x) & N_BTMASK) +#define DTYPE(x) (((x) & N_TMASK) >> N_BTSHFT) + +#define ISPTR(x) \ + (((unsigned long) (x) & N_TMASK) == ((unsigned long) DT_PTR << N_BTSHFT)) +#define ISFCN(x) \ + (((unsigned long) (x) & N_TMASK) == ((unsigned long) DT_FCN << N_BTSHFT)) +#define ISARY(x) \ + (((unsigned long) (x) & N_TMASK) == ((unsigned long) DT_ARY << N_BTSHFT)) +#define ISTAG(x) \ + ((x) == C_STRTAG || (x) == C_UNTAG || (x) == C_ENTAG) +#define DECREF(x) \ + ((((x) >> N_TSHIFT) & ~ N_BTMASK) | ((x) & N_BTMASK)) + +union internal_auxent +{ + struct + { + + union + { + long l; /* str, un, or enum tag indx */ + struct coff_ptr_struct *p; + } x_tagndx; + + union + { + struct + { + unsigned short x_lnno; /* declaration line number */ + unsigned short x_size; /* str/union/array size */ + } x_lnsz; + long x_fsize; /* size of function */ + } x_misc; + + union + { + struct + { /* if ISFCN, tag, or .bb */ + bfd_signed_vma x_lnnoptr; /* ptr to fcn line # */ + union + { /* entry ndx past block end */ + long l; + struct coff_ptr_struct *p; + } x_endndx; + } x_fcn; + + struct + { /* if ISARY, up to 4 dimen. */ + unsigned short x_dimen[DIMNUM]; + } x_ary; + } x_fcnary; + + unsigned short x_tvndx; /* tv index */ + } x_sym; + + union + { + char x_fname[FILNMLEN]; + struct + { + long x_zeroes; + long x_offset; + } x_n; + } x_file; + + struct + { + long x_scnlen; /* section length */ + unsigned short x_nreloc; /* # relocation entries */ + unsigned short x_nlinno; /* # line numbers */ + unsigned long x_checksum; /* section COMDAT checksum for PE */ + unsigned short x_associated; /* COMDAT associated section index for PE */ + unsigned char x_comdat; /* COMDAT selection number for PE */ + } x_scn; + + struct + { + long x_tvfill; /* tv fill value */ + unsigned short x_tvlen; /* length of .tv */ + unsigned short x_tvran[2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ + + /****************************************** + * RS/6000-specific auxent - last auxent for every external symbol + ******************************************/ + struct + { + union + { /* csect length or enclosing csect */ + bfd_signed_vma l; + struct coff_ptr_struct *p; + } x_scnlen; + long x_parmhash; /* parm type hash index */ + unsigned short x_snhash; /* sect num with parm hash */ + unsigned char x_smtyp; /* symbol align and type */ + /* 0-4 - Log 2 of alignment */ + /* 5-7 - symbol type */ + unsigned char x_smclas; /* storage mapping class */ + long x_stab; /* dbx stab info index */ + unsigned short x_snstab; /* sect num with dbx stab */ + } x_csect; /* csect definition information */ + +/* x_smtyp values: */ + +#define SMTYP_ALIGN(x) ((x) >> 3) /* log2 of alignment */ +#define SMTYP_SMTYP(x) ((x) & 0x7) /* symbol type */ +/* Symbol type values: */ +#define XTY_ER 0 /* External reference */ +#define XTY_SD 1 /* Csect definition */ +#define XTY_LD 2 /* Label definition */ +#define XTY_CM 3 /* .BSS */ +#define XTY_EM 4 /* Error message */ +#define XTY_US 5 /* "Reserved for internal use" */ + +/* x_smclas values: */ + +#define XMC_PR 0 /* Read-only program code */ +#define XMC_RO 1 /* Read-only constant */ +#define XMC_DB 2 /* Read-only debug dictionary table */ +#define XMC_TC 3 /* Read-write general TOC entry */ +#define XMC_UA 4 /* Read-write unclassified */ +#define XMC_RW 5 /* Read-write data */ +#define XMC_GL 6 /* Read-only global linkage */ +#define XMC_XO 7 /* Read-only extended operation */ +#define XMC_SV 8 /* Read-only supervisor call */ +#define XMC_BS 9 /* Read-write BSS */ +#define XMC_DS 10 /* Read-write descriptor csect */ +#define XMC_UC 11 /* Read-write unnamed Fortran common */ +#define XMC_TI 12 /* Read-only traceback index csect */ +#define XMC_TB 13 /* Read-only traceback table csect */ +/* 14 ??? */ +#define XMC_TC0 15 /* Read-write TOC anchor */ +#define XMC_TD 16 /* Read-write data in TOC */ + + /****************************************** + * I960-specific *2nd* aux. entry formats + ******************************************/ + struct + { + /* This is a very old typo that keeps getting propagated. */ +#define x_stdindx x_stindx + long x_stindx; /* sys. table entry */ + } x_sc; /* system call entry */ + + struct + { + unsigned long x_balntry; /* BAL entry point */ + } x_bal; /* BAL-callable function */ + + struct + { + unsigned long x_timestamp; /* time stamp */ + char x_idstring[20]; /* producer identity string */ + } x_ident; /* Producer ident info */ + +}; + +/********************** RELOCATION DIRECTIVES **********************/ + +struct internal_reloc +{ + bfd_vma r_vaddr; /* Virtual address of reference */ + long r_symndx; /* Index into symbol table */ + unsigned short r_type; /* Relocation type */ + unsigned char r_size; /* Used by RS/6000 and ECOFF */ + unsigned char r_extern; /* Used by ECOFF */ + unsigned long r_offset; /* Used by Alpha ECOFF, SPARC, others */ +}; + +#define R_DIR16 1 +#define R_REL24 5 +#define R_DIR32 6 +#define R_IMAGEBASE 7 +#define R_RELBYTE 15 +#define R_RELWORD 16 +#define R_RELLONG 17 +#define R_PCRBYTE 18 +#define R_PCRWORD 19 +#define R_PCRLONG 20 +#define R_PCR24 21 +#define R_IPRSHORT 24 +#define R_IPRLONG 26 +#define R_GETSEG 29 +#define R_GETPA 30 +#define R_TAGWORD 31 +#define R_JUMPTARG 32 /* strange 29k 00xx00xx reloc */ +#define R_PARTLS16 32 +#define R_PARTMS8 33 + +#define R_PCR16L 128 +#define R_PCR26L 129 +#define R_VRT16 130 +#define R_HVRT16 131 +#define R_LVRT16 132 +#define R_VRT32 133 + + +/* This reloc identifies mov.b instructions with a 16bit absolute + address. The linker tries to turn insns with this reloc into + an absolute 8-bit address. */ +#define R_MOV16B1 0x41 + +/* This reloc identifies mov.b instructions which had a 16bit + absolute address which have been shortened into a 8-bit + absolute address. */ +#define R_MOV16B2 0x42 + +/* This reloc identifies jmp insns with a 16bit target address; + the linker tries to turn these insns into bra insns with + an 8bit pc-relative target. */ +#define R_JMP1 0x43 + +/* This reloc identifies a bra with an 8-bit pc-relative + target that was formerly a jmp insn with a 16bit target. */ +#define R_JMP2 0x44 + +/* ??? */ +#define R_RELLONG_NEG 0x45 + +/* This reloc identifies jmp insns with a 24bit target address; + the linker tries to turn these insns into bra insns with + an 8bit pc-relative target. */ +#define R_JMPL1 0x46 + +/* This reloc identifies a bra with an 8-bit pc-relative + target that was formerly a jmp insn with a 24bit target. */ +#define R_JMPL2 0x47 + +/* This reloc identifies mov.b instructions with a 24bit absolute + address. The linker tries to turn insns with this reloc into + an absolute 8-bit address. */ + +#define R_MOV24B1 0x48 + +/* This reloc identifies mov.b instructions which had a 24bit + absolute address which have been shortened into a 8-bit + absolute address. */ +#define R_MOV24B2 0x49 + +/* An h8300 memory indirect jump/call. Forces the address of the jump/call + target into the function vector (in page zero), and the address of the + vector entry to be placed in the jump/call instruction. */ +#define R_MEM_INDIRECT 0x4a + +/* This reloc identifies a 16bit pc-relative branch target which was + shortened into an 8bit pc-relative branch target. */ +#define R_PCRWORD_B 0x4b + +/* This reloc identifies mov.[wl] instructions with a 32/24 bit + absolute address; the linker may turn this into a mov.[wl] + insn with a 16bit absolute address. */ +#define R_MOVL1 0x4c + +/* This reloc identifies mov.[wl] insns which formerly had + a 32/24bit absolute address and now have a 16bit absolute address. */ +#define R_MOVL2 0x4d + +/* This reloc identifies a bCC:8 which will have it's condition + inverted and its target redirected to the target of the branch + in the following insn. */ +#define R_BCC_INV 0x4e + +/* This reloc identifies a jmp instruction that has been deleted. */ +#define R_JMP_DEL 0x4f + +/* Z8k modes */ +#define R_IMM16 0x01 /* 16 bit abs */ +#define R_JR 0x02 /* jr 8 bit disp */ +#define R_IMM4L 0x23 /* low nibble */ +#define R_IMM8 0x22 /* 8 bit abs */ +#define R_IMM32 R_RELLONG /* 32 bit abs */ +#define R_CALL R_DA /* Absolute address which could be a callr */ +#define R_JP R_DA /* Absolute address which could be a jp */ +#define R_REL16 0x04 /* 16 bit PC rel */ +#define R_CALLR 0x05 /* callr 12 bit disp */ +#define R_SEG 0x10 /* set if in segmented mode */ +#define R_IMM4H 0x24 /* high nibble */ +#define R_DISP7 0x25 /* djnz displacement */ + +/* H8500 modes */ + +#define R_H8500_IMM8 1 /* 8 bit immediate */ +#define R_H8500_IMM16 2 /* 16 bit immediate */ +#define R_H8500_PCREL8 3 /* 8 bit pcrel */ +#define R_H8500_PCREL16 4 /* 16 bit pcrel */ +#define R_H8500_HIGH8 5 /* high 8 bits of 24 bit address */ +#define R_H8500_LOW16 7 /* low 16 bits of 24 bit immediate */ +#define R_H8500_IMM24 6 /* 24 bit immediate */ +#define R_H8500_IMM32 8 /* 32 bit immediate */ +#define R_H8500_HIGH16 9 /* high 16 bits of 32 bit immediate */ + +/* W65 modes */ + +#define R_W65_ABS8 1 /* addr & 0xff */ +#define R_W65_ABS16 2 /* addr & 0xffff */ +#define R_W65_ABS24 3 /* addr & 0xffffff */ + +#define R_W65_ABS8S8 4 /* (addr >> 8) & 0xff */ +#define R_W65_ABS8S16 5 /* (addr >> 16) & 0xff */ + +#define R_W65_ABS16S8 6 /* (addr >> 8) & 0ffff */ +#define R_W65_ABS16S16 7 /* (addr >> 16) & 0ffff */ + +#define R_W65_PCR8 8 +#define R_W65_PCR16 9 + +#define R_W65_DP 10 /* direct page 8 bits only */ + +#endif /* GNU_COFF_INTERNAL_H */ diff --git a/contrib/binutils-2.14/include/coff/sym.h b/contrib/binutils-2.14/include/coff/sym.h new file mode 100644 index 0000000000..76204af59a --- /dev/null +++ b/contrib/binutils-2.14/include/coff/sym.h @@ -0,0 +1,484 @@ +/* Declarations of internal format of MIPS ECOFF symbols. + Originally contributed by MIPS Computer Systems and Third Eye Software. + Changes contributed by Cygnus Support are in the public domain. + + This file is just aggregated with the files that make up the GNU + release; it is not considered part of GAS, GDB, or other GNU + programs. */ + +/* + * |-----------------------------------------------------------| + * | Copyright (c) 1992, 1991, 1990 MIPS Computer Systems, Inc.| + * | MIPS Computer Systems, Inc. grants reproduction and use | + * | rights to all parties, PROVIDED that this comment is | + * | maintained in the copy. | + * |-----------------------------------------------------------| + */ +#ifndef _SYM_H +#define _SYM_H + +/* (C) Copyright 1984 by Third Eye Software, Inc. + * + * Third Eye Software, Inc. grants reproduction and use rights to + * all parties, PROVIDED that this comment is maintained in the copy. + * + * Third Eye makes no claims about the applicability of this + * symbol table to a particular use. + */ + +/* + * This file contains the definition of the Third Eye Symbol Table. + * + * Symbols are assumed to be in 'encounter order' - i.e. the order that + * the things they represent were encountered by the compiler/assembler/loader. + * EXCEPT for globals! These are assumed to be bunched together, + * probably right after the last 'normal' symbol. Globals ARE sorted + * in ascending order. + * + * ----------------------------------------------------------------------- + * A brief word about Third Eye naming/use conventions: + * + * All arrays and index's are 0 based. + * All "ifooMax" values are the highest legal value PLUS ONE. This makes + * them good for allocating arrays, etc. All checks are "ifoo < ifooMax". + * + * "isym" Index into the SYMbol table. + * "ipd" Index into the Procedure Descriptor array. + * "ifd" Index into the File Descriptor array. + * "iss" Index into String Space. + * "cb" Count of Bytes. + * "rgPd" array whose domain is "0..ipdMax-1" and RanGe is PDR. + * "rgFd" array whose domain is "0..ifdMax-1" and RanGe is FDR. + */ + + +/* + * Symbolic Header (HDR) structure. + * As long as all the pointers are set correctly, + * we don't care WHAT order the various sections come out in! + * + * A file produced solely for the use of CDB will probably NOT have + * any instructions or data areas in it, as these are available + * in the original. + */ + +typedef struct { + short magic; /* to verify validity of the table */ + short vstamp; /* version stamp */ + long ilineMax; /* number of line number entries */ + bfd_vma cbLine; /* number of bytes for line number entries */ + bfd_vma cbLineOffset; /* offset to start of line number entries*/ + long idnMax; /* max index into dense number table */ + bfd_vma cbDnOffset; /* offset to start dense number table */ + long ipdMax; /* number of procedures */ + bfd_vma cbPdOffset; /* offset to procedure descriptor table */ + long isymMax; /* number of local symbols */ + bfd_vma cbSymOffset; /* offset to start of local symbols*/ + long ioptMax; /* max index into optimization symbol entries */ + bfd_vma cbOptOffset; /* offset to optimization symbol entries */ + long iauxMax; /* number of auxillary symbol entries */ + bfd_vma cbAuxOffset; /* offset to start of auxillary symbol entries*/ + long issMax; /* max index into local strings */ + bfd_vma cbSsOffset; /* offset to start of local strings */ + long issExtMax; /* max index into external strings */ + bfd_vma cbSsExtOffset; /* offset to start of external strings */ + long ifdMax; /* number of file descriptor entries */ + bfd_vma cbFdOffset; /* offset to file descriptor table */ + long crfd; /* number of relative file descriptor entries */ + bfd_vma cbRfdOffset; /* offset to relative file descriptor table */ + long iextMax; /* max index into external symbols */ + bfd_vma cbExtOffset; /* offset to start of external symbol entries*/ + /* If you add machine dependent fields, add them here */ + } HDRR, *pHDRR; +#define cbHDRR sizeof(HDRR) +#define hdrNil ((pHDRR)0) + +/* + * The FDR and PDR structures speed mapping of address <-> name. + * They are sorted in ascending memory order and are kept in + * memory by CDB at runtime. + */ + +/* + * File Descriptor + * + * There is one of these for EVERY FILE, whether compiled with + * full debugging symbols or not. The name of a file should be + * the path name given to the compiler. This allows the user + * to simply specify the names of the directories where the COMPILES + * were done, and we will be able to find their files. + * A field whose comment starts with "R - " indicates that it will be + * setup at runtime. + */ +typedef struct fdr { + bfd_vma adr; /* memory address of beginning of file */ + long rss; /* file name (of source, if known) */ + long issBase; /* file's string space */ + bfd_vma cbSs; /* number of bytes in the ss */ + long isymBase; /* beginning of symbols */ + long csym; /* count file's of symbols */ + long ilineBase; /* file's line symbols */ + long cline; /* count of file's line symbols */ + long ioptBase; /* file's optimization entries */ + long copt; /* count of file's optimization entries */ + unsigned short ipdFirst;/* start of procedures for this file */ + short cpd; /* count of procedures for this file */ + long iauxBase; /* file's auxiliary entries */ + long caux; /* count of file's auxiliary entries */ + long rfdBase; /* index into the file indirect table */ + long crfd; /* count file indirect entries */ + unsigned lang: 5; /* language for this file */ + unsigned fMerge : 1; /* whether this file can be merged */ + unsigned fReadin : 1; /* true if it was read in (not just created) */ + unsigned fBigendian : 1;/* if set, was compiled on big endian machine */ + /* aux's will be in compile host's sex */ + unsigned glevel : 2; /* level this file was compiled with */ + unsigned reserved : 22; /* reserved for future use */ + bfd_vma cbLineOffset; /* byte offset from header for this file ln's */ + bfd_vma cbLine; /* size of lines for this file */ + } FDR, *pFDR; +#define cbFDR sizeof(FDR) +#define fdNil ((pFDR)0) +#define ifdNil -1 +#define ifdTemp 0 +#define ilnNil -1 + + +/* + * Procedure Descriptor + * + * There is one of these for EVERY TEXT LABEL. + * If a procedure is in a file with full symbols, then isym + * will point to the PROC symbols, else it will point to the + * global symbol for the label. + */ + +typedef struct pdr { + bfd_vma adr; /* memory address of start of procedure */ + long isym; /* start of local symbol entries */ + long iline; /* start of line number entries*/ + long regmask; /* save register mask */ + long regoffset; /* save register offset */ + long iopt; /* start of optimization symbol entries*/ + long fregmask; /* save floating point register mask */ + long fregoffset; /* save floating point register offset */ + long frameoffset; /* frame size */ + short framereg; /* frame pointer register */ + short pcreg; /* offset or reg of return pc */ + long lnLow; /* lowest line in the procedure */ + long lnHigh; /* highest line in the procedure */ + bfd_vma cbLineOffset; /* byte offset for this procedure from the fd base */ + /* These fields are new for 64 bit ECOFF. */ + unsigned gp_prologue : 8; /* byte size of GP prologue */ + unsigned gp_used : 1; /* true if the procedure uses GP */ + unsigned reg_frame : 1; /* true if register frame procedure */ + unsigned prof : 1; /* true if compiled with -pg */ + unsigned reserved : 13; /* reserved: must be zero */ + unsigned localoff : 8; /* offset of local variables from vfp */ + } PDR, *pPDR; +#define cbPDR sizeof(PDR) +#define pdNil ((pPDR) 0) +#define ipdNil -1 + +/* + * The structure of the runtime procedure descriptor created by the loader + * for use by the static exception system. + */ +/* + * If 0'd out because exception_info chokes Visual C++ and because there + * don't seem to be any references to this structure elsewhere in gdb. + */ +#if 0 +typedef struct runtime_pdr { + bfd_vma adr; /* memory address of start of procedure */ + long regmask; /* save register mask */ + long regoffset; /* save register offset */ + long fregmask; /* save floating point register mask */ + long fregoffset; /* save floating point register offset */ + long frameoffset; /* frame size */ + short framereg; /* frame pointer register */ + short pcreg; /* offset or reg of return pc */ + long irpss; /* index into the runtime string table */ + long reserved; + struct exception_info *exception_info;/* pointer to exception array */ +} RPDR, *pRPDR; +#define cbRPDR sizeof(RPDR) +#define rpdNil ((pRPDR) 0) +#endif + +/* + * Line Numbers + * + * Line Numbers are segregated from the normal symbols because they + * are [1] smaller , [2] are of no interest to your + * average loader, and [3] are never needed in the middle of normal + * scanning and therefore slow things down. + * + * By definition, the first LINER for any given procedure will have + * the first line of a procedure and represent the first address. + */ + +typedef long LINER, *pLINER; +#define lineNil ((pLINER)0) +#define cbLINER sizeof(LINER) +#define ilineNil -1 + + + +/* + * The Symbol Structure (GFW, to those who Know!) + */ + +typedef struct { + long iss; /* index into String Space of name */ + bfd_vma value; /* value of symbol */ + unsigned st : 6; /* symbol type */ + unsigned sc : 5; /* storage class - text, data, etc */ + unsigned reserved : 1; /* reserved */ + unsigned index : 20; /* index into sym/aux table */ + } SYMR, *pSYMR; +#define symNil ((pSYMR)0) +#define cbSYMR sizeof(SYMR) +#define isymNil -1 +#define indexNil 0xfffff +#define issNil -1 +#define issNull 0 + + +/* The following converts a memory resident string to an iss. + * This hack is recognized in SbFIss, in sym.c of the debugger. + */ +#define IssFSb(sb) (0x80000000 | ((unsigned long)(sb))) + +/* E X T E R N A L S Y M B O L R E C O R D + * + * Same as the SYMR except it contains file context to determine where + * the index is. + */ +typedef struct ecoff_extr { + unsigned jmptbl:1; /* symbol is a jump table entry for shlibs */ + unsigned cobol_main:1; /* symbol is a cobol main procedure */ + unsigned weakext:1; /* symbol is weak external */ + unsigned reserved:13; /* reserved for future use */ + int ifd; /* where the iss and index fields point into */ + SYMR asym; /* symbol for the external */ + } EXTR, *pEXTR; +#define extNil ((pEXTR)0) +#define cbEXTR sizeof(EXTR) + + +/* A U X I L L A R Y T Y P E I N F O R M A T I O N */ + +/* + * Type Information Record + */ +typedef struct { + unsigned fBitfield : 1; /* set if bit width is specified */ + unsigned continued : 1; /* indicates additional TQ info in next AUX */ + unsigned bt : 6; /* basic type */ + unsigned tq4 : 4; + unsigned tq5 : 4; + /* ---- 16 bit boundary ---- */ + unsigned tq0 : 4; + unsigned tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */ + unsigned tq2 : 4; + unsigned tq3 : 4; + } TIR, *pTIR; +#define cbTIR sizeof(TIR) +#define tiNil ((pTIR)0) +#define itqMax 6 + +/* + * Relative symbol record + * + * If the rfd field is 4095, the index field indexes into the global symbol + * table. + */ + +typedef struct { + unsigned rfd : 12; /* index into the file indirect table */ + unsigned index : 20; /* index int sym/aux/iss tables */ + } RNDXR, *pRNDXR; +#define cbRNDXR sizeof(RNDXR) +#define rndxNil ((pRNDXR)0) + +/* dense numbers or sometimes called block numbers are stored in this type, + * a rfd of 0xffffffff is an index into the global table. + */ +typedef struct { + unsigned long rfd; /* index into the file table */ + unsigned long index; /* index int sym/aux/iss tables */ + } DNR, *pDNR; +#define cbDNR sizeof(DNR) +#define dnNil ((pDNR)0) + + + +/* + * Auxillary information occurs only if needed. + * It ALWAYS occurs in this order when present. + + isymMac used by stProc only + TIR type info + TIR additional TQ info (if first TIR was not enough) + rndx if (bt == btStruct,btUnion,btEnum,btSet,btRange, + btTypedef): + rsym.index == iaux for btSet or btRange + else rsym.index == isym + dimLow btRange, btSet + dimMac btRange, btSet + rndx0 As many as there are tq arrays + dimLow0 + dimHigh0 + ... + rndxMax-1 + dimLowMax-1 + dimHighMax-1 + width in bits if (bit field), width in bits. + */ +#define cAuxMax (6 + (idimMax*3)) + +/* a union of all possible info in the AUX universe */ +typedef union { + TIR ti; /* type information record */ + RNDXR rndx; /* relative index into symbol table */ + long dnLow; /* low dimension */ + long dnHigh; /* high dimension */ + long isym; /* symbol table index (end of proc) */ + long iss; /* index into string space (not used) */ + long width; /* width for non-default sized struc fields */ + long count; /* count of ranges for variant arm */ + } AUXU, *pAUXU; +#define cbAUXU sizeof(AUXU) +#define auxNil ((pAUXU)0) +#define iauxNil -1 + + +/* + * Optimization symbols + * + * Optimization symbols contain some overlap information with the normal + * symbol table. In particular, the proc information + * is somewhat redundant but necessary to easily find the other information + * present. + * + * All of the offsets are relative to the beginning of the last otProc + */ + +typedef struct { + unsigned ot: 8; /* optimization type */ + unsigned value: 24; /* address where we are moving it to */ + RNDXR rndx; /* points to a symbol or opt entry */ + unsigned long offset; /* relative offset this occured */ + } OPTR, *pOPTR; +#define optNil ((pOPTR) 0) +#define cbOPTR sizeof(OPTR) +#define ioptNil -1 + +/* + * File Indirect + * + * When a symbol is referenced across files the following procedure is used: + * 1) use the file index to get the File indirect entry. + * 2) use the file indirect entry to get the File descriptor. + * 3) add the sym index to the base of that file's sym table + * + */ + +typedef long RFDT, *pRFDT; +#define cbRFDT sizeof(RFDT) +#define rfdNil -1 + +/* + * The file indirect table in the mips loader is known as an array of FITs. + * This is done to keep the code in the loader readable in the area where + * these tables are merged. Note this is only a name change. + */ +typedef long FIT, *pFIT; +#define cbFIT sizeof(FIT) +#define ifiNil -1 +#define fiNil ((pFIT) 0) + +#ifdef _LANGUAGE_PASCAL +#define ifdNil -1 +#define ilnNil -1 +#define ipdNil -1 +#define ilineNil -1 +#define isymNil -1 +#define indexNil 16#fffff +#define issNil -1 +#define issNull 0 +#define itqMax 6 +#define iauxNil -1 +#define ioptNil -1 +#define rfdNil -1 +#define ifiNil -1 +#endif /* _LANGUAGE_PASCAL */ + + +/* Dense numbers + * + * Rather than use file index, symbol index pairs to represent symbols + * and globals, we use dense number so that they can be easily embeded + * in intermediate code and the programs that process them can + * use direct access tabls instead of hash table (which would be + * necesary otherwise because of the sparse name space caused by + * file index, symbol index pairs. Dense number are represented + * by RNDXRs. + */ + +/* + * The following table defines the meaning of each SYM field as + * a function of the "st". (scD/B == scData OR scBss) + * + * Note: the value "isymMac" is used by symbols that have the concept + * of enclosing a block of related information. This value is the + * isym of the first symbol AFTER the end associated with the primary + * symbol. For example if a procedure was at isym==90 and had an + * isymMac==155, the associated end would be at isym==154, and the + * symbol at 155 would probably (although not necessarily) be the + * symbol for the next procedure. This allows rapid skipping over + * internal information of various sorts. "stEnd"s ALWAYS have the + * isym of the primary symbol that started the block. + * + +ST SC VALUE INDEX +-------- ------ -------- ------ +stFile scText address isymMac +stLabel scText address --- +stGlobal scD/B address iaux +stStatic scD/B address iaux +stParam scAbs offset iaux +stLocal scAbs offset iaux +stProc scText address iaux (isymMac is first AUX) +stStaticProc scText address iaux (isymMac is first AUX) + +stMember scNil ordinal --- (if member of enum) + (mipsread thinks the case below has a bit, not byte, offset.) +stMember scNil byte offset iaux (if member of struct/union) +stMember scBits bit offset iaux (bit field spec) + +stBlock scText address isymMac (text block) + (the code seems to think that rather than scNil, we see scInfo for + the two cases below.) +stBlock scNil cb isymMac (struct/union member define) +stBlock scNil cMembers isymMac (enum member define) + + (New types added by SGI to simplify things:) +stStruct scInfo cb isymMac (struct type define) +stUnion scInfo cb isymMac (union type define) +stEnum scInfo cMembers isymMac (enum type define) + +stEnd scText address isymStart +stEnd scNil ------- isymStart (struct/union/enum) + +stTypedef scNil ------- iaux +stRegReloc sc??? value old register number +stForward sc??? new address isym to original symbol + +stConstant scInfo value --- (scalar) +stConstant scInfo iss --- (complex, e.g. string) + + * + */ +#endif diff --git a/contrib/binutils-2.14/include/demangle.h b/contrib/binutils-2.14/include/demangle.h new file mode 100644 index 0000000000..21e9dd3382 --- /dev/null +++ b/contrib/binutils-2.14/include/demangle.h @@ -0,0 +1,163 @@ +/* Defs for interface to demanglers. + Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002 + Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + + +#if !defined (DEMANGLE_H) +#define DEMANGLE_H + +#include "ansidecl.h" + +/* Options passed to cplus_demangle (in 2nd parameter). */ + +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ +#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */ +#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */ + +#define DMGL_AUTO (1 << 8) +#define DMGL_GNU (1 << 9) +#define DMGL_LUCID (1 << 10) +#define DMGL_ARM (1 << 11) +#define DMGL_HP (1 << 12) /* For the HP aCC compiler; + same as ARM except for + template arguments, etc. */ +#define DMGL_EDG (1 << 13) +#define DMGL_GNU_V3 (1 << 14) +#define DMGL_GNAT (1 << 15) + +/* If none of these are set, use 'current_demangling_style' as the default. */ +#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT) + +/* Enumeration of possible demangling styles. + + Lucid and ARM styles are still kept logically distinct, even though + they now both behave identically. The resulting style is actual the + union of both. I.E. either style recognizes both "__pt__" and "__rf__" + for operator "->", even though the first is lucid style and the second + is ARM style. (FIXME?) */ + +extern enum demangling_styles +{ + no_demangling = -1, + unknown_demangling = 0, + auto_demangling = DMGL_AUTO, + gnu_demangling = DMGL_GNU, + lucid_demangling = DMGL_LUCID, + arm_demangling = DMGL_ARM, + hp_demangling = DMGL_HP, + edg_demangling = DMGL_EDG, + gnu_v3_demangling = DMGL_GNU_V3, + java_demangling = DMGL_JAVA, + gnat_demangling = DMGL_GNAT +} current_demangling_style; + +/* Define string names for the various demangling styles. */ + +#define NO_DEMANGLING_STYLE_STRING "none" +#define AUTO_DEMANGLING_STYLE_STRING "auto" +#define GNU_DEMANGLING_STYLE_STRING "gnu" +#define LUCID_DEMANGLING_STYLE_STRING "lucid" +#define ARM_DEMANGLING_STYLE_STRING "arm" +#define HP_DEMANGLING_STYLE_STRING "hp" +#define EDG_DEMANGLING_STYLE_STRING "edg" +#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3" +#define JAVA_DEMANGLING_STYLE_STRING "java" +#define GNAT_DEMANGLING_STYLE_STRING "gnat" + +/* Some macros to test what demangling style is active. */ + +#define CURRENT_DEMANGLING_STYLE current_demangling_style +#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO) +#define GNU_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU) +#define LUCID_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_LUCID) +#define ARM_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_ARM) +#define HP_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_HP) +#define EDG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_EDG) +#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3) +#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA) +#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT) + +/* Provide information about the available demangle styles. This code is + pulled from gdb into libiberty because it is useful to binutils also. */ + +extern const struct demangler_engine +{ + const char *const demangling_style_name; + const enum demangling_styles demangling_style; + const char *const demangling_style_doc; +} libiberty_demanglers[]; + +extern char * +cplus_demangle PARAMS ((const char *mangled, int options)); + +extern int +cplus_demangle_opname PARAMS ((const char *opname, char *result, int options)); + +extern const char * +cplus_mangle_opname PARAMS ((const char *opname, int options)); + +/* Note: This sets global state. FIXME if you care about multi-threading. */ + +extern void +set_cplus_marker_for_demangling PARAMS ((int ch)); + +extern enum demangling_styles +cplus_demangle_set_style PARAMS ((enum demangling_styles style)); + +extern enum demangling_styles +cplus_demangle_name_to_style PARAMS ((const char *name)); + +/* V3 ABI demangling entry points, defined in cp-demangle.c. */ +extern char* +cplus_demangle_v3 PARAMS ((const char* mangled, int options)); + +extern char* +java_demangle_v3 PARAMS ((const char* mangled)); + + +enum gnu_v3_ctor_kinds { + gnu_v3_complete_object_ctor = 1, + gnu_v3_base_object_ctor, + gnu_v3_complete_object_allocating_ctor +}; + +/* Return non-zero iff NAME is the mangled form of a constructor name + in the G++ V3 ABI demangling style. Specifically, return an `enum + gnu_v3_ctor_kinds' value indicating what kind of constructor + it is. */ +extern enum gnu_v3_ctor_kinds + is_gnu_v3_mangled_ctor PARAMS ((const char *name)); + + +enum gnu_v3_dtor_kinds { + gnu_v3_deleting_dtor = 1, + gnu_v3_complete_object_dtor, + gnu_v3_base_object_dtor +}; + +/* Return non-zero iff NAME is the mangled form of a destructor name + in the G++ V3 ABI demangling style. Specifically, return an `enum + gnu_v3_dtor_kinds' value, indicating what kind of destructor + it is. */ +extern enum gnu_v3_dtor_kinds + is_gnu_v3_mangled_dtor PARAMS ((const char *name)); + +#endif /* DEMANGLE_H */ diff --git a/contrib/binutils-2.14/include/dis-asm.h b/contrib/binutils-2.14/include/dis-asm.h new file mode 100644 index 0000000000..392cbf9b46 --- /dev/null +++ b/contrib/binutils-2.14/include/dis-asm.h @@ -0,0 +1,328 @@ +/* Interface between the opcode library and its callers. + + Copyright 2001, 2002 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Written by Cygnus Support, 1993. + + The opcode library (libopcodes.a) provides instruction decoders for + a large variety of instruction sets, callable with an identical + interface, for making instruction-processing programs more independent + of the instruction set being processed. */ + +#ifndef DIS_ASM_H +#define DIS_ASM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "bfd.h" + +typedef int (*fprintf_ftype) PARAMS((PTR, const char*, ...)); + +enum dis_insn_type { + dis_noninsn, /* Not a valid instruction */ + dis_nonbranch, /* Not a branch instruction */ + dis_branch, /* Unconditional branch */ + dis_condbranch, /* Conditional branch */ + dis_jsr, /* Jump to subroutine */ + dis_condjsr, /* Conditional jump to subroutine */ + dis_dref, /* Data reference instruction */ + dis_dref2 /* Two data references in instruction */ +}; + +/* This struct is passed into the instruction decoding routine, + and is passed back out into each callback. The various fields are used + for conveying information from your main routine into your callbacks, + for passing information into the instruction decoders (such as the + addresses of the callback functions), or for passing information + back from the instruction decoders to their callers. + + It must be initialized before it is first passed; this can be done + by hand, or using one of the initialization macros below. */ + +typedef struct disassemble_info { + fprintf_ftype fprintf_func; + PTR stream; + PTR application_data; + + /* Target description. We could replace this with a pointer to the bfd, + but that would require one. There currently isn't any such requirement + so to avoid introducing one we record these explicitly. */ + /* The bfd_flavour. This can be bfd_target_unknown_flavour. */ + enum bfd_flavour flavour; + /* The bfd_arch value. */ + enum bfd_architecture arch; + /* The bfd_mach value. */ + unsigned long mach; + /* Endianness (for bi-endian cpus). Mono-endian cpus can ignore this. */ + enum bfd_endian endian; + /* An arch/mach-specific bitmask of selected instruction subsets, mainly + for processors with run-time-switchable instruction sets. The default, + zero, means that there is no constraint. CGEN-based opcodes ports + may use ISA_foo masks. */ + unsigned long insn_sets; + + /* Some targets need information about the current section to accurately + display insns. If this is NULL, the target disassembler function + will have to make its best guess. */ + asection *section; + + /* An array of pointers to symbols either at the location being disassembled + or at the start of the function being disassembled. The array is sorted + so that the first symbol is intended to be the one used. The others are + present for any misc. purposes. This is not set reliably, but if it is + not NULL, it is correct. */ + asymbol **symbols; + /* Number of symbols in array. */ + int num_symbols; + + /* For use by the disassembler. + The top 16 bits are reserved for public use (and are documented here). + The bottom 16 bits are for the internal use of the disassembler. */ + unsigned long flags; +#define INSN_HAS_RELOC 0x80000000 + PTR private_data; + + /* Function used to get bytes to disassemble. MEMADDR is the + address of the stuff to be disassembled, MYADDR is the address to + put the bytes in, and LENGTH is the number of bytes to read. + INFO is a pointer to this struct. + Returns an errno value or 0 for success. */ + int (*read_memory_func) + PARAMS ((bfd_vma memaddr, bfd_byte *myaddr, unsigned int length, + struct disassemble_info *info)); + + /* Function which should be called if we get an error that we can't + recover from. STATUS is the errno value from read_memory_func and + MEMADDR is the address that we were trying to read. INFO is a + pointer to this struct. */ + void (*memory_error_func) + PARAMS ((int status, bfd_vma memaddr, struct disassemble_info *info)); + + /* Function called to print ADDR. */ + void (*print_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info *info)); + + /* Function called to determine if there is a symbol at the given ADDR. + If there is, the function returns 1, otherwise it returns 0. + This is used by ports which support an overlay manager where + the overlay number is held in the top part of an address. In + some circumstances we want to include the overlay number in the + address, (normally because there is a symbol associated with + that address), but sometimes we want to mask out the overlay bits. */ + int (* symbol_at_address_func) + PARAMS ((bfd_vma addr, struct disassemble_info * info)); + + /* These are for buffer_read_memory. */ + bfd_byte *buffer; + bfd_vma buffer_vma; + unsigned int buffer_length; + + /* This variable may be set by the instruction decoder. It suggests + the number of bytes objdump should display on a single line. If + the instruction decoder sets this, it should always set it to + the same value in order to get reasonable looking output. */ + int bytes_per_line; + + /* the next two variables control the way objdump displays the raw data */ + /* For example, if bytes_per_line is 8 and bytes_per_chunk is 4, the */ + /* output will look like this: + 00: 00000000 00000000 + with the chunks displayed according to "display_endian". */ + int bytes_per_chunk; + enum bfd_endian display_endian; + + /* Number of octets per incremented target address + Normally one, but some DSPs have byte sizes of 16 or 32 bits. */ + unsigned int octets_per_byte; + + /* Results from instruction decoders. Not all decoders yet support + this information. This info is set each time an instruction is + decoded, and is only valid for the last such instruction. + + To determine whether this decoder supports this information, set + insn_info_valid to 0, decode an instruction, then check it. */ + + char insn_info_valid; /* Branch info has been set. */ + char branch_delay_insns; /* How many sequential insn's will run before + a branch takes effect. (0 = normal) */ + char data_size; /* Size of data reference in insn, in bytes */ + enum dis_insn_type insn_type; /* Type of instruction */ + bfd_vma target; /* Target address of branch or dref, if known; + zero if unknown. */ + bfd_vma target2; /* Second target address for dref2 */ + + /* Command line options specific to the target disassembler. */ + char * disassembler_options; + +} disassemble_info; + + +/* Standard disassemblers. Disassemble one instruction at the given + target address. Return number of octets processed. */ +typedef int (*disassembler_ftype) + PARAMS((bfd_vma, disassemble_info *)); + +extern int print_insn_big_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_mips PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386 PARAMS ((bfd_vma, disassemble_info *)); +extern int print_insn_i386_att PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i386_intel PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ia64 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i370 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc11 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68hc12 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m68k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8001 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_z8002 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300h PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8300s PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_h8500 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_arm PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sparc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_a29k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_avr PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_d10v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_d30v PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_dlx PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_fr30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_hppa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i860 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_i960 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ip2k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m32r PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_m88k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mcore PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mmix PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10200 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_mn10300 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_msp430 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_ns32k PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_openrisc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_or32 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_or32 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_pdp11 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_pj PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_big_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_little_powerpc PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_rs6000 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_s390 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic4x PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic54x PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_tic80 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_vax PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_w65 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_xstormy16 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_xtensa PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_sh64 PARAMS ((bfd_vma, disassemble_info *)); +extern int print_insn_sh64x_media PARAMS ((bfd_vma, disassemble_info *)); +extern int print_insn_frv PARAMS ((bfd_vma, disassemble_info *)); +extern int print_insn_iq2000 PARAMS ((bfd_vma, disassemble_info *)); + +extern disassembler_ftype arc_get_disassembler PARAMS ((void *)); +extern disassembler_ftype cris_get_disassembler PARAMS ((bfd *)); + +extern void print_mips_disassembler_options PARAMS ((FILE *)); +extern void print_ppc_disassembler_options PARAMS ((FILE *)); +extern void print_arm_disassembler_options PARAMS ((FILE *)); +extern void parse_arm_disassembler_option PARAMS ((char *)); +extern int get_arm_regname_num_options PARAMS ((void)); +extern int set_arm_regname_option PARAMS ((int)); +extern int get_arm_regnames PARAMS ((int, const char **, const char **, const char ***)); + +/* Fetch the disassembler for a given BFD, if that support is available. */ +extern disassembler_ftype disassembler PARAMS ((bfd *)); + +/* Document any target specific options available from the disassembler. */ +extern void disassembler_usage PARAMS ((FILE *)); + + +/* This block of definitions is for particular callers who read instructions + into a buffer before calling the instruction decoder. */ + +/* Here is a function which callers may wish to use for read_memory_func. + It gets bytes from a buffer. */ +extern int buffer_read_memory + PARAMS ((bfd_vma, bfd_byte *, unsigned int, struct disassemble_info *)); + +/* This function goes with buffer_read_memory. + It prints a message using info->fprintf_func and info->stream. */ +extern void perror_memory PARAMS ((int, bfd_vma, struct disassemble_info *)); + + +/* Just print the address in hex. This is included for completeness even + though both GDB and objdump provide their own (to print symbolic + addresses). */ +extern void generic_print_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Always true. */ +extern int generic_symbol_at_address + PARAMS ((bfd_vma, struct disassemble_info *)); + +/* Macro to initialize a disassemble_info struct. This should be called + by all applications creating such a struct. */ +#define INIT_DISASSEMBLE_INFO(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).flavour = bfd_target_unknown_flavour, \ + (INFO).arch = bfd_arch_unknown, \ + (INFO).mach = 0, \ + (INFO).insn_sets = 0, \ + (INFO).endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).octets_per_byte = 1, \ + INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) + +/* Call this macro to initialize only the internal variables for the + disassembler. Architecture dependent things such as byte order, or machine + variant are not touched by this macro. This makes things much easier for + GDB which must initialize these things separately. */ + +#define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \ + (INFO).fprintf_func = (fprintf_ftype)(FPRINTF_FUNC), \ + (INFO).stream = (PTR)(STREAM), \ + (INFO).section = NULL, \ + (INFO).symbols = NULL, \ + (INFO).num_symbols = 0, \ + (INFO).private_data = NULL, \ + (INFO).buffer = NULL, \ + (INFO).buffer_vma = 0, \ + (INFO).buffer_length = 0, \ + (INFO).read_memory_func = buffer_read_memory, \ + (INFO).memory_error_func = perror_memory, \ + (INFO).print_address_func = generic_print_address, \ + (INFO).symbol_at_address_func = generic_symbol_at_address, \ + (INFO).flags = 0, \ + (INFO).bytes_per_line = 0, \ + (INFO).bytes_per_chunk = 0, \ + (INFO).display_endian = BFD_ENDIAN_UNKNOWN, \ + (INFO).disassembler_options = NULL, \ + (INFO).insn_info_valid = 0 + +#ifdef __cplusplus +} +#endif + +#endif /* ! defined (DIS_ASM_H) */ diff --git a/contrib/binutils-2.14/include/dyn-string.h b/contrib/binutils-2.14/include/dyn-string.h new file mode 100644 index 0000000000..2a771c7a5d --- /dev/null +++ b/contrib/binutils-2.14/include/dyn-string.h @@ -0,0 +1,92 @@ +/* An abstract string datatype. + Copyright (C) 1998, 1999, 2000, 2002 Free Software Foundation, Inc. + Contributed by Mark Mitchell (mark@markmitchell.com). + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +typedef struct dyn_string +{ + int allocated; /* The amount of space allocated for the string. */ + int length; /* The actual length of the string. */ + char *s; /* The string itself, NUL-terminated. */ +}* dyn_string_t; + +/* The length STR, in bytes, not including the terminating NUL. */ +#define dyn_string_length(STR) \ + ((STR)->length) + +/* The NTBS in which the contents of STR are stored. */ +#define dyn_string_buf(STR) \ + ((STR)->s) + +/* Compare DS1 to DS2 with strcmp. */ +#define dyn_string_compare(DS1, DS2) \ + (strcmp ((DS1)->s, (DS2)->s)) + + +/* dyn_string functions are used in the demangling implementation + included in the G++ runtime library. To prevent collisions with + names in user programs, the functions that are used in the + demangler are given implementation-reserved names. */ + +#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3) + +#define dyn_string_init __cxa_dyn_string_init +#define dyn_string_new __cxa_dyn_string_new +#define dyn_string_delete __cxa_dyn_string_delete +#define dyn_string_release __cxa_dyn_string_release +#define dyn_string_resize __cxa_dyn_string_resize +#define dyn_string_clear __cxa_dyn_string_clear +#define dyn_string_copy __cxa_dyn_string_copy +#define dyn_string_copy_cstr __cxa_dyn_string_copy_cstr +#define dyn_string_prepend __cxa_dyn_string_prepend +#define dyn_string_prepend_cstr __cxa_dyn_string_prepend_cstr +#define dyn_string_insert __cxa_dyn_string_insert +#define dyn_string_insert_cstr __cxa_dyn_string_insert_cstr +#define dyn_string_insert_char __cxa_dyn_string_insert_char +#define dyn_string_append __cxa_dyn_string_append +#define dyn_string_append_cstr __cxa_dyn_string_append_cstr +#define dyn_string_append_char __cxa_dyn_string_append_char +#define dyn_string_substring __cxa_dyn_string_substring +#define dyn_string_eq __cxa_dyn_string_eq + +#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */ + + +extern int dyn_string_init PARAMS ((struct dyn_string *, int)); +extern dyn_string_t dyn_string_new PARAMS ((int)); +extern void dyn_string_delete PARAMS ((dyn_string_t)); +extern char *dyn_string_release PARAMS ((dyn_string_t)); +extern dyn_string_t dyn_string_resize PARAMS ((dyn_string_t, int)); +extern void dyn_string_clear PARAMS ((dyn_string_t)); +extern int dyn_string_copy PARAMS ((dyn_string_t, dyn_string_t)); +extern int dyn_string_copy_cstr PARAMS ((dyn_string_t, const char *)); +extern int dyn_string_prepend PARAMS ((dyn_string_t, dyn_string_t)); +extern int dyn_string_prepend_cstr PARAMS ((dyn_string_t, const char *)); +extern int dyn_string_insert PARAMS ((dyn_string_t, int, + dyn_string_t)); +extern int dyn_string_insert_cstr PARAMS ((dyn_string_t, int, + const char *)); +extern int dyn_string_insert_char PARAMS ((dyn_string_t, int, int)); +extern int dyn_string_append PARAMS ((dyn_string_t, dyn_string_t)); +extern int dyn_string_append_cstr PARAMS ((dyn_string_t, const char *)); +extern int dyn_string_append_char PARAMS ((dyn_string_t, int)); +extern int dyn_string_substring PARAMS ((dyn_string_t, + dyn_string_t, int, int)); +extern int dyn_string_eq PARAMS ((dyn_string_t, dyn_string_t)); diff --git a/contrib/binutils-2.14/include/elf/alpha.h b/contrib/binutils-2.14/include/elf/alpha.h new file mode 100644 index 0000000000..0313b5be6b --- /dev/null +++ b/contrib/binutils-2.14/include/elf/alpha.h @@ -0,0 +1,126 @@ +/* ALPHA ELF support for BFD. + Copyright 1996, 1998, 2000 Free Software Foundation, Inc. + + By Eric Youngdale, . No processor supplement available + for this platform. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the ALPHA ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_ALPHA_H +#define _ELF_ALPHA_H + +/* Processor specific flags for the ELF header e_flags field. */ + +/* All addresses must be below 2GB. */ +#define EF_ALPHA_32BIT 0x00000001 + +/* All relocations needed for relaxation with code movement are present. */ +#define EF_ALPHA_CANRELAX 0x00000002 + +/* Processor specific section flags. */ + +/* This section must be in the global data area. */ +#define SHF_ALPHA_GPREL 0x10000000 + +/* Section contains some sort of debugging information. The exact + format is unspecified. It's probably ECOFF symbols. */ +#define SHT_ALPHA_DEBUG 0x70000001 + +/* Section contains register usage information. */ +#define SHT_ALPHA_REGINFO 0x70000002 + +/* A section of type SHT_MIPS_REGINFO contains the following + structure. */ +typedef struct +{ + /* Mask of general purpose registers used. */ + unsigned long ri_gprmask; + /* Mask of co-processor registers used. */ + unsigned long ri_cprmask[4]; + /* GP register value for this object file. */ + long ri_gp_value; +} Elf64_RegInfo; + +/* Special values for the st_other field in the symbol table. */ + +#define STO_ALPHA_NOPV 0x80 +#define STO_ALPHA_STD_GPLOAD 0x88 + +#include "elf/reloc-macros.h" + +/* Alpha relocs. */ +START_RELOC_NUMBERS (elf_alpha_reloc_type) + RELOC_NUMBER (R_ALPHA_NONE, 0) /* No reloc */ + RELOC_NUMBER (R_ALPHA_REFLONG, 1) /* Direct 32 bit */ + RELOC_NUMBER (R_ALPHA_REFQUAD, 2) /* Direct 64 bit */ + RELOC_NUMBER (R_ALPHA_GPREL32, 3) /* GP relative 32 bit */ + RELOC_NUMBER (R_ALPHA_LITERAL, 4) /* GP relative 16 bit w/optimization */ + RELOC_NUMBER (R_ALPHA_LITUSE, 5) /* Optimization hint for LITERAL */ + RELOC_NUMBER (R_ALPHA_GPDISP, 6) /* Add displacement to GP */ + RELOC_NUMBER (R_ALPHA_BRADDR, 7) /* PC+4 relative 23 bit shifted */ + RELOC_NUMBER (R_ALPHA_HINT, 8) /* PC+4 relative 16 bit shifted */ + RELOC_NUMBER (R_ALPHA_SREL16, 9) /* PC relative 16 bit */ + RELOC_NUMBER (R_ALPHA_SREL32, 10) /* PC relative 32 bit */ + RELOC_NUMBER (R_ALPHA_SREL64, 11) /* PC relative 64 bit */ + + /* Skip 12 - 16; deprecated ECOFF relocs. */ + + RELOC_NUMBER (R_ALPHA_GPRELHIGH, 17) /* GP relative 32 bit, high 16 bits */ + RELOC_NUMBER (R_ALPHA_GPRELLOW, 18) /* GP relative 32 bit, low 16 bits */ + RELOC_NUMBER (R_ALPHA_GPREL16, 19) /* GP relative 16 bit */ + + /* Skip 20 - 23; deprecated ECOFF relocs. */ + + /* These relocations are specific to shared libraries. */ + RELOC_NUMBER (R_ALPHA_COPY, 24) /* Copy symbol at runtime */ + RELOC_NUMBER (R_ALPHA_GLOB_DAT, 25) /* Create GOT entry */ + RELOC_NUMBER (R_ALPHA_JMP_SLOT, 26) /* Create PLT entry */ + RELOC_NUMBER (R_ALPHA_RELATIVE, 27) /* Adjust by program base */ + + /* Like BRADDR, but assert that the source and target object file + share the same GP value, and adjust the target address for + STO_ALPHA_STD_GPLOAD. */ + RELOC_NUMBER (R_ALPHA_BRSGP, 28) + + /* Thread-Local Storage. */ + RELOC_NUMBER (R_ALPHA_TLSGD, 29) + RELOC_NUMBER (R_ALPHA_TLSLDM, 30) + RELOC_NUMBER (R_ALPHA_DTPMOD64, 31) + RELOC_NUMBER (R_ALPHA_GOTDTPREL, 32) + RELOC_NUMBER (R_ALPHA_DTPREL64, 33) + RELOC_NUMBER (R_ALPHA_DTPRELHI, 34) + RELOC_NUMBER (R_ALPHA_DTPRELLO, 35) + RELOC_NUMBER (R_ALPHA_DTPREL16, 36) + RELOC_NUMBER (R_ALPHA_GOTTPREL, 37) + RELOC_NUMBER (R_ALPHA_TPREL64, 38) + RELOC_NUMBER (R_ALPHA_TPRELHI, 39) + RELOC_NUMBER (R_ALPHA_TPRELLO, 40) + RELOC_NUMBER (R_ALPHA_TPREL16, 41) + +END_RELOC_NUMBERS (R_ALPHA_max) + +#define LITUSE_ALPHA_ADDR 0 +#define LITUSE_ALPHA_BASE 1 +#define LITUSE_ALPHA_BYTOFF 2 +#define LITUSE_ALPHA_JSR 3 +#define LITUSE_ALPHA_TLSGD 4 +#define LITUSE_ALPHA_TLSLDM 5 + +#endif /* _ELF_ALPHA_H */ diff --git a/contrib/binutils-2.14/include/elf/arc.h b/contrib/binutils-2.14/include/elf/arc.h new file mode 100644 index 0000000000..6e94c29dbc --- /dev/null +++ b/contrib/binutils-2.14/include/elf/arc.h @@ -0,0 +1,56 @@ +/* ARC ELF support for BFD. + Copyright 1995, 1997, 1998, 2000, 2001 Free Software Foundation, Inc. + Contributed by Doug Evans, (dje@cygnus.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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the ARC ELF ABI. */ + +#ifndef _ELF_ARC_H +#define _ELF_ARC_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ + +START_RELOC_NUMBERS (elf_arc_reloc_type) + RELOC_NUMBER (R_ARC_NONE, 0) + RELOC_NUMBER (R_ARC_32, 1) + RELOC_NUMBER (R_ARC_B26, 2) + RELOC_NUMBER (R_ARC_B22_PCREL, 3) +END_RELOC_NUMBERS (R_ARC_max) + +/* Processor specific flags for the ELF header e_flags field. */ + +/* Four bit ARC machine type field. */ + +#define EF_ARC_MACH 0x0000000f + +/* Various CPU types. */ + +#define E_ARC_MACH_ARC5 0 +#define E_ARC_MACH_ARC6 1 +#define E_ARC_MACH_ARC7 2 +#define E_ARC_MACH_ARC8 3 + +/* Leave bits 0xf0 alone in case we ever have more than 16 cpu types. */ + +/* File contains position independent code. */ + +#define EF_ARC_PIC 0x00000100 + +#endif /* _ELF_ARC_H */ diff --git a/contrib/binutils-2.14/include/elf/arm.h b/contrib/binutils-2.14/include/elf/arm.h new file mode 100644 index 0000000000..181a9f0c5c --- /dev/null +++ b/contrib/binutils-2.14/include/elf/arm.h @@ -0,0 +1,146 @@ +/* ARM ELF support for BFD. + Copyright 1998, 1999, 2000, 2001, 2002 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_ARM_H +#define _ELF_ARM_H + +#include "elf/reloc-macros.h" + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_ARM_RELEXEC 0x01 +#define EF_ARM_HASENTRY 0x02 +#define EF_ARM_INTERWORK 0x04 +#define EF_ARM_APCS_26 0x08 +#define EF_ARM_APCS_FLOAT 0x10 +#define EF_ARM_PIC 0x20 +#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use. */ +#define EF_ARM_NEW_ABI 0x80 +#define EF_ARM_OLD_ABI 0x100 +#define EF_ARM_SOFT_FLOAT 0x200 +#define EF_ARM_VFP_FLOAT 0x400 +#define EF_ARM_MAVERICK_FLOAT 0x800 + +/* Other constants defined in the ARM ELF spec. version B-01. */ +#define EF_ARM_SYMSARESORTED 0x04 /* NB conflicts with EF_INTERWORK */ +#define EF_ARM_DYNSYMSUSESEGIDX 0x08 /* NB conflicts with EF_APCS26 */ +#define EF_ARM_MAPSYMSFIRST 0x10 /* NB conflicts with EF_APCS_FLOAT */ +#define EF_ARM_EABIMASK 0xFF000000 + +#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) +#define EF_ARM_EABI_UNKNOWN 0x00000000 +#define EF_ARM_EABI_VER1 0x01000000 +#define EF_ARM_EABI_VER2 0x02000000 + +/* Local aliases for some flags to match names used by COFF port. */ +#define F_INTERWORK EF_ARM_INTERWORK +#define F_APCS26 EF_ARM_APCS_26 +#define F_APCS_FLOAT EF_ARM_APCS_FLOAT +#define F_PIC EF_ARM_PIC +#define F_SOFT_FLOAT EF_ARM_SOFT_FLOAT +#define F_VFP_FLOAT EF_ARM_VFP_FLOAT + +/* Additional symbol types for Thumb. */ +#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ +#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ + +/* ARM-specific values for sh_flags. */ +#define SHF_ENTRYSECT 0x10000000 /* Section contains an entry point. */ +#define SHF_COMDEF 0x80000000 /* Section may be multiply defined in the input to a link step. */ + +/* ARM-specific program header flags. */ +#define PF_ARM_SB 0x10000000 /* Segment contains the location addressed by the static base. */ +#define PF_ARM_PI 0x20000000 /* Segment is position-independent. */ +#define PF_ARM_ABS 0x40000000 /* Segment must be loaded at its base address. */ + +/* Relocation types. */ + +START_RELOC_NUMBERS (elf_arm_reloc_type) + RELOC_NUMBER (R_ARM_NONE, 0) + RELOC_NUMBER (R_ARM_PC24, 1) + RELOC_NUMBER (R_ARM_ABS32, 2) + RELOC_NUMBER (R_ARM_REL32, 3) +#ifdef OLD_ARM_ABI + RELOC_NUMBER (R_ARM_ABS8, 4) + RELOC_NUMBER (R_ARM_ABS16, 5) + RELOC_NUMBER (R_ARM_ABS12, 6) + RELOC_NUMBER (R_ARM_THM_ABS5, 7) + RELOC_NUMBER (R_ARM_THM_PC22, 8) + RELOC_NUMBER (R_ARM_SBREL32, 9) + RELOC_NUMBER (R_ARM_AMP_VCALL9, 10) + RELOC_NUMBER (R_ARM_THM_PC11, 11) /* Cygnus extension to abi: Thumb unconditional branch. */ + RELOC_NUMBER (R_ARM_THM_PC9, 12) /* Cygnus extension to abi: Thumb conditional branch. */ + RELOC_NUMBER (R_ARM_GNU_VTINHERIT, 13) + RELOC_NUMBER (R_ARM_GNU_VTENTRY, 14) +#else /* not OLD_ARM_ABI */ + RELOC_NUMBER (R_ARM_PC13, 4) + RELOC_NUMBER (R_ARM_ABS16, 5) + RELOC_NUMBER (R_ARM_ABS12, 6) + RELOC_NUMBER (R_ARM_THM_ABS5, 7) + RELOC_NUMBER (R_ARM_ABS8, 8) + RELOC_NUMBER (R_ARM_SBREL32, 9) + RELOC_NUMBER (R_ARM_THM_PC22, 10) + RELOC_NUMBER (R_ARM_THM_PC8, 11) + RELOC_NUMBER (R_ARM_AMP_VCALL9, 12) + RELOC_NUMBER (R_ARM_SWI24, 13) + RELOC_NUMBER (R_ARM_THM_SWI8, 14) + RELOC_NUMBER (R_ARM_XPC25, 15) + RELOC_NUMBER (R_ARM_THM_XPC22, 16) +#endif /* not OLD_ARM_ABI */ + RELOC_NUMBER (R_ARM_COPY, 20) /* Copy symbol at runtime. */ + RELOC_NUMBER (R_ARM_GLOB_DAT, 21) /* Create GOT entry. */ + RELOC_NUMBER (R_ARM_JUMP_SLOT, 22) /* Create PLT entry. */ + RELOC_NUMBER (R_ARM_RELATIVE, 23) /* Adjust by program base. */ + RELOC_NUMBER (R_ARM_GOTOFF, 24) /* 32 bit offset to GOT. */ + RELOC_NUMBER (R_ARM_GOTPC, 25) /* 32 bit PC relative offset to GOT. */ + RELOC_NUMBER (R_ARM_GOT32, 26) /* 32 bit GOT entry. */ + RELOC_NUMBER (R_ARM_PLT32, 27) /* 32 bit PLT address. */ +#ifdef OLD_ARM_ABI + FAKE_RELOC (FIRST_INVALID_RELOC, 28) + FAKE_RELOC (LAST_INVALID_RELOC, 249) +#else /* not OLD_ARM_ABI */ + FAKE_RELOC (FIRST_INVALID_RELOC1, 28) + FAKE_RELOC (LAST_INVALID_RELOC1, 31) + RELOC_NUMBER (R_ARM_ALU_PCREL7_0, 32) + RELOC_NUMBER (R_ARM_ALU_PCREL15_8, 33) + RELOC_NUMBER (R_ARM_ALU_PCREL23_15, 34) + RELOC_NUMBER (R_ARM_LDR_SBREL11_0, 35) + RELOC_NUMBER (R_ARM_ALU_SBREL19_12, 36) + RELOC_NUMBER (R_ARM_ALU_SBREL27_20, 37) + FAKE_RELOC (FIRST_INVALID_RELOC2, 38) + FAKE_RELOC (LAST_INVALID_RELOC2, 99) + RELOC_NUMBER (R_ARM_GNU_VTENTRY, 100) + RELOC_NUMBER (R_ARM_GNU_VTINHERIT, 101) + RELOC_NUMBER (R_ARM_THM_PC11, 102) /* Cygnus extension to abi: Thumb unconditional branch. */ + RELOC_NUMBER (R_ARM_THM_PC9, 103) /* Cygnus extension to abi: Thumb conditional branch. */ + FAKE_RELOC (FIRST_INVALID_RELOC3, 104) + FAKE_RELOC (LAST_INVALID_RELOC3, 248) + RELOC_NUMBER (R_ARM_RXPC25, 249) +#endif /* not OLD_ARM_ABI */ + RELOC_NUMBER (R_ARM_RSBREL32, 250) + RELOC_NUMBER (R_ARM_THM_RPC22, 251) + RELOC_NUMBER (R_ARM_RREL32, 252) + RELOC_NUMBER (R_ARM_RABS32, 253) + RELOC_NUMBER (R_ARM_RPC24, 254) + RELOC_NUMBER (R_ARM_RBASE, 255) +END_RELOC_NUMBERS (R_ARM_max) + +/* The name of the note section used to identify arm variants. */ +#define ARM_NOTE_SECTION ".note.gnu.arm.ident" + +#endif /* _ELF_ARM_H */ diff --git a/contrib/binutils-2.14/include/elf/avr.h b/contrib/binutils-2.14/include/elf/avr.h new file mode 100644 index 0000000000..59cf073471 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/avr.h @@ -0,0 +1,58 @@ +/* AVR ELF support for BFD. + Copyright 1999, 2000 Free Software Foundation, Inc. + Contributed by Denis Chertykov + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_AVR_H +#define _ELF_AVR_H + +#include "elf/reloc-macros.h" + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_AVR_MACH 0xf + +#define E_AVR_MACH_AVR1 1 +#define E_AVR_MACH_AVR2 2 +#define E_AVR_MACH_AVR3 3 +#define E_AVR_MACH_AVR4 4 +#define E_AVR_MACH_AVR5 5 + +/* Relocations. */ +START_RELOC_NUMBERS (elf_avr_reloc_type) + RELOC_NUMBER (R_AVR_NONE, 0) + RELOC_NUMBER (R_AVR_32, 1) + RELOC_NUMBER (R_AVR_7_PCREL, 2) + RELOC_NUMBER (R_AVR_13_PCREL, 3) + RELOC_NUMBER (R_AVR_16, 4) + RELOC_NUMBER (R_AVR_16_PM, 5) + RELOC_NUMBER (R_AVR_LO8_LDI, 6) + RELOC_NUMBER (R_AVR_HI8_LDI, 7) + RELOC_NUMBER (R_AVR_HH8_LDI, 8) + RELOC_NUMBER (R_AVR_LO8_LDI_NEG, 9) + RELOC_NUMBER (R_AVR_HI8_LDI_NEG, 10) + RELOC_NUMBER (R_AVR_HH8_LDI_NEG, 11) + RELOC_NUMBER (R_AVR_LO8_LDI_PM, 12) + RELOC_NUMBER (R_AVR_HI8_LDI_PM, 13) + RELOC_NUMBER (R_AVR_HH8_LDI_PM, 14) + RELOC_NUMBER (R_AVR_LO8_LDI_PM_NEG, 15) + RELOC_NUMBER (R_AVR_HI8_LDI_PM_NEG, 16) + RELOC_NUMBER (R_AVR_HH8_LDI_PM_NEG, 17) + RELOC_NUMBER (R_AVR_CALL, 18) +END_RELOC_NUMBERS (R_AVR_max) + +#endif /* _ELF_AVR_H */ diff --git a/contrib/binutils-2.14/include/elf/common.h b/contrib/binutils-2.14/include/elf/common.h new file mode 100644 index 0000000000..ca79342860 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/common.h @@ -0,0 +1,690 @@ +/* ELF support for BFD. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 + Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that are common to both the internal and external representations. + For example, ELFMAG0 is the byte 0x7F in both the internal (in-memory) + and external (in-file) representations. */ + +#ifndef _ELF_COMMON_H +#define _ELF_COMMON_H + +/* Fields in e_ident[]. */ + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7F /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +#define EI_CLASS 4 /* File class */ +#define ELFCLASSNONE 0 /* Invalid class */ +#define ELFCLASS32 1 /* 32-bit objects */ +#define ELFCLASS64 2 /* 64-bit objects */ + +#define EI_DATA 5 /* Data encoding */ +#define ELFDATANONE 0 /* Invalid data encoding */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ +#define ELFDATA2MSB 2 /* 2's complement, big endian */ + +#define EI_VERSION 6 /* File version */ + +#define EI_OSABI 7 /* Operating System/ABI indication */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_HPUX 1 /* HP-UX operating system */ +#define ELFOSABI_NETBSD 2 /* NetBSD */ +#define ELFOSABI_LINUX 3 /* GNU/Linux */ +#define ELFOSABI_HURD 4 /* GNU/Hurd */ +#define ELFOSABI_SOLARIS 6 /* Solaris */ +#define ELFOSABI_AIX 7 /* AIX */ +#define ELFOSABI_IRIX 8 /* IRIX */ +#define ELFOSABI_FREEBSD 9 /* FreeBSD */ +#define ELFOSABI_TRU64 10 /* TRU64 UNIX */ +#define ELFOSABI_MODESTO 11 /* Novell Modesto */ +#define ELFOSABI_OPENBSD 12 /* OpenBSD */ +#define ELFOSABI_OPENVMS 13 /* OpenVMS */ +#define ELFOSABI_NSK 14 /* Hewlett-Packard Non-Stop Kernel */ +#define ELFOSABI_AROS 15 /* Amiga Research OS */ +#define ELFOSABI_ARM 97 /* ARM */ +#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Start of padding bytes */ + + +/* Values for e_type, which identifies the object file type. */ + +#define ET_NONE 0 /* No file type */ +#define ET_REL 1 /* Relocatable file */ +#define ET_EXEC 2 /* Executable file */ +#define ET_DYN 3 /* Shared object file */ +#define ET_CORE 4 /* Core file */ +#define ET_LOOS 0xFE00 /* Operating system-specific */ +#define ET_HIOS 0xFEFF /* Operating system-specific */ +#define ET_LOPROC 0xFF00 /* Processor-specific */ +#define ET_HIPROC 0xFFFF /* Processor-specific */ + +/* Values for e_machine, which identifies the architecture. These numbers + are officially assigned by registry@caldera.com. See below for a list of + ad-hoc numbers used during initial development. */ + +#define EM_NONE 0 /* No machine */ +#define EM_M32 1 /* AT&T WE 32100 */ +#define EM_SPARC 2 /* SUN SPARC */ +#define EM_386 3 /* Intel 80386 */ +#define EM_68K 4 /* Motorola m68k family */ +#define EM_88K 5 /* Motorola m88k family */ +#define EM_486 6 /* Intel 80486 *//* Reserved for future use */ +#define EM_860 7 /* Intel 80860 */ +#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ +#define EM_S370 9 /* IBM System/370 */ +#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated */ + +#define EM_PARISC 15 /* HPPA */ + +#define EM_VPP550 17 /* Fujitsu VPP500 */ +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ +#define EM_960 19 /* Intel 80960 */ +#define EM_PPC 20 /* PowerPC */ +#define EM_PPC64 21 /* 64-bit PowerPC */ +#define EM_S390 22 /* IBM S/390 */ + +#define EM_V800 36 /* NEC V800 series */ +#define EM_FR20 37 /* Fujitsu FR20 */ +#define EM_RH32 38 /* TRW RH32 */ +#define EM_MCORE 39 /* Motorola M*Core */ /* May also be taken by Fujitsu MMA */ +#define EM_RCE 39 /* Old name for MCore */ +#define EM_ARM 40 /* ARM */ +#define EM_OLD_ALPHA 41 /* Digital Alpha */ +#define EM_SH 42 /* Renesas (formerly Hitachi) / SuperH SH */ +#define EM_SPARCV9 43 /* SPARC v9 64-bit */ +#define EM_TRICORE 44 /* Siemens Tricore embedded processor */ +#define EM_ARC 45 /* ARC Cores */ +#define EM_H8_300 46 /* Renesas (formerly Hitachi) H8/300 */ +#define EM_H8_300H 47 /* Renesas (formerly Hitachi) H8/300H */ +#define EM_H8S 48 /* Renesas (formerly Hitachi) H8S */ +#define EM_H8_500 49 /* Renesas (formerly Hitachi) H8/500 */ +#define EM_IA_64 50 /* Intel IA-64 Processor */ +#define EM_MIPS_X 51 /* Stanford MIPS-X */ +#define EM_COLDFIRE 52 /* Motorola Coldfire */ +#define EM_68HC12 53 /* Motorola M68HC12 */ +#define EM_MMA 54 /* Fujitsu Multimedia Accelerator */ +#define EM_PCP 55 /* Siemens PCP */ +#define EM_NCPU 56 /* Sony nCPU embedded RISC processor */ +#define EM_NDR1 57 /* Denso NDR1 microprocesspr */ +#define EM_STARCORE 58 /* Motorola Star*Core processor */ +#define EM_ME16 59 /* Toyota ME16 processor */ +#define EM_ST100 60 /* STMicroelectronics ST100 processor */ +#define EM_TINYJ 61 /* Advanced Logic Corp. TinyJ embedded processor */ +#define EM_X86_64 62 /* Advanced Micro Devices X86-64 processor */ + +#define EM_PDP10 64 /* Digital Equipment Corp. PDP-10 */ +#define EM_PDP11 65 /* Digital Equipment Corp. PDP-11 */ +#define EM_FX66 66 /* Siemens FX66 microcontroller */ +#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 bit microcontroller */ +#define EM_ST7 68 /* STMicroelectronics ST7 8-bit microcontroller */ +#define EM_68HC16 69 /* Motorola MC68HC16 Microcontroller */ +#define EM_68HC11 70 /* Motorola MC68HC11 Microcontroller */ +#define EM_68HC08 71 /* Motorola MC68HC08 Microcontroller */ +#define EM_68HC05 72 /* Motorola MC68HC05 Microcontroller */ +#define EM_SVX 73 /* Silicon Graphics SVx */ +#define EM_ST19 74 /* STMicroelectronics ST19 8-bit cpu */ +#define EM_VAX 75 /* Digital VAX */ +#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ +#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded cpu */ +#define EM_FIREPATH 78 /* Element 14 64-bit DSP processor */ +#define EM_ZSP 79 /* LSI Logic's 16-bit DSP processor */ +#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ +#define EM_HUANY 81 /* Harvard's machine-independent format */ +#define EM_PRISM 82 /* SiTera Prism */ +#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ +#define EM_FR30 84 /* Fujitsu FR30 */ +#define EM_D10V 85 /* Mitsubishi D10V */ +#define EM_D30V 86 /* Mitsubishi D30V */ +#define EM_V850 87 /* NEC v850 */ +#define EM_M32R 88 /* Renesas M32R (formerly Mitsubishi M32R) */ +#define EM_MN10300 89 /* Matsushita MN10300 */ +#define EM_MN10200 90 /* Matsushita MN10200 */ +#define EM_PJ 91 /* picoJava */ +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ +#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ +#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ +#define EM_IP2K 101 /* Ubicom IP2022 micro controller */ +#define EM_MSP430 105 /* TI msp430 micro controller */ + +/* If it is necessary to assign new unofficial EM_* values, please pick large + random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision + with official or non-GNU unofficial values. + + NOTE: Do not just increment the most recent number by one. + Somebody else somewhere will do exactly the same thing, and you + will have a collision. Instead, pick a random number. + + Normally, each entity or maintainer responsible for a machine with an + unofficial e_machine number should eventually ask registry@caldera.com for + an officially blessed number to be added to the list above. */ + +#define EM_PJ_OLD 99 /* picoJava */ + +/* Cygnus PowerPC ELF backend. Written in the absence of an ABI. */ +#define EM_CYGNUS_POWERPC 0x9025 + +/* Old version of Sparc v9, from before the ABI; this should be + removed shortly. */ +#define EM_OLD_SPARCV9 11 + +/* Old version of PowerPC, this should be removed shortly. */ +#define EM_PPC_OLD 17 + +/* (Deprecated) Temporary number for the OpenRISC processor. */ +#define EM_OR32 0x8472 + +/* Cygnus M32R ELF backend. Written in the absence of an ABI. */ +#define EM_CYGNUS_M32R 0x9041 + +/* Alpha backend magic number. Written in the absence of an ABI. */ +#define EM_ALPHA 0x9026 + +/* old S/390 backend magic number. Written in the absence of an ABI. */ +#define EM_S390_OLD 0xa390 + +/* D10V backend magic number. Written in the absence of an ABI. */ +#define EM_CYGNUS_D10V 0x7650 + +/* D30V backend magic number. Written in the absence of an ABI. */ +#define EM_CYGNUS_D30V 0x7676 + +/* V850 backend magic number. Written in the absense of an ABI. */ +#define EM_CYGNUS_V850 0x9080 + +/* mn10200 and mn10300 backend magic numbers. + Written in the absense of an ABI. */ +#define EM_CYGNUS_MN10200 0xdead +#define EM_CYGNUS_MN10300 0xbeef + +/* FR30 magic number - no EABI available. */ +#define EM_CYGNUS_FR30 0x3330 + +/* AVR magic number + Written in the absense of an ABI. */ +#define EM_AVR_OLD 0x1057 + +/* OpenRISC magic number + Written in the absense of an ABI. */ +#define EM_OPENRISC_OLD 0x3426 + +/* DLX magic number + Written in the absense of an ABI. */ +#define EM_DLX 0x5aa5 + +#define EM_XSTORMY16 0xad45 + +/* FRV magic number - no EABI available??. */ +#define EM_CYGNUS_FRV 0x5441 + +/* Ubicom IP2xxx; no ABI */ +#define EM_IP2K_OLD 0x8217 + +/* MSP430 magic number + Written in the absense everything. */ +#define EM_MSP430_OLD 0x1059 + +/* Vitesse IQ2000. */ +#define EM_IQ2000 0xFEBA + +/* Old, unofficial value for Xtensa. */ +#define EM_XTENSA_OLD 0xabc7 + +/* See the above comment before you add a new EM_* value here. */ + +/* Values for e_version. */ + +#define EV_NONE 0 /* Invalid ELF version */ +#define EV_CURRENT 1 /* Current version */ + +/* Values for program header, p_type field. */ + +#define PT_NULL 0 /* Program header table entry unused */ +#define PT_LOAD 1 /* Loadable program segment */ +#define PT_DYNAMIC 2 /* Dynamic linking information */ +#define PT_INTERP 3 /* Program interpreter */ +#define PT_NOTE 4 /* Auxiliary information */ +#define PT_SHLIB 5 /* Reserved, unspecified semantics */ +#define PT_PHDR 6 /* Entry for header table itself */ +#define PT_TLS 7 /* Thread local storage segment */ +#define PT_LOOS 0x60000000 /* OS-specific */ +#define PT_HIOS 0x6fffffff /* OS-specific */ +#define PT_LOPROC 0x70000000 /* Processor-specific */ +#define PT_HIPROC 0x7FFFFFFF /* Processor-specific */ + +#define PT_GNU_EH_FRAME (PT_LOOS + 0x474e550) + +/* Program segment permissions, in program header p_flags field. */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ +/* #define PF_MASKOS 0x0F000000 *//* OS-specific reserved bits */ +#define PF_MASKOS 0x0FF00000 /* New value, Oct 4, 1999 Draft */ +#define PF_MASKPROC 0xF0000000 /* Processor-specific reserved bits */ + +/* Values for section header, sh_type field. */ + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program specific (private) data */ +#define SHT_SYMTAB 2 /* Link editing symbol table */ +#define SHT_STRTAB 3 /* A string table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* A symbol hash table */ +#define SHT_DYNAMIC 6 /* Information for dynamic linking */ +#define SHT_NOTE 7 /* Information that marks file */ +#define SHT_NOBITS 8 /* Section occupies no space in file */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved, unspecified semantics */ +#define SHT_DYNSYM 11 /* Dynamic linking symbol table */ + +#define SHT_INIT_ARRAY 14 /* Array of ptrs to init functions */ +#define SHT_FINI_ARRAY 15 /* Array of ptrs to finish functions */ +#define SHT_PREINIT_ARRAY 16 /* Array of ptrs to pre-init funcs */ +#define SHT_GROUP 17 /* Section contains a section group */ +#define SHT_SYMTAB_SHNDX 18 /* Indicies for SHN_XINDEX entries */ + +#define SHT_LOOS 0x60000000 /* First of OS specific semantics */ +#define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ + +#define SHT_GNU_LIBLIST 0x6ffffff7 /* List of prelink dependencies */ + +/* The next three section types are defined by Solaris, and are named + SHT_SUNW*. We use them in GNU code, so we also define SHT_GNU* + versions. */ +#define SHT_SUNW_verdef 0x6ffffffd /* Versions defined by file */ +#define SHT_SUNW_verneed 0x6ffffffe /* Versions needed by file */ +#define SHT_SUNW_versym 0x6fffffff /* Symbol versions */ + +#define SHT_GNU_verdef SHT_SUNW_verdef +#define SHT_GNU_verneed SHT_SUNW_verneed +#define SHT_GNU_versym SHT_SUNW_versym + +#define SHT_LOPROC 0x70000000 /* Processor-specific semantics, lo */ +#define SHT_HIPROC 0x7FFFFFFF /* Processor-specific semantics, hi */ +#define SHT_LOUSER 0x80000000 /* Application-specific semantics */ +/* #define SHT_HIUSER 0x8FFFFFFF *//* Application-specific semantics */ +#define SHT_HIUSER 0xFFFFFFFF /* New value, defined in Oct 4, 1999 Draft */ + +/* Values for section header, sh_flags field. */ + +#define SHF_WRITE (1 << 0) /* Writable data during execution */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable machine instructions */ +#define SHF_MERGE (1 << 4) /* Data in this section can be merged */ +#define SHF_STRINGS (1 << 5) /* Contains null terminated character strings */ +#define SHF_INFO_LINK (1 << 6) /* sh_info holds section header table index */ +#define SHF_LINK_ORDER (1 << 7) /* Preserve section ordering when linking */ +#define SHF_OS_NONCONFORMING (1 << 8) /* OS specific processing required */ +#define SHF_GROUP (1 << 9) /* Member of a section group */ +#define SHF_TLS (1 << 10) /* Thread local storage section */ + +/* #define SHF_MASKOS 0x0F000000 *//* OS-specific semantics */ +#define SHF_MASKOS 0x0FF00000 /* New value, Oct 4, 1999 Draft */ +#define SHF_MASKPROC 0xF0000000 /* Processor-specific semantics */ + +/* Values of note segment descriptor types for core files. */ + +#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ +#define NT_FPREGSET 2 /* Contains copy of fpregset struct */ +#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ +#define NT_TASKSTRUCT 4 /* Contains copy of task struct */ +#define NT_PRXFPREG 0x46e62b7f /* Contains a user_xfpregs_struct; */ + /* note name must be "LINUX". */ + +/* Note segments for core files on dir-style procfs systems. */ + +#define NT_PSTATUS 10 /* Has a struct pstatus */ +#define NT_FPREGS 12 /* Has a struct fpregset */ +#define NT_PSINFO 13 /* Has a struct psinfo */ +#define NT_LWPSTATUS 16 /* Has a struct lwpstatus_t */ +#define NT_LWPSINFO 17 /* Has a struct lwpsinfo_t */ +#define NT_WIN32PSTATUS 18 /* Has a struct win32_pstatus */ + + +/* Note segments for core files on NetBSD systems. Note name + must start with "NetBSD-CORE". */ + +#define NT_NETBSDCORE_PROCINFO 1 /* Has a struct procinfo */ +#define NT_NETBSDCORE_FIRSTMACH 32 /* start of machdep note types */ + + +/* Values of note segment descriptor types for object files. */ + +#define NT_VERSION 1 /* Contains a version string. */ +#define NT_ARCH 2 /* Contains an architecture string. */ + +/* Values for GNU .note.ABI-tag notes. Note name is "GNU". */ + +#define NT_GNU_ABI_TAG 1 +#define GNU_ABI_TAG_LINUX 0 +#define GNU_ABI_TAG_HURD 1 +#define GNU_ABI_TAG_SOLARIS 2 + +/* Values for NetBSD .note.netbsd.ident notes. Note name is "NetBSD". */ + +#define NT_NETBSD_IDENT 1 + +/* Values for FreeBSD .note.ABI-tag notes. Note name is "FreeBSD". */ + +#define NT_FREEBSD_ABI_TAG 1 + +/* These three macros disassemble and assemble a symbol table st_info field, + which contains the symbol binding and symbol type. The STB_ and STT_ + defines identify the binding and type. */ + +#define ELF_ST_BIND(val) (((unsigned int)(val)) >> 4) +#define ELF_ST_TYPE(val) ((val) & 0xF) +#define ELF_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xF)) + +/* The 64bit and 32bit versions of these macros are identical, but + the ELF spec defines them, so here they are. */ +#define ELF32_ST_BIND ELF_ST_BIND +#define ELF32_ST_TYPE ELF_ST_TYPE +#define ELF32_ST_INFO ELF_ST_INFO +#define ELF64_ST_BIND ELF_ST_BIND +#define ELF64_ST_TYPE ELF_ST_TYPE +#define ELF64_ST_INFO ELF_ST_INFO + +/* This macro disassembles and assembles a symbol's visibility into + the st_other field. The STV_ defines specificy the actual visibility. */ + +#define ELF_ST_VISIBILITY(v) ((v) & 0x3) +/* The remaining bits in the st_other field are not currently used. + They should be set to zero. */ + +#define ELF32_ST_VISIBILITY ELF_ST_VISIBILITY +#define ELF64_ST_VISIBILITY ELF_ST_VISIBILITY + + +#define STN_UNDEF 0 /* Undefined symbol index */ + +#define STB_LOCAL 0 /* Symbol not visible outside obj */ +#define STB_GLOBAL 1 /* Symbol visible outside obj */ +#define STB_WEAK 2 /* Like globals, lower precedence */ +#define STB_LOOS 10 /* OS-specific semantics */ +#define STB_HIOS 12 /* OS-specific semantics */ +#define STB_LOPROC 13 /* Application-specific semantics */ +#define STB_HIPROC 15 /* Application-specific semantics */ + +#define STT_NOTYPE 0 /* Symbol type is unspecified */ +#define STT_OBJECT 1 /* Symbol is a data object */ +#define STT_FUNC 2 /* Symbol is a code object */ +#define STT_SECTION 3 /* Symbol associated with a section */ +#define STT_FILE 4 /* Symbol gives a file name */ +#define STT_COMMON 5 /* An uninitialised common block */ +#define STT_TLS 6 /* Thread local data object */ +#define STT_LOOS 10 /* OS-specific semantics */ +#define STT_HIOS 12 /* OS-specific semantics */ +#define STT_LOPROC 13 /* Application-specific semantics */ +#define STT_HIPROC 15 /* Application-specific semantics */ + +/* Special section indices, which may show up in st_shndx fields, among + other places. */ + +#define SHN_UNDEF 0 /* Undefined section reference */ +#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ +#define SHN_LOPROC 0xFF00 /* Begin range of appl-specific */ +#define SHN_HIPROC 0xFF1F /* End range of appl-specific */ +#define SHN_LOOS 0xFF20 /* OS specific semantics, lo */ +#define SHN_HIOS 0xFF3F /* OS specific semantics, hi */ +#define SHN_ABS 0xFFF1 /* Associated symbol is absolute */ +#define SHN_COMMON 0xFFF2 /* Associated symbol is in common */ +#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ +#define SHN_HIRESERVE 0xFFFF /* End range of reserved indices */ +#define SHN_BAD ((unsigned) -1) /* Used internally by bfd */ + +/* The following constants control how a symbol may be accessed once it has + become part of an executable or shared library. */ + +#define STV_DEFAULT 0 /* Visibility is specified by binding type */ +#define STV_INTERNAL 1 /* OS specific version of STV_HIDDEN */ +#define STV_HIDDEN 2 /* Can only be seen inside currect component */ +#define STV_PROTECTED 3 /* Treat as STB_LOCAL inside current component */ + +/* Relocation info handling macros. */ + +#define ELF32_R_SYM(i) ((i) >> 8) +#define ELF32_R_TYPE(i) ((i) & 0xff) +#define ELF32_R_INFO(s,t) (((s) << 8) + ((t) & 0xff)) + +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffff) +#define ELF64_R_INFO(s,t) (((bfd_vma) (s) << 32) + (bfd_vma) (t)) + +/* Dynamic section tags. */ + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_BIND_NOW 24 +#define DT_INIT_ARRAY 25 +#define DT_FINI_ARRAY 26 +#define DT_INIT_ARRAYSZ 27 +#define DT_FINI_ARRAYSZ 28 +#define DT_RUNPATH 29 +#define DT_FLAGS 30 +#define DT_ENCODING 31 +#define DT_PREINIT_ARRAY 32 +#define DT_PREINIT_ARRAYSZ 33 + +/* Note, the Oct 4, 1999 draft of the ELF ABI changed the values + for DT_LOOS and DT_HIOS. Some implementations however, use + values outside of the new range (see below). */ +#define OLD_DT_LOOS 0x60000000 +#define DT_LOOS 0x6000000d +#define DT_HIOS 0x6fff0000 +#define OLD_DT_HIOS 0x6fffffff + +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* The next four dynamic tags are used on Solaris. We support them + everywhere. Note these values lie outside of the (new) range for + OS specific values. This is a deliberate special case and we + maintain it for backwards compatability. */ +#define DT_VALRNGLO 0x6ffffd00 +#define DT_GNU_PRELINKED 0x6ffffdf5 +#define DT_GNU_CONFLICTSZ 0x6ffffdf6 +#define DT_GNU_LIBLISTSZ 0x6ffffdf7 +#define DT_CHECKSUM 0x6ffffdf8 +#define DT_PLTPADSZ 0x6ffffdf9 +#define DT_MOVEENT 0x6ffffdfa +#define DT_MOVESZ 0x6ffffdfb +#define DT_FEATURE 0x6ffffdfc +#define DT_POSFLAG_1 0x6ffffdfd +#define DT_SYMINSZ 0x6ffffdfe +#define DT_SYMINENT 0x6ffffdff +#define DT_VALRNGHI 0x6ffffdff + +#define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_CONFLICT 0x6ffffef8 +#define DT_GNU_LIBLIST 0x6ffffef9 +#define DT_CONFIG 0x6ffffefa +#define DT_DEPAUDIT 0x6ffffefb +#define DT_AUDIT 0x6ffffefc +#define DT_PLTPAD 0x6ffffefd +#define DT_MOVETAB 0x6ffffefe +#define DT_SYMINFO 0x6ffffeff +#define DT_ADDRRNGHI 0x6ffffeff + +#define DT_RELACOUNT 0x6ffffff9 +#define DT_RELCOUNT 0x6ffffffa +#define DT_FLAGS_1 0x6ffffffb +#define DT_VERDEF 0x6ffffffc +#define DT_VERDEFNUM 0x6ffffffd +#define DT_VERNEED 0x6ffffffe +#define DT_VERNEEDNUM 0x6fffffff + +/* This tag is a GNU extension to the Solaris version scheme. */ +#define DT_VERSYM 0x6ffffff0 + +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* These section tags are used on Solaris. We support them + everywhere, and hope they do not conflict. */ + +#define DT_AUXILIARY 0x7ffffffd +#define DT_USED 0x7ffffffe +#define DT_FILTER 0x7fffffff + + +/* Values used in DT_FEATURE .dynamic entry. */ +#define DTF_1_PARINIT 0x00000001 +/* From + + http://docs.sun.com:80/ab2/coll.45.13/LLM/@Ab2PageView/21165?Ab2Lang=C&Ab2Enc=iso-8859-1 + + DTF_1_CONFEXP is the same as DTF_1_PARINIT. It is a typo. The value + defined here is the same as the one in on Solaris 8. */ +#define DTF_1_CONFEXP 0x00000002 + +/* Flag values used in the DT_POSFLAG_1 .dynamic entry. */ +#define DF_P1_LAZYLOAD 0x00000001 +#define DF_P1_GROUPPERM 0x00000002 + +/* Flag value in in the DT_FLAGS_1 .dynamic entry. */ +#define DF_1_NOW 0x00000001 +#define DF_1_GLOBAL 0x00000002 +#define DF_1_GROUP 0x00000004 +#define DF_1_NODELETE 0x00000008 +#define DF_1_LOADFLTR 0x00000010 +#define DF_1_INITFIRST 0x00000020 +#define DF_1_NOOPEN 0x00000040 +#define DF_1_ORIGIN 0x00000080 +#define DF_1_DIRECT 0x00000100 +#define DF_1_TRANS 0x00000200 +#define DF_1_INTERPOSE 0x00000400 +#define DF_1_NODEFLIB 0x00000800 +#define DF_1_NODUMP 0x00001000 +#define DF_1_CONLFAT 0x00002000 + +/* Flag values for the DT_FLAGS entry. */ +#define DF_ORIGIN (1 << 0) +#define DF_SYMBOLIC (1 << 1) +#define DF_TEXTREL (1 << 2) +#define DF_BIND_NOW (1 << 3) +#define DF_STATIC_TLS (1 << 4) + +/* These constants are used for the version number of a Elf32_Verdef + structure. */ + +#define VER_DEF_NONE 0 +#define VER_DEF_CURRENT 1 + +/* These constants appear in the vd_flags field of a Elf32_Verdef + structure. */ + +#define VER_FLG_BASE 0x1 +#define VER_FLG_WEAK 0x2 + +/* These special constants can be found in an Elf32_Versym field. */ + +#define VER_NDX_LOCAL 0 +#define VER_NDX_GLOBAL 1 + +/* These constants are used for the version number of a Elf32_Verneed + structure. */ + +#define VER_NEED_NONE 0 +#define VER_NEED_CURRENT 1 + +/* This flag appears in a Versym structure. It means that the symbol + is hidden, and is only visible with an explicit version number. + This is a GNU extension. */ + +#define VERSYM_HIDDEN 0x8000 + +/* This is the mask for the rest of the Versym information. */ + +#define VERSYM_VERSION 0x7fff + +/* This is a special token which appears as part of a symbol name. It + indictes that the rest of the name is actually the name of a + version node, and is not part of the actual name. This is a GNU + extension. For example, the symbol name `stat@ver2' is taken to + mean the symbol `stat' in version `ver2'. */ + +#define ELF_VER_CHR '@' + +/* Possible values for si_boundto. */ + +#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ +#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ +#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ + +/* Possible bitmasks for si_flags. */ + +#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ +#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ +#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ +#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy loaded */ + +/* Syminfo version values. */ + +#define SYMINFO_NONE 0 +#define SYMINFO_CURRENT 1 +#define SYMINFO_NUM 2 + +/* Section Group Flags. */ + +#define GRP_COMDAT 0x1 /* A COMDAT group */ + +#endif /* _ELF_COMMON_H */ diff --git a/contrib/binutils-2.14/include/elf/cris.h b/contrib/binutils-2.14/include/elf/cris.h new file mode 100644 index 0000000000..3bd03e8aa8 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/cris.h @@ -0,0 +1,101 @@ +/* CRIS ELF support for BFD. + Copyright 2000, 2001 Free Software Foundation, Inc. + Contributed by Axis Communications AB, Lund, Sweden. + Written by Hans-Peter Nilsson. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_CRIS_H +#define _ELF_CRIS_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_cris_reloc_type) + RELOC_NUMBER (R_CRIS_NONE, 0) + RELOC_NUMBER (R_CRIS_8, 1) + RELOC_NUMBER (R_CRIS_16, 2) + RELOC_NUMBER (R_CRIS_32, 3) + + /* The "PC" position is the location right after the relocation. */ + RELOC_NUMBER (R_CRIS_8_PCREL, 4) + RELOC_NUMBER (R_CRIS_16_PCREL, 5) + RELOC_NUMBER (R_CRIS_32_PCREL, 6) + + RELOC_NUMBER (R_CRIS_GNU_VTINHERIT, 7) + RELOC_NUMBER (R_CRIS_GNU_VTENTRY, 8) + + /* Copy contents at dynlinking. Generated by the linker. + The BFD equivalent is BFD_RELOC_CRIS_COPY. */ + RELOC_NUMBER (R_CRIS_COPY, 9) + + /* Create GOT entry. Generated by the linker. + The BFD equivalent is BFD_RELOC_CRIS_GLOB_DAT. */ + RELOC_NUMBER (R_CRIS_GLOB_DAT, 10) + + /* Create PLT entry. Generated by the linker. + The BFD equivalent is BFD_RELOC_CRIS_JUMP_SLOT. */ + RELOC_NUMBER (R_CRIS_JUMP_SLOT, 11) + + /* Adjust by program base. Generated by the linker. + The BFD equivalent is BFD_RELOC_CRIS_RELATIVE. */ + RELOC_NUMBER (R_CRIS_RELATIVE, 12) + + /* A 16-bit offset to entry in GOT and request to create GOT entry for + that symbol. + The BFD equivalent is BFD_RELOC_CRIS_16_GOT. */ + RELOC_NUMBER (R_CRIS_16_GOT, 13) + + /* A 32-bit offset to entry in GOT and request to create GOT entry for + that symbol. + The BFD equivalent is BFD_RELOC_CRIS_32_GOT. */ + RELOC_NUMBER (R_CRIS_32_GOT, 14) + + /* A 16-bit offset to entry in PLT part of GOT and request to create PLT + entry for that symbol. + The BFD equivalent is BFD_RELOC_CRIS_16_GOTPLT. */ + RELOC_NUMBER (R_CRIS_16_GOTPLT, 15) + + /* A 32-bit offset to entry in PLT part of GOT and request to create PLT + entry for that symbol. + The BFD equivalent is BFD_RELOC_CRIS_32_GOTPLT. */ + RELOC_NUMBER (R_CRIS_32_GOTPLT, 16) + + /* A 32-bit offset from GOT to (local) symbol: no GOT entry should be + necessary. + The BFD equivalent is BFD_RELOC_CRIS_32_GOTREL. */ + RELOC_NUMBER (R_CRIS_32_GOTREL, 17) + + /* A 32-bit offset from GOT to entry for this symbol in PLT and request + to create PLT entry for symbol. + The BFD equivalent is BFD_RELOC_CRIS_32_GOTREL. */ + RELOC_NUMBER (R_CRIS_32_PLT_GOTREL, 18) + + /* A 32-bit offset from location after this relocation (addend specifies + offset) to entry for this symbol in PLT and request to create PLT + entry for symbol. + The BFD equivalent is BFD_RELOC_CRIS_32_PLT_PCREL. */ + RELOC_NUMBER (R_CRIS_32_PLT_PCREL, 19) + + /* No other relocs must be visible outside the assembler. */ + +END_RELOC_NUMBERS (R_CRIS_max) + +/* User symbols in this file have a leading underscore. */ +#define EF_CRIS_UNDERSCORE 0x00000001 + +#endif /* _ELF_CRIS_H */ diff --git a/contrib/binutils-2.14/include/elf/d10v.h b/contrib/binutils-2.14/include/elf/d10v.h new file mode 100644 index 0000000000..5bc613bc3b --- /dev/null +++ b/contrib/binutils-2.14/include/elf/d10v.h @@ -0,0 +1,38 @@ +/* d10v ELF support for BFD. + Copyright 1998, 2000 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_D10V_H +#define _ELF_D10V_H + +#include "elf/reloc-macros.h" + +/* Relocation types. */ +START_RELOC_NUMBERS (elf_d10v_reloc_type) + RELOC_NUMBER (R_D10V_NONE, 0) + RELOC_NUMBER (R_D10V_10_PCREL_R, 1) + RELOC_NUMBER (R_D10V_10_PCREL_L, 2) + RELOC_NUMBER (R_D10V_16, 3) + RELOC_NUMBER (R_D10V_18, 4) + RELOC_NUMBER (R_D10V_18_PCREL, 5) + RELOC_NUMBER (R_D10V_32, 6) + RELOC_NUMBER (R_D10V_GNU_VTINHERIT, 7) + RELOC_NUMBER (R_D10V_GNU_VTENTRY, 8) +END_RELOC_NUMBERS (R_D10V_max) + +#endif diff --git a/contrib/binutils-2.14/include/elf/d30v.h b/contrib/binutils-2.14/include/elf/d30v.h new file mode 100644 index 0000000000..5abb06a551 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/d30v.h @@ -0,0 +1,42 @@ +/* d30v ELF support for BFD. + Copyright 1998, 2000 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_D30V_H +#define _ELF_D30V_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_d30v_reloc_type) + RELOC_NUMBER (R_D30V_NONE, 0) + RELOC_NUMBER (R_D30V_6, 1) + RELOC_NUMBER (R_D30V_9_PCREL, 2) + RELOC_NUMBER (R_D30V_9_PCREL_R, 3) + RELOC_NUMBER (R_D30V_15, 4) + RELOC_NUMBER (R_D30V_15_PCREL, 5) + RELOC_NUMBER (R_D30V_15_PCREL_R, 6) + RELOC_NUMBER (R_D30V_21, 7) + RELOC_NUMBER (R_D30V_21_PCREL, 8) + RELOC_NUMBER (R_D30V_21_PCREL_R, 9) + RELOC_NUMBER (R_D30V_32, 10) + RELOC_NUMBER (R_D30V_32_PCREL, 11) + RELOC_NUMBER (R_D30V_32_NORMAL, 12) +END_RELOC_NUMBERS (R_D30V_max) + +#endif diff --git a/contrib/binutils-2.14/include/elf/dlx.h b/contrib/binutils-2.14/include/elf/dlx.h new file mode 100644 index 0000000000..562f600f35 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/dlx.h @@ -0,0 +1,53 @@ +/* DLX support for BFD. + Copyright 2002 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_DLX_H +#define _ELF_DLX_H + +#include "elf/reloc-macros.h" + +#if 0 +START_RELOC_NUMBERS (elf_dlx_reloc_type) + RELOC_NUMBER (R_DLX_NONE, 0) + RELOC_NUMBER (R_DLX_RELOC_16, 1) + RELOC_NUMBER (R_DLX_RELOC_26, 2) + RELOC_NUMBER (R_DLX_RELOC_32, 3) + RELOC_NUMBER (R_DLX_GNU_VTINHERIT, 4) + RELOC_NUMBER (R_DLX_GNU_VTENTRY, 5) + RELOC_NUMBER (R_DLX_RELOC_16_HI, 6) + RELOC_NUMBER (R_DLX_RELOC_16_LO, 7) + RELOC_NUMBER (R_DLX_RELOC_16_PCREL, 8) + RELOC_NUMBER (R_DLX_RELOC_26_PCREL, 9) +END_RELOC_NUMBERS (R_DLX_max) +#else +START_RELOC_NUMBERS (elf_dlx_reloc_type) + RELOC_NUMBER (R_DLX_NONE, 0) + RELOC_NUMBER (R_DLX_RELOC_8, 1) + RELOC_NUMBER (R_DLX_RELOC_16, 2) + RELOC_NUMBER (R_DLX_RELOC_32, 3) + RELOC_NUMBER (R_DLX_GNU_VTINHERIT, 4) + RELOC_NUMBER (R_DLX_GNU_VTENTRY, 5) + RELOC_NUMBER (R_DLX_RELOC_16_HI, 6) + RELOC_NUMBER (R_DLX_RELOC_16_LO, 7) + RELOC_NUMBER (R_DLX_RELOC_16_PCREL, 8) + RELOC_NUMBER (R_DLX_RELOC_26_PCREL, 9) +END_RELOC_NUMBERS (R_DLX_max) +#endif /* 0 */ + +#endif /* _ELF_DLX_H */ diff --git a/contrib/binutils-2.14/include/elf/dwarf.h b/contrib/binutils-2.14/include/elf/dwarf.h new file mode 100644 index 0000000000..f79397253a --- /dev/null +++ b/contrib/binutils-2.14/include/elf/dwarf.h @@ -0,0 +1,320 @@ +/* Declarations and definitions of codes relating to the DWARF symbolic + debugging information format. + + Written by Ron Guilmette (rfg@ncd.com) + +Copyright 1992, 1993, 1995, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 1.0.1 (April 8, 1992) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. +*/ + +#ifndef _ELF_DWARF_H +#define _ELF_DWARF_H + +/* Tag names and codes. */ + +enum dwarf_tag { + TAG_padding = 0x0000, + TAG_array_type = 0x0001, + TAG_class_type = 0x0002, + TAG_entry_point = 0x0003, + TAG_enumeration_type = 0x0004, + TAG_formal_parameter = 0x0005, + TAG_global_subroutine = 0x0006, + TAG_global_variable = 0x0007, + /* 0x0008 -- reserved */ + /* 0x0009 -- reserved */ + TAG_label = 0x000a, + TAG_lexical_block = 0x000b, + TAG_local_variable = 0x000c, + TAG_member = 0x000d, + /* 0x000e -- reserved */ + TAG_pointer_type = 0x000f, + TAG_reference_type = 0x0010, + TAG_compile_unit = 0x0011, + TAG_string_type = 0x0012, + TAG_structure_type = 0x0013, + TAG_subroutine = 0x0014, + TAG_subroutine_type = 0x0015, + TAG_typedef = 0x0016, + TAG_union_type = 0x0017, + TAG_unspecified_parameters = 0x0018, + TAG_variant = 0x0019, + TAG_common_block = 0x001a, + TAG_common_inclusion = 0x001b, + TAG_inheritance = 0x001c, + TAG_inlined_subroutine = 0x001d, + TAG_module = 0x001e, + TAG_ptr_to_member_type = 0x001f, + TAG_set_type = 0x0020, + TAG_subrange_type = 0x0021, + TAG_with_stmt = 0x0022, + + /* GNU extensions */ + + TAG_format_label = 0x8000, /* for FORTRAN 77 and Fortran 90 */ + TAG_namelist = 0x8001, /* For Fortran 90 */ + TAG_function_template = 0x8002, /* for C++ */ + TAG_class_template = 0x8003 /* for C++ */ +}; + +#define TAG_lo_user 0x8000 /* implementation-defined range start */ +#define TAG_hi_user 0xffff /* implementation-defined range end */ +#define TAG_source_file TAG_compile_unit /* for backward compatibility */ + +/* Form names and codes. */ + +enum dwarf_form { + FORM_ADDR = 0x1, + FORM_REF = 0x2, + FORM_BLOCK2 = 0x3, + FORM_BLOCK4 = 0x4, + FORM_DATA2 = 0x5, + FORM_DATA4 = 0x6, + FORM_DATA8 = 0x7, + FORM_STRING = 0x8 +}; + +/* Attribute names and codes. */ + +enum dwarf_attribute { + AT_sibling = (0x0010|FORM_REF), + AT_location = (0x0020|FORM_BLOCK2), + AT_name = (0x0030|FORM_STRING), + AT_fund_type = (0x0050|FORM_DATA2), + AT_mod_fund_type = (0x0060|FORM_BLOCK2), + AT_user_def_type = (0x0070|FORM_REF), + AT_mod_u_d_type = (0x0080|FORM_BLOCK2), + AT_ordering = (0x0090|FORM_DATA2), + AT_subscr_data = (0x00a0|FORM_BLOCK2), + AT_byte_size = (0x00b0|FORM_DATA4), + AT_bit_offset = (0x00c0|FORM_DATA2), + AT_bit_size = (0x00d0|FORM_DATA4), + /* (0x00e0|FORM_xxxx) -- reserved */ + AT_element_list = (0x00f0|FORM_BLOCK4), + AT_stmt_list = (0x0100|FORM_DATA4), + AT_low_pc = (0x0110|FORM_ADDR), + AT_high_pc = (0x0120|FORM_ADDR), + AT_language = (0x0130|FORM_DATA4), + AT_member = (0x0140|FORM_REF), + AT_discr = (0x0150|FORM_REF), + AT_discr_value = (0x0160|FORM_BLOCK2), + /* (0x0170|FORM_xxxx) -- reserved */ + /* (0x0180|FORM_xxxx) -- reserved */ + AT_string_length = (0x0190|FORM_BLOCK2), + AT_common_reference = (0x01a0|FORM_REF), + AT_comp_dir = (0x01b0|FORM_STRING), + AT_const_value_string = (0x01c0|FORM_STRING), + AT_const_value_data2 = (0x01c0|FORM_DATA2), + AT_const_value_data4 = (0x01c0|FORM_DATA4), + AT_const_value_data8 = (0x01c0|FORM_DATA8), + AT_const_value_block2 = (0x01c0|FORM_BLOCK2), + AT_const_value_block4 = (0x01c0|FORM_BLOCK4), + AT_containing_type = (0x01d0|FORM_REF), + AT_default_value_addr = (0x01e0|FORM_ADDR), + AT_default_value_data2 = (0x01e0|FORM_DATA2), + AT_default_value_data4 = (0x01e0|FORM_DATA4), + AT_default_value_data8 = (0x01e0|FORM_DATA8), + AT_default_value_string = (0x01e0|FORM_STRING), + AT_friends = (0x01f0|FORM_BLOCK2), + AT_inline = (0x0200|FORM_STRING), + AT_is_optional = (0x0210|FORM_STRING), + AT_lower_bound_ref = (0x0220|FORM_REF), + AT_lower_bound_data2 = (0x0220|FORM_DATA2), + AT_lower_bound_data4 = (0x0220|FORM_DATA4), + AT_lower_bound_data8 = (0x0220|FORM_DATA8), + AT_private = (0x0240|FORM_STRING), + AT_producer = (0x0250|FORM_STRING), + AT_program = (0x0230|FORM_STRING), + AT_protected = (0x0260|FORM_STRING), + AT_prototyped = (0x0270|FORM_STRING), + AT_public = (0x0280|FORM_STRING), + AT_pure_virtual = (0x0290|FORM_STRING), + AT_return_addr = (0x02a0|FORM_BLOCK2), + AT_abstract_origin = (0x02b0|FORM_REF), + AT_start_scope = (0x02c0|FORM_DATA4), + AT_stride_size = (0x02e0|FORM_DATA4), + AT_upper_bound_ref = (0x02f0|FORM_REF), + AT_upper_bound_data2 = (0x02f0|FORM_DATA2), + AT_upper_bound_data4 = (0x02f0|FORM_DATA4), + AT_upper_bound_data8 = (0x02f0|FORM_DATA8), + AT_virtual = (0x0300|FORM_STRING), + + /* GNU extensions. */ + + AT_sf_names = (0x8000|FORM_DATA4), + AT_src_info = (0x8010|FORM_DATA4), + AT_mac_info = (0x8020|FORM_DATA4), + AT_src_coords = (0x8030|FORM_DATA4), + AT_body_begin = (0x8040|FORM_ADDR), + AT_body_end = (0x8050|FORM_ADDR) +}; + +#define AT_lo_user 0x8000 /* implementation-defined range start */ +#define AT_hi_user 0xffff /* implementation-defined range end */ + +/* Location atom names and codes. */ + +enum dwarf_location_atom { + OP_REG = 0x01, + OP_BASEREG = 0x02, + OP_ADDR = 0x03, + OP_CONST = 0x04, + OP_DEREF2 = 0x05, + OP_DEREF4 = 0x06, + OP_ADD = 0x07 +}; + +#define OP_LO_USER 0x80 /* implementation-defined range start */ +#define OP_HI_USER 0xff /* implementation-defined range end */ + +/* Fundamental type names and codes. */ + +enum dwarf_fundamental_type { + FT_char = 0x0001, + FT_signed_char = 0x0002, + FT_unsigned_char = 0x0003, + FT_short = 0x0004, + FT_signed_short = 0x0005, + FT_unsigned_short = 0x0006, + FT_integer = 0x0007, + FT_signed_integer = 0x0008, + FT_unsigned_integer = 0x0009, + FT_long = 0x000a, + FT_signed_long = 0x000b, + FT_unsigned_long = 0x000c, + FT_pointer = 0x000d, /* an alias for (void *) */ + FT_float = 0x000e, + FT_dbl_prec_float = 0x000f, + FT_ext_prec_float = 0x0010, /* breaks "classic" svr4 SDB */ + FT_complex = 0x0011, /* breaks "classic" svr4 SDB */ + FT_dbl_prec_complex = 0x0012, /* breaks "classic" svr4 SDB */ + /* 0x0013 -- reserved */ + FT_void = 0x0014, + FT_boolean = 0x0015, /* breaks "classic" svr4 SDB */ + FT_ext_prec_complex = 0x0016, /* breaks "classic" svr4 SDB */ + FT_label = 0x0017, + + /* GNU extensions + The low order byte must indicate the size (in bytes) for the type. + All of these types will probably break "classic" svr4 SDB */ + + FT_long_long = 0x8008, + FT_signed_long_long = 0x8108, + FT_unsigned_long_long = 0x8208, + + FT_int8 = 0x9001, + FT_signed_int8 = 0x9101, + FT_unsigned_int8 = 0x9201, + FT_int16 = 0x9302, + FT_signed_int16 = 0x9402, + FT_unsigned_int16 = 0x9502, + FT_int32 = 0x9604, + FT_signed_int32 = 0x9704, + FT_unsigned_int32 = 0x9804, + FT_int64 = 0x9908, + FT_signed_int64 = 0x9a08, + FT_unsigned_int64 = 0x9b08, + + FT_real32 = 0xa004, + FT_real64 = 0xa108, + FT_real96 = 0xa20c, + FT_real128 = 0xa310 +}; + +#define FT_lo_user 0x8000 /* implementation-defined range start */ +#define FT_hi_user 0xffff /* implementation defined range end */ + +/* Type modifier names and codes. */ + +enum dwarf_type_modifier { + MOD_pointer_to = 0x01, + MOD_reference_to = 0x02, + MOD_const = 0x03, + MOD_volatile = 0x04 +}; + +#define MOD_lo_user 0x80 /* implementation-defined range start */ +#define MOD_hi_user 0xff /* implementation-defined range end */ + +/* Array ordering names and codes. */ + +enum dwarf_array_dim_ordering { + ORD_row_major = 0, + ORD_col_major = 1 +}; + +/* Array subscript format names and codes. */ + +enum dwarf_subscr_data_formats { + FMT_FT_C_C = 0x0, + FMT_FT_C_X = 0x1, + FMT_FT_X_C = 0x2, + FMT_FT_X_X = 0x3, + FMT_UT_C_C = 0x4, + FMT_UT_C_X = 0x5, + FMT_UT_X_C = 0x6, + FMT_UT_X_X = 0x7, + FMT_ET = 0x8 +}; + +/* Derived from above for ease of use. */ + +#define FMT_CODE(_FUNDAMENTAL_TYPE_P, _UB_CONST_P, _LB_CONST_P) \ + (((_FUNDAMENTAL_TYPE_P) ? 0 : 4) \ + | ((_UB_CONST_P) ? 0 : 2) \ + | ((_LB_CONST_P) ? 0 : 1)) + +/* Source language names and codes. */ + +enum dwarf_source_language { + LANG_C89 = 0x00000001, + LANG_C = 0x00000002, + LANG_ADA83 = 0x00000003, + LANG_C_PLUS_PLUS = 0x00000004, + LANG_COBOL74 = 0x00000005, + LANG_COBOL85 = 0x00000006, + LANG_FORTRAN77 = 0x00000007, + LANG_FORTRAN90 = 0x00000008, + LANG_PASCAL83 = 0x00000009, + LANG_MODULA2 = 0x0000000a, + + /* GNU extensions */ + + LANG_CHILL = 0x00009af3, /* random value for GNU Chill */ + LANG_JAVA = 0x00009af4 /* random value + 1 for GNU Java */ +}; + +#define LANG_lo_user 0x00008000 /* implementation-defined range start */ +#define LANG_hi_user 0x0000ffff /* implementation-defined range end */ + +/* Names and codes for GNU "macinfo" extension. */ + +enum dwarf_macinfo_record_type { + MACINFO_start = 's', + MACINFO_resume = 'r', + MACINFO_define = 'd', + MACINFO_undef = 'u' +}; + +#endif /* _ELF_DWARF_H */ diff --git a/contrib/binutils-2.14/include/elf/dwarf2.h b/contrib/binutils-2.14/include/elf/dwarf2.h new file mode 100644 index 0000000000..9c8ce4e006 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/dwarf2.h @@ -0,0 +1,728 @@ +/* Declarations and definitions of codes relating to the DWARF2 symbolic + debugging information format. + Copyright (C) 1992, 1993, 1995, 1996, 1997, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + + Written by Gary Funck (gary@intrepid.com) The Ada Joint Program + Office (AJPO), Florida State Unviversity and Silicon Graphics Inc. + provided support for this effort -- June 21, 1995. + + Derived from the DWARF 1 implementation written by Ron Guilmette + (rfg@netcom.com), November 1990. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file is derived from the DWARF specification (a public document) + Revision 2.0.0 (July 27, 1993) developed by the UNIX International + Programming Languages Special Interest Group (UI/PLSIG) and distributed + by UNIX International. Copies of this specification are available from + UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. + + This file also now contains definitions from the DWARF 3 specification. */ + +/* This file is shared between GCC and GDB, and should not contain + prototypes. */ + +#ifndef _ELF_DWARF2_H +#define _ELF_DWARF2_H + +/* Structure found in the .debug_line section. */ +typedef struct +{ + unsigned char li_length [4]; + unsigned char li_version [2]; + unsigned char li_prologue_length [4]; + unsigned char li_min_insn_length [1]; + unsigned char li_default_is_stmt [1]; + unsigned char li_line_base [1]; + unsigned char li_line_range [1]; + unsigned char li_opcode_base [1]; +} +DWARF2_External_LineInfo; + +typedef struct +{ + unsigned long li_length; + unsigned short li_version; + unsigned int li_prologue_length; + unsigned char li_min_insn_length; + unsigned char li_default_is_stmt; + int li_line_base; + unsigned char li_line_range; + unsigned char li_opcode_base; +} +DWARF2_Internal_LineInfo; + +/* Structure found in .debug_pubnames section. */ +typedef struct +{ + unsigned char pn_length [4]; + unsigned char pn_version [2]; + unsigned char pn_offset [4]; + unsigned char pn_size [4]; +} +DWARF2_External_PubNames; + +typedef struct +{ + unsigned long pn_length; + unsigned short pn_version; + unsigned long pn_offset; + unsigned long pn_size; +} +DWARF2_Internal_PubNames; + +/* Structure found in .debug_info section. */ +typedef struct +{ + unsigned char cu_length [4]; + unsigned char cu_version [2]; + unsigned char cu_abbrev_offset [4]; + unsigned char cu_pointer_size [1]; +} +DWARF2_External_CompUnit; + +typedef struct +{ + unsigned long cu_length; + unsigned short cu_version; + unsigned long cu_abbrev_offset; + unsigned char cu_pointer_size; +} +DWARF2_Internal_CompUnit; + +typedef struct +{ + unsigned char ar_length [4]; + unsigned char ar_version [2]; + unsigned char ar_info_offset [4]; + unsigned char ar_pointer_size [1]; + unsigned char ar_segment_size [1]; +} +DWARF2_External_ARange; + +typedef struct +{ + unsigned long ar_length; + unsigned short ar_version; + unsigned long ar_info_offset; + unsigned char ar_pointer_size; + unsigned char ar_segment_size; +} +DWARF2_Internal_ARange; + + +/* Tag names and codes. */ +enum dwarf_tag + { + DW_TAG_padding = 0x00, + DW_TAG_array_type = 0x01, + DW_TAG_class_type = 0x02, + DW_TAG_entry_point = 0x03, + DW_TAG_enumeration_type = 0x04, + DW_TAG_formal_parameter = 0x05, + DW_TAG_imported_declaration = 0x08, + DW_TAG_label = 0x0a, + DW_TAG_lexical_block = 0x0b, + DW_TAG_member = 0x0d, + DW_TAG_pointer_type = 0x0f, + DW_TAG_reference_type = 0x10, + DW_TAG_compile_unit = 0x11, + DW_TAG_string_type = 0x12, + DW_TAG_structure_type = 0x13, + DW_TAG_subroutine_type = 0x15, + DW_TAG_typedef = 0x16, + DW_TAG_union_type = 0x17, + DW_TAG_unspecified_parameters = 0x18, + DW_TAG_variant = 0x19, + DW_TAG_common_block = 0x1a, + DW_TAG_common_inclusion = 0x1b, + DW_TAG_inheritance = 0x1c, + DW_TAG_inlined_subroutine = 0x1d, + DW_TAG_module = 0x1e, + DW_TAG_ptr_to_member_type = 0x1f, + DW_TAG_set_type = 0x20, + DW_TAG_subrange_type = 0x21, + DW_TAG_with_stmt = 0x22, + DW_TAG_access_declaration = 0x23, + DW_TAG_base_type = 0x24, + DW_TAG_catch_block = 0x25, + DW_TAG_const_type = 0x26, + DW_TAG_constant = 0x27, + DW_TAG_enumerator = 0x28, + DW_TAG_file_type = 0x29, + DW_TAG_friend = 0x2a, + DW_TAG_namelist = 0x2b, + DW_TAG_namelist_item = 0x2c, + DW_TAG_packed_type = 0x2d, + DW_TAG_subprogram = 0x2e, + DW_TAG_template_type_param = 0x2f, + DW_TAG_template_value_param = 0x30, + DW_TAG_thrown_type = 0x31, + DW_TAG_try_block = 0x32, + DW_TAG_variant_part = 0x33, + DW_TAG_variable = 0x34, + DW_TAG_volatile_type = 0x35, + /* DWARF 3. */ + DW_TAG_dwarf_procedure = 0x36, + DW_TAG_restrict_type = 0x37, + DW_TAG_interface_type = 0x38, + DW_TAG_namespace = 0x39, + DW_TAG_imported_module = 0x3a, + DW_TAG_unspecified_type = 0x3b, + DW_TAG_partial_unit = 0x3c, + DW_TAG_imported_unit = 0x3d, + /* SGI/MIPS Extensions. */ + DW_TAG_MIPS_loop = 0x4081, + /* GNU extensions. */ + DW_TAG_format_label = 0x4101, /* For FORTRAN 77 and Fortran 90. */ + DW_TAG_function_template = 0x4102, /* For C++. */ + DW_TAG_class_template = 0x4103, /* For C++. */ + DW_TAG_GNU_BINCL = 0x4104, + DW_TAG_GNU_EINCL = 0x4105, + /* Extensions for UPC. See: http://upc.gwu.edu/~upc. */ + DW_TAG_upc_shared_type = 0x8765, + DW_TAG_upc_strict_type = 0x8766, + DW_TAG_upc_relaxed_type = 0x8767 + }; + +#define DW_TAG_lo_user 0x4080 +#define DW_TAG_hi_user 0xffff + +/* Flag that tells whether entry has a child or not. */ +#define DW_children_no 0 +#define DW_children_yes 1 + +/* Form names and codes. */ +enum dwarf_form + { + DW_FORM_addr = 0x01, + DW_FORM_block2 = 0x03, + DW_FORM_block4 = 0x04, + DW_FORM_data2 = 0x05, + DW_FORM_data4 = 0x06, + DW_FORM_data8 = 0x07, + DW_FORM_string = 0x08, + DW_FORM_block = 0x09, + DW_FORM_block1 = 0x0a, + DW_FORM_data1 = 0x0b, + DW_FORM_flag = 0x0c, + DW_FORM_sdata = 0x0d, + DW_FORM_strp = 0x0e, + DW_FORM_udata = 0x0f, + DW_FORM_ref_addr = 0x10, + DW_FORM_ref1 = 0x11, + DW_FORM_ref2 = 0x12, + DW_FORM_ref4 = 0x13, + DW_FORM_ref8 = 0x14, + DW_FORM_ref_udata = 0x15, + DW_FORM_indirect = 0x16 + }; + +/* Attribute names and codes. */ + +enum dwarf_attribute + { + DW_AT_sibling = 0x01, + DW_AT_location = 0x02, + DW_AT_name = 0x03, + DW_AT_ordering = 0x09, + DW_AT_subscr_data = 0x0a, + DW_AT_byte_size = 0x0b, + DW_AT_bit_offset = 0x0c, + DW_AT_bit_size = 0x0d, + DW_AT_element_list = 0x0f, + DW_AT_stmt_list = 0x10, + DW_AT_low_pc = 0x11, + DW_AT_high_pc = 0x12, + DW_AT_language = 0x13, + DW_AT_member = 0x14, + DW_AT_discr = 0x15, + DW_AT_discr_value = 0x16, + DW_AT_visibility = 0x17, + DW_AT_import = 0x18, + DW_AT_string_length = 0x19, + DW_AT_common_reference = 0x1a, + DW_AT_comp_dir = 0x1b, + DW_AT_const_value = 0x1c, + DW_AT_containing_type = 0x1d, + DW_AT_default_value = 0x1e, + DW_AT_inline = 0x20, + DW_AT_is_optional = 0x21, + DW_AT_lower_bound = 0x22, + DW_AT_producer = 0x25, + DW_AT_prototyped = 0x27, + DW_AT_return_addr = 0x2a, + DW_AT_start_scope = 0x2c, + DW_AT_stride_size = 0x2e, + DW_AT_upper_bound = 0x2f, + DW_AT_abstract_origin = 0x31, + DW_AT_accessibility = 0x32, + DW_AT_address_class = 0x33, + DW_AT_artificial = 0x34, + DW_AT_base_types = 0x35, + DW_AT_calling_convention = 0x36, + DW_AT_count = 0x37, + DW_AT_data_member_location = 0x38, + DW_AT_decl_column = 0x39, + DW_AT_decl_file = 0x3a, + DW_AT_decl_line = 0x3b, + DW_AT_declaration = 0x3c, + DW_AT_discr_list = 0x3d, + DW_AT_encoding = 0x3e, + DW_AT_external = 0x3f, + DW_AT_frame_base = 0x40, + DW_AT_friend = 0x41, + DW_AT_identifier_case = 0x42, + DW_AT_macro_info = 0x43, + DW_AT_namelist_items = 0x44, + DW_AT_priority = 0x45, + DW_AT_segment = 0x46, + DW_AT_specification = 0x47, + DW_AT_static_link = 0x48, + DW_AT_type = 0x49, + DW_AT_use_location = 0x4a, + DW_AT_variable_parameter = 0x4b, + DW_AT_virtuality = 0x4c, + DW_AT_vtable_elem_location = 0x4d, + /* DWARF 3 values. */ + DW_AT_allocated = 0x4e, + DW_AT_associated = 0x4f, + DW_AT_data_location = 0x50, + DW_AT_stride = 0x51, + DW_AT_entry_pc = 0x52, + DW_AT_use_UTF8 = 0x53, + DW_AT_extension = 0x54, + DW_AT_ranges = 0x55, + DW_AT_trampoline = 0x56, + DW_AT_call_column = 0x57, + DW_AT_call_file = 0x58, + DW_AT_call_line = 0x59, + /* SGI/MIPS extensions. */ + DW_AT_MIPS_fde = 0x2001, + DW_AT_MIPS_loop_begin = 0x2002, + DW_AT_MIPS_tail_loop_begin = 0x2003, + DW_AT_MIPS_epilog_begin = 0x2004, + DW_AT_MIPS_loop_unroll_factor = 0x2005, + DW_AT_MIPS_software_pipeline_depth = 0x2006, + DW_AT_MIPS_linkage_name = 0x2007, + DW_AT_MIPS_stride = 0x2008, + DW_AT_MIPS_abstract_name = 0x2009, + DW_AT_MIPS_clone_origin = 0x200a, + DW_AT_MIPS_has_inlines = 0x200b, + /* GNU extensions. */ + DW_AT_sf_names = 0x2101, + DW_AT_src_info = 0x2102, + DW_AT_mac_info = 0x2103, + DW_AT_src_coords = 0x2104, + DW_AT_body_begin = 0x2105, + DW_AT_body_end = 0x2106, + DW_AT_GNU_vector = 0x2107, + /* VMS extensions. */ + DW_AT_VMS_rtnbeg_pd_address = 0x2201, + /* UPC extension. */ + DW_AT_upc_threads_scaled = 0x3210 + }; + +#define DW_AT_lo_user 0x2000 /* Implementation-defined range start. */ +#define DW_AT_hi_user 0x3ff0 /* Implementation-defined range end. */ + +/* Location atom names and codes. */ +enum dwarf_location_atom + { + DW_OP_addr = 0x03, + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, + DW_OP_const1s = 0x09, + DW_OP_const2u = 0x0a, + DW_OP_const2s = 0x0b, + DW_OP_const4u = 0x0c, + DW_OP_const4s = 0x0d, + DW_OP_const8u = 0x0e, + DW_OP_const8s = 0x0f, + DW_OP_constu = 0x10, + DW_OP_consts = 0x11, + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1a, + DW_OP_div = 0x1b, + DW_OP_minus = 0x1c, + DW_OP_mod = 0x1d, + DW_OP_mul = 0x1e, + DW_OP_neg = 0x1f, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_bra = 0x28, + DW_OP_eq = 0x29, + DW_OP_ge = 0x2a, + DW_OP_gt = 0x2b, + DW_OP_le = 0x2c, + DW_OP_lt = 0x2d, + DW_OP_ne = 0x2e, + DW_OP_skip = 0x2f, + DW_OP_lit0 = 0x30, + DW_OP_lit1 = 0x31, + DW_OP_lit2 = 0x32, + DW_OP_lit3 = 0x33, + DW_OP_lit4 = 0x34, + DW_OP_lit5 = 0x35, + DW_OP_lit6 = 0x36, + DW_OP_lit7 = 0x37, + DW_OP_lit8 = 0x38, + DW_OP_lit9 = 0x39, + DW_OP_lit10 = 0x3a, + DW_OP_lit11 = 0x3b, + DW_OP_lit12 = 0x3c, + DW_OP_lit13 = 0x3d, + DW_OP_lit14 = 0x3e, + DW_OP_lit15 = 0x3f, + DW_OP_lit16 = 0x40, + DW_OP_lit17 = 0x41, + DW_OP_lit18 = 0x42, + DW_OP_lit19 = 0x43, + DW_OP_lit20 = 0x44, + DW_OP_lit21 = 0x45, + DW_OP_lit22 = 0x46, + DW_OP_lit23 = 0x47, + DW_OP_lit24 = 0x48, + DW_OP_lit25 = 0x49, + DW_OP_lit26 = 0x4a, + DW_OP_lit27 = 0x4b, + DW_OP_lit28 = 0x4c, + DW_OP_lit29 = 0x4d, + DW_OP_lit30 = 0x4e, + DW_OP_lit31 = 0x4f, + DW_OP_reg0 = 0x50, + DW_OP_reg1 = 0x51, + DW_OP_reg2 = 0x52, + DW_OP_reg3 = 0x53, + DW_OP_reg4 = 0x54, + DW_OP_reg5 = 0x55, + DW_OP_reg6 = 0x56, + DW_OP_reg7 = 0x57, + DW_OP_reg8 = 0x58, + DW_OP_reg9 = 0x59, + DW_OP_reg10 = 0x5a, + DW_OP_reg11 = 0x5b, + DW_OP_reg12 = 0x5c, + DW_OP_reg13 = 0x5d, + DW_OP_reg14 = 0x5e, + DW_OP_reg15 = 0x5f, + DW_OP_reg16 = 0x60, + DW_OP_reg17 = 0x61, + DW_OP_reg18 = 0x62, + DW_OP_reg19 = 0x63, + DW_OP_reg20 = 0x64, + DW_OP_reg21 = 0x65, + DW_OP_reg22 = 0x66, + DW_OP_reg23 = 0x67, + DW_OP_reg24 = 0x68, + DW_OP_reg25 = 0x69, + DW_OP_reg26 = 0x6a, + DW_OP_reg27 = 0x6b, + DW_OP_reg28 = 0x6c, + DW_OP_reg29 = 0x6d, + DW_OP_reg30 = 0x6e, + DW_OP_reg31 = 0x6f, + DW_OP_breg0 = 0x70, + DW_OP_breg1 = 0x71, + DW_OP_breg2 = 0x72, + DW_OP_breg3 = 0x73, + DW_OP_breg4 = 0x74, + DW_OP_breg5 = 0x75, + DW_OP_breg6 = 0x76, + DW_OP_breg7 = 0x77, + DW_OP_breg8 = 0x78, + DW_OP_breg9 = 0x79, + DW_OP_breg10 = 0x7a, + DW_OP_breg11 = 0x7b, + DW_OP_breg12 = 0x7c, + DW_OP_breg13 = 0x7d, + DW_OP_breg14 = 0x7e, + DW_OP_breg15 = 0x7f, + DW_OP_breg16 = 0x80, + DW_OP_breg17 = 0x81, + DW_OP_breg18 = 0x82, + DW_OP_breg19 = 0x83, + DW_OP_breg20 = 0x84, + DW_OP_breg21 = 0x85, + DW_OP_breg22 = 0x86, + DW_OP_breg23 = 0x87, + DW_OP_breg24 = 0x88, + DW_OP_breg25 = 0x89, + DW_OP_breg26 = 0x8a, + DW_OP_breg27 = 0x8b, + DW_OP_breg28 = 0x8c, + DW_OP_breg29 = 0x8d, + DW_OP_breg30 = 0x8e, + DW_OP_breg31 = 0x8f, + DW_OP_regx = 0x90, + DW_OP_fbreg = 0x91, + DW_OP_bregx = 0x92, + DW_OP_piece = 0x93, + DW_OP_deref_size = 0x94, + DW_OP_xderef_size = 0x95, + DW_OP_nop = 0x96, + /* DWARF 3 extensions. */ + DW_OP_push_object_address = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9a, + /* GNU extensions. */ + DW_OP_GNU_push_tls_address = 0xe0 + }; + +#define DW_OP_lo_user 0xe0 /* Implementation-defined range start. */ +#define DW_OP_hi_user 0xff /* Implementation-defined range end. */ + +/* Type encodings. */ +enum dwarf_type + { + DW_ATE_void = 0x0, + DW_ATE_address = 0x1, + DW_ATE_boolean = 0x2, + DW_ATE_complex_float = 0x3, + DW_ATE_float = 0x4, + DW_ATE_signed = 0x5, + DW_ATE_signed_char = 0x6, + DW_ATE_unsigned = 0x7, + DW_ATE_unsigned_char = 0x8, + /* DWARF 3. */ + DW_ATE_imaginary_float = 0x9 + }; + +#define DW_ATE_lo_user 0x80 +#define DW_ATE_hi_user 0xff + +/* Array ordering names and codes. */ +enum dwarf_array_dim_ordering + { + DW_ORD_row_major = 0, + DW_ORD_col_major = 1 + }; + +/* Access attribute. */ +enum dwarf_access_attribute + { + DW_ACCESS_public = 1, + DW_ACCESS_protected = 2, + DW_ACCESS_private = 3 + }; + +/* Visibility. */ +enum dwarf_visibility_attribute + { + DW_VIS_local = 1, + DW_VIS_exported = 2, + DW_VIS_qualified = 3 + }; + +/* Virtuality. */ +enum dwarf_virtuality_attribute + { + DW_VIRTUALITY_none = 0, + DW_VIRTUALITY_virtual = 1, + DW_VIRTUALITY_pure_virtual = 2 + }; + +/* Case sensitivity. */ +enum dwarf_id_case + { + DW_ID_case_sensitive = 0, + DW_ID_up_case = 1, + DW_ID_down_case = 2, + DW_ID_case_insensitive = 3 + }; + +/* Calling convention. */ +enum dwarf_calling_convention + { + DW_CC_normal = 0x1, + DW_CC_program = 0x2, + DW_CC_nocall = 0x3 + }; + +#define DW_CC_lo_user 0x40 +#define DW_CC_hi_user 0xff + +/* Inline attribute. */ +enum dwarf_inline_attribute + { + DW_INL_not_inlined = 0, + DW_INL_inlined = 1, + DW_INL_declared_not_inlined = 2, + DW_INL_declared_inlined = 3 + }; + +/* Discriminant lists. */ +enum dwarf_discrim_list + { + DW_DSC_label = 0, + DW_DSC_range = 1 + }; + +/* Line number opcodes. */ +enum dwarf_line_number_ops + { + DW_LNS_extended_op = 0, + DW_LNS_copy = 1, + DW_LNS_advance_pc = 2, + DW_LNS_advance_line = 3, + DW_LNS_set_file = 4, + DW_LNS_set_column = 5, + DW_LNS_negate_stmt = 6, + DW_LNS_set_basic_block = 7, + DW_LNS_const_add_pc = 8, + DW_LNS_fixed_advance_pc = 9, + /* DWARF 3. */ + DW_LNS_set_prologue_end = 10, + DW_LNS_set_epilogue_begin = 11, + DW_LNS_set_isa = 12 + }; + +/* Line number extended opcodes. */ +enum dwarf_line_number_x_ops + { + DW_LNE_end_sequence = 1, + DW_LNE_set_address = 2, + DW_LNE_define_file = 3 + }; + +/* Call frame information. */ +enum dwarf_call_frame_info + { + DW_CFA_advance_loc = 0x40, + DW_CFA_offset = 0x80, + DW_CFA_restore = 0xc0, + DW_CFA_nop = 0x00, + DW_CFA_set_loc = 0x01, + DW_CFA_advance_loc1 = 0x02, + DW_CFA_advance_loc2 = 0x03, + DW_CFA_advance_loc4 = 0x04, + DW_CFA_offset_extended = 0x05, + DW_CFA_restore_extended = 0x06, + DW_CFA_undefined = 0x07, + DW_CFA_same_value = 0x08, + DW_CFA_register = 0x09, + DW_CFA_remember_state = 0x0a, + DW_CFA_restore_state = 0x0b, + DW_CFA_def_cfa = 0x0c, + DW_CFA_def_cfa_register = 0x0d, + DW_CFA_def_cfa_offset = 0x0e, + + /* DWARF 3. */ + DW_CFA_def_cfa_expression = 0x0f, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + + /* SGI/MIPS specific. */ + DW_CFA_MIPS_advance_loc8 = 0x1d, + + /* GNU extensions. */ + DW_CFA_GNU_window_save = 0x2d, + DW_CFA_GNU_args_size = 0x2e, + DW_CFA_GNU_negative_offset_extended = 0x2f + }; + +#define DW_CIE_ID 0xffffffff +#define DW_CIE_VERSION 1 + +#define DW_CFA_extended 0 +#define DW_CFA_lo_user 0x1c +#define DW_CFA_hi_user 0x3f + +#define DW_CHILDREN_no 0x00 +#define DW_CHILDREN_yes 0x01 + +#define DW_ADDR_none 0 + +/* Source language names and codes. */ +enum dwarf_source_language + { + DW_LANG_C89 = 0x0001, + DW_LANG_C = 0x0002, + DW_LANG_Ada83 = 0x0003, + DW_LANG_C_plus_plus = 0x0004, + DW_LANG_Cobol74 = 0x0005, + DW_LANG_Cobol85 = 0x0006, + DW_LANG_Fortran77 = 0x0007, + DW_LANG_Fortran90 = 0x0008, + DW_LANG_Pascal83 = 0x0009, + DW_LANG_Modula2 = 0x000a, + DW_LANG_Java = 0x000b, + /* DWARF 3. */ + DW_LANG_C99 = 0x000c, + DW_LANG_Ada95 = 0x000d, + DW_LANG_Fortran95 = 0x000e, + /* MIPS. */ + DW_LANG_Mips_Assembler = 0x8001, + /* UPC. */ + DW_LANG_Upc = 0x8765 + }; + +#define DW_LANG_lo_user 0x8000 /* Implementation-defined range start. */ +#define DW_LANG_hi_user 0xffff /* Implementation-defined range start. */ + +/* Names and codes for macro information. */ +enum dwarf_macinfo_record_type + { + DW_MACINFO_define = 1, + DW_MACINFO_undef = 2, + DW_MACINFO_start_file = 3, + DW_MACINFO_end_file = 4, + DW_MACINFO_vendor_ext = 255 + }; + +/* @@@ For use with GNU frame unwind information. */ + +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff + +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0A +#define DW_EH_PE_sdata4 0x0B +#define DW_EH_PE_sdata8 0x0C +#define DW_EH_PE_signed 0x08 + +#define DW_EH_PE_pcrel 0x10 +#define DW_EH_PE_textrel 0x20 +#define DW_EH_PE_datarel 0x30 +#define DW_EH_PE_funcrel 0x40 +#define DW_EH_PE_aligned 0x50 + +#define DW_EH_PE_indirect 0x80 + +#endif /* _ELF_DWARF2_H */ diff --git a/contrib/binutils-2.14/include/elf/external.h b/contrib/binutils-2.14/include/elf/external.h new file mode 100644 index 0000000000..403ee622b5 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/external.h @@ -0,0 +1,261 @@ +/* ELF support for BFD. + Copyright 1991, 1992, 1993, 1995, 1997, 1998, 1999, 2001 + Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that describe how ELF is represented externally by the BFD library. + I.E. it describes the in-file representation of ELF. It requires + the elf/common.h file which contains the portions that are common to + both the internal and external representations. */ + +/* The 64-bit stuff is kind of random. Perhaps someone will publish a + spec someday. */ + +#ifndef _ELF_EXTERNAL_H +#define _ELF_EXTERNAL_H + +/* ELF Header (32-bit implementations) */ + +typedef struct { + unsigned char e_ident[16]; /* ELF "magic number" */ + unsigned char e_type[2]; /* Identifies object file type */ + unsigned char e_machine[2]; /* Specifies required architecture */ + unsigned char e_version[4]; /* Identifies object file version */ + unsigned char e_entry[4]; /* Entry point virtual address */ + unsigned char e_phoff[4]; /* Program header table file offset */ + unsigned char e_shoff[4]; /* Section header table file offset */ + unsigned char e_flags[4]; /* Processor-specific flags */ + unsigned char e_ehsize[2]; /* ELF header size in bytes */ + unsigned char e_phentsize[2]; /* Program header table entry size */ + unsigned char e_phnum[2]; /* Program header table entry count */ + unsigned char e_shentsize[2]; /* Section header table entry size */ + unsigned char e_shnum[2]; /* Section header table entry count */ + unsigned char e_shstrndx[2]; /* Section header string table index */ +} Elf32_External_Ehdr; + +typedef struct { + unsigned char e_ident[16]; /* ELF "magic number" */ + unsigned char e_type[2]; /* Identifies object file type */ + unsigned char e_machine[2]; /* Specifies required architecture */ + unsigned char e_version[4]; /* Identifies object file version */ + unsigned char e_entry[8]; /* Entry point virtual address */ + unsigned char e_phoff[8]; /* Program header table file offset */ + unsigned char e_shoff[8]; /* Section header table file offset */ + unsigned char e_flags[4]; /* Processor-specific flags */ + unsigned char e_ehsize[2]; /* ELF header size in bytes */ + unsigned char e_phentsize[2]; /* Program header table entry size */ + unsigned char e_phnum[2]; /* Program header table entry count */ + unsigned char e_shentsize[2]; /* Section header table entry size */ + unsigned char e_shnum[2]; /* Section header table entry count */ + unsigned char e_shstrndx[2]; /* Section header string table index */ +} Elf64_External_Ehdr; + +/* Program header */ + +typedef struct { + unsigned char p_type[4]; /* Identifies program segment type */ + unsigned char p_offset[4]; /* Segment file offset */ + unsigned char p_vaddr[4]; /* Segment virtual address */ + unsigned char p_paddr[4]; /* Segment physical address */ + unsigned char p_filesz[4]; /* Segment size in file */ + unsigned char p_memsz[4]; /* Segment size in memory */ + unsigned char p_flags[4]; /* Segment flags */ + unsigned char p_align[4]; /* Segment alignment, file & memory */ +} Elf32_External_Phdr; + +typedef struct { + unsigned char p_type[4]; /* Identifies program segment type */ + unsigned char p_flags[4]; /* Segment flags */ + unsigned char p_offset[8]; /* Segment file offset */ + unsigned char p_vaddr[8]; /* Segment virtual address */ + unsigned char p_paddr[8]; /* Segment physical address */ + unsigned char p_filesz[8]; /* Segment size in file */ + unsigned char p_memsz[8]; /* Segment size in memory */ + unsigned char p_align[8]; /* Segment alignment, file & memory */ +} Elf64_External_Phdr; + +/* Section header */ + +typedef struct { + unsigned char sh_name[4]; /* Section name, index in string tbl */ + unsigned char sh_type[4]; /* Type of section */ + unsigned char sh_flags[4]; /* Miscellaneous section attributes */ + unsigned char sh_addr[4]; /* Section virtual addr at execution */ + unsigned char sh_offset[4]; /* Section file offset */ + unsigned char sh_size[4]; /* Size of section in bytes */ + unsigned char sh_link[4]; /* Index of another section */ + unsigned char sh_info[4]; /* Additional section information */ + unsigned char sh_addralign[4]; /* Section alignment */ + unsigned char sh_entsize[4]; /* Entry size if section holds table */ +} Elf32_External_Shdr; + +typedef struct { + unsigned char sh_name[4]; /* Section name, index in string tbl */ + unsigned char sh_type[4]; /* Type of section */ + unsigned char sh_flags[8]; /* Miscellaneous section attributes */ + unsigned char sh_addr[8]; /* Section virtual addr at execution */ + unsigned char sh_offset[8]; /* Section file offset */ + unsigned char sh_size[8]; /* Size of section in bytes */ + unsigned char sh_link[4]; /* Index of another section */ + unsigned char sh_info[4]; /* Additional section information */ + unsigned char sh_addralign[8]; /* Section alignment */ + unsigned char sh_entsize[8]; /* Entry size if section holds table */ +} Elf64_External_Shdr; + +/* Symbol table entry */ + +typedef struct { + unsigned char st_name[4]; /* Symbol name, index in string tbl */ + unsigned char st_value[4]; /* Value of the symbol */ + unsigned char st_size[4]; /* Associated symbol size */ + unsigned char st_info[1]; /* Type and binding attributes */ + unsigned char st_other[1]; /* No defined meaning, 0 */ + unsigned char st_shndx[2]; /* Associated section index */ +} Elf32_External_Sym; + +typedef struct { + unsigned char st_name[4]; /* Symbol name, index in string tbl */ + unsigned char st_info[1]; /* Type and binding attributes */ + unsigned char st_other[1]; /* No defined meaning, 0 */ + unsigned char st_shndx[2]; /* Associated section index */ + unsigned char st_value[8]; /* Value of the symbol */ + unsigned char st_size[8]; /* Associated symbol size */ +} Elf64_External_Sym; + +typedef struct { + unsigned char est_shndx[4]; /* Section index */ +} Elf_External_Sym_Shndx; + +/* Note segments */ + +typedef struct { + unsigned char namesz[4]; /* Size of entry's owner string */ + unsigned char descsz[4]; /* Size of the note descriptor */ + unsigned char type[4]; /* Interpretation of the descriptor */ + char name[1]; /* Start of the name+desc data */ +} Elf_External_Note; + +/* Relocation Entries */ +typedef struct { + unsigned char r_offset[4]; /* Location at which to apply the action */ + unsigned char r_info[4]; /* index and type of relocation */ +} Elf32_External_Rel; + +typedef struct { + unsigned char r_offset[4]; /* Location at which to apply the action */ + unsigned char r_info[4]; /* index and type of relocation */ + unsigned char r_addend[4]; /* Constant addend used to compute value */ +} Elf32_External_Rela; + +typedef struct { + unsigned char r_offset[8]; /* Location at which to apply the action */ + unsigned char r_info[8]; /* index and type of relocation */ +} Elf64_External_Rel; + +typedef struct { + unsigned char r_offset[8]; /* Location at which to apply the action */ + unsigned char r_info[8]; /* index and type of relocation */ + unsigned char r_addend[8]; /* Constant addend used to compute value */ +} Elf64_External_Rela; + +/* dynamic section structure */ + +typedef struct { + unsigned char d_tag[4]; /* entry tag value */ + union { + unsigned char d_val[4]; + unsigned char d_ptr[4]; + } d_un; +} Elf32_External_Dyn; + +typedef struct { + unsigned char d_tag[8]; /* entry tag value */ + union { + unsigned char d_val[8]; + unsigned char d_ptr[8]; + } d_un; +} Elf64_External_Dyn; + +/* The version structures are currently size independent. They are + named without a 32 or 64. If that ever changes, these structures + will need to be renamed. */ + +/* This structure appears in a SHT_GNU_verdef section. */ + +typedef struct { + unsigned char vd_version[2]; + unsigned char vd_flags[2]; + unsigned char vd_ndx[2]; + unsigned char vd_cnt[2]; + unsigned char vd_hash[4]; + unsigned char vd_aux[4]; + unsigned char vd_next[4]; +} Elf_External_Verdef; + +/* This structure appears in a SHT_GNU_verdef section. */ + +typedef struct { + unsigned char vda_name[4]; + unsigned char vda_next[4]; +} Elf_External_Verdaux; + +/* This structure appears in a SHT_GNU_verneed section. */ + +typedef struct { + unsigned char vn_version[2]; + unsigned char vn_cnt[2]; + unsigned char vn_file[4]; + unsigned char vn_aux[4]; + unsigned char vn_next[4]; +} Elf_External_Verneed; + +/* This structure appears in a SHT_GNU_verneed section. */ + +typedef struct { + unsigned char vna_hash[4]; + unsigned char vna_flags[2]; + unsigned char vna_other[2]; + unsigned char vna_name[4]; + unsigned char vna_next[4]; +} Elf_External_Vernaux; + +/* This structure appears in a SHT_GNU_versym section. This is not a + standard ELF structure; ELF just uses Elf32_Half. */ + +typedef struct { + unsigned char vs_vers[2]; +} +#ifdef __GNUC__ + __attribute__ ((packed)) +#endif + Elf_External_Versym; + +/* Structure for syminfo section. */ +typedef struct +{ + unsigned char si_boundto[2]; + unsigned char si_flags[2]; +} Elf_External_Syminfo; + +#endif /* _ELF_EXTERNAL_H */ diff --git a/contrib/binutils-2.14/include/elf/fr30.h b/contrib/binutils-2.14/include/elf/fr30.h new file mode 100644 index 0000000000..12a450dffd --- /dev/null +++ b/contrib/binutils-2.14/include/elf/fr30.h @@ -0,0 +1,42 @@ +/* FR30 ELF support for BFD. + Copyright 1998, 1999, 2000 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_FR30_H +#define _ELF_FR30_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_fr30_reloc_type) + RELOC_NUMBER (R_FR30_NONE, 0) + RELOC_NUMBER (R_FR30_8, 1) + RELOC_NUMBER (R_FR30_20, 2) + RELOC_NUMBER (R_FR30_32, 3) + RELOC_NUMBER (R_FR30_48, 4) + RELOC_NUMBER (R_FR30_6_IN_4, 5) + RELOC_NUMBER (R_FR30_8_IN_8, 6) + RELOC_NUMBER (R_FR30_9_IN_8, 7) + RELOC_NUMBER (R_FR30_10_IN_8, 8) + RELOC_NUMBER (R_FR30_9_PCREL, 9) + RELOC_NUMBER (R_FR30_12_PCREL, 10) + RELOC_NUMBER (R_FR30_GNU_VTINHERIT, 11) + RELOC_NUMBER (R_FR30_GNU_VTENTRY, 12) +END_RELOC_NUMBERS (R_FR30_max) + +#endif /* _ELF_FR30_H */ diff --git a/contrib/binutils-2.14/include/elf/frv.h b/contrib/binutils-2.14/include/elf/frv.h new file mode 100644 index 0000000000..65ce97d1ee --- /dev/null +++ b/contrib/binutils-2.14/include/elf/frv.h @@ -0,0 +1,95 @@ +/* FRV ELF support for BFD. + Copyright (C) 2002 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_FRV_H +#define _ELF_FRV_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_frv_reloc_type) + RELOC_NUMBER (R_FRV_NONE, 0) + RELOC_NUMBER (R_FRV_32, 1) + RELOC_NUMBER (R_FRV_LABEL16, 2) + RELOC_NUMBER (R_FRV_LABEL24, 3) + RELOC_NUMBER (R_FRV_LO16, 4) + RELOC_NUMBER (R_FRV_HI16, 5) + RELOC_NUMBER (R_FRV_GPREL12, 6) + RELOC_NUMBER (R_FRV_GPRELU12, 7) + RELOC_NUMBER (R_FRV_GPREL32, 8) + RELOC_NUMBER (R_FRV_GPRELHI, 9) + RELOC_NUMBER (R_FRV_GPRELLO, 10) + RELOC_NUMBER (R_FRV_GNU_VTINHERIT, 200) + RELOC_NUMBER (R_FRV_GNU_VTENTRY, 201) +END_RELOC_NUMBERS(R_FRV_max) + +/* Processor specific flags for the ELF header e_flags field. */ + /* gpr support */ +#define EF_FRV_GPR_MASK 0x00000003 /* mask for # of gprs */ +#define EF_FRV_GPR_32 0x00000001 /* -mgpr-32 */ +#define EF_FRV_GPR_64 0x00000002 /* -mgpr-64 */ + + /* fpr support */ +#define EF_FRV_FPR_MASK 0x0000000c /* mask for # of fprs */ +#define EF_FRV_FPR_32 0x00000004 /* -mfpr-32 */ +#define EF_FRV_FPR_64 0x00000008 /* -mfpr-64 */ +#define EF_FRV_FPR_NONE 0x0000000c /* -msoft-float */ + + /* double word support */ +#define EF_FRV_DWORD_MASK 0x00000030 /* mask for dword support */ +#define EF_FRV_DWORD_YES 0x00000010 /* use double word insns */ +#define EF_FRV_DWORD_NO 0x00000020 /* don't use double word insn*/ + +#define EF_FRV_DOUBLE 0x00000040 /* -mdouble */ +#define EF_FRV_MEDIA 0x00000080 /* -mmedia */ + +#define EF_FRV_PIC 0x00000100 /* -fpic */ +#define EF_FRV_NON_PIC_RELOCS 0x00000200 /* used non pic safe relocs */ + +#define EF_FRV_MULADD 0x00000400 /* -mmuladd */ +#define EF_FRV_BIGPIC 0x00000800 /* -fPIC */ +#define EF_FRV_LIBPIC 0x00001000 /* -mlibrary-pic */ +#define EF_FRV_G0 0x00002000 /* -G 0, no small data ptr */ +#define EF_FRV_NOPACK 0x00004000 /* -mnopack */ + +#define EF_FRV_CPU_MASK 0xff000000 /* specific cpu bits */ +#define EF_FRV_CPU_GENERIC 0x00000000 /* generic FRV */ +#define EF_FRV_CPU_FR500 0x01000000 /* FRV500 */ +#define EF_FRV_CPU_FR300 0x02000000 /* FRV300 */ +#define EF_FRV_CPU_SIMPLE 0x03000000 /* SIMPLE */ +#define EF_FRV_CPU_TOMCAT 0x04000000 /* Tomcat, FR500 prototype */ +#define EF_FRV_CPU_FR400 0x05000000 /* FRV400 */ + + /* Mask of PIC related bits */ +#define EF_FRV_PIC_FLAGS (EF_FRV_PIC | EF_FRV_LIBPIC | EF_FRV_BIGPIC) + + /* Mask of all flags */ +#define EF_FRV_ALL_FLAGS (EF_FRV_GPR_MASK | \ + EF_FRV_FPR_MASK | \ + EF_FRV_DWORD_MASK | \ + EF_FRV_DOUBLE | \ + EF_FRV_MEDIA | \ + EF_FRV_PIC_FLAGS | \ + EF_FRV_NON_PIC_RELOCS | \ + EF_FRV_MULADD | \ + EF_FRV_G0 | \ + EF_FRV_NOPACK | \ + EF_FRV_CPU_MASK) + +#endif /* _ELF_FRV_H */ diff --git a/contrib/binutils-2.14/include/elf/h8.h b/contrib/binutils-2.14/include/elf/h8.h new file mode 100644 index 0000000000..5fdf62c500 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/h8.h @@ -0,0 +1,98 @@ +/* H8300/h8500 ELF support for BFD. + Copyright 2001, 2003 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_H8_H +#define _ELF_H8_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +/* Relocations 59..63 are GNU extensions. */ +START_RELOC_NUMBERS (elf_h8_reloc_type) + RELOC_NUMBER (R_H8_NONE, 0) + RELOC_NUMBER (R_H8_DIR32, 1) + RELOC_NUMBER (R_H8_DIR32_28, 2) + RELOC_NUMBER (R_H8_DIR32_24, 3) + RELOC_NUMBER (R_H8_DIR32_16, 4) + RELOC_NUMBER (R_H8_DIR32U, 6) + RELOC_NUMBER (R_H8_DIR32U_28, 7) + RELOC_NUMBER (R_H8_DIR32U_24, 8) + RELOC_NUMBER (R_H8_DIR32U_20, 9) + RELOC_NUMBER (R_H8_DIR32U_16, 10) + RELOC_NUMBER (R_H8_DIR24, 11) + RELOC_NUMBER (R_H8_DIR24_20, 12) + RELOC_NUMBER (R_H8_DIR24_16, 13) + RELOC_NUMBER (R_H8_DIR24U, 14) + RELOC_NUMBER (R_H8_DIR24U_20, 15) + RELOC_NUMBER (R_H8_DIR24U_16, 16) + RELOC_NUMBER (R_H8_DIR16, 17) + RELOC_NUMBER (R_H8_DIR16U, 18) + RELOC_NUMBER (R_H8_DIR16S_32, 19) + RELOC_NUMBER (R_H8_DIR16S_28, 20) + RELOC_NUMBER (R_H8_DIR16S_24, 21) + RELOC_NUMBER (R_H8_DIR16S_20, 22) + RELOC_NUMBER (R_H8_DIR16S, 23) + RELOC_NUMBER (R_H8_DIR8, 24) + RELOC_NUMBER (R_H8_DIR8U, 25) + RELOC_NUMBER (R_H8_DIR8Z_32, 26) + RELOC_NUMBER (R_H8_DIR8Z_28, 27) + RELOC_NUMBER (R_H8_DIR8Z_24, 28) + RELOC_NUMBER (R_H8_DIR8Z_20, 29) + RELOC_NUMBER (R_H8_DIR8Z_16, 30) + RELOC_NUMBER (R_H8_PCREL16, 31) + RELOC_NUMBER (R_H8_PCREL8, 32) + RELOC_NUMBER (R_H8_BPOS, 33) + FAKE_RELOC (R_H8_FIRST_INVALID_DIR_RELOC, 34) + FAKE_RELOC (R_H8_LAST_INVALID_DIR_RELOC, 58) + RELOC_NUMBER (R_H8_DIR16A8, 59) + RELOC_NUMBER (R_H8_DIR16R8, 60) + RELOC_NUMBER (R_H8_DIR24A8, 61) + RELOC_NUMBER (R_H8_DIR24R8, 62) + RELOC_NUMBER (R_H8_DIR32A16, 63) + RELOC_NUMBER (R_H8_ABS32, 65) + RELOC_NUMBER (R_H8_ABS32A16, 127) + RELOC_NUMBER (R_H8_SYM, 128) + RELOC_NUMBER (R_H8_OPneg, 129) + RELOC_NUMBER (R_H8_OPadd, 130) + RELOC_NUMBER (R_H8_OPsub, 131) + RELOC_NUMBER (R_H8_OPmul, 132) + RELOC_NUMBER (R_H8_OPdiv, 133) + RELOC_NUMBER (R_H8_OPshla, 134) + RELOC_NUMBER (R_H8_OPshra, 135) + RELOC_NUMBER (R_H8_OPsctsize, 136) + RELOC_NUMBER (R_H8_OPhword, 137) + RELOC_NUMBER (R_H8_OPlword, 138) + RELOC_NUMBER (R_H8_OPhigh, 139) + RELOC_NUMBER (R_H8_OPlow, 140) + RELOC_NUMBER (R_H8_OPscttop, 141) +END_RELOC_NUMBERS (R_H8_max) + +/* Machine variant if we know it. This field was invented at Cygnus, + but it is hoped that other vendors will adopt it. If some standard + is developed, this code should be changed to follow it. */ + +#define EF_H8_MACH 0x00FF0000 + +#define E_H8_MACH_H8300 0x00800000 +#define E_H8_MACH_H8300H 0x00810000 +#define E_H8_MACH_H8300S 0x00820000 +#define E_H8_MACH_H8300HN 0x00830000 +#define E_H8_MACH_H8300SN 0x00840000 + +#endif diff --git a/contrib/binutils-2.14/include/elf/hppa.h b/contrib/binutils-2.14/include/elf/hppa.h new file mode 100644 index 0000000000..45e0b9f0f0 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/hppa.h @@ -0,0 +1,552 @@ +/* HPPA ELF support for BFD. + Copyright 1993, 1994, 1995, 1998, 1999, 2000 + 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the HPPA ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_HPPA_H +#define _ELF_HPPA_H + +/* Processor specific flags for the ELF header e_flags field. */ + +/* Trap null address dereferences. */ +#define EF_PARISC_TRAPNIL 0x00010000 + +/* .PARISC.archext section is present. */ +#define EF_PARISC_EXT 0x00020000 + +/* Program expects little-endian mode. */ +#define EF_PARISC_LSB 0x00040000 + +/* Program expects wide mode. */ +#define EF_PARISC_WIDE 0x00080000 + +/* Do not allow kernel-assisted branch prediction. */ +#define EF_PARISC_NO_KABP 0x00100000 + +/* Allow lazy swap for dynamically allocated program segments. */ +#define EF_PARISC_LAZYSWAP 0x00400000 + +/* Architecture version */ +#define EF_PARISC_ARCH 0x0000ffff + +#define EFA_PARISC_1_0 0x020b +#define EFA_PARISC_1_1 0x0210 +#define EFA_PARISC_2_0 0x0214 + +/* Special section indices. */ +/* A symbol that has been declared as a tentative definition in an ANSI C + compilation. */ +#define SHN_PARISC_ANSI_COMMON 0xff00 + +/* A symbol that has been declared as a common block using the + huge memory model. */ +#define SHN_PARISC_HUGE_COMMON 0xff01 + +/* Processor specific section types. */ + +/* Section contains product specific extension bits. */ +#define SHT_PARISC_EXT 0x70000000 + +/* Section contains unwind table entries. */ +#define SHT_PARISC_UNWIND 0x70000001 + +/* Section contains debug information for optimized code. */ +#define SHT_PARISC_DOC 0x70000002 + +/* Section contains code annotations. */ +#define SHT_PARISC_ANNOT 0x70000003 + +/* These are strictly for compatibility with the older elf32-hppa + implementation. Hopefully we can eliminate them in the future. */ +/* Optional section holding argument location/relocation info. */ +#define SHT_PARISC_SYMEXTN SHT_LOPROC+8 + +/* Option section for linker stubs. */ +#define SHT_PARISC_STUBS SHT_LOPROC+9 + +/* Processor specific section flags. */ + +/* Section contains code compiled for static branch prediction. */ +#define SHF_PARISC_SBP 0x80000000 + +/* Section should be allocated from from GP. */ +#define SHF_PARISC_HUGE 0x40000000 + +/* Section should go near GP. */ +#define SHF_PARISC_SHORT 0x20000000 + + +/* Identifies the entry point of a millicode routine. */ +#define STT_PARISC_MILLI 13 + +/* ELF/HPPA relocation types */ + +/* Note: PA-ELF is defined to use only RELA relocations. */ +#include "elf/reloc-macros.h" + +START_RELOC_NUMBERS (elf_hppa_reloc_type) +RELOC_NUMBER (R_PARISC_NONE, 0) /* No reloc */ + +/* Data / Inst. Format Relocation Expression */ + +RELOC_NUMBER (R_PARISC_DIR32, 1) +/* 32-bit word symbol + addend */ + +RELOC_NUMBER (R_PARISC_DIR21L, 2) +/* long immediate (7) LR(symbol, addend) */ + +RELOC_NUMBER (R_PARISC_DIR17R, 3) +/* branch external (19) RR(symbol, addend) */ + +RELOC_NUMBER (R_PARISC_DIR17F, 4) +/* branch external (19) symbol + addend */ + +RELOC_NUMBER (R_PARISC_DIR14R, 6) +/* load/store (1) RR(symbol, addend) */ + +RELOC_NUMBER (R_PARISC_DIR14F, 7) +/* load/store (1) symbol, addend */ + +/* PC-relative relocation types + Typically used for calls. + Note PCREL17C and PCREL17F differ only in overflow handling. + PCREL17C never reports a relocation error. + + When supporting argument relocations, function calls must be + accompanied by parameter relocation information. This information is + carried in the ten high-order bits of the addend field. The remaining + 22 bits of of the addend field are sign-extended to form the Addend. + + Note the code to build argument relocations depends on the + addend being zero. A consequence of this limitation is GAS + can not perform relocation reductions for function symbols. */ + +RELOC_NUMBER (R_PARISC_PCREL12F, 8) +/* op & branch (17) symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL32, 9) +/* 32-bit word symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL21L, 10) +/* long immediate (7) L(symbol - PC - 8 + addend) */ + +RELOC_NUMBER (R_PARISC_PCREL17R, 11) +/* branch external (19) R(symbol - PC - 8 + addend) */ + +RELOC_NUMBER (R_PARISC_PCREL17F, 12) +/* branch (20) symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL17C, 13) +/* branch (20) symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL14R, 14) +/* load/store (1) R(symbol - PC - 8 + addend) */ + +RELOC_NUMBER (R_PARISC_PCREL14F, 15) +/* load/store (1) symbol - PC - 8 + addend */ + + +/* DP-relative relocation types. */ +RELOC_NUMBER (R_PARISC_DPREL21L, 18) +/* long immediate (7) LR(symbol - GP, addend) */ + +RELOC_NUMBER (R_PARISC_DPREL14WR, 19) +/* load/store mod. comp. (2) RR(symbol - GP, addend) */ + +RELOC_NUMBER (R_PARISC_DPREL14DR, 20) +/* load/store doubleword (3) RR(symbol - GP, addend) */ + +RELOC_NUMBER (R_PARISC_DPREL14R, 22) +/* load/store (1) RR(symbol - GP, addend) */ + +RELOC_NUMBER (R_PARISC_DPREL14F, 23) +/* load/store (1) symbol - GP + addend */ + + +/* Data linkage table (DLT) relocation types + + SOM DLT_REL fixup requests are used to for static data references + from position-independent code within shared libraries. They are + similar to the GOT relocation types in some SVR4 implementations. */ + +RELOC_NUMBER (R_PARISC_DLTREL21L, 26) +/* long immediate (7) LR(symbol - GP, addend) */ + +RELOC_NUMBER (R_PARISC_DLTREL14R, 30) +/* load/store (1) RR(symbol - GP, addend) */ + +RELOC_NUMBER (R_PARISC_DLTREL14F, 31) +/* load/store (1) symbol - GP + addend */ + + +/* DLT indirect relocation types */ +RELOC_NUMBER (R_PARISC_DLTIND21L, 34) +/* long immediate (7) L(ltoff(symbol + addend)) */ + +RELOC_NUMBER (R_PARISC_DLTIND14R, 38) +/* load/store (1) R(ltoff(symbol + addend)) */ + +RELOC_NUMBER (R_PARISC_DLTIND14F, 39) +/* load/store (1) ltoff(symbol + addend) */ + + +/* Base relative relocation types. Ugh. These imply lots of state */ +RELOC_NUMBER (R_PARISC_SETBASE, 40) +/* none no reloc; base := sym */ + +RELOC_NUMBER (R_PARISC_SECREL32, 41) +/* 32-bit word symbol - SECT + addend */ + +RELOC_NUMBER (R_PARISC_BASEREL21L, 42) +/* long immediate (7) LR(symbol - base, addend) */ + +RELOC_NUMBER (R_PARISC_BASEREL17R, 43) +/* branch external (19) RR(symbol - base, addend) */ + +RELOC_NUMBER (R_PARISC_BASEREL17F, 44) +/* branch external (19) symbol - base + addend */ + +RELOC_NUMBER (R_PARISC_BASEREL14R, 46) +/* load/store (1) RR(symbol - base, addend) */ + +RELOC_NUMBER (R_PARISC_BASEREL14F, 47) +/* load/store (1) symbol - base, addend */ + + +/* Segment relative relocation types. */ +RELOC_NUMBER (R_PARISC_SEGBASE, 48) +/* none no relocation; SB := sym */ + +RELOC_NUMBER (R_PARISC_SEGREL32, 49) +/* 32-bit word symbol - SB + addend */ + + +/* Offsets from the PLT. */ +RELOC_NUMBER (R_PARISC_PLTOFF21L, 50) +/* long immediate (7) LR(pltoff(symbol), addend) */ + +RELOC_NUMBER (R_PARISC_PLTOFF14R, 54) +/* load/store (1) RR(pltoff(symbol), addend) */ + +RELOC_NUMBER (R_PARISC_PLTOFF14F, 55) +/* load/store (1) pltoff(symbol) + addend */ + + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR32, 57) +/* 32-bit word ltoff(fptr(symbol+addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR21L, 58) +/* long immediate (7) L(ltoff(fptr(symbol+addend))) */ + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR14R, 62) +/* load/store (1) R(ltoff(fptr(symbol+addend))) */ + + +RELOC_NUMBER (R_PARISC_FPTR64, 64) +/* 64-bit doubleword fptr(symbol+addend) */ + + +/* Plabel relocation types. */ +RELOC_NUMBER (R_PARISC_PLABEL32, 65) +/* 32-bit word fptr(symbol) */ + +RELOC_NUMBER (R_PARISC_PLABEL21L, 66) +/* long immediate (7) L(fptr(symbol)) */ + +RELOC_NUMBER (R_PARISC_PLABEL14R, 70) +/* load/store (1) R(fptr(symbol)) */ + + +/* PCREL relocations. */ +RELOC_NUMBER (R_PARISC_PCREL64, 72) +/* 64-bit doubleword symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL22C, 73) +/* branch & link (21) symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL22F, 74) +/* branch & link (21) symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL14WR, 75) +/* load/store mod. comp. (2) R(symbol - PC - 8 + addend) */ + +RELOC_NUMBER (R_PARISC_PCREL14DR, 76) +/* load/store doubleword (3) R(symbol - PC - 8 + addend) */ + +RELOC_NUMBER (R_PARISC_PCREL16F, 77) +/* load/store (1) symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL16WF, 78) +/* load/store mod. comp. (2) symbol - PC - 8 + addend */ + +RELOC_NUMBER (R_PARISC_PCREL16DF, 79) +/* load/store doubleword (3) symbol - PC - 8 + addend */ + + +RELOC_NUMBER (R_PARISC_DIR64, 80) +/* 64-bit doubleword symbol + addend */ + +RELOC_NUMBER (R_PARISC_DIR64WR, 81) +/* 64-bit doubleword RR(symbol, addend) */ + +RELOC_NUMBER (R_PARISC_DIR64DR, 82) +/* 64-bit doubleword RR(symbol, addend) */ + +RELOC_NUMBER (R_PARISC_DIR14WR, 83) +/* load/store mod. comp. (2) RR(symbol, addend) */ + +RELOC_NUMBER (R_PARISC_DIR14DR, 84) +/* load/store doubleword (3) RR(symbol, addend) */ + +RELOC_NUMBER (R_PARISC_DIR16F, 85) +/* load/store (1) symbol + addend */ + +RELOC_NUMBER (R_PARISC_DIR16WF, 86) +/* load/store mod. comp. (2) symbol + addend */ + +RELOC_NUMBER (R_PARISC_DIR16DF, 87) +/* load/store doubleword (3) symbol + addend */ + +RELOC_NUMBER (R_PARISC_GPREL64, 88) +/* 64-bit doubleword symbol - GP + addend */ + +RELOC_NUMBER (R_PARISC_DLTREL14WR, 91) +/* load/store mod. comp. (2) RR(symbol - GP, addend) */ + +RELOC_NUMBER (R_PARISC_DLTREL14DR, 92) +/* load/store doubleword (3) RR(symbol - GP, addend) */ + +RELOC_NUMBER (R_PARISC_GPREL16F, 93) +/* load/store (1) symbol - GP + addend */ + +RELOC_NUMBER (R_PARISC_GPREL16WF, 94) +/* load/store mod. comp. (2) symbol - GP + addend */ + +RELOC_NUMBER (R_PARISC_GPREL16DF, 95) +/* load/store doubleword (3) symbol - GP + addend */ + + +RELOC_NUMBER (R_PARISC_LTOFF64, 96) +/* 64-bit doubleword ltoff(symbol + addend) */ + +RELOC_NUMBER (R_PARISC_DLTIND14WR, 99) +/* load/store mod. comp. (2) R(ltoff(symbol + addend)) */ + +RELOC_NUMBER (R_PARISC_DLTIND14DR, 100) +/* load/store doubleword (3) R(ltoff(symbol + addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF16F, 101) +/* load/store (1) ltoff(symbol + addend) */ + +RELOC_NUMBER (R_PARISC_LTOFF16WF, 102) +/* load/store mod. comp. (2) ltoff(symbol + addend) */ + +RELOC_NUMBER (R_PARISC_LTOFF16DF, 103) +/* load/store doubleword (3) ltoff(symbol + addend) */ + + +RELOC_NUMBER (R_PARISC_SECREL64, 104) +/* 64-bit doubleword symbol - SECT + addend */ + +RELOC_NUMBER (R_PARISC_BASEREL14WR, 107) +/* load/store mod. comp. (2) RR(symbol - base, addend) */ + +RELOC_NUMBER (R_PARISC_BASEREL14DR, 108) +/* load/store doubleword (3) RR(symbol - base, addend) */ + + +RELOC_NUMBER (R_PARISC_SEGREL64, 112) +/* 64-bit doubleword symbol - SB + addend */ + +RELOC_NUMBER (R_PARISC_PLTOFF14WR, 115) +/* load/store mod. comp. (2) RR(pltoff(symbol), addend) */ + +RELOC_NUMBER (R_PARISC_PLTOFF14DR, 116) +/* load/store doubleword (3) RR(pltoff(symbol), addend) */ + +RELOC_NUMBER (R_PARISC_PLTOFF16F, 117) +/* load/store (1) pltoff(symbol) + addend */ + +RELOC_NUMBER (R_PARISC_PLTOFF16WF, 118) +/* load/store mod. comp. (2) pltoff(symbol) + addend */ + +RELOC_NUMBER (R_PARISC_PLTOFF16DF, 119) +/* load/store doubleword (3) pltoff(symbol) + addend */ + + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR64, 120) +/* 64-bit doubleword ltoff(fptr(symbol+addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR14WR, 123) +/* load/store mod. comp. (2) R(ltoff(fptr(symbol+addend))) */ + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR14DR, 124) +/* load/store doubleword (3) R(ltoff(fptr(symbol+addend))) */ + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR16F, 125) +/* load/store (1) ltoff(fptr(symbol+addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR16WF, 126) +/* load/store mod. comp. (2) ltoff(fptr(symbol+addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF_FPTR16DF, 127) +/* load/store doubleword (3) ltoff(fptr(symbol+addend)) */ + + +RELOC_NUMBER (R_PARISC_COPY, 128) +/* data Dynamic relocations only */ + +RELOC_NUMBER (R_PARISC_IPLT, 129) +/* plt */ + +RELOC_NUMBER (R_PARISC_EPLT, 130) +/* plt */ + + +RELOC_NUMBER (R_PARISC_TPREL32, 153) +/* 32-bit word symbol - TP + addend */ + +RELOC_NUMBER (R_PARISC_TPREL21L, 154) +/* long immediate (7) LR(symbol - TP, addend) */ + +RELOC_NUMBER (R_PARISC_TPREL14R, 158) +/* load/store (1) RR(symbol - TP, addend) */ + + +RELOC_NUMBER (R_PARISC_LTOFF_TP21L, 162) +/* long immediate (7) L(ltoff(symbol - TP + addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF_TP14R, 166) +/* load/store (1) R(ltoff(symbol - TP + addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF_TP14F, 167) +/* load/store (1) ltoff(symbol - TP + addend) */ + + +RELOC_NUMBER (R_PARISC_TPREL64, 216) +/* 64-bit word symbol - TP + addend */ + +RELOC_NUMBER (R_PARISC_TPREL14WR, 219) +/* load/store mod. comp. (2) RR(symbol - TP, addend) */ + +RELOC_NUMBER (R_PARISC_TPREL14DR, 220) +/* load/store doubleword (3) RR(symbol - TP, addend) */ + +RELOC_NUMBER (R_PARISC_TPREL16F, 221) +/* load/store (1) symbol - TP + addend */ + +RELOC_NUMBER (R_PARISC_TPREL16WF, 222) +/* load/store mod. comp. (2) symbol - TP + addend */ + +RELOC_NUMBER (R_PARISC_TPREL16DF, 223) +/* load/store doubleword (3) symbol - TP + addend */ + + +RELOC_NUMBER (R_PARISC_LTOFF_TP64, 224) +/* 64-bit doubleword ltoff(symbol - TP + addend) */ + +RELOC_NUMBER (R_PARISC_LTOFF_TP14WR, 227) +/* load/store mod. comp. (2) R(ltoff(symbol - TP + addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF_TP14DR, 228) +/* load/store doubleword (3) R(ltoff(symbol - TP + addend)) */ + +RELOC_NUMBER (R_PARISC_LTOFF_TP16F, 229) +/* load/store (1) ltoff(symbol - TP + addend) */ + +RELOC_NUMBER (R_PARISC_LTOFF_TP16WF, 230) +/* load/store mod. comp. (2) ltoff(symbol - TP + addend) */ + +RELOC_NUMBER (R_PARISC_LTOFF_TP16DF, 231) +/* load/store doubleword (3) ltoff(symbol - TP + addend) */ + +RELOC_NUMBER (R_PARISC_GNU_VTENTRY, 232) +RELOC_NUMBER (R_PARISC_GNU_VTINHERIT, 233) + +END_RELOC_NUMBERS (R_PARISC_UNIMPLEMENTED) + +#ifndef RELOC_MACROS_GEN_FUNC +typedef enum elf_hppa_reloc_type elf_hppa_reloc_type; +#endif + +#define PT_PARISC_ARCHEXT 0x70000000 +#define PT_PARISC_UNWIND 0x70000001 +#define PF_PARISC_SBP 0x08000000 +#define PF_HP_PAGE_SIZE 0x00100000 +#define PF_HP_FAR_SHARED 0x00200000 +#define PF_HP_NEAR_SHARED 0x00400000 +#define PF_HP_CODE 0x01000000 +#define PF_HP_MODIFY 0x02000000 +#define PF_HP_LAZYSWAP 0x04000000 +#define PF_HP_SBP 0x08000000 + + +/* Processor specific dynamic array tags. */ + +/* Arggh. HP's tools define these symbols based on the + old value of DT_LOOS. So we must do the same to be + compatible. */ +#define DT_HP_LOAD_MAP (OLD_DT_LOOS + 0x0) +#define DT_HP_DLD_FLAGS (OLD_DT_LOOS + 0x1) +#define DT_HP_DLD_HOOK (OLD_DT_LOOS + 0x2) +#define DT_HP_UX10_INIT (OLD_DT_LOOS + 0x3) +#define DT_HP_UX10_INITSZ (OLD_DT_LOOS + 0x4) +#define DT_HP_PREINIT (OLD_DT_LOOS + 0x5) +#define DT_HP_PREINITSZ (OLD_DT_LOOS + 0x6) +#define DT_HP_NEEDED (OLD_DT_LOOS + 0x7) +#define DT_HP_TIME_STAMP (OLD_DT_LOOS + 0x8) +#define DT_HP_CHECKSUM (OLD_DT_LOOS + 0x9) +#define DT_HP_GST_SIZE (OLD_DT_LOOS + 0xa) +#define DT_HP_GST_VERSION (OLD_DT_LOOS + 0xb) +#define DT_HP_GST_HASHVAL (OLD_DT_LOOS + 0xc) + +/* Values for DT_HP_DLD_FLAGS. */ +#define DT_HP_DEBUG_PRIVATE 0x0001 /* Map text private */ +#define DT_HP_DEBUG_CALLBACK 0x0002 /* Callback */ +#define DT_HP_DEBUG_CALLBACK_BOR 0x0004 /* BOR callback */ +#define DT_HP_NO_ENVVAR 0x0008 /* No env var */ +#define DT_HP_BIND_NOW 0x0010 /* Bind now */ +#define DT_HP_BIND_NONFATAL 0x0020 /* Bind non-fatal */ +#define DT_HP_BIND_VERBOSE 0x0040 /* Bind verbose */ +#define DT_HP_BIND_RESTRICTED 0x0080 /* Bind restricted */ +#define DT_HP_BIND_SYMBOLIC 0x0100 /* Bind symbolic */ +#define DT_HP_RPATH_FIRST 0x0200 /* RPATH first */ +#define DT_HP_BIND_DEPTH_FIRST 0x0400 /* Bind depth-first */ + +/* Program header extensions. */ +#define PT_HP_TLS (PT_LOOS + 0x0) +#define PT_HP_CORE_NONE (PT_LOOS + 0x1) +#define PT_HP_CORE_VERSION (PT_LOOS + 0x2) +#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) +#define PT_HP_CORE_COMM (PT_LOOS + 0x4) +#define PT_HP_CORE_PROC (PT_LOOS + 0x5) +#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) +#define PT_HP_CORE_STACK (PT_LOOS + 0x7) +#define PT_HP_CORE_SHM (PT_LOOS + 0x8) +#define PT_HP_CORE_MMF (PT_LOOS + 0x9) +#define PT_HP_PARALLEL (PT_LOOS + 0x10) +#define PT_HP_FASTBIND (PT_LOOS + 0x11) + +/* Additional symbol types. */ +#define STT_HP_OPAQUE (STT_LOOS + 0x1) +#define STT_HP_STUB (STT_LOOS + 0x2) + +#endif /* _ELF_HPPA_H */ diff --git a/contrib/binutils-2.14/include/elf/i370.h b/contrib/binutils-2.14/include/elf/i370.h new file mode 100644 index 0000000000..fd5ec4739d --- /dev/null +++ b/contrib/binutils-2.14/include/elf/i370.h @@ -0,0 +1,68 @@ +/* i370 ELF support for BFD. + Copyright 2000, 2002 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the i370 ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_I370_H +#define _ELF_I370_H + +#include "elf/reloc-macros.h" + +/* Processor specific section headers, sh_type field */ + +#define SHT_ORDERED SHT_HIPROC /* Link editor is to sort the \ + entries in this section \ + based on the address \ + specified in the associated \ + symbol table entry. */ + +#define EF_I370_RELOCATABLE 0x00010000 /* i370 -mrelocatable flag */ +#define EF_I370_RELOCATABLE_LIB 0x00008000 /* i370 -mrelocatable-lib flag */ +/* Processor specific section flags, sh_flags field */ + +#define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude \ + this section from executable \ + and shared objects that it \ + builds when those objects \ + are not to be furhter \ + relocated. */ + +/* i370 relocations + Note that there is really just one relocation that we currently + support (and only one that we seem to need, at the moment), and + that is the 31-bit address relocation. Note that the 370/390 + only supports a 31-bit (2GB) address space. */ + +START_RELOC_NUMBERS (i370_reloc_type) + RELOC_NUMBER (R_I370_NONE, 0) + RELOC_NUMBER (R_I370_ADDR31, 1) + RELOC_NUMBER (R_I370_ADDR32, 2) + RELOC_NUMBER (R_I370_ADDR16, 3) + RELOC_NUMBER (R_I370_REL31, 4) + RELOC_NUMBER (R_I370_REL32, 5) + RELOC_NUMBER (R_I370_ADDR12, 6) + RELOC_NUMBER (R_I370_REL12, 7) + RELOC_NUMBER (R_I370_ADDR8, 8) + RELOC_NUMBER (R_I370_REL8, 9) + RELOC_NUMBER (R_I370_COPY, 10) + RELOC_NUMBER (R_I370_RELATIVE, 11) +END_RELOC_NUMBERS (R_I370_max) + +#endif /* _ELF_I370_H */ diff --git a/contrib/binutils-2.14/include/elf/i386.h b/contrib/binutils-2.14/include/elf/i386.h new file mode 100644 index 0000000000..95941196c7 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/i386.h @@ -0,0 +1,70 @@ +/* ix86 ELF support for BFD. + Copyright 1998, 1999, 2000 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_I386_H +#define _ELF_I386_H + +#include "elf/reloc-macros.h" + +START_RELOC_NUMBERS (elf_i386_reloc_type) + RELOC_NUMBER (R_386_NONE, 0) /* No reloc */ + RELOC_NUMBER (R_386_32, 1) /* Direct 32 bit */ + RELOC_NUMBER (R_386_PC32, 2) /* PC relative 32 bit */ + RELOC_NUMBER (R_386_GOT32, 3) /* 32 bit GOT entry */ + RELOC_NUMBER (R_386_PLT32, 4) /* 32 bit PLT address */ + RELOC_NUMBER (R_386_COPY, 5) /* Copy symbol at runtime */ + RELOC_NUMBER (R_386_GLOB_DAT, 6) /* Create GOT entry */ + RELOC_NUMBER (R_386_JUMP_SLOT, 7) /* Create PLT entry */ + RELOC_NUMBER (R_386_RELATIVE, 8) /* Adjust by program base */ + RELOC_NUMBER (R_386_GOTOFF, 9) /* 32 bit offset to GOT */ + RELOC_NUMBER (R_386_GOTPC, 10) /* 32 bit PC relative offset to GOT */ + RELOC_NUMBER (R_386_32PLT, 11) /* Used by Sun */ + FAKE_RELOC (FIRST_INVALID_RELOC, 12) + FAKE_RELOC (LAST_INVALID_RELOC, 13) + RELOC_NUMBER (R_386_TLS_TPOFF,14) + RELOC_NUMBER (R_386_TLS_IE, 15) + RELOC_NUMBER (R_386_TLS_GOTIE,16) + RELOC_NUMBER (R_386_TLS_LE, 17) + RELOC_NUMBER (R_386_TLS_GD, 18) + RELOC_NUMBER (R_386_TLS_LDM, 19) + RELOC_NUMBER (R_386_16, 20) + RELOC_NUMBER (R_386_PC16, 21) + RELOC_NUMBER (R_386_8, 22) + RELOC_NUMBER (R_386_PC8, 23) + RELOC_NUMBER (R_386_TLS_GD_32, 24) + RELOC_NUMBER (R_386_TLS_GD_PUSH, 25) + RELOC_NUMBER (R_386_TLS_GD_CALL, 26) + RELOC_NUMBER (R_386_TLS_GD_POP, 27) + RELOC_NUMBER (R_386_TLS_LDM_32, 28) + RELOC_NUMBER (R_386_TLS_LDM_PUSH, 29) + RELOC_NUMBER (R_386_TLS_LDM_CALL, 30) + RELOC_NUMBER (R_386_TLS_LDM_POP, 31) + RELOC_NUMBER (R_386_TLS_LDO_32, 32) + RELOC_NUMBER (R_386_TLS_IE_32, 33) + RELOC_NUMBER (R_386_TLS_LE_32, 34) + RELOC_NUMBER (R_386_TLS_DTPMOD32, 35) + RELOC_NUMBER (R_386_TLS_DTPOFF32, 36) + RELOC_NUMBER (R_386_TLS_TPOFF32, 37) + + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_386_GNU_VTINHERIT, 250) + RELOC_NUMBER (R_386_GNU_VTENTRY, 251) +END_RELOC_NUMBERS (R_386_max) + +#endif diff --git a/contrib/binutils-2.14/include/elf/i860.h b/contrib/binutils-2.14/include/elf/i860.h new file mode 100644 index 0000000000..de34aeb014 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/i860.h @@ -0,0 +1,66 @@ +/* i860 ELF support for BFD. + Copyright 2000 Free Software Foundation, Inc. + + Contributed by Jason Eckhardt . + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_I860_H +#define _ELF_I860_H + +/* Note: i860 ELF is defined to use only RELA relocations. */ + +#include "elf/reloc-macros.h" + +START_RELOC_NUMBERS (elf_i860_reloc_type) + RELOC_NUMBER (R_860_NONE, 0x00) /* No reloc */ + RELOC_NUMBER (R_860_32, 0x01) /* S+A */ + RELOC_NUMBER (R_860_COPY, 0x02) /* No calculation */ + RELOC_NUMBER (R_860_GLOB_DAT, 0x03) /* S, Create GOT entry */ + RELOC_NUMBER (R_860_JUMP_SLOT, 0x04) /* S+A, Create PLT entry */ + RELOC_NUMBER (R_860_RELATIVE, 0x05) /* B+A, Adj by program base */ + RELOC_NUMBER (R_860_PC26, 0x30) /* (S+A-P) >> 2 */ + RELOC_NUMBER (R_860_PLT26, 0x31) /* (L+A-P) >> 2 */ + RELOC_NUMBER (R_860_PC16, 0x32) /* (S+A-P) >> 2 */ + RELOC_NUMBER (R_860_LOW0, 0x40) /* S+A */ + RELOC_NUMBER (R_860_SPLIT0, 0x42) /* S+A */ + RELOC_NUMBER (R_860_LOW1, 0x44) /* S+A */ + RELOC_NUMBER (R_860_SPLIT1, 0x46) /* S+A */ + RELOC_NUMBER (R_860_LOW2, 0x48) /* S+A */ + RELOC_NUMBER (R_860_SPLIT2, 0x4A) /* S+A */ + RELOC_NUMBER (R_860_LOW3, 0x4C) /* S+A */ + RELOC_NUMBER (R_860_LOGOT0, 0x50) /* G */ + RELOC_NUMBER (R_860_SPGOT0, 0x52) /* G */ + RELOC_NUMBER (R_860_LOGOT1, 0x54) /* G */ + RELOC_NUMBER (R_860_SPGOT1, 0x56) /* G */ + RELOC_NUMBER (R_860_LOGOTOFF0, 0x60) /* O */ + RELOC_NUMBER (R_860_SPGOTOFF0, 0x62) /* O */ + RELOC_NUMBER (R_860_LOGOTOFF1, 0x64) /* O */ + RELOC_NUMBER (R_860_SPGOTOFF1, 0x66) /* O */ + RELOC_NUMBER (R_860_LOGOTOFF2, 0x68) /* O */ + RELOC_NUMBER (R_860_LOGOTOFF3, 0x6C) /* O */ + RELOC_NUMBER (R_860_LOPC, 0x70) /* (S+A-P) >> 2 */ + RELOC_NUMBER (R_860_HIGHADJ, 0x80) /* hiadj(S+A) */ + RELOC_NUMBER (R_860_HAGOT, 0x90) /* hiadj(G) */ + RELOC_NUMBER (R_860_HAGOTOFF, 0xA0) /* hiadj(O) */ + RELOC_NUMBER (R_860_HAPC, 0xB0) /* hiadj((S+A-P) >> 2) */ + RELOC_NUMBER (R_860_HIGH, 0xC0) /* (S+A) >> 16 */ + RELOC_NUMBER (R_860_HIGOT, 0xD0) /* G >> 16 */ + RELOC_NUMBER (R_860_HIGOTOFF, 0xE0) /* O */ +END_RELOC_NUMBERS (R_860_max) + +#endif diff --git a/contrib/binutils-2.14/include/elf/i960.h b/contrib/binutils-2.14/include/elf/i960.h new file mode 100644 index 0000000000..253e438522 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/i960.h @@ -0,0 +1,37 @@ +/* Intel 960 ELF support for BFD. + Copyright 1999, 2000 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_I960_H +#define _ELF_I960_H + +#include "elf/reloc-macros.h" + + +START_RELOC_NUMBERS (elf_i960_reloc_type) + RELOC_NUMBER (R_960_NONE, 0) + RELOC_NUMBER (R_960_12, 1) + RELOC_NUMBER (R_960_32, 2) + RELOC_NUMBER (R_960_IP24, 3) + RELOC_NUMBER (R_960_SUB, 4) + RELOC_NUMBER (R_960_OPTCALL, 5) + RELOC_NUMBER (R_960_OPTCALLX, 6) + RELOC_NUMBER (R_960_OPTCALLXA, 7) +END_RELOC_NUMBERS (R_960_max) + +#endif /* _ELF_I960_H */ diff --git a/contrib/binutils-2.14/include/elf/ia64.h b/contrib/binutils-2.14/include/elf/ia64.h new file mode 100644 index 0000000000..06dfa606dc --- /dev/null +++ b/contrib/binutils-2.14/include/elf/ia64.h @@ -0,0 +1,216 @@ +/* IA-64 ELF support for BFD. + Copyright 1998, 1999, 2000, 2003 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_IA64_H +#define _ELF_IA64_H + +/* Bits in the e_flags field of the Elf64_Ehdr: */ + +#define EF_IA_64_MASKOS 0x0000000f /* OS-specific flags. */ +#define EF_IA_64_ARCH 0xff000000 /* Arch. version mask. */ + +/* ??? These four definitions are not part of the SVR4 ABI. + They were present in David's initial code drop, so it is probable + that they are used by HP/UX. */ +#define EF_IA_64_TRAPNIL (1 << 0) /* Trap NIL pointer dereferences. */ +#define EF_IA_64_EXT (1 << 2) /* Program uses arch. extensions. */ +#define EF_IA_64_BE (1 << 3) /* PSR BE bit set (big-endian). */ +#define EFA_IA_64_EAS2_3 0x23000000 /* IA64 EAS 2.3. */ + +#define EF_IA_64_ABI64 (1 << 4) /* 64-bit ABI. */ +/* Not used yet. */ +#define EF_IA_64_REDUCEDFP (1 << 5) /* Only FP6-FP11 used. */ +#define EF_IA_64_CONS_GP (1 << 6) /* gp as program wide constant. */ +#define EF_IA_64_NOFUNCDESC_CONS_GP (1 << 7) /* And no function descriptors. */ +/* Not used yet. */ +#define EF_IA_64_ABSOLUTE (1 << 8) /* Load at absolute addresses. */ + +#define ELF_STRING_ia64_archext ".IA_64.archext" +#define ELF_STRING_ia64_pltoff ".IA_64.pltoff" +#define ELF_STRING_ia64_unwind ".IA_64.unwind" +#define ELF_STRING_ia64_unwind_info ".IA_64.unwind_info" +#define ELF_STRING_ia64_unwind_once ".gnu.linkonce.ia64unw." +#define ELF_STRING_ia64_unwind_info_once ".gnu.linkonce.ia64unwi." +/* .IA_64.unwind_hdr is only used by HP-UX. */ +#define ELF_STRING_ia64_unwind_hdr ".IA_64.unwind_hdr" + +/* Bits in the sh_flags field of Elf64_Shdr: */ + +#define SHF_IA_64_SHORT 0x10000000 /* Section near gp. */ +#define SHF_IA_64_NORECOV 0x20000000 /* Spec insns w/o recovery. */ + +/* Possible values for sh_type in Elf64_Shdr: */ + +#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* Extension bits. */ +#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* Unwind bits. */ +#define SHT_IA_64_LOPSREG (SHT_LOPROC + 0x8000000) +/* ABI says (SHT_LOPROC + 0xfffffff) but I think it's a typo -- this makes sense. */ +#define SHT_IA_64_HIPSREG (SHT_LOPROC + 0x8ffffff) +#define SHT_IA_64_PRIORITY_INIT (SHT_LOPROC + 0x9000000) + +/* SHT_IA_64_HP_OPT_ANOT is only generated by HPUX compilers for its + optimization annotation section. GCC does not generate it but we + want readelf to know what they are. Do not use two capital Ns in + annotate or sed will turn it into 32 or 64 during the build. */ +#define SHT_IA_64_HP_OPT_ANOT 0x60000004 + +/* Bits in the p_flags field of Elf64_Phdr: */ + +#define PF_IA_64_NORECOV 0x80000000 + +/* Possible values for p_type in Elf64_Phdr: */ + +#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* Arch extension bits, */ +#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* IA64 unwind bits. */ + +/* HP-UX specific values for p_type in Elf64_Phdr. + These values are currently just used to make + readelf more usable on HP-UX. */ + +#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) +#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) +#define PT_IA_64_HP_STACK (PT_LOOS + 0x14) + +/* Possible values for d_tag in Elf64_Dyn: */ + +#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) + +/* This section only used by HP-UX, The HP linker gives weak symbols + precedence over regular common symbols. We want common to override + weak. Using this common instead of SHN_COMMON does that. */ +#define SHN_IA_64_ANSI_COMMON 0xFF00 + +/* IA64-specific relocation types: */ + +/* Relocs apply to specific instructions within a bundle. The least + significant 2 bits of the address indicate which instruction in the + bundle the reloc refers to (0=first slot, 1=second slow, 2=third + slot, 3=undefined) and the remaining bits give the address of the + bundle (16 byte aligned). + + The top 5 bits of the reloc code specifies the expression type, the + low 3 bits the format of the data word being relocated. */ + +#include "elf/reloc-macros.h" + +START_RELOC_NUMBERS (elf_ia64_reloc_type) + RELOC_NUMBER (R_IA64_NONE, 0x00) /* none */ + + RELOC_NUMBER (R_IA64_IMM14, 0x21) /* symbol + addend, add imm14 */ + RELOC_NUMBER (R_IA64_IMM22, 0x22) /* symbol + addend, add imm22 */ + RELOC_NUMBER (R_IA64_IMM64, 0x23) /* symbol + addend, mov imm64 */ + RELOC_NUMBER (R_IA64_DIR32MSB, 0x24) /* symbol + addend, data4 MSB */ + RELOC_NUMBER (R_IA64_DIR32LSB, 0x25) /* symbol + addend, data4 LSB */ + RELOC_NUMBER (R_IA64_DIR64MSB, 0x26) /* symbol + addend, data8 MSB */ + RELOC_NUMBER (R_IA64_DIR64LSB, 0x27) /* symbol + addend, data8 LSB */ + + RELOC_NUMBER (R_IA64_GPREL22, 0x2a) /* @gprel(sym+add), add imm22 */ + RELOC_NUMBER (R_IA64_GPREL64I, 0x2b) /* @gprel(sym+add), mov imm64 */ + RELOC_NUMBER (R_IA64_GPREL32MSB, 0x2c) /* @gprel(sym+add), data4 MSB */ + RELOC_NUMBER (R_IA64_GPREL32LSB, 0x2d) /* @gprel(sym+add), data4 LSB */ + RELOC_NUMBER (R_IA64_GPREL64MSB, 0x2e) /* @gprel(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_GPREL64LSB, 0x2f) /* @gprel(sym+add), data8 LSB */ + + RELOC_NUMBER (R_IA64_LTOFF22, 0x32) /* @ltoff(sym+add), add imm22 */ + RELOC_NUMBER (R_IA64_LTOFF64I, 0x33) /* @ltoff(sym+add), mov imm64 */ + + RELOC_NUMBER (R_IA64_PLTOFF22, 0x3a) /* @pltoff(sym+add), add imm22 */ + RELOC_NUMBER (R_IA64_PLTOFF64I, 0x3b) /* @pltoff(sym+add), mov imm64 */ + RELOC_NUMBER (R_IA64_PLTOFF64MSB, 0x3e) /* @pltoff(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_PLTOFF64LSB, 0x3f) /* @pltoff(sym+add), data8 LSB */ + + RELOC_NUMBER (R_IA64_FPTR64I, 0x43) /* @fptr(sym+add), mov imm64 */ + RELOC_NUMBER (R_IA64_FPTR32MSB, 0x44) /* @fptr(sym+add), data4 MSB */ + RELOC_NUMBER (R_IA64_FPTR32LSB, 0x45) /* @fptr(sym+add), data4 LSB */ + RELOC_NUMBER (R_IA64_FPTR64MSB, 0x46) /* @fptr(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_FPTR64LSB, 0x47) /* @fptr(sym+add), data8 LSB */ + + RELOC_NUMBER (R_IA64_PCREL60B, 0x48) /* @pcrel(sym+add), brl */ + RELOC_NUMBER (R_IA64_PCREL21B, 0x49) /* @pcrel(sym+add), ptb, call */ + RELOC_NUMBER (R_IA64_PCREL21M, 0x4a) /* @pcrel(sym+add), chk.s */ + RELOC_NUMBER (R_IA64_PCREL21F, 0x4b) /* @pcrel(sym+add), fchkf */ + RELOC_NUMBER (R_IA64_PCREL32MSB, 0x4c) /* @pcrel(sym+add), data4 MSB */ + RELOC_NUMBER (R_IA64_PCREL32LSB, 0x4d) /* @pcrel(sym+add), data4 LSB */ + RELOC_NUMBER (R_IA64_PCREL64MSB, 0x4e) /* @pcrel(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_PCREL64LSB, 0x4f) /* @pcrel(sym+add), data8 LSB */ + + RELOC_NUMBER (R_IA64_LTOFF_FPTR22, 0x52) /* @ltoff(@fptr(s+a)), imm22 */ + RELOC_NUMBER (R_IA64_LTOFF_FPTR64I, 0x53) /* @ltoff(@fptr(s+a)), imm64 */ + RELOC_NUMBER (R_IA64_LTOFF_FPTR32MSB, 0x54) /* @ltoff(@fptr(s+a)), 4 MSB */ + RELOC_NUMBER (R_IA64_LTOFF_FPTR32LSB, 0x55) /* @ltoff(@fptr(s+a)), 4 LSB */ + RELOC_NUMBER (R_IA64_LTOFF_FPTR64MSB, 0x56) /* @ltoff(@fptr(s+a)), 8 MSB */ + RELOC_NUMBER (R_IA64_LTOFF_FPTR64LSB, 0x57) /* @ltoff(@fptr(s+a)), 8 LSB */ + + RELOC_NUMBER (R_IA64_SEGREL32MSB, 0x5c) /* @segrel(sym+add), data4 MSB */ + RELOC_NUMBER (R_IA64_SEGREL32LSB, 0x5d) /* @segrel(sym+add), data4 LSB */ + RELOC_NUMBER (R_IA64_SEGREL64MSB, 0x5e) /* @segrel(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_SEGREL64LSB, 0x5f) /* @segrel(sym+add), data8 LSB */ + + RELOC_NUMBER (R_IA64_SECREL32MSB, 0x64) /* @secrel(sym+add), data4 MSB */ + RELOC_NUMBER (R_IA64_SECREL32LSB, 0x65) /* @secrel(sym+add), data4 LSB */ + RELOC_NUMBER (R_IA64_SECREL64MSB, 0x66) /* @secrel(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_SECREL64LSB, 0x67) /* @secrel(sym+add), data8 LSB */ + + RELOC_NUMBER (R_IA64_REL32MSB, 0x6c) /* data 4 + REL */ + RELOC_NUMBER (R_IA64_REL32LSB, 0x6d) /* data 4 + REL */ + RELOC_NUMBER (R_IA64_REL64MSB, 0x6e) /* data 8 + REL */ + RELOC_NUMBER (R_IA64_REL64LSB, 0x6f) /* data 8 + REL */ + + RELOC_NUMBER (R_IA64_LTV32MSB, 0x74) /* symbol + addend, data4 MSB */ + RELOC_NUMBER (R_IA64_LTV32LSB, 0x75) /* symbol + addend, data4 LSB */ + RELOC_NUMBER (R_IA64_LTV64MSB, 0x76) /* symbol + addend, data8 MSB */ + RELOC_NUMBER (R_IA64_LTV64LSB, 0x77) /* symbol + addend, data8 LSB */ + + RELOC_NUMBER (R_IA64_PCREL21BI, 0x79) /* @pcrel(sym+add), ptb, call */ + RELOC_NUMBER (R_IA64_PCREL22, 0x7a) /* @pcrel(sym+add), imm22 */ + RELOC_NUMBER (R_IA64_PCREL64I, 0x7b) /* @pcrel(sym+add), imm64 */ + + RELOC_NUMBER (R_IA64_IPLTMSB, 0x80) /* dynamic reloc, imported PLT, MSB */ + RELOC_NUMBER (R_IA64_IPLTLSB, 0x81) /* dynamic reloc, imported PLT, LSB */ + RELOC_NUMBER (R_IA64_COPY, 0x84) /* dynamic reloc, data copy */ + RELOC_NUMBER (R_IA64_LTOFF22X, 0x86) /* LTOFF22, relaxable. */ + RELOC_NUMBER (R_IA64_LDXMOV, 0x87) /* Use of LTOFF22X. */ + + RELOC_NUMBER (R_IA64_TPREL14, 0x91) /* @tprel(sym+add), add imm14 */ + RELOC_NUMBER (R_IA64_TPREL22, 0x92) /* @tprel(sym+add), add imm22 */ + RELOC_NUMBER (R_IA64_TPREL64I, 0x93) /* @tprel(sym+add), add imm64 */ + RELOC_NUMBER (R_IA64_TPREL64MSB, 0x96) /* @tprel(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_TPREL64LSB, 0x97) /* @tprel(sym+add), data8 LSB */ + + RELOC_NUMBER (R_IA64_LTOFF_TPREL22, 0x9a) /* @ltoff(@tprel(s+a)), add imm22 */ + + RELOC_NUMBER (R_IA64_DTPMOD64MSB, 0xa6) /* @dtpmod(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_DTPMOD64LSB, 0xa7) /* @dtpmod(sym+add), data8 LSB */ + RELOC_NUMBER (R_IA64_LTOFF_DTPMOD22, 0xaa) /* @ltoff(@dtpmod(s+a)), imm22 */ + + RELOC_NUMBER (R_IA64_DTPREL14, 0xb1) /* @dtprel(sym+add), imm14 */ + RELOC_NUMBER (R_IA64_DTPREL22, 0xb2) /* @dtprel(sym+add), imm22 */ + RELOC_NUMBER (R_IA64_DTPREL64I, 0xb3) /* @dtprel(sym+add), imm64 */ + RELOC_NUMBER (R_IA64_DTPREL32MSB, 0xb4) /* @dtprel(sym+add), data4 MSB */ + RELOC_NUMBER (R_IA64_DTPREL32LSB, 0xb5) /* @dtprel(sym+add), data4 LSB */ + RELOC_NUMBER (R_IA64_DTPREL64MSB, 0xb6) /* @dtprel(sym+add), data8 MSB */ + RELOC_NUMBER (R_IA64_DTPREL64LSB, 0xb7) /* @dtprel(sym+add), data8 LSB */ + + RELOC_NUMBER (R_IA64_LTOFF_DTPREL22, 0xba) /* @ltoff(@dtprel(s+a)), imm22 */ + + FAKE_RELOC (R_IA64_MAX_RELOC_CODE, 0xba) +END_RELOC_NUMBERS (R_IA64_max) + +#endif /* _ELF_IA64_H */ diff --git a/contrib/binutils-2.14/include/elf/internal.h b/contrib/binutils-2.14/include/elf/internal.h new file mode 100644 index 0000000000..45d682a225 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/internal.h @@ -0,0 +1,247 @@ +/* ELF support for BFD. + Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002 + Free Software Foundation, Inc. + + Written by Fred Fish @ Cygnus Support, from information published + in "UNIX System V Release 4, Programmers Guide: ANSI C and + Programming Support Tools". + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + +/* This file is part of ELF support for BFD, and contains the portions + that describe how ELF is represented internally in the BFD library. + I.E. it describes the in-memory representation of ELF. It requires + the elf-common.h file which contains the portions that are common to + both the internal and external representations. */ + + +/* NOTE that these structures are not kept in the same order as they appear + in the object file. In some cases they've been reordered for more optimal + packing under various circumstances. */ + +#ifndef _ELF_INTERNAL_H +#define _ELF_INTERNAL_H + +/* ELF Header */ + +#define EI_NIDENT 16 /* Size of e_ident[] */ + +typedef struct elf_internal_ehdr { + unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ + bfd_vma e_entry; /* Entry point virtual address */ + bfd_size_type e_phoff; /* Program header table file offset */ + bfd_size_type e_shoff; /* Section header table file offset */ + unsigned long e_version; /* Identifies object file version */ + unsigned long e_flags; /* Processor-specific flags */ + unsigned short e_type; /* Identifies object file type */ + unsigned short e_machine; /* Specifies required architecture */ + unsigned int e_ehsize; /* ELF header size in bytes */ + unsigned int e_phentsize; /* Program header table entry size */ + unsigned int e_phnum; /* Program header table entry count */ + unsigned int e_shentsize; /* Section header table entry size */ + unsigned int e_shnum; /* Section header table entry count */ + unsigned int e_shstrndx; /* Section header string table index */ +} Elf_Internal_Ehdr; + +/* Program header */ + +struct elf_internal_phdr { + unsigned long p_type; /* Identifies program segment type */ + unsigned long p_flags; /* Segment flags */ + bfd_vma p_offset; /* Segment file offset */ + bfd_vma p_vaddr; /* Segment virtual address */ + bfd_vma p_paddr; /* Segment physical address */ + bfd_vma p_filesz; /* Segment size in file */ + bfd_vma p_memsz; /* Segment size in memory */ + bfd_vma p_align; /* Segment alignment, file & memory */ +}; + +typedef struct elf_internal_phdr Elf_Internal_Phdr; + +/* Section header */ + +typedef struct elf_internal_shdr { + unsigned int sh_name; /* Section name, index in string tbl */ + unsigned int sh_type; /* Type of section */ + bfd_vma sh_flags; /* Miscellaneous section attributes */ + bfd_vma sh_addr; /* Section virtual addr at execution */ + bfd_size_type sh_size; /* Size of section in bytes */ + bfd_size_type sh_entsize; /* Entry size if section holds table */ + unsigned long sh_link; /* Index of another section */ + unsigned long sh_info; /* Additional section information */ + file_ptr sh_offset; /* Section file offset */ + unsigned int sh_addralign; /* Section alignment */ + + /* The internal rep also has some cached info associated with it. */ + asection * bfd_section; /* Associated BFD section. */ + unsigned char *contents; /* Section contents. */ +} Elf_Internal_Shdr; + +/* Symbol table entry */ + +struct elf_internal_sym { + bfd_vma st_value; /* Value of the symbol */ + bfd_vma st_size; /* Associated symbol size */ + unsigned long st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* Visibilty, and target specific */ + unsigned int st_shndx; /* Associated section index */ +}; + +typedef struct elf_internal_sym Elf_Internal_Sym; + +/* Note segments */ + +typedef struct elf_internal_note { + unsigned long namesz; /* Size of entry's owner string */ + unsigned long descsz; /* Size of the note descriptor */ + unsigned long type; /* Interpretation of the descriptor */ + char * namedata; /* Start of the name+desc data */ + char * descdata; /* Start of the desc data */ + bfd_vma descpos; /* File offset of the descdata */ +} Elf_Internal_Note; + +/* Relocation Entries */ + +typedef struct elf_internal_rela { + bfd_vma r_offset; /* Location at which to apply the action */ + bfd_vma r_info; /* Index and Type of relocation */ + bfd_vma r_addend; /* Constant addend used to compute value */ +} Elf_Internal_Rela; + +/* dynamic section structure */ + +typedef struct elf_internal_dyn { + /* This needs to support 64-bit values in elf64. */ + bfd_vma d_tag; /* entry tag value */ + union { + /* This needs to support 64-bit values in elf64. */ + bfd_vma d_val; + bfd_vma d_ptr; + } d_un; +} Elf_Internal_Dyn; + +/* This structure appears in a SHT_GNU_verdef section. */ + +typedef struct elf_internal_verdef { + unsigned short vd_version; /* Version number of structure. */ + unsigned short vd_flags; /* Flags (VER_FLG_*). */ + unsigned short vd_ndx; /* Version index. */ + unsigned short vd_cnt; /* Number of verdaux entries. */ + unsigned long vd_hash; /* Hash of name. */ + unsigned long vd_aux; /* Offset to verdaux entries. */ + unsigned long vd_next; /* Offset to next verdef. */ + + /* These fields are set up when BFD reads in the structure. FIXME: + It would be cleaner to store these in a different structure. */ + bfd *vd_bfd; /* BFD. */ + const char *vd_nodename; /* Version name. */ + struct elf_internal_verdef *vd_nextdef; /* vd_next as pointer. */ + struct elf_internal_verdaux *vd_auxptr; /* vd_aux as pointer. */ + unsigned int vd_exp_refno; /* Used by the linker. */ +} Elf_Internal_Verdef; + +/* This structure appears in a SHT_GNU_verdef section. */ + +typedef struct elf_internal_verdaux { + unsigned long vda_name; /* String table offset of name. */ + unsigned long vda_next; /* Offset to next verdaux. */ + + /* These fields are set up when BFD reads in the structure. FIXME: + It would be cleaner to store these in a different structure. */ + const char *vda_nodename; /* vda_name as pointer. */ + struct elf_internal_verdaux *vda_nextptr; /* vda_next as pointer. */ +} Elf_Internal_Verdaux; + +/* This structure appears in a SHT_GNU_verneed section. */ + +typedef struct elf_internal_verneed { + unsigned short vn_version; /* Version number of structure. */ + unsigned short vn_cnt; /* Number of vernaux entries. */ + unsigned long vn_file; /* String table offset of library name. */ + unsigned long vn_aux; /* Offset to vernaux entries. */ + unsigned long vn_next; /* Offset to next verneed. */ + + /* These fields are set up when BFD reads in the structure. FIXME: + It would be cleaner to store these in a different structure. */ + bfd *vn_bfd; /* BFD. */ + const char *vn_filename; /* vn_file as pointer. */ + struct elf_internal_vernaux *vn_auxptr; /* vn_aux as pointer. */ + struct elf_internal_verneed *vn_nextref; /* vn_nextref as pointer. */ +} Elf_Internal_Verneed; + +/* This structure appears in a SHT_GNU_verneed section. */ + +typedef struct elf_internal_vernaux { + unsigned long vna_hash; /* Hash of dependency name. */ + unsigned short vna_flags; /* Flags (VER_FLG_*). */ + unsigned short vna_other; /* Unused. */ + unsigned long vna_name; /* String table offset to version name. */ + unsigned long vna_next; /* Offset to next vernaux. */ + + /* These fields are set up when BFD reads in the structure. FIXME: + It would be cleaner to store these in a different structure. */ + const char *vna_nodename; /* vna_name as pointer. */ + struct elf_internal_vernaux *vna_nextptr; /* vna_next as pointer. */ +} Elf_Internal_Vernaux; + +/* This structure appears in a SHT_GNU_versym section. This is not a + standard ELF structure; ELF just uses Elf32_Half. */ + +typedef struct elf_internal_versym { + unsigned short vs_vers; +} Elf_Internal_Versym; + +/* Structure for syminfo section. */ +typedef struct +{ + unsigned short int si_boundto; + unsigned short int si_flags; +} Elf_Internal_Syminfo; + + +/* This structure is used to describe how sections should be assigned + to program segments. */ + +struct elf_segment_map +{ + /* Next program segment. */ + struct elf_segment_map *next; + /* Program segment type. */ + unsigned long p_type; + /* Program segment flags. */ + unsigned long p_flags; + /* Program segment physical address. */ + bfd_vma p_paddr; + /* Whether the p_flags field is valid; if not, the flags are based + on the section flags. */ + unsigned int p_flags_valid : 1; + /* Whether the p_paddr field is valid; if not, the physical address + is based on the section lma values. */ + unsigned int p_paddr_valid : 1; + /* Whether this segment includes the file header. */ + unsigned int includes_filehdr : 1; + /* Whether this segment includes the program headers. */ + unsigned int includes_phdrs : 1; + /* Number of sections (may be 0). */ + unsigned int count; + /* Sections. Actual number of elements is in count field. */ + asection *sections[1]; +}; + +#endif /* _ELF_INTERNAL_H */ diff --git a/contrib/binutils-2.14/include/elf/ip2k.h b/contrib/binutils-2.14/include/elf/ip2k.h new file mode 100644 index 0000000000..c331b720fa --- /dev/null +++ b/contrib/binutils-2.14/include/elf/ip2k.h @@ -0,0 +1,62 @@ +/* IP2xxx ELF support for BFD. + Copyright (C) 2000, 2002 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_IP2K_H +#define _ELF_IP2K_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_ip2k_reloc_type) + RELOC_NUMBER (R_IP2K_NONE, 0) + RELOC_NUMBER (R_IP2K_16, 1) + RELOC_NUMBER (R_IP2K_32, 2) + RELOC_NUMBER (R_IP2K_FR9, 3) + RELOC_NUMBER (R_IP2K_BANK, 4) + RELOC_NUMBER (R_IP2K_ADDR16CJP, 5) + RELOC_NUMBER (R_IP2K_PAGE3, 6) + RELOC_NUMBER (R_IP2K_LO8DATA, 7) + RELOC_NUMBER (R_IP2K_HI8DATA, 8) + RELOC_NUMBER (R_IP2K_LO8INSN, 9) + RELOC_NUMBER (R_IP2K_HI8INSN, 10) + RELOC_NUMBER (R_IP2K_PC_SKIP, 11) + RELOC_NUMBER (R_IP2K_TEXT, 12) + RELOC_NUMBER (R_IP2K_FR_OFFSET, 13) + RELOC_NUMBER (R_IP2K_EX8DATA, 14) +END_RELOC_NUMBERS(R_IP2K_max) + + +/* Define the data & instruction memory discriminator. In a linked + executable, an symbol should be deemed to point to an instruction + if ((address & IP2K_INSN_MASK) == IP2K_INSN_VALUE), and similarly + for the data space. See also `ld/emulparams/elf32ip2k.sh'. */ +/* ??? Consider extending the _MASK values to include all the + intermediate bits that must be zero due to the limited physical + memory size on the IP2K. */ + +#define IP2K_DATA_MASK 0xff000000 +#define IP2K_DATA_VALUE 0x01000000 +#define IP2K_INSN_MASK 0xff000000 +#define IP2K_INSN_VALUE 0x02000000 + +/* The location of the memory mapped hardware stack. */ +#define IP2K_STACK_VALUE 0x0f000000 +#define IP2K_STACK_SIZE 0x20 + +#endif /* _ELF_IP2K_H */ diff --git a/contrib/binutils-2.14/include/elf/iq2000.h b/contrib/binutils-2.14/include/elf/iq2000.h new file mode 100644 index 0000000000..83c690c709 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/iq2000.h @@ -0,0 +1,58 @@ +/* IQ2000 ELF support for BFD. + Copyright (C) 2002 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_IQ2000_H +#define _ELF_IQ2000_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_iq2000_reloc_type) + RELOC_NUMBER (R_IQ2000_NONE, 0) + RELOC_NUMBER (R_IQ2000_16, 1) + RELOC_NUMBER (R_IQ2000_32, 2) + RELOC_NUMBER (R_IQ2000_26, 3) + RELOC_NUMBER (R_IQ2000_PC16, 4) + RELOC_NUMBER (R_IQ2000_HI16, 5) + RELOC_NUMBER (R_IQ2000_LO16, 6) + RELOC_NUMBER (R_IQ2000_OFFSET_16, 7) + RELOC_NUMBER (R_IQ2000_OFFSET_21, 8) + RELOC_NUMBER (R_IQ2000_UHI16, 9) + RELOC_NUMBER (R_IQ2000_32_DEBUG, 10) + RELOC_NUMBER (R_IQ2000_GNU_VTINHERIT, 200) + RELOC_NUMBER (R_IQ2000_GNU_VTENTRY, 201) +END_RELOC_NUMBERS(R_IQ2000_max) + +#define EF_IQ2000_CPU_IQ2000 0x00000001 /* default */ +#define EF_IQ2000_CPU_IQ10 0x00000002 /* IQ10 */ +#define EF_IQ2000_CPU_MASK 0x00000003 /* specific cpu bits */ +#define EF_IQ2000_ALL_FLAGS (EF_IQ2000_CPU_MASK) + +/* Define the data & instruction memory discriminator. In a linked + executable, an symbol should be deemed to point to an instruction + if ((address & IQ2000_INSN_MASK) == IQ2000_INSN_VALUE), and similarly + for the data space. */ + +#define IQ2000_DATA_MASK 0x80000000 +#define IQ2000_DATA_VALUE 0x00000000 +#define IQ2000_INSN_MASK 0x80000000 +#define IQ2000_INSN_VALUE 0x80000000 + + +#endif /* _ELF_IQ2000_H */ diff --git a/contrib/binutils-2.14/include/elf/m32r.h b/contrib/binutils-2.14/include/elf/m32r.h new file mode 100644 index 0000000000..2cb308d3a9 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/m32r.h @@ -0,0 +1,67 @@ +/* M32R ELF support for BFD. + Copyright 1996, 1997, 1998, 1999, 2000 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_M32R_H +#define _ELF_M32R_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_m32r_reloc_type) + RELOC_NUMBER (R_M32R_NONE, 0) + RELOC_NUMBER (R_M32R_16, 1) + RELOC_NUMBER (R_M32R_32, 2) + RELOC_NUMBER (R_M32R_24, 3) + RELOC_NUMBER (R_M32R_10_PCREL, 4) + RELOC_NUMBER (R_M32R_18_PCREL, 5) + RELOC_NUMBER (R_M32R_26_PCREL, 6) + RELOC_NUMBER (R_M32R_HI16_ULO, 7) + RELOC_NUMBER (R_M32R_HI16_SLO, 8) + RELOC_NUMBER (R_M32R_LO16, 9) + RELOC_NUMBER (R_M32R_SDA16, 10) + RELOC_NUMBER (R_M32R_GNU_VTINHERIT, 11) + RELOC_NUMBER (R_M32R_GNU_VTENTRY, 12) +END_RELOC_NUMBERS (R_M32R_max) + +/* Processor specific section indices. These sections do not actually + exist. Symbols with a st_shndx field corresponding to one of these + values have a special meaning. */ + +/* Small common symbol. */ +#define SHN_M32R_SCOMMON 0xff00 + +/* Processor specific section flags. */ + +/* This section contains sufficient relocs to be relaxed. + When relaxing, even relocs of branch instructions the assembler could + complete must be present because relaxing may cause the branch target to + move. */ +#define SHF_M32R_CAN_RELAX 0x10000000 + +/* Processor specific flags for the ELF header e_flags field. */ + +/* Two bit m32r architecture field. */ +#define EF_M32R_ARCH 0x30000000 + +/* m32r code. */ +#define E_M32R_ARCH 0x00000000 +/* m32rx code. */ +#define E_M32RX_ARCH 0x10000000 + +#endif diff --git a/contrib/binutils-2.14/include/elf/m68hc11.h b/contrib/binutils-2.14/include/elf/m68hc11.h new file mode 100644 index 0000000000..1902f7fa67 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/m68hc11.h @@ -0,0 +1,95 @@ +/* m68hc11 & m68hc12 ELF support for BFD. + Copyright 1999, 2000, 2001, 2002 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_M68HC11_H +#define _ELF_M68HC11_H + +#include "elf/reloc-macros.h" + +/* Relocation types. */ +START_RELOC_NUMBERS (elf_m68hc11_reloc_type) + RELOC_NUMBER (R_M68HC11_NONE, 0) + RELOC_NUMBER (R_M68HC11_8, 1) + RELOC_NUMBER (R_M68HC11_HI8, 2) + RELOC_NUMBER (R_M68HC11_LO8, 3) + RELOC_NUMBER (R_M68HC11_PCREL_8, 4) + RELOC_NUMBER (R_M68HC11_16, 5) + RELOC_NUMBER (R_M68HC11_32, 6) + RELOC_NUMBER (R_M68HC11_3B, 7) + RELOC_NUMBER (R_M68HC11_PCREL_16, 8) + + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_M68HC11_GNU_VTINHERIT, 9) + RELOC_NUMBER (R_M68HC11_GNU_VTENTRY, 10) + + RELOC_NUMBER (R_M68HC11_24, 11) + RELOC_NUMBER (R_M68HC11_LO16, 12) + RELOC_NUMBER (R_M68HC11_PAGE, 13) + + /* GNU extension for linker relaxation. + Mark beginning of a jump instruction (any form). */ + RELOC_NUMBER (R_M68HC11_RL_JUMP, 20) + + /* Mark beginning of Gcc relaxation group instruction. */ + RELOC_NUMBER (R_M68HC11_RL_GROUP, 21) +END_RELOC_NUMBERS (R_M68HC11_max) + +/* Processor specific flags for the ELF header e_flags field. */ + +/* ABI identification. */ +#define EF_M68HC11_ABI 0x00000000F + +/* Integers are 32-bit long. */ +#define E_M68HC11_I32 0x000000001 + +/* Doubles are 64-bit long. */ +#define E_M68HC11_F64 0x000000002 + +/* Uses 68HC12 memory banks. */ +#define E_M68HC12_BANKS 0x000000004 + +#define EF_M68HC11_MACH_MASK 0xF0 +#define EF_M68HC11_GENERIC 0x00 /* Generic 68HC12/backward compatibility. */ +#define EF_M68HC12_MACH 0x10 /* 68HC12 microcontroller. */ +#define EF_M68HCS12_MACH 0x20 /* 68HCS12 microcontroller. */ +#define EF_M68HC11_MACH(mach) ((mach) & EF_M68HC11_MACH_MASK) + +/* True if we can merge machines. A generic HC12 can work on any proc + but once we have specific code, merge is not possible. */ +#define EF_M68HC11_CAN_MERGE_MACH(mach1, mach2) \ + ((EF_M68HC11_MACH (mach1) == EF_M68HC11_MACH (mach2)) \ + || (EF_M68HC11_MACH (mach1) == EF_M68HC11_GENERIC) \ + || (EF_M68HC11_MACH (mach2) == EF_M68HC11_GENERIC)) + +#define EF_M68HC11_MERGE_MACH(mach1, mach2) \ + (((EF_M68HC11_MACH (mach1) == EF_M68HC11_MACH (mach2)) \ + || (EF_M68HC11_MACH (mach1) == EF_M68HC11_GENERIC)) ? \ + EF_M68HC11_MACH (mach2) : EF_M68HC11_MACH (mach1)) + + +/* Special values for the st_other field in the symbol table. These + are used for 68HC12 to identify far functions (must be called with + 'call' and returns with 'rtc'). */ +#define STO_M68HC12_FAR 0x80 + +/* Identify interrupt handlers. This is used by the debugger to + correctly compute the stack frame. */ +#define STO_M68HC12_INTERRUPT 0x40 + +#endif diff --git a/contrib/binutils-2.14/include/elf/m68k.h b/contrib/binutils-2.14/include/elf/m68k.h new file mode 100644 index 0000000000..7769c59eb3 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/m68k.h @@ -0,0 +1,58 @@ +/* MC68k ELF support for BFD. + Copyright 1998, 1999, 2000 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_M68K_H +#define _ELF_M68K_H + +#include "elf/reloc-macros.h" + +/* Relocation types. */ +START_RELOC_NUMBERS (elf_m68k_reloc_type) + RELOC_NUMBER (R_68K_NONE, 0) /* No reloc */ + RELOC_NUMBER (R_68K_32, 1) /* Direct 32 bit */ + RELOC_NUMBER (R_68K_16, 2) /* Direct 16 bit */ + RELOC_NUMBER (R_68K_8, 3) /* Direct 8 bit */ + RELOC_NUMBER (R_68K_PC32, 4) /* PC relative 32 bit */ + RELOC_NUMBER (R_68K_PC16, 5) /* PC relative 16 bit */ + RELOC_NUMBER (R_68K_PC8, 6) /* PC relative 8 bit */ + RELOC_NUMBER (R_68K_GOT32, 7) /* 32 bit PC relative GOT entry */ + RELOC_NUMBER (R_68K_GOT16, 8) /* 16 bit PC relative GOT entry */ + RELOC_NUMBER (R_68K_GOT8, 9) /* 8 bit PC relative GOT entry */ + RELOC_NUMBER (R_68K_GOT32O, 10) /* 32 bit GOT offset */ + RELOC_NUMBER (R_68K_GOT16O, 11) /* 16 bit GOT offset */ + RELOC_NUMBER (R_68K_GOT8O, 12) /* 8 bit GOT offset */ + RELOC_NUMBER (R_68K_PLT32, 13) /* 32 bit PC relative PLT address */ + RELOC_NUMBER (R_68K_PLT16, 14) /* 16 bit PC relative PLT address */ + RELOC_NUMBER (R_68K_PLT8, 15) /* 8 bit PC relative PLT address */ + RELOC_NUMBER (R_68K_PLT32O, 16) /* 32 bit PLT offset */ + RELOC_NUMBER (R_68K_PLT16O, 17) /* 16 bit PLT offset */ + RELOC_NUMBER (R_68K_PLT8O, 18) /* 8 bit PLT offset */ + RELOC_NUMBER (R_68K_COPY, 19) /* Copy symbol at runtime */ + RELOC_NUMBER (R_68K_GLOB_DAT, 20) /* Create GOT entry */ + RELOC_NUMBER (R_68K_JMP_SLOT, 21) /* Create PLT entry */ + RELOC_NUMBER (R_68K_RELATIVE, 22) /* Adjust by program base */ + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_68K_GNU_VTINHERIT, 23) + RELOC_NUMBER (R_68K_GNU_VTENTRY, 24) +END_RELOC_NUMBERS (R_68K_max) + +#define EF_CPU32 0x00810000 +#define EF_M68000 0x01000000 + +#endif diff --git a/contrib/binutils-2.14/include/elf/mcore.h b/contrib/binutils-2.14/include/elf/mcore.h new file mode 100644 index 0000000000..387a57d451 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/mcore.h @@ -0,0 +1,46 @@ +/* Motorola MCore support for BFD. + Copyright 1995, 1999, 2000 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the MCore ELF ABI. */ +#ifndef _ELF_MORE_H +#define _ELF_MORE_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_mcore_reloc_type) + RELOC_NUMBER (R_MCORE_NONE, 0) + RELOC_NUMBER (R_MCORE_ADDR32, 1) + RELOC_NUMBER (R_MCORE_PCRELIMM8BY4, 2) + RELOC_NUMBER (R_MCORE_PCRELIMM11BY2, 3) + RELOC_NUMBER (R_MCORE_PCRELIMM4BY2, 4) + RELOC_NUMBER (R_MCORE_PCREL32, 5) + RELOC_NUMBER (R_MCORE_PCRELJSR_IMM11BY2, 6) + RELOC_NUMBER (R_MCORE_GNU_VTINHERIT, 7) + RELOC_NUMBER (R_MCORE_GNU_VTENTRY, 8) + RELOC_NUMBER (R_MCORE_RELATIVE, 9) + RELOC_NUMBER (R_MCORE_COPY, 10) + RELOC_NUMBER (R_MCORE_GLOB_DAT, 11) + RELOC_NUMBER (R_MCORE_JUMP_SLOT, 12) +END_RELOC_NUMBERS (R_MCORE_max) + +/* Section Attributes. */ +#define SHF_MCORE_NOREAD 0x80000000 + +#endif /* _ELF_MCORE_H */ diff --git a/contrib/binutils-2.14/include/elf/mips.h b/contrib/binutils-2.14/include/elf/mips.h new file mode 100644 index 0000000000..44f7cb9292 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/mips.h @@ -0,0 +1,972 @@ +/* MIPS ELF support for BFD. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. + + By Ian Lance Taylor, Cygnus Support, , from + information in the System V Application Binary Interface, MIPS + Processor Supplement. + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the MIPS ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_MIPS_H +#define _ELF_MIPS_H + +#include "elf/reloc-macros.h" + +/* Relocation types. */ +START_RELOC_NUMBERS (elf_mips_reloc_type) + RELOC_NUMBER (R_MIPS_NONE, 0) + RELOC_NUMBER (R_MIPS_16, 1) + RELOC_NUMBER (R_MIPS_32, 2) /* In Elf 64: alias R_MIPS_ADD */ + RELOC_NUMBER (R_MIPS_REL32, 3) /* In Elf 64: alias R_MIPS_REL */ + RELOC_NUMBER (R_MIPS_26, 4) + RELOC_NUMBER (R_MIPS_HI16, 5) + RELOC_NUMBER (R_MIPS_LO16, 6) + RELOC_NUMBER (R_MIPS_GPREL16, 7) /* In Elf 64: alias R_MIPS_GPREL */ + RELOC_NUMBER (R_MIPS_LITERAL, 8) + RELOC_NUMBER (R_MIPS_GOT16, 9) /* In Elf 64: alias R_MIPS_GOT */ + RELOC_NUMBER (R_MIPS_PC16, 10) + RELOC_NUMBER (R_MIPS_CALL16, 11) /* In Elf 64: alias R_MIPS_CALL */ + RELOC_NUMBER (R_MIPS_GPREL32, 12) + /* The remaining relocs are defined on Irix, although they are not + in the MIPS ELF ABI. */ + RELOC_NUMBER (R_MIPS_UNUSED1, 13) + RELOC_NUMBER (R_MIPS_UNUSED2, 14) + RELOC_NUMBER (R_MIPS_UNUSED3, 15) + RELOC_NUMBER (R_MIPS_SHIFT5, 16) + RELOC_NUMBER (R_MIPS_SHIFT6, 17) + RELOC_NUMBER (R_MIPS_64, 18) + RELOC_NUMBER (R_MIPS_GOT_DISP, 19) + RELOC_NUMBER (R_MIPS_GOT_PAGE, 20) + RELOC_NUMBER (R_MIPS_GOT_OFST, 21) + RELOC_NUMBER (R_MIPS_GOT_HI16, 22) + RELOC_NUMBER (R_MIPS_GOT_LO16, 23) + RELOC_NUMBER (R_MIPS_SUB, 24) + RELOC_NUMBER (R_MIPS_INSERT_A, 25) + RELOC_NUMBER (R_MIPS_INSERT_B, 26) + RELOC_NUMBER (R_MIPS_DELETE, 27) + RELOC_NUMBER (R_MIPS_HIGHER, 28) + RELOC_NUMBER (R_MIPS_HIGHEST, 29) + RELOC_NUMBER (R_MIPS_CALL_HI16, 30) + RELOC_NUMBER (R_MIPS_CALL_LO16, 31) + RELOC_NUMBER (R_MIPS_SCN_DISP, 32) + RELOC_NUMBER (R_MIPS_REL16, 33) + RELOC_NUMBER (R_MIPS_ADD_IMMEDIATE, 34) + RELOC_NUMBER (R_MIPS_PJUMP, 35) + RELOC_NUMBER (R_MIPS_RELGOT, 36) + RELOC_NUMBER (R_MIPS_JALR, 37) + RELOC_NUMBER (R_MIPS_max, 38) + /* These relocs are used for the mips16. */ + RELOC_NUMBER (R_MIPS16_26, 100) + RELOC_NUMBER (R_MIPS16_GPREL, 101) + /* These are GNU extensions to handle embedded-pic. */ + RELOC_NUMBER (R_MIPS_PC32, 248) + RELOC_NUMBER (R_MIPS_PC64, 249) + RELOC_NUMBER (R_MIPS_GNU_REL16_S2, 250) + RELOC_NUMBER (R_MIPS_GNU_REL_LO16, 251) + RELOC_NUMBER (R_MIPS_GNU_REL_HI16, 252) + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_MIPS_GNU_VTINHERIT, 253) + RELOC_NUMBER (R_MIPS_GNU_VTENTRY, 254) +END_RELOC_NUMBERS (R_MIPS_maxext) + +/* Processor specific flags for the ELF header e_flags field. */ + +/* At least one .noreorder directive appears in the source. */ +#define EF_MIPS_NOREORDER 0x00000001 + +/* File contains position independent code. */ +#define EF_MIPS_PIC 0x00000002 + +/* Code in file uses the standard calling sequence for calling + position independent code. */ +#define EF_MIPS_CPIC 0x00000004 + +/* ??? Unknown flag, set in IRIX 6's BSDdup2.o in libbsd.a. */ +#define EF_MIPS_XGOT 0x00000008 + +/* Code in file uses UCODE (obsolete) */ +#define EF_MIPS_UCODE 0x00000010 + +/* Code in file uses new ABI (-n32 on Irix 6). */ +#define EF_MIPS_ABI2 0x00000020 + +/* Process the .MIPS.options section first by ld */ +#define EF_MIPS_OPTIONS_FIRST 0x00000080 + +/* Architectural Extensions used by this file */ +#define EF_MIPS_ARCH_ASE 0x0f000000 + +/* Use MDMX multimedia extensions */ +#define EF_MIPS_ARCH_ASE_MDMX 0x08000000 + +/* Use MIPS-16 ISA extensions */ +#define EF_MIPS_ARCH_ASE_M16 0x04000000 + +/* Indicates code compiled for a 64-bit machine in 32-bit mode. + (regs are 32-bits wide.) */ +#define EF_MIPS_32BITMODE 0x00000100 + +/* Four bit MIPS architecture field. */ +#define EF_MIPS_ARCH 0xf0000000 + +/* -mips1 code. */ +#define E_MIPS_ARCH_1 0x00000000 + +/* -mips2 code. */ +#define E_MIPS_ARCH_2 0x10000000 + +/* -mips3 code. */ +#define E_MIPS_ARCH_3 0x20000000 + +/* -mips4 code. */ +#define E_MIPS_ARCH_4 0x30000000 + +/* -mips5 code. */ +#define E_MIPS_ARCH_5 0x40000000 + +/* -mips32 code. */ +#define E_MIPS_ARCH_32 0x50000000 + +/* -mips64 code. */ +#define E_MIPS_ARCH_64 0x60000000 + +/* -mips32r2 code. */ +#define E_MIPS_ARCH_32R2 0x70000000 + +/* The ABI of the file. Also see EF_MIPS_ABI2 above. */ +#define EF_MIPS_ABI 0x0000F000 + +/* The original o32 abi. */ +#define E_MIPS_ABI_O32 0x00001000 + +/* O32 extended to work on 64 bit architectures */ +#define E_MIPS_ABI_O64 0x00002000 + +/* EABI in 32 bit mode */ +#define E_MIPS_ABI_EABI32 0x00003000 + +/* EABI in 64 bit mode */ +#define E_MIPS_ABI_EABI64 0x00004000 + + +/* Machine variant if we know it. This field was invented at Cygnus, + but it is hoped that other vendors will adopt it. If some standard + is developed, this code should be changed to follow it. */ + +#define EF_MIPS_MACH 0x00FF0000 + +/* Cygnus is choosing values between 80 and 9F; + 00 - 7F should be left for a future standard; + the rest are open. */ + +#define E_MIPS_MACH_3900 0x00810000 +#define E_MIPS_MACH_4010 0x00820000 +#define E_MIPS_MACH_4100 0x00830000 +#define E_MIPS_MACH_4650 0x00850000 +#define E_MIPS_MACH_4120 0x00870000 +#define E_MIPS_MACH_4111 0x00880000 +#define E_MIPS_MACH_SB1 0x008a0000 +#define E_MIPS_MACH_5400 0x00910000 +#define E_MIPS_MACH_5500 0x00980000 + +/* Processor specific section indices. These sections do not actually + exist. Symbols with a st_shndx field corresponding to one of these + values have a special meaning. */ + +/* Defined and allocated common symbol. Value is virtual address. If + relocated, alignment must be preserved. */ +#define SHN_MIPS_ACOMMON 0xff00 + +/* Defined and allocated text symbol. Value is virtual address. + Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables. */ +#define SHN_MIPS_TEXT 0xff01 + +/* Defined and allocated data symbol. Value is virtual address. + Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables. */ +#define SHN_MIPS_DATA 0xff02 + +/* Small common symbol. */ +#define SHN_MIPS_SCOMMON 0xff03 + +/* Small undefined symbol. */ +#define SHN_MIPS_SUNDEFINED 0xff04 + +/* Processor specific section types. */ + +/* Section contains the set of dynamic shared objects used when + statically linking. */ +#define SHT_MIPS_LIBLIST 0x70000000 + +/* I'm not sure what this is, but it's used on Irix 5. */ +#define SHT_MIPS_MSYM 0x70000001 + +/* Section contains list of symbols whose definitions conflict with + symbols defined in shared objects. */ +#define SHT_MIPS_CONFLICT 0x70000002 + +/* Section contains the global pointer table. */ +#define SHT_MIPS_GPTAB 0x70000003 + +/* Section contains microcode information. The exact format is + unspecified. */ +#define SHT_MIPS_UCODE 0x70000004 + +/* Section contains some sort of debugging information. The exact + format is unspecified. It's probably ECOFF symbols. */ +#define SHT_MIPS_DEBUG 0x70000005 + +/* Section contains register usage information. */ +#define SHT_MIPS_REGINFO 0x70000006 + +/* ??? */ +#define SHT_MIPS_PACKAGE 0x70000007 + +/* ??? */ +#define SHT_MIPS_PACKSYM 0x70000008 + +/* ??? */ +#define SHT_MIPS_RELD 0x70000009 + +/* Section contains interface information. */ +#define SHT_MIPS_IFACE 0x7000000b + +/* Section contains description of contents of another section. */ +#define SHT_MIPS_CONTENT 0x7000000c + +/* Section contains miscellaneous options. */ +#define SHT_MIPS_OPTIONS 0x7000000d + +/* ??? */ +#define SHT_MIPS_SHDR 0x70000010 + +/* ??? */ +#define SHT_MIPS_FDESC 0x70000011 + +/* ??? */ +#define SHT_MIPS_EXTSYM 0x70000012 + +/* ??? */ +#define SHT_MIPS_DENSE 0x70000013 + +/* ??? */ +#define SHT_MIPS_PDESC 0x70000014 + +/* ??? */ +#define SHT_MIPS_LOCSYM 0x70000015 + +/* ??? */ +#define SHT_MIPS_AUXSYM 0x70000016 + +/* ??? */ +#define SHT_MIPS_OPTSYM 0x70000017 + +/* ??? */ +#define SHT_MIPS_LOCSTR 0x70000018 + +/* ??? */ +#define SHT_MIPS_LINE 0x70000019 + +/* ??? */ +#define SHT_MIPS_RFDESC 0x7000001a + +/* Delta C++: symbol table */ +#define SHT_MIPS_DELTASYM 0x7000001b + +/* Delta C++: instance table */ +#define SHT_MIPS_DELTAINST 0x7000001c + +/* Delta C++: class table */ +#define SHT_MIPS_DELTACLASS 0x7000001d + +/* DWARF debugging section. */ +#define SHT_MIPS_DWARF 0x7000001e + +/* Delta C++: declarations */ +#define SHT_MIPS_DELTADECL 0x7000001f + +/* List of libraries the binary depends on. Includes a time stamp, version + number. */ +#define SHT_MIPS_SYMBOL_LIB 0x70000020 + +/* Events section. */ +#define SHT_MIPS_EVENTS 0x70000021 + +/* ??? */ +#define SHT_MIPS_TRANSLATE 0x70000022 + +/* Special pixie sections */ +#define SHT_MIPS_PIXIE 0x70000023 + +/* Address translation table (for debug info) */ +#define SHT_MIPS_XLATE 0x70000024 + +/* SGI internal address translation table (for debug info) */ +#define SHT_MIPS_XLATE_DEBUG 0x70000025 + +/* Intermediate code */ +#define SHT_MIPS_WHIRL 0x70000026 + +/* C++ exception handling region info */ +#define SHT_MIPS_EH_REGION 0x70000027 + +/* Obsolete address translation table (for debug info) */ +#define SHT_MIPS_XLATE_OLD 0x70000028 + +/* Runtime procedure descriptor table exception information (ucode) ??? */ +#define SHT_MIPS_PDR_EXCEPTION 0x70000029 + + +/* A section of type SHT_MIPS_LIBLIST contains an array of the + following structure. The sh_link field is the section index of the + string table. The sh_info field is the number of entries in the + section. */ +typedef struct +{ + /* String table index for name of shared object. */ + unsigned long l_name; + /* Time stamp. */ + unsigned long l_time_stamp; + /* Checksum of symbol names and common sizes. */ + unsigned long l_checksum; + /* String table index for version. */ + unsigned long l_version; + /* Flags. */ + unsigned long l_flags; +} Elf32_Lib; + +/* The external version of Elf32_Lib. */ +typedef struct +{ + unsigned char l_name[4]; + unsigned char l_time_stamp[4]; + unsigned char l_checksum[4]; + unsigned char l_version[4]; + unsigned char l_flags[4]; +} Elf32_External_Lib; + +/* The l_flags field of an Elf32_Lib structure may contain the + following flags. */ + +/* Require an exact match at runtime. */ +#define LL_EXACT_MATCH 0x00000001 + +/* Ignore version incompatibilities at runtime. */ +#define LL_IGNORE_INT_VER 0x00000002 + +/* Require matching minor version number. */ +#define LL_REQUIRE_MINOR 0x00000004 + +/* ??? */ +#define LL_EXPORTS 0x00000008 + +/* Delay loading of this library until really needed. */ +#define LL_DELAY_LOAD 0x00000010 + +/* ??? Delta C++ stuff ??? */ +#define LL_DELTA 0x00000020 + + +/* A section of type SHT_MIPS_CONFLICT is an array of indices into the + .dynsym section. Each element has the following type. */ +typedef unsigned long Elf32_Conflict; +typedef unsigned char Elf32_External_Conflict[4]; + +typedef unsigned long Elf64_Conflict; +typedef unsigned char Elf64_External_Conflict[8]; + +/* A section of type SHT_MIPS_GPTAB contains information about how + much GP space would be required for different -G arguments. This + information is only used so that the linker can provide informative + suggestions as to the best -G value to use. The sh_info field is + the index of the section for which this information applies. The + contents of the section are an array of the following union. The + first element uses the gt_header field. The remaining elements use + the gt_entry field. */ +typedef union +{ + struct + { + /* -G value actually used for this object file. */ + unsigned long gt_current_g_value; + /* Unused. */ + unsigned long gt_unused; + } gt_header; + struct + { + /* If this -G argument has been used... */ + unsigned long gt_g_value; + /* ...this many GP section bytes would be required. */ + unsigned long gt_bytes; + } gt_entry; +} Elf32_gptab; + +/* The external version of Elf32_gptab. */ + +typedef union +{ + struct + { + unsigned char gt_current_g_value[4]; + unsigned char gt_unused[4]; + } gt_header; + struct + { + unsigned char gt_g_value[4]; + unsigned char gt_bytes[4]; + } gt_entry; +} Elf32_External_gptab; + +/* A section of type SHT_MIPS_REGINFO contains the following + structure. */ +typedef struct +{ + /* Mask of general purpose registers used. */ + unsigned long ri_gprmask; + /* Mask of co-processor registers used. */ + unsigned long ri_cprmask[4]; + /* GP register value for this object file. */ + long ri_gp_value; +} Elf32_RegInfo; + +/* The external version of the Elf_RegInfo structure. */ +typedef struct +{ + unsigned char ri_gprmask[4]; + unsigned char ri_cprmask[4][4]; + unsigned char ri_gp_value[4]; +} Elf32_External_RegInfo; + +/* MIPS ELF .reginfo swapping routines. */ +extern void bfd_mips_elf32_swap_reginfo_in + PARAMS ((bfd *, const Elf32_External_RegInfo *, Elf32_RegInfo *)); +extern void bfd_mips_elf32_swap_reginfo_out + PARAMS ((bfd *, const Elf32_RegInfo *, Elf32_External_RegInfo *)); + +/* Processor specific section flags. */ + +/* This section must be in the global data area. */ +#define SHF_MIPS_GPREL 0x10000000 + +/* This section should be merged. */ +#define SHF_MIPS_MERGE 0x20000000 + +/* This section contains address data of size implied by section + element size. */ +#define SHF_MIPS_ADDR 0x40000000 + +/* This section contains string data. */ +#define SHF_MIPS_STRING 0x80000000 + +/* This section may not be stripped. */ +#define SHF_MIPS_NOSTRIP 0x08000000 + +/* This section is local to threads. */ +#define SHF_MIPS_LOCAL 0x04000000 + +/* Linker should generate implicit weak names for this section. */ +#define SHF_MIPS_NAMES 0x02000000 + +/* Section contais text/data which may be replicated in other sections. + Linker should retain only one copy. */ +#define SHF_MIPS_NODUPES 0x01000000 + +/* Processor specific program header types. */ + +/* Register usage information. Identifies one .reginfo section. */ +#define PT_MIPS_REGINFO 0x70000000 + +/* Runtime procedure table. */ +#define PT_MIPS_RTPROC 0x70000001 + +/* .MIPS.options section. */ +#define PT_MIPS_OPTIONS 0x70000002 + +/* Processor specific dynamic array tags. */ + +/* 32 bit version number for runtime linker interface. */ +#define DT_MIPS_RLD_VERSION 0x70000001 + +/* Time stamp. */ +#define DT_MIPS_TIME_STAMP 0x70000002 + +/* Checksum of external strings and common sizes. */ +#define DT_MIPS_ICHECKSUM 0x70000003 + +/* Index of version string in string table. */ +#define DT_MIPS_IVERSION 0x70000004 + +/* 32 bits of flags. */ +#define DT_MIPS_FLAGS 0x70000005 + +/* Base address of the segment. */ +#define DT_MIPS_BASE_ADDRESS 0x70000006 + +/* ??? */ +#define DT_MIPS_MSYM 0x70000007 + +/* Address of .conflict section. */ +#define DT_MIPS_CONFLICT 0x70000008 + +/* Address of .liblist section. */ +#define DT_MIPS_LIBLIST 0x70000009 + +/* Number of local global offset table entries. */ +#define DT_MIPS_LOCAL_GOTNO 0x7000000a + +/* Number of entries in the .conflict section. */ +#define DT_MIPS_CONFLICTNO 0x7000000b + +/* Number of entries in the .liblist section. */ +#define DT_MIPS_LIBLISTNO 0x70000010 + +/* Number of entries in the .dynsym section. */ +#define DT_MIPS_SYMTABNO 0x70000011 + +/* Index of first external dynamic symbol not referenced locally. */ +#define DT_MIPS_UNREFEXTNO 0x70000012 + +/* Index of first dynamic symbol in global offset table. */ +#define DT_MIPS_GOTSYM 0x70000013 + +/* Number of page table entries in global offset table. */ +#define DT_MIPS_HIPAGENO 0x70000014 + +/* Address of run time loader map, used for debugging. */ +#define DT_MIPS_RLD_MAP 0x70000016 + +/* Delta C++ class definition. */ +#define DT_MIPS_DELTA_CLASS 0x70000017 + +/* Number of entries in DT_MIPS_DELTA_CLASS. */ +#define DT_MIPS_DELTA_CLASS_NO 0x70000018 + +/* Delta C++ class instances. */ +#define DT_MIPS_DELTA_INSTANCE 0x70000019 + +/* Number of entries in DT_MIPS_DELTA_INSTANCE. */ +#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a + +/* Delta relocations. */ +#define DT_MIPS_DELTA_RELOC 0x7000001b + +/* Number of entries in DT_MIPS_DELTA_RELOC. */ +#define DT_MIPS_DELTA_RELOC_NO 0x7000001c + +/* Delta symbols that Delta relocations refer to. */ +#define DT_MIPS_DELTA_SYM 0x7000001d + +/* Number of entries in DT_MIPS_DELTA_SYM. */ +#define DT_MIPS_DELTA_SYM_NO 0x7000001e + +/* Delta symbols that hold class declarations. */ +#define DT_MIPS_DELTA_CLASSSYM 0x70000020 + +/* Number of entries in DT_MIPS_DELTA_CLASSSYM. */ +#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 + +/* Flags indicating information about C++ flavor. */ +#define DT_MIPS_CXX_FLAGS 0x70000022 + +/* Pixie information (???). */ +#define DT_MIPS_PIXIE_INIT 0x70000023 + +/* Address of .MIPS.symlib */ +#define DT_MIPS_SYMBOL_LIB 0x70000024 + +/* The GOT index of the first PTE for a segment */ +#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 + +/* The GOT index of the first PTE for a local symbol */ +#define DT_MIPS_LOCAL_GOTIDX 0x70000026 + +/* The GOT index of the first PTE for a hidden symbol */ +#define DT_MIPS_HIDDEN_GOTIDX 0x70000027 + +/* The GOT index of the first PTE for a protected symbol */ +#define DT_MIPS_PROTECTED_GOTIDX 0x70000028 + +/* Address of `.MIPS.options'. */ +#define DT_MIPS_OPTIONS 0x70000029 + +/* Address of `.interface'. */ +#define DT_MIPS_INTERFACE 0x7000002a + +/* ??? */ +#define DT_MIPS_DYNSTR_ALIGN 0x7000002b + +/* Size of the .interface section. */ +#define DT_MIPS_INTERFACE_SIZE 0x7000002c + +/* Size of rld_text_resolve function stored in the GOT. */ +#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d + +/* Default suffix of DSO to be added by rld on dlopen() calls. */ +#define DT_MIPS_PERF_SUFFIX 0x7000002e + +/* Size of compact relocation section (O32). */ +#define DT_MIPS_COMPACT_SIZE 0x7000002f + +/* GP value for auxiliary GOTs. */ +#define DT_MIPS_GP_VALUE 0x70000030 + +/* Address of auxiliary .dynamic. */ +#define DT_MIPS_AUX_DYNAMIC 0x70000031 + +/* Flags which may appear in a DT_MIPS_FLAGS entry. */ + +/* No flags. */ +#define RHF_NONE 0x00000000 + +/* Uses shortcut pointers. */ +#define RHF_QUICKSTART 0x00000001 + +/* Hash size is not a power of two. */ +#define RHF_NOTPOT 0x00000002 + +/* Ignore LD_LIBRARY_PATH. */ +#define RHS_NO_LIBRARY_REPLACEMENT 0x00000004 + +/* DSO address may not be relocated. */ +#define RHF_NO_MOVE 0x00000008 + +/* SGI specific features. */ +#define RHF_SGI_ONLY 0x00000010 + +/* Guarantee that .init will finish executing before any non-init + code in DSO is called. */ +#define RHF_GUARANTEE_INIT 0x00000020 + +/* Contains Delta C++ code. */ +#define RHF_DELTA_C_PLUS_PLUS 0x00000040 + +/* Guarantee that .init will start executing before any non-init + code in DSO is called. */ +#define RHF_GUARANTEE_START_INIT 0x00000080 + +/* Generated by pixie. */ +#define RHF_PIXIE 0x00000100 + +/* Delay-load DSO by default. */ +#define RHF_DEFAULT_DELAY_LOAD 0x00000200 + +/* Object may be requickstarted */ +#define RHF_REQUICKSTART 0x00000400 + +/* Object has been requickstarted */ +#define RHF_REQUICKSTARTED 0x00000800 + +/* Generated by cord. */ +#define RHF_CORD 0x00001000 + +/* Object contains no unresolved undef symbols. */ +#define RHF_NO_UNRES_UNDEF 0x00002000 + +/* Symbol table is in a safe order. */ +#define RHF_RLD_ORDER_SAFE 0x00004000 + +/* Special values for the st_other field in the symbol table. These + are used in an Irix 5 dynamic symbol table. */ + +#define STO_DEFAULT STV_DEFAULT +#define STO_INTERNAL STV_INTERNAL +#define STO_HIDDEN STV_HIDDEN +#define STO_PROTECTED STV_PROTECTED + +/* This value is used for a mips16 .text symbol. */ +#define STO_MIPS16 0xf0 + +/* The 64-bit MIPS ELF ABI uses an unusual reloc format. Each + relocation entry specifies up to three actual relocations, all at + the same address. The first relocation which required a symbol + uses the symbol in the r_sym field. The second relocation which + requires a symbol uses the symbol in the r_ssym field. If all + three relocations require a symbol, the third one uses a zero + value. */ + +/* An entry in a 64 bit SHT_REL section. */ + +typedef struct +{ + /* Address of relocation. */ + unsigned char r_offset[8]; + /* Symbol index. */ + unsigned char r_sym[4]; + /* Special symbol. */ + unsigned char r_ssym[1]; + /* Third relocation. */ + unsigned char r_type3[1]; + /* Second relocation. */ + unsigned char r_type2[1]; + /* First relocation. */ + unsigned char r_type[1]; +} Elf64_Mips_External_Rel; + +typedef struct +{ + /* Address of relocation. */ + bfd_vma r_offset; + /* Symbol index. */ + unsigned long r_sym; + /* Special symbol. */ + unsigned char r_ssym; + /* Third relocation. */ + unsigned char r_type3; + /* Second relocation. */ + unsigned char r_type2; + /* First relocation. */ + unsigned char r_type; +} Elf64_Mips_Internal_Rel; + +/* An entry in a 64 bit SHT_RELA section. */ + +typedef struct +{ + /* Address of relocation. */ + unsigned char r_offset[8]; + /* Symbol index. */ + unsigned char r_sym[4]; + /* Special symbol. */ + unsigned char r_ssym[1]; + /* Third relocation. */ + unsigned char r_type3[1]; + /* Second relocation. */ + unsigned char r_type2[1]; + /* First relocation. */ + unsigned char r_type[1]; + /* Addend. */ + unsigned char r_addend[8]; +} Elf64_Mips_External_Rela; + +typedef struct +{ + /* Address of relocation. */ + bfd_vma r_offset; + /* Symbol index. */ + unsigned long r_sym; + /* Special symbol. */ + unsigned char r_ssym; + /* Third relocation. */ + unsigned char r_type3; + /* Second relocation. */ + unsigned char r_type2; + /* First relocation. */ + unsigned char r_type; + /* Addend. */ + bfd_signed_vma r_addend; +} Elf64_Mips_Internal_Rela; + +/* MIPS ELF 64 relocation info access macros. */ +#define ELF64_MIPS_R_SSYM(i) (((i) >> 24) & 0xff) +#define ELF64_MIPS_R_TYPE3(i) (((i) >> 16) & 0xff) +#define ELF64_MIPS_R_TYPE2(i) (((i) >> 8) & 0xff) +#define ELF64_MIPS_R_TYPE(i) ((i) & 0xff) + +/* Values found in the r_ssym field of a relocation entry. */ + +/* No relocation. */ +#define RSS_UNDEF 0 + +/* Value of GP. */ +#define RSS_GP 1 + +/* Value of GP in object being relocated. */ +#define RSS_GP0 2 + +/* Address of location being relocated. */ +#define RSS_LOC 3 + +/* A SHT_MIPS_OPTIONS section contains a series of options, each of + which starts with this header. */ + +typedef struct +{ + /* Type of option. */ + unsigned char kind[1]; + /* Size of option descriptor, including header. */ + unsigned char size[1]; + /* Section index of affected section, or 0 for global option. */ + unsigned char section[2]; + /* Information specific to this kind of option. */ + unsigned char info[4]; +} Elf_External_Options; + +typedef struct +{ + /* Type of option. */ + unsigned char kind; + /* Size of option descriptor, including header. */ + unsigned char size; + /* Section index of affected section, or 0 for global option. */ + unsigned short section; + /* Information specific to this kind of option. */ + unsigned long info; +} Elf_Internal_Options; + +/* MIPS ELF option header swapping routines. */ +extern void bfd_mips_elf_swap_options_in + PARAMS ((bfd *, const Elf_External_Options *, Elf_Internal_Options *)); +extern void bfd_mips_elf_swap_options_out + PARAMS ((bfd *, const Elf_Internal_Options *, Elf_External_Options *)); + +/* Values which may appear in the kind field of an Elf_Options + structure. */ + +/* Undefined. */ +#define ODK_NULL 0 + +/* Register usage and GP value. */ +#define ODK_REGINFO 1 + +/* Exception processing information. */ +#define ODK_EXCEPTIONS 2 + +/* Section padding information. */ +#define ODK_PAD 3 + +/* Hardware workarounds performed. */ +#define ODK_HWPATCH 4 + +/* Fill value used by the linker. */ +#define ODK_FILL 5 + +/* Reserved space for desktop tools. */ +#define ODK_TAGS 6 + +/* Hardware workarounds, AND bits when merging. */ +#define ODK_HWAND 7 + +/* Hardware workarounds, OR bits when merging. */ +#define ODK_HWOR 8 + +/* GP group to use for text/data sections. */ +#define ODK_GP_GROUP 9 + +/* ID information. */ +#define ODK_IDENT 10 + +/* In the 32 bit ABI, an ODK_REGINFO option is just a Elf32_RegInfo + structure. In the 64 bit ABI, it is the following structure. The + info field of the options header is not used. */ + +typedef struct +{ + /* Mask of general purpose registers used. */ + unsigned char ri_gprmask[4]; + /* Padding. */ + unsigned char ri_pad[4]; + /* Mask of co-processor registers used. */ + unsigned char ri_cprmask[4][4]; + /* GP register value for this object file. */ + unsigned char ri_gp_value[8]; +} Elf64_External_RegInfo; + +typedef struct +{ + /* Mask of general purpose registers used. */ + unsigned long ri_gprmask; + /* Padding. */ + unsigned long ri_pad; + /* Mask of co-processor registers used. */ + unsigned long ri_cprmask[4]; + /* GP register value for this object file. */ + bfd_vma ri_gp_value; +} Elf64_Internal_RegInfo; + +typedef struct +{ + /* The hash value computed from the name of the corresponding + dynamic symbol. */ + unsigned char ms_hash_value[4]; + /* Contains both the dynamic relocation index and the symbol flags + field. The macros ELF32_MS_REL_INDEX and ELF32_MS_FLAGS are used + to access the individual values. The dynamic relocation index + identifies the first entry in the .rel.dyn section that + references the dynamic symbol corresponding to this msym entry. + If the index is 0, no dynamic relocations are associated with the + symbol. The symbol flags field is reserved for future use. */ + unsigned char ms_info[4]; +} Elf32_External_Msym; + +typedef struct +{ + /* The hash value computed from the name of the corresponding + dynamic symbol. */ + unsigned long ms_hash_value; + /* Contains both the dynamic relocation index and the symbol flags + field. The macros ELF32_MS_REL_INDEX and ELF32_MS_FLAGS are used + to access the individual values. The dynamic relocation index + identifies the first entry in the .rel.dyn section that + references the dynamic symbol corresponding to this msym entry. + If the index is 0, no dynamic relocations are associated with the + symbol. The symbol flags field is reserved for future use. */ + unsigned long ms_info; +} Elf32_Internal_Msym; + +#define ELF32_MS_REL_INDEX(i) ((i) >> 8) +#define ELF32_MS_FLAGS(i) (i) & 0xff) +#define ELF32_MS_INFO(r, f) (((r) << 8) + ((f) & 0xff)) + +/* MIPS ELF reginfo swapping routines. */ +extern void bfd_mips_elf64_swap_reginfo_in + PARAMS ((bfd *, const Elf64_External_RegInfo *, Elf64_Internal_RegInfo *)); +extern void bfd_mips_elf64_swap_reginfo_out + PARAMS ((bfd *, const Elf64_Internal_RegInfo *, Elf64_External_RegInfo *)); + +/* Masks for the info work of an ODK_EXCEPTIONS descriptor. */ +#define OEX_FPU_MIN 0x1f /* FPEs which must be enabled. */ +#define OEX_FPU_MAX 0x1f00 /* FPEs which may be enabled. */ +#define OEX_PAGE0 0x10000 /* Page zero must be mapped. */ +#define OEX_SMM 0x20000 /* Force sequential memory mode. */ +#define OEX_FPDBUG 0x40000 /* Force precise floating-point + exceptions (debug mode). */ +#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults. */ + +/* Masks of the FP exceptions for OEX_FPU_MIN and OEX_FPU_MAX. */ +#define OEX_FPU_INVAL 0x10 /* Invalid operation exception. */ +#define OEX_FPU_DIV0 0x08 /* Division by zero exception. */ +#define OEX_FPU_OFLO 0x04 /* Overflow exception. */ +#define OEX_FPU_UFLO 0x02 /* Underflow exception. */ +#define OEX_FPU_INEX 0x01 /* Inexact exception. */ + +/* Masks for the info word of an ODK_PAD descriptor. */ +#define OPAD_PREFIX 0x01 +#define OPAD_POSTFIX 0x02 +#define OPAD_SYMBOL 0x04 + +/* Masks for the info word of an ODK_HWPATCH descriptor. */ +#define OHW_R4KEOP 0x00000001 /* R4000 end-of-page patch. */ +#define OHW_R8KPFETCH 0x00000002 /* May need R8000 prefetch patch. */ +#define OHW_R5KEOP 0x00000004 /* R5000 end-of-page patch. */ +#define OHW_R5KCVTL 0x00000008 /* R5000 cvt.[ds].l bug + (clean == 1). */ +#define OHW_R10KLDL 0x00000010 /* Needs R10K misaligned + load patch. */ + +/* Masks for the info word of an ODK_IDENT/ODK_GP_GROUP descriptor. */ +#define OGP_GROUP 0x0000ffff /* GP group number. */ +#define OGP_SELF 0xffff0000 /* Self-contained GP groups. */ + +/* Masks for the info word of an ODK_HWAND/ODK_HWOR descriptor. */ +#define OHWA0_R4KEOP_CHECKED 0x00000001 +#define OHWA0_R4KEOP_CLEAN 0x00000002 + + +#endif /* _ELF_MIPS_H */ diff --git a/contrib/binutils-2.14/include/elf/mmix.h b/contrib/binutils-2.14/include/elf/mmix.h new file mode 100644 index 0000000000..98536e2465 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/mmix.h @@ -0,0 +1,168 @@ +/* MMIX support for BFD. + Copyright 2001, 2002 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the MMIX ELF ABI. */ +#ifndef ELF_MMIX_H +#define ELF_MMIX_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_mmix_reloc_type) + RELOC_NUMBER (R_MMIX_NONE, 0) + + /* Standard absolute relocations. */ + RELOC_NUMBER (R_MMIX_8, 1) + RELOC_NUMBER (R_MMIX_16, 2) + RELOC_NUMBER (R_MMIX_24, 3) + RELOC_NUMBER (R_MMIX_32, 4) + RELOC_NUMBER (R_MMIX_64, 5) + + /* Standard relative relocations. */ + RELOC_NUMBER (R_MMIX_PC_8, 6) + RELOC_NUMBER (R_MMIX_PC_16, 7) + RELOC_NUMBER (R_MMIX_PC_24, 8) + RELOC_NUMBER (R_MMIX_PC_32, 9) + RELOC_NUMBER (R_MMIX_PC_64, 10) + + /* GNU extensions for C++ vtables. */ + RELOC_NUMBER (R_MMIX_GNU_VTINHERIT, 11) + RELOC_NUMBER (R_MMIX_GNU_VTENTRY, 12) + + /* A GETA instruction. */ + RELOC_NUMBER (R_MMIX_GETA, 13) + RELOC_NUMBER (R_MMIX_GETA_1, 14) + RELOC_NUMBER (R_MMIX_GETA_2, 15) + RELOC_NUMBER (R_MMIX_GETA_3, 16) + + /* A conditional branch instruction. */ + RELOC_NUMBER (R_MMIX_CBRANCH, 17) + RELOC_NUMBER (R_MMIX_CBRANCH_J, 18) + RELOC_NUMBER (R_MMIX_CBRANCH_1, 19) + RELOC_NUMBER (R_MMIX_CBRANCH_2, 20) + RELOC_NUMBER (R_MMIX_CBRANCH_3, 21) + + /* A PUSHJ instruction. */ + RELOC_NUMBER (R_MMIX_PUSHJ, 22) + RELOC_NUMBER (R_MMIX_PUSHJ_1, 23) + RELOC_NUMBER (R_MMIX_PUSHJ_2, 24) + RELOC_NUMBER (R_MMIX_PUSHJ_3, 25) + + /* A JMP instruction. */ + RELOC_NUMBER (R_MMIX_JMP, 26) + RELOC_NUMBER (R_MMIX_JMP_1, 27) + RELOC_NUMBER (R_MMIX_JMP_2, 28) + RELOC_NUMBER (R_MMIX_JMP_3, 29) + + /* A relative address such as in a GETA or a branch. */ + RELOC_NUMBER (R_MMIX_ADDR19, 30) + + /* A relative address such as in a JMP (only). */ + RELOC_NUMBER (R_MMIX_ADDR27, 31) + + /* A general register or a number 0..255. */ + RELOC_NUMBER (R_MMIX_REG_OR_BYTE, 32) + + /* A general register. */ + RELOC_NUMBER (R_MMIX_REG, 33) + + /* A global register and an offset, the global register (allocated at + link time) contents plus the offset made equivalent to the relocation + expression at link time. The relocation must point at the Y field of + an instruction. */ + RELOC_NUMBER (R_MMIX_BASE_PLUS_OFFSET, 34) + + /* A LOCAL assertion. */ + RELOC_NUMBER (R_MMIX_LOCAL, 35) +END_RELOC_NUMBERS (R_MMIX_max) + + +/* Section Attributes. */ +/* A section containing necessary information for relaxation. */ +#define SHF_MMIX_CANRELAX 0x80000000 + +/* Symbol attributes. */ +/* A symbol with this section-index is a register. */ +#define SHN_REGISTER SHN_LOPROC + +/* This section holds contents for each initialized register, at VMA + regno*8. A symbol relative to this section will be transformed to an + absolute symbol with the value corresponding to the register number at + final link time. A symbol with a value outside the inclusive range + 32*8 .. 254*8 is an error. It is highly recommended to only use an + upper bound of 253*8 or lower as specified in the (currently + unspecified) ABI. */ +#define MMIX_REG_CONTENTS_SECTION_NAME ".MMIX.reg_contents" + +/* At link time, a section by this name is created, expected to be + included in MMIX_REG_CONTENTS_SECTION_NAME in the output. */ +#define MMIX_LD_ALLOCATED_REG_CONTENTS_SECTION_NAME \ + ".MMIX.reg_contents.linker_allocated" + +/* This is a faked section holding symbols with SHN_REGISTER. Don't + confuse it with MMIX_REG_CONTENTS_SECTION_NAME; this one has no + contents, just values. It is an error for a value in this section to + be outside the range 32..255 and it must never become an actual section + in an object file. */ +#define MMIX_REG_SECTION_NAME "*REG*" + +/* Appended with a number N=0..65535, this is a representation of the + mmixal "BSPEC N" ... "ESPEC" directive pair; the contents go into an + ELF section by name ".MMIX.spec_data.N". */ +#define MMIX_OTHER_SPEC_SECTION_PREFIX ".MMIX.spec_data." + +/* A section SECNAME is noted to start at "__.MMIX.start.SECNAME" by the + presence of this symbol. Currently only implemented for ".text" + through the symbol "__.MMIX.start..text". */ +#define MMIX_LOC_SECTION_START_SYMBOL_PREFIX "__.MMIX.start." + +/* This symbol is always a function. */ +#define MMIX_START_SYMBOL_NAME "Main" + + +/* We smuggle in a few MMO specifics here. We don't make a specific MMO + file, since we can't reasonably support MMO without ELF; we have to + include this file anyway. */ + +#define MMO_TEXT_SECTION_NAME ".text" +#define MMO_DATA_SECTION_NAME ".data" + +/* A definition for the flags we put in spec data in files. A copy of our + own of some flags to keep immune to BFD flag changes. See section.c of + 2001-07-18 for flag documentation. */ +#define MMO_SEC_ALLOC 0x001 +#define MMO_SEC_LOAD 0x002 +#define MMO_SEC_RELOC 0x004 +#define MMO_SEC_READONLY 0x010 +#define MMO_SEC_CODE 0x020 +#define MMO_SEC_DATA 0x040 +#define MMO_SEC_NEVER_LOAD 0x400 +#define MMO_SEC_IS_COMMON 0x8000 +#define MMO_SEC_DEBUGGING 0x10000 + +#ifdef BFD_ARCH_SIZE +extern bfd_boolean _bfd_mmix_prepare_linker_allocated_gregs + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_mmix_finalize_linker_allocated_gregs + PARAMS ((bfd *, struct bfd_link_info *)); +extern bfd_boolean _bfd_mmix_check_all_relocs + PARAMS ((bfd *, struct bfd_link_info *)); +#endif + +#endif /* ELF_MMIX_H */ diff --git a/contrib/binutils-2.14/include/elf/mn10200.h b/contrib/binutils-2.14/include/elf/mn10200.h new file mode 100644 index 0000000000..1dfade5ccd --- /dev/null +++ b/contrib/binutils-2.14/include/elf/mn10200.h @@ -0,0 +1,39 @@ +/* MN10200 ELF support for BFD. + Copyright 1998, 2000 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the MN10200 ELF ABI. */ + +#ifndef _ELF_MN10200_H +#define _ELF_MN10200_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_mn10200_reloc_type) + RELOC_NUMBER (R_MN10200_NONE, 0) + RELOC_NUMBER (R_MN10200_32, 1) + RELOC_NUMBER (R_MN10200_16, 2) + RELOC_NUMBER (R_MN10200_8, 3) + RELOC_NUMBER (R_MN10200_24, 4) + RELOC_NUMBER (R_MN10200_PCREL8, 5) + RELOC_NUMBER (R_MN10200_PCREL16, 6) + RELOC_NUMBER (R_MN10200_PCREL24, 7) +END_RELOC_NUMBERS (R_MN10200_max) + +#endif /* _ELF_MN10200_H */ diff --git a/contrib/binutils-2.14/include/elf/mn10300.h b/contrib/binutils-2.14/include/elf/mn10300.h new file mode 100644 index 0000000000..e10be900a4 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/mn10300.h @@ -0,0 +1,53 @@ +/* MN10300 ELF support for BFD. + Copyright 1998, 1999, 2000 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the MN10300 ELF ABI. */ + +#ifndef _ELF_MN10300_H +#define _ELF_MN10300_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_mn10300_reloc_type) + RELOC_NUMBER (R_MN10300_NONE, 0) + RELOC_NUMBER (R_MN10300_32, 1) + RELOC_NUMBER (R_MN10300_16, 2) + RELOC_NUMBER (R_MN10300_8, 3) + RELOC_NUMBER (R_MN10300_PCREL32, 4) + RELOC_NUMBER (R_MN10300_PCREL16, 5) + RELOC_NUMBER (R_MN10300_PCREL8, 6) + RELOC_NUMBER (R_MN10300_GNU_VTINHERIT, 7) + RELOC_NUMBER (R_MN10300_GNU_VTENTRY, 8) + RELOC_NUMBER (R_MN10300_24, 9) +END_RELOC_NUMBERS (R_MN10300_MAX) + +/* Machine variant if we know it. This field was invented at Cygnus, + but it is hoped that other vendors will adopt it. If some standard + is developed, this code should be changed to follow it. */ + +#define EF_MN10300_MACH 0x00FF0000 + +/* Cygnus is choosing values between 80 and 9F; + 00 - 7F should be left for a future standard; + the rest are open. */ + +#define E_MN10300_MACH_MN10300 0x00810000 +#define E_MN10300_MACH_AM33 0x00820000 +#endif /* _ELF_MN10300_H */ diff --git a/contrib/binutils-2.14/include/elf/msp430.h b/contrib/binutils-2.14/include/elf/msp430.h new file mode 100644 index 0000000000..cb3f241dea --- /dev/null +++ b/contrib/binutils-2.14/include/elf/msp430.h @@ -0,0 +1,55 @@ +/* MSP430 ELF support for BFD. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Dmitry Diky + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_MSP430_H +#define _ELF_MSP430_H + +#include "elf/reloc-macros.h" + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_MSP430_MACH 0xff + +#define E_MSP430_MACH_MSP430x11x1 110 +#define E_MSP430_MACH_MSP430x11 11 +#define E_MSP430_MACH_MSP430x12 12 +#define E_MSP430_MACH_MSP430x13 13 +#define E_MSP430_MACH_MSP430x14 14 +#define E_MSP430_MACH_MSP430x31 31 +#define E_MSP430_MACH_MSP430x32 32 +#define E_MSP430_MACH_MSP430x33 33 +#define E_MSP430_MACH_MSP430x41 41 +#define E_MSP430_MACH_MSP430x43 43 +#define E_MSP430_MACH_MSP430x44 44 +#define E_MSP430_MACH_MSP430x15 15 +#define E_MSP430_MACH_MSP430x16 16 + +/* Relocations. */ +START_RELOC_NUMBERS (elf_msp430_reloc_type) + RELOC_NUMBER (R_MSP430_NONE, 0) + RELOC_NUMBER (R_MSP430_32, 1) + RELOC_NUMBER (R_MSP430_10_PCREL, 2) + RELOC_NUMBER (R_MSP430_16, 3) + RELOC_NUMBER (R_MSP430_16_PCREL, 4) + RELOC_NUMBER (R_MSP430_16_BYTE, 5) + RELOC_NUMBER (R_MSP430_16_PCREL_BYTE, 6) + +END_RELOC_NUMBERS (R_MSP430_max) + +#endif /* _ELF_MSP430_H */ diff --git a/contrib/binutils-2.14/include/elf/or32.h b/contrib/binutils-2.14/include/elf/or32.h new file mode 100644 index 0000000000..14884f330c --- /dev/null +++ b/contrib/binutils-2.14/include/elf/or32.h @@ -0,0 +1,62 @@ +/* OR1K ELF support for BFD. Derived from ppc.h. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_OR1K_H +#define _ELF_OR1K_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_or32_reloc_type) + RELOC_NUMBER (R_OR32_NONE, 0) + RELOC_NUMBER (R_OR32_32, 1) + RELOC_NUMBER (R_OR32_16, 2) + RELOC_NUMBER (R_OR32_8, 3) + RELOC_NUMBER (R_OR32_CONST, 4) + RELOC_NUMBER (R_OR32_CONSTH, 5) + RELOC_NUMBER (R_OR32_JUMPTARG, 6) + RELOC_NUMBER (R_OR32_GNU_VTENTRY, 7) + RELOC_NUMBER (R_OR32_GNU_VTINHERIT, 8) +END_RELOC_NUMBERS (R_OR32_max) + +/* Four bit OR32 machine type field. */ +#define EF_OR32_MACH 0x0000000f + +/* Various CPU types. */ +#define E_OR32_MACH_BASE 0x00000000 +#define E_OR32_MACH_UNUSED1 0x00000001 +#define E_OR32_MACH_UNUSED2 0x00000002 +#define E_OR32_MACH_UNUSED4 0x00000003 + +/* Processor specific section headers, sh_type field */ +#define SHT_ORDERED SHT_HIPROC /* Link editor is to sort the \ + entries in this section \ + based on the address \ + specified in the associated \ + symbol table entry. */ + +/* Processor specific section flags, sh_flags field */ +#define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude \ + this section from executable \ + and shared objects that it \ + builds when those objects \ + are not to be furhter \ + relocated. */ +#endif /* _ELF_OR1K_H */ diff --git a/contrib/binutils-2.14/include/elf/pj.h b/contrib/binutils-2.14/include/elf/pj.h new file mode 100644 index 0000000000..586fd3a360 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/pj.h @@ -0,0 +1,44 @@ +/* picoJava ELF support for BFD. + Copyright 1999, 2000 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_PJ_H +#define _ELF_PJ_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ + +START_RELOC_NUMBERS (elf_pj_reloc_type) + RELOC_NUMBER (R_PJ_NONE, 0) + RELOC_NUMBER (R_PJ_DATA_DIR32, 1) + RELOC_NUMBER (R_PJ_CODE_REL32, 2) + RELOC_NUMBER (R_PJ_CODE_REL16, 3) + RELOC_NUMBER (R_PJ_CODE_DIR32, 6) + RELOC_NUMBER (R_PJ_CODE_DIR16, 7) + RELOC_NUMBER (R_PJ_CODE_LO16, 13) + RELOC_NUMBER (R_PJ_CODE_HI16, 14) + RELOC_NUMBER (R_PJ_GNU_VTINHERIT, 15) + RELOC_NUMBER (R_PJ_GNU_VTENTRY, 16) +END_RELOC_NUMBERS (R_PJ_max) + +#define EF_PICOJAVA_ARCH 0x0000000f +#define EF_PICOJAVA_NEWCALLS 0x00000010 +#define EF_PICOJAVA_GNUCALLS 0x00000020 /* The (currently) non standard GNU calling convention */ + +#endif diff --git a/contrib/binutils-2.14/include/elf/ppc.h b/contrib/binutils-2.14/include/elf/ppc.h new file mode 100644 index 0000000000..52bcc1e055 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/ppc.h @@ -0,0 +1,159 @@ +/* PPC ELF support for BFD. + Copyright 1995, 1996, 1998, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + By Michael Meissner, Cygnus Support, , from information + in the System V Application Binary Interface, PowerPC Processor Supplement + and the PowerPC Embedded Application Binary Interface (eabi). + +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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the PPC ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_PPC_H +#define _ELF_PPC_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_ppc_reloc_type) + RELOC_NUMBER (R_PPC_NONE, 0) + RELOC_NUMBER (R_PPC_ADDR32, 1) + RELOC_NUMBER (R_PPC_ADDR24, 2) + RELOC_NUMBER (R_PPC_ADDR16, 3) + RELOC_NUMBER (R_PPC_ADDR16_LO, 4) + RELOC_NUMBER (R_PPC_ADDR16_HI, 5) + RELOC_NUMBER (R_PPC_ADDR16_HA, 6) + RELOC_NUMBER (R_PPC_ADDR14, 7) + RELOC_NUMBER (R_PPC_ADDR14_BRTAKEN, 8) + RELOC_NUMBER (R_PPC_ADDR14_BRNTAKEN, 9) + RELOC_NUMBER (R_PPC_REL24, 10) + RELOC_NUMBER (R_PPC_REL14, 11) + RELOC_NUMBER (R_PPC_REL14_BRTAKEN, 12) + RELOC_NUMBER (R_PPC_REL14_BRNTAKEN, 13) + RELOC_NUMBER (R_PPC_GOT16, 14) + RELOC_NUMBER (R_PPC_GOT16_LO, 15) + RELOC_NUMBER (R_PPC_GOT16_HI, 16) + RELOC_NUMBER (R_PPC_GOT16_HA, 17) + RELOC_NUMBER (R_PPC_PLTREL24, 18) + RELOC_NUMBER (R_PPC_COPY, 19) + RELOC_NUMBER (R_PPC_GLOB_DAT, 20) + RELOC_NUMBER (R_PPC_JMP_SLOT, 21) + RELOC_NUMBER (R_PPC_RELATIVE, 22) + RELOC_NUMBER (R_PPC_LOCAL24PC, 23) + RELOC_NUMBER (R_PPC_UADDR32, 24) + RELOC_NUMBER (R_PPC_UADDR16, 25) + RELOC_NUMBER (R_PPC_REL32, 26) + RELOC_NUMBER (R_PPC_PLT32, 27) + RELOC_NUMBER (R_PPC_PLTREL32, 28) + RELOC_NUMBER (R_PPC_PLT16_LO, 29) + RELOC_NUMBER (R_PPC_PLT16_HI, 30) + RELOC_NUMBER (R_PPC_PLT16_HA, 31) + RELOC_NUMBER (R_PPC_SDAREL16, 32) + RELOC_NUMBER (R_PPC_SECTOFF, 33) + RELOC_NUMBER (R_PPC_SECTOFF_LO, 34) + RELOC_NUMBER (R_PPC_SECTOFF_HI, 35) + RELOC_NUMBER (R_PPC_SECTOFF_HA, 36) + RELOC_NUMBER (R_PPC_ADDR30, 37) + + /* Relocs added to support TLS. */ + RELOC_NUMBER (R_PPC_TLS, 67) + RELOC_NUMBER (R_PPC_DTPMOD32, 68) + RELOC_NUMBER (R_PPC_TPREL16, 69) + RELOC_NUMBER (R_PPC_TPREL16_LO, 70) + RELOC_NUMBER (R_PPC_TPREL16_HI, 71) + RELOC_NUMBER (R_PPC_TPREL16_HA, 72) + RELOC_NUMBER (R_PPC_TPREL32, 73) + RELOC_NUMBER (R_PPC_DTPREL16, 74) + RELOC_NUMBER (R_PPC_DTPREL16_LO, 75) + RELOC_NUMBER (R_PPC_DTPREL16_HI, 76) + RELOC_NUMBER (R_PPC_DTPREL16_HA, 77) + RELOC_NUMBER (R_PPC_DTPREL32, 78) + RELOC_NUMBER (R_PPC_GOT_TLSGD16, 79) + RELOC_NUMBER (R_PPC_GOT_TLSGD16_LO, 80) + RELOC_NUMBER (R_PPC_GOT_TLSGD16_HI, 81) + RELOC_NUMBER (R_PPC_GOT_TLSGD16_HA, 82) + RELOC_NUMBER (R_PPC_GOT_TLSLD16, 83) + RELOC_NUMBER (R_PPC_GOT_TLSLD16_LO, 84) + RELOC_NUMBER (R_PPC_GOT_TLSLD16_HI, 85) + RELOC_NUMBER (R_PPC_GOT_TLSLD16_HA, 86) + RELOC_NUMBER (R_PPC_GOT_TPREL16, 87) + RELOC_NUMBER (R_PPC_GOT_TPREL16_LO, 88) + RELOC_NUMBER (R_PPC_GOT_TPREL16_HI, 89) + RELOC_NUMBER (R_PPC_GOT_TPREL16_HA, 90) + RELOC_NUMBER (R_PPC_GOT_DTPREL16, 91) + RELOC_NUMBER (R_PPC_GOT_DTPREL16_LO, 92) + RELOC_NUMBER (R_PPC_GOT_DTPREL16_HI, 93) + RELOC_NUMBER (R_PPC_GOT_DTPREL16_HA, 94) + +/* The remaining relocs are from the Embedded ELF ABI, and are not + in the SVR4 ELF ABI. */ + RELOC_NUMBER (R_PPC_EMB_NADDR32, 101) + RELOC_NUMBER (R_PPC_EMB_NADDR16, 102) + RELOC_NUMBER (R_PPC_EMB_NADDR16_LO, 103) + RELOC_NUMBER (R_PPC_EMB_NADDR16_HI, 104) + RELOC_NUMBER (R_PPC_EMB_NADDR16_HA, 105) + RELOC_NUMBER (R_PPC_EMB_SDAI16, 106) + RELOC_NUMBER (R_PPC_EMB_SDA2I16, 107) + RELOC_NUMBER (R_PPC_EMB_SDA2REL, 108) + RELOC_NUMBER (R_PPC_EMB_SDA21, 109) + RELOC_NUMBER (R_PPC_EMB_MRKREF, 110) + RELOC_NUMBER (R_PPC_EMB_RELSEC16, 111) + RELOC_NUMBER (R_PPC_EMB_RELST_LO, 112) + RELOC_NUMBER (R_PPC_EMB_RELST_HI, 113) + RELOC_NUMBER (R_PPC_EMB_RELST_HA, 114) + RELOC_NUMBER (R_PPC_EMB_BIT_FLD, 115) + RELOC_NUMBER (R_PPC_EMB_RELSDA, 116) + + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_PPC_GNU_VTINHERIT, 253) + RELOC_NUMBER (R_PPC_GNU_VTENTRY, 254) + +/* This is a phony reloc to handle any old fashioned TOC16 references + that may still be in object files. */ + RELOC_NUMBER (R_PPC_TOC16, 255) + +END_RELOC_NUMBERS (R_PPC_max) + +#define IS_PPC_TLS_RELOC(R) \ + ((R) >= R_PPC_TLS && (R) <= R_PPC_GOT_DTPREL16_HA) + +/* Processor specific flags for the ELF header e_flags field. */ + +#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag. */ + +#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag. */ +#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag. */ + +/* Processor specific section headers, sh_type field. */ + +#define SHT_ORDERED SHT_HIPROC /* Link editor is to sort the \ + entries in this section \ + based on the address \ + specified in the associated \ + symbol table entry. */ + +/* Processor specific section flags, sh_flags field. */ + +#define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude \ + this section from executable \ + and shared objects that it \ + builds when those objects \ + are not to be furhter \ + relocated. */ +#endif /* _ELF_PPC_H */ diff --git a/contrib/binutils-2.14/include/elf/ppc64.h b/contrib/binutils-2.14/include/elf/ppc64.h new file mode 100644 index 0000000000..ee2b0ea533 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/ppc64.h @@ -0,0 +1,156 @@ +/* PPC64 ELF support for BFD. + Copyright 2003 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_PPC64_H +#define _ELF_PPC64_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_ppc64_reloc_type) + RELOC_NUMBER (R_PPC64_NONE, 0) + RELOC_NUMBER (R_PPC64_ADDR32, 1) + RELOC_NUMBER (R_PPC64_ADDR24, 2) + RELOC_NUMBER (R_PPC64_ADDR16, 3) + RELOC_NUMBER (R_PPC64_ADDR16_LO, 4) + RELOC_NUMBER (R_PPC64_ADDR16_HI, 5) + RELOC_NUMBER (R_PPC64_ADDR16_HA, 6) + RELOC_NUMBER (R_PPC64_ADDR14, 7) + RELOC_NUMBER (R_PPC64_ADDR14_BRTAKEN, 8) + RELOC_NUMBER (R_PPC64_ADDR14_BRNTAKEN, 9) + RELOC_NUMBER (R_PPC64_REL24, 10) + RELOC_NUMBER (R_PPC64_REL14, 11) + RELOC_NUMBER (R_PPC64_REL14_BRTAKEN, 12) + RELOC_NUMBER (R_PPC64_REL14_BRNTAKEN, 13) + RELOC_NUMBER (R_PPC64_GOT16, 14) + RELOC_NUMBER (R_PPC64_GOT16_LO, 15) + RELOC_NUMBER (R_PPC64_GOT16_HI, 16) + RELOC_NUMBER (R_PPC64_GOT16_HA, 17) + /* 18 unused. 32-bit reloc is R_PPC_PLTREL24. */ + RELOC_NUMBER (R_PPC64_COPY, 19) + RELOC_NUMBER (R_PPC64_GLOB_DAT, 20) + RELOC_NUMBER (R_PPC64_JMP_SLOT, 21) + RELOC_NUMBER (R_PPC64_RELATIVE, 22) + /* 23 unused. 32-bit reloc is R_PPC_LOCAL24PC. */ + RELOC_NUMBER (R_PPC64_UADDR32, 24) + RELOC_NUMBER (R_PPC64_UADDR16, 25) + RELOC_NUMBER (R_PPC64_REL32, 26) + RELOC_NUMBER (R_PPC64_PLT32, 27) + RELOC_NUMBER (R_PPC64_PLTREL32, 28) + RELOC_NUMBER (R_PPC64_PLT16_LO, 29) + RELOC_NUMBER (R_PPC64_PLT16_HI, 30) + RELOC_NUMBER (R_PPC64_PLT16_HA, 31) + /* 32 unused. 32-bit reloc is R_PPC_SDAREL16. */ + RELOC_NUMBER (R_PPC64_SECTOFF, 33) + RELOC_NUMBER (R_PPC64_SECTOFF_LO, 34) + RELOC_NUMBER (R_PPC64_SECTOFF_HI, 35) + RELOC_NUMBER (R_PPC64_SECTOFF_HA, 36) + RELOC_NUMBER (R_PPC64_REL30, 37) + RELOC_NUMBER (R_PPC64_ADDR64, 38) + RELOC_NUMBER (R_PPC64_ADDR16_HIGHER, 39) + RELOC_NUMBER (R_PPC64_ADDR16_HIGHERA, 40) + RELOC_NUMBER (R_PPC64_ADDR16_HIGHEST, 41) + RELOC_NUMBER (R_PPC64_ADDR16_HIGHESTA, 42) + RELOC_NUMBER (R_PPC64_UADDR64, 43) + RELOC_NUMBER (R_PPC64_REL64, 44) + RELOC_NUMBER (R_PPC64_PLT64, 45) + RELOC_NUMBER (R_PPC64_PLTREL64, 46) + RELOC_NUMBER (R_PPC64_TOC16, 47) + RELOC_NUMBER (R_PPC64_TOC16_LO, 48) + RELOC_NUMBER (R_PPC64_TOC16_HI, 49) + RELOC_NUMBER (R_PPC64_TOC16_HA, 50) + RELOC_NUMBER (R_PPC64_TOC, 51) + RELOC_NUMBER (R_PPC64_PLTGOT16, 52) + RELOC_NUMBER (R_PPC64_PLTGOT16_LO, 53) + RELOC_NUMBER (R_PPC64_PLTGOT16_HI, 54) + RELOC_NUMBER (R_PPC64_PLTGOT16_HA, 55) + + /* The following relocs were added in the 64-bit PowerPC ELF ABI + revision 1.2. */ + RELOC_NUMBER (R_PPC64_ADDR16_DS, 56) + RELOC_NUMBER (R_PPC64_ADDR16_LO_DS, 57) + RELOC_NUMBER (R_PPC64_GOT16_DS, 58) + RELOC_NUMBER (R_PPC64_GOT16_LO_DS, 59) + RELOC_NUMBER (R_PPC64_PLT16_LO_DS, 60) + RELOC_NUMBER (R_PPC64_SECTOFF_DS, 61) + RELOC_NUMBER (R_PPC64_SECTOFF_LO_DS, 62) + RELOC_NUMBER (R_PPC64_TOC16_DS, 63) + RELOC_NUMBER (R_PPC64_TOC16_LO_DS, 64) + RELOC_NUMBER (R_PPC64_PLTGOT16_DS, 65) + RELOC_NUMBER (R_PPC64_PLTGOT16_LO_DS, 66) + + /* Relocs added to support TLS. PowerPC64 ELF ABI revision 1.5. */ + RELOC_NUMBER (R_PPC64_TLS, 67) + RELOC_NUMBER (R_PPC64_DTPMOD64, 68) + RELOC_NUMBER (R_PPC64_TPREL16, 69) + RELOC_NUMBER (R_PPC64_TPREL16_LO, 70) + RELOC_NUMBER (R_PPC64_TPREL16_HI, 71) + RELOC_NUMBER (R_PPC64_TPREL16_HA, 72) + RELOC_NUMBER (R_PPC64_TPREL64, 73) + RELOC_NUMBER (R_PPC64_DTPREL16, 74) + RELOC_NUMBER (R_PPC64_DTPREL16_LO, 75) + RELOC_NUMBER (R_PPC64_DTPREL16_HI, 76) + RELOC_NUMBER (R_PPC64_DTPREL16_HA, 77) + RELOC_NUMBER (R_PPC64_DTPREL64, 78) + RELOC_NUMBER (R_PPC64_GOT_TLSGD16, 79) + RELOC_NUMBER (R_PPC64_GOT_TLSGD16_LO, 80) + RELOC_NUMBER (R_PPC64_GOT_TLSGD16_HI, 81) + RELOC_NUMBER (R_PPC64_GOT_TLSGD16_HA, 82) + RELOC_NUMBER (R_PPC64_GOT_TLSLD16, 83) + RELOC_NUMBER (R_PPC64_GOT_TLSLD16_LO, 84) + RELOC_NUMBER (R_PPC64_GOT_TLSLD16_HI, 85) + RELOC_NUMBER (R_PPC64_GOT_TLSLD16_HA, 86) + RELOC_NUMBER (R_PPC64_GOT_TPREL16_DS, 87) + RELOC_NUMBER (R_PPC64_GOT_TPREL16_LO_DS, 88) + RELOC_NUMBER (R_PPC64_GOT_TPREL16_HI, 89) + RELOC_NUMBER (R_PPC64_GOT_TPREL16_HA, 90) + RELOC_NUMBER (R_PPC64_GOT_DTPREL16_DS, 91) + RELOC_NUMBER (R_PPC64_GOT_DTPREL16_LO_DS, 92) + RELOC_NUMBER (R_PPC64_GOT_DTPREL16_HI, 93) + RELOC_NUMBER (R_PPC64_GOT_DTPREL16_HA, 94) + RELOC_NUMBER (R_PPC64_TPREL16_DS, 95) + RELOC_NUMBER (R_PPC64_TPREL16_LO_DS, 96) + RELOC_NUMBER (R_PPC64_TPREL16_HIGHER, 97) + RELOC_NUMBER (R_PPC64_TPREL16_HIGHERA, 98) + RELOC_NUMBER (R_PPC64_TPREL16_HIGHEST, 99) + RELOC_NUMBER (R_PPC64_TPREL16_HIGHESTA, 100) + RELOC_NUMBER (R_PPC64_DTPREL16_DS, 101) + RELOC_NUMBER (R_PPC64_DTPREL16_LO_DS, 102) + RELOC_NUMBER (R_PPC64_DTPREL16_HIGHER, 103) + RELOC_NUMBER (R_PPC64_DTPREL16_HIGHERA, 104) + RELOC_NUMBER (R_PPC64_DTPREL16_HIGHEST, 105) + RELOC_NUMBER (R_PPC64_DTPREL16_HIGHESTA, 106) + + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_PPC64_GNU_VTINHERIT, 253) + RELOC_NUMBER (R_PPC64_GNU_VTENTRY, 254) + +END_RELOC_NUMBERS (R_PPC64_max) + +#define IS_PPC64_TLS_RELOC(R) \ + ((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) + +/* Specify the start of the .glink section. */ +#define DT_PPC64_GLINK DT_LOPROC + +/* Specify the start and size of the .opd section. */ +#define DT_PPC64_OPD (DT_LOPROC + 1) +#define DT_PPC64_OPDSZ (DT_LOPROC + 2) + +#endif /* _ELF_PPC64_H */ diff --git a/contrib/binutils-2.14/include/elf/reloc-macros.h b/contrib/binutils-2.14/include/elf/reloc-macros.h new file mode 100644 index 0000000000..9ad346c9f3 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/reloc-macros.h @@ -0,0 +1,106 @@ +/* Generic relocation support for BFD. + Copyright 1998, 1999, 2000 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* These macros are used by the various *.h target specific header + files to either generate an enum containing all the known relocations + for that target, or if RELOC_MACROS_GEN_FUNC is defined, a recognition + function is generated instead. (This is used by binutils/readelf.c) + + Given a header file like this: + + START_RELOC_NUMBERS (foo) + RELOC_NUMBER (R_foo_NONE, 0) + RELOC_NUMBER (R_foo_32, 1) + EMPTY_RELOC (R_foo_good) + FAKE_RELOC (R_foo_illegal, 9) + END_RELOC_NUMBERS (R_foo_count) + + Then the following will be produced by default (ie if + RELOC_MACROS_GEN_FUNC is *not* defined). + + enum foo + { + R_foo_NONE = 0, + R_foo_32 = 1, + R_foo_good, + R_foo_illegal = 9, + R_foo_count + }; + + If RELOC_MACROS_GEN_FUNC *is* defined, then instead the + following function will be generated: + + static const char * foo PARAMS ((unsigned long rtype)); + static const char * + foo (rtype) + unsigned long rtype; + { + switch (rtype) + { + case 0: return "R_foo_NONE"; + case 1: return "R_foo_32"; + default: return NULL; + } + } + */ + +#ifndef _RELOC_MACROS_H +#define _RELOC_MACROS_H + +#ifdef RELOC_MACROS_GEN_FUNC + +/* This function takes the relocation number and returns the + string version name of the name of that relocation. If + the relocation is not recognised, NULL is returned. */ + +#define START_RELOC_NUMBERS(name) \ +static const char * name PARAMS ((unsigned long rtype)); \ +static const char * \ +name (rtype) \ + unsigned long rtype; \ +{ \ + switch (rtype) \ + { + +#if defined (__STDC__) || defined (ALMOST_STDC) +#define RELOC_NUMBER(name, number) case number : return #name ; +#else +#define RELOC_NUMBER(name, number) case number : return "name" ; +#endif + +#define FAKE_RELOC(name, number) +#define EMPTY_RELOC(name) + +#define END_RELOC_NUMBERS(name) \ + default: return NULL; \ + } \ +} + + +#else /* Default to generating enum. */ + +#define START_RELOC_NUMBERS(name) enum name { +#define RELOC_NUMBER(name, number) name = number, +#define FAKE_RELOC(name, number) name = number, +#define EMPTY_RELOC(name) name, +#define END_RELOC_NUMBERS(name) name }; + +#endif + +#endif /* RELOC_MACROS_H */ diff --git a/contrib/binutils-2.14/include/elf/s390.h b/contrib/binutils-2.14/include/elf/s390.h new file mode 100644 index 0000000000..6a21c3b6fe --- /dev/null +++ b/contrib/binutils-2.14/include/elf/s390.h @@ -0,0 +1,120 @@ +/* 390 ELF support for BFD. + Copyright 2000, 2001 Free Software Foundation, Inc. + Contributed by Carl B. Pedersen and Martin Schwidefsky. + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef _ELF_390_H +#define _ELF_390_H + +/* Processor specific flags for the ELF header e_flags field. */ + +/* Symbol types. */ + +#define STACK_REG 15 /* Global Stack reg */ +#define BACKL_REG 14 /* Global Backlink reg */ +#define BASE_REG 13 /* Global Base reg */ +#define GOT_REG 12 /* Holds addr of GOT */ + +#include "elf/reloc-macros.h" + +/* Relocation types. */ + +START_RELOC_NUMBERS (elf_s390_reloc_type) + RELOC_NUMBER (R_390_NONE, 0) /* No reloc. */ + RELOC_NUMBER (R_390_8, 1) /* Direct 8 bit. */ + RELOC_NUMBER (R_390_12, 2) /* Direct 12 bit. */ + RELOC_NUMBER (R_390_16, 3) /* Direct 16 bit. */ + RELOC_NUMBER (R_390_32, 4) /* Direct 32 bit. */ + RELOC_NUMBER (R_390_PC32, 5) /* PC relative 32 bit. */ + RELOC_NUMBER (R_390_GOT12, 6) /* 12 bit GOT offset. */ + RELOC_NUMBER (R_390_GOT32, 7) /* 32 bit GOT offset. */ + RELOC_NUMBER (R_390_PLT32, 8) /* 32 bit PC relative PLT address. */ + RELOC_NUMBER (R_390_COPY, 9) /* Copy symbol at runtime. */ + RELOC_NUMBER (R_390_GLOB_DAT, 10) /* Create GOT entry. */ + RELOC_NUMBER (R_390_JMP_SLOT, 11) /* Create PLT entry. */ + RELOC_NUMBER (R_390_RELATIVE, 12) /* Adjust by program base. */ + RELOC_NUMBER (R_390_GOTOFF32, 13) /* 32 bit offset to GOT. */ + RELOC_NUMBER (R_390_GOTPC, 14) /* 32 bit PC relative offset to GOT. */ + RELOC_NUMBER (R_390_GOT16, 15) /* 16 bit GOT offset. */ + RELOC_NUMBER (R_390_PC16, 16) /* PC relative 16 bit. */ + RELOC_NUMBER (R_390_PC16DBL, 17) /* PC relative 16 bit shifted by 1. */ + RELOC_NUMBER (R_390_PLT16DBL, 18) /* 16 bit PC rel. PLT shifted by 1. */ + RELOC_NUMBER (R_390_PC32DBL, 19) /* PC relative 32 bit shifted by 1. */ + RELOC_NUMBER (R_390_PLT32DBL, 20) /* 32 bit PC rel. PLT shifted by 1. */ + RELOC_NUMBER (R_390_GOTPCDBL, 21) /* 32 bit PC rel. GOT shifted by 1. */ + RELOC_NUMBER (R_390_64, 22) /* Direct 64 bit. */ + RELOC_NUMBER (R_390_PC64, 23) /* PC relative 64 bit. */ + RELOC_NUMBER (R_390_GOT64, 24) /* 64 bit GOT offset. */ + RELOC_NUMBER (R_390_PLT64, 25) /* 64 bit PC relative PLT address. */ + RELOC_NUMBER (R_390_GOTENT, 26) /* 32 bit PC rel. to GOT entry >> 1. */ + RELOC_NUMBER (R_390_GOTOFF16, 27) /* 16 bit offset to GOT. */ + RELOC_NUMBER (R_390_GOTOFF64, 28) /* 64 bit offset to GOT. */ + RELOC_NUMBER (R_390_GOTPLT12, 29) /* 12 bit offset to jump slot. */ + RELOC_NUMBER (R_390_GOTPLT16, 30) /* 16 bit offset to jump slot. */ + RELOC_NUMBER (R_390_GOTPLT32, 31) /* 32 bit offset to jump slot. */ + RELOC_NUMBER (R_390_GOTPLT64, 32) /* 64 bit offset to jump slot. */ + RELOC_NUMBER (R_390_GOTPLTENT, 33) /* 32 bit rel. offset to jump slot. */ + RELOC_NUMBER (R_390_PLTOFF16, 34) /* 16 bit offset from GOT to PLT. */ + RELOC_NUMBER (R_390_PLTOFF32, 35) /* 32 bit offset from GOT to PLT. */ + RELOC_NUMBER (R_390_PLTOFF64, 36) /* 16 bit offset from GOT to PLT. */ + RELOC_NUMBER (R_390_TLS_LOAD, 37) /* Tag for load insn in TLS code. */ + RELOC_NUMBER (R_390_TLS_GDCALL, 38) /* Tag for function call in general + dynamic TLS code. */ + RELOC_NUMBER (R_390_TLS_LDCALL, 39) /* Tag for function call in local + dynamic TLS code. */ + RELOC_NUMBER (R_390_TLS_GD32, 40) /* Direct 32 bit for general dynamic + thread local data. */ + RELOC_NUMBER (R_390_TLS_GD64, 41) /* Direct 64 bit for general dynamic + thread local data. */ + RELOC_NUMBER (R_390_TLS_GOTIE12, 42)/* 12 bit GOT offset for static TLS + block offset. */ + RELOC_NUMBER (R_390_TLS_GOTIE32, 43)/* 32 bit GOT offset for static TLS + block offset. */ + RELOC_NUMBER (R_390_TLS_GOTIE64, 44)/* 64 bit GOT offset for static TLS + block offset. */ + RELOC_NUMBER (R_390_TLS_LDM32, 45) /* Direct 32 bit for local dynamic + thread local data in LD code. */ + RELOC_NUMBER (R_390_TLS_LDM64, 46) /* Direct 64 bit for local dynamic + thread local data in LD code. */ + RELOC_NUMBER (R_390_TLS_IE32, 47) /* 32 bit address of GOT entry for + negated static TLS block offset. */ + RELOC_NUMBER (R_390_TLS_IE64, 48) /* 64 bit address of GOT entry for + negated static TLS block offset. */ + RELOC_NUMBER (R_390_TLS_IEENT, 49) /* 32 bit rel. offset to GOT entry for + negated static TLS block offset. */ + RELOC_NUMBER (R_390_TLS_LE32, 50) /* 32 bit negated offset relative to + static TLS block. */ + RELOC_NUMBER (R_390_TLS_LE64, 51) /* 64 bit negated offset relative to + static TLS block. */ + RELOC_NUMBER (R_390_TLS_LDO32, 52) /* 32 bit offset relative to TLS + block. */ + RELOC_NUMBER (R_390_TLS_LDO64, 53) /* 64 bit offset relative to TLS + block. */ + RELOC_NUMBER (R_390_TLS_DTPMOD, 54) /* ID of module containing symbol. */ + RELOC_NUMBER (R_390_TLS_DTPOFF, 55) /* Offset in TLS block. */ + RELOC_NUMBER (R_390_TLS_TPOFF, 56) /* Negate offset in static TLS + block. */ + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_390_GNU_VTINHERIT, 250) + RELOC_NUMBER (R_390_GNU_VTENTRY, 251) +END_RELOC_NUMBERS (R_390_max) + +#endif /* _ELF_390_H */ + + diff --git a/contrib/binutils-2.14/include/elf/sh.h b/contrib/binutils-2.14/include/elf/sh.h new file mode 100644 index 0000000000..00a5f2adce --- /dev/null +++ b/contrib/binutils-2.14/include/elf/sh.h @@ -0,0 +1,190 @@ +/* SH ELF support for BFD. + Copyright 1998, 2000, 2001, 2002, 2003 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_SH_H +#define _ELF_SH_H + +/* Processor specific flags for the ELF header e_flags field. */ + +#define EF_SH_MACH_MASK 0x1f +#define EF_SH_UNKNOWN 0 /* For backwards compatibility. */ +#define EF_SH1 1 +#define EF_SH2 2 +#define EF_SH3 3 +#define EF_SH_HAS_DSP(flags) ((flags) & 4) +#define EF_SH_DSP 4 +#define EF_SH3_DSP 5 +#define EF_SH_HAS_FP(flags) ((flags) & 8) +#define EF_SH3E 8 +#define EF_SH4 9 +#define EF_SH2E 11 + +/* This one can only mix in objects from other EF_SH5 objects. */ +#define EF_SH5 10 + +#define EF_SH_MERGE_MACH(mach1, mach2) \ + (((((mach1) == EF_SH3 || (mach1) == EF_SH_UNKNOWN) && (mach2) == EF_SH_DSP) \ + || ((mach1) == EF_SH_DSP \ + && ((mach2) == EF_SH3 || (mach2) == EF_SH_UNKNOWN))) \ + ? EF_SH3_DSP \ + : (((mach1) < EF_SH3 && (mach2) == EF_SH_UNKNOWN) \ + || ((mach2) < EF_SH3 && (mach1) == EF_SH_UNKNOWN)) \ + ? EF_SH3 \ + : ((mach1) == EF_SH2E && EF_SH_HAS_FP (mach2)) \ + ? (mach2) \ + : ((mach2) == EF_SH2E && EF_SH_HAS_FP (mach1)) \ + ? (mach1) \ + : (((mach1) == EF_SH2E && (mach2) == EF_SH_UNKNOWN) \ + || ((mach2) == EF_SH2E && (mach1) == EF_SH_UNKNOWN)) \ + ? EF_SH2E \ + : (((mach1) == EF_SH3E && (mach2) == EF_SH_UNKNOWN) \ + || ((mach2) == EF_SH3E && (mach1) == EF_SH_UNKNOWN)) \ + ? EF_SH4 \ + : (((mach1) == EF_SH2E ? 7 : (mach1)) > ((mach2) == EF_SH2E ? 7 : (mach2)) \ + ? (mach1) : (mach2))) + +/* Flags for the st_other symbol field. + Keep away from the STV_ visibility flags (bit 0..1). */ + +/* A reference to this symbol should by default add 1. */ +#define STO_SH5_ISA32 (1 << 2) + +/* Section contains only SHmedia code (no SHcompact code). */ +#define SHF_SH5_ISA32 0x40000000 + +/* Section contains both SHmedia and SHcompact code, and possibly also + constants. */ +#define SHF_SH5_ISA32_MIXED 0x20000000 + +/* If applied to a .cranges section, marks that the section is sorted by + increasing cr_addr values. */ +#define SHT_SH5_CR_SORTED 0x80000001 + +/* Symbol should be handled as DataLabel (attached to global SHN_UNDEF + symbols). */ +#define STT_DATALABEL STT_LOPROC + +#include "elf/reloc-macros.h" + +/* Relocations. */ +/* Relocations 25ff are GNU extensions. + 25..33 are used for relaxation and use the same constants as COFF uses. */ +START_RELOC_NUMBERS (elf_sh_reloc_type) + RELOC_NUMBER (R_SH_NONE, 0) + RELOC_NUMBER (R_SH_DIR32, 1) + RELOC_NUMBER (R_SH_REL32, 2) + RELOC_NUMBER (R_SH_DIR8WPN, 3) + RELOC_NUMBER (R_SH_IND12W, 4) + RELOC_NUMBER (R_SH_DIR8WPL, 5) + RELOC_NUMBER (R_SH_DIR8WPZ, 6) + RELOC_NUMBER (R_SH_DIR8BP, 7) + RELOC_NUMBER (R_SH_DIR8W, 8) + RELOC_NUMBER (R_SH_DIR8L, 9) + FAKE_RELOC (R_SH_FIRST_INVALID_RELOC, 10) + FAKE_RELOC (R_SH_LAST_INVALID_RELOC, 24) + RELOC_NUMBER (R_SH_SWITCH16, 25) + RELOC_NUMBER (R_SH_SWITCH32, 26) + RELOC_NUMBER (R_SH_USES, 27) + RELOC_NUMBER (R_SH_COUNT, 28) + RELOC_NUMBER (R_SH_ALIGN, 29) + RELOC_NUMBER (R_SH_CODE, 30) + RELOC_NUMBER (R_SH_DATA, 31) + RELOC_NUMBER (R_SH_LABEL, 32) + RELOC_NUMBER (R_SH_SWITCH8, 33) + RELOC_NUMBER (R_SH_GNU_VTINHERIT, 34) + RELOC_NUMBER (R_SH_GNU_VTENTRY, 35) + RELOC_NUMBER (R_SH_LOOP_START, 36) + RELOC_NUMBER (R_SH_LOOP_END, 37) + FAKE_RELOC (R_SH_FIRST_INVALID_RELOC_2, 38) + FAKE_RELOC (R_SH_LAST_INVALID_RELOC_2, 44) + RELOC_NUMBER (R_SH_DIR5U, 45) + RELOC_NUMBER (R_SH_DIR6U, 46) + RELOC_NUMBER (R_SH_DIR6S, 47) + RELOC_NUMBER (R_SH_DIR10S, 48) + RELOC_NUMBER (R_SH_DIR10SW, 49) + RELOC_NUMBER (R_SH_DIR10SL, 50) + RELOC_NUMBER (R_SH_DIR10SQ, 51) + FAKE_RELOC (R_SH_FIRST_INVALID_RELOC_3, 52) + FAKE_RELOC (R_SH_LAST_INVALID_RELOC_3, 143) + RELOC_NUMBER (R_SH_TLS_GD_32, 144) + RELOC_NUMBER (R_SH_TLS_LD_32, 145) + RELOC_NUMBER (R_SH_TLS_LDO_32, 146) + RELOC_NUMBER (R_SH_TLS_IE_32, 147) + RELOC_NUMBER (R_SH_TLS_LE_32, 148) + RELOC_NUMBER (R_SH_TLS_DTPMOD32, 149) + RELOC_NUMBER (R_SH_TLS_DTPOFF32, 150) + RELOC_NUMBER (R_SH_TLS_TPOFF32, 151) + FAKE_RELOC (R_SH_FIRST_INVALID_RELOC_4, 152) + FAKE_RELOC (R_SH_LAST_INVALID_RELOC_4, 159) + RELOC_NUMBER (R_SH_GOT32, 160) + RELOC_NUMBER (R_SH_PLT32, 161) + RELOC_NUMBER (R_SH_COPY, 162) + RELOC_NUMBER (R_SH_GLOB_DAT, 163) + RELOC_NUMBER (R_SH_JMP_SLOT, 164) + RELOC_NUMBER (R_SH_RELATIVE, 165) + RELOC_NUMBER (R_SH_GOTOFF, 166) + RELOC_NUMBER (R_SH_GOTPC, 167) + RELOC_NUMBER (R_SH_GOTPLT32, 168) + RELOC_NUMBER (R_SH_GOT_LOW16, 169) + RELOC_NUMBER (R_SH_GOT_MEDLOW16, 170) + RELOC_NUMBER (R_SH_GOT_MEDHI16, 171) + RELOC_NUMBER (R_SH_GOT_HI16, 172) + RELOC_NUMBER (R_SH_GOTPLT_LOW16, 173) + RELOC_NUMBER (R_SH_GOTPLT_MEDLOW16, 174) + RELOC_NUMBER (R_SH_GOTPLT_MEDHI16, 175) + RELOC_NUMBER (R_SH_GOTPLT_HI16, 176) + RELOC_NUMBER (R_SH_PLT_LOW16, 177) + RELOC_NUMBER (R_SH_PLT_MEDLOW16, 178) + RELOC_NUMBER (R_SH_PLT_MEDHI16, 179) + RELOC_NUMBER (R_SH_PLT_HI16, 180) + RELOC_NUMBER (R_SH_GOTOFF_LOW16, 181) + RELOC_NUMBER (R_SH_GOTOFF_MEDLOW16, 182) + RELOC_NUMBER (R_SH_GOTOFF_MEDHI16, 183) + RELOC_NUMBER (R_SH_GOTOFF_HI16, 184) + RELOC_NUMBER (R_SH_GOTPC_LOW16, 185) + RELOC_NUMBER (R_SH_GOTPC_MEDLOW16, 186) + RELOC_NUMBER (R_SH_GOTPC_MEDHI16, 187) + RELOC_NUMBER (R_SH_GOTPC_HI16, 188) + RELOC_NUMBER (R_SH_GOT10BY4, 189) + RELOC_NUMBER (R_SH_GOTPLT10BY4, 190) + RELOC_NUMBER (R_SH_GOT10BY8, 191) + RELOC_NUMBER (R_SH_GOTPLT10BY8, 192) + RELOC_NUMBER (R_SH_COPY64, 193) + RELOC_NUMBER (R_SH_GLOB_DAT64, 194) + RELOC_NUMBER (R_SH_JMP_SLOT64, 195) + RELOC_NUMBER (R_SH_RELATIVE64, 196) + FAKE_RELOC (R_SH_FIRST_INVALID_RELOC_5, 197) + FAKE_RELOC (R_SH_LAST_INVALID_RELOC_5, 241) + RELOC_NUMBER (R_SH_SHMEDIA_CODE, 242) + RELOC_NUMBER (R_SH_PT_16, 243) + RELOC_NUMBER (R_SH_IMMS16, 244) + RELOC_NUMBER (R_SH_IMMU16, 245) + RELOC_NUMBER (R_SH_IMM_LOW16, 246) + RELOC_NUMBER (R_SH_IMM_LOW16_PCREL, 247) + RELOC_NUMBER (R_SH_IMM_MEDLOW16, 248) + RELOC_NUMBER (R_SH_IMM_MEDLOW16_PCREL, 249) + RELOC_NUMBER (R_SH_IMM_MEDHI16, 250) + RELOC_NUMBER (R_SH_IMM_MEDHI16_PCREL, 251) + RELOC_NUMBER (R_SH_IMM_HI16, 252) + RELOC_NUMBER (R_SH_IMM_HI16_PCREL, 253) + RELOC_NUMBER (R_SH_64, 254) + RELOC_NUMBER (R_SH_64_PCREL, 255) +END_RELOC_NUMBERS (R_SH_max) + +#endif diff --git a/contrib/binutils-2.14/include/elf/sparc.h b/contrib/binutils-2.14/include/elf/sparc.h new file mode 100644 index 0000000000..2d28d26f9b --- /dev/null +++ b/contrib/binutils-2.14/include/elf/sparc.h @@ -0,0 +1,175 @@ +/* SPARC ELF support for BFD. + Copyright 1996, 1997, 1998, 1999, 2000, 2002 Free Software Foundation, Inc. + By Doug Evans, 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_SPARC_H +#define _ELF_SPARC_H + +/* Processor specific flags for the ELF header e_flags field. */ + +/* These are defined by Sun. */ + +#define EF_SPARC_32PLUS_MASK 0xffff00 /* bits indicating V8+ type */ +#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ +#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ +#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ +#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ + +#define EF_SPARC_LEDATA 0x800000 /* little endian data */ + +/* This name is used in the V9 ABI. */ +#define EF_SPARC_EXT_MASK 0xffff00 /* reserved for vendor extensions */ + +/* V9 memory models */ +#define EF_SPARCV9_MM 0x3 /* memory model mask */ +#define EF_SPARCV9_TSO 0x0 /* total store ordering */ +#define EF_SPARCV9_PSO 0x1 /* partial store ordering */ +#define EF_SPARCV9_RMO 0x2 /* relaxed store ordering */ + +/* Section indices. */ + +#define SHN_BEFORE 0xff00 /* used with SHF_ORDERED */ +#define SHN_AFTER 0xff01 /* used with SHF_ORDERED */ + +/* Section flags. */ + +#define SHF_EXCLUDE 0x80000000 /* exclude from linking */ +#define SHF_ORDERED 0x40000000 /* treat sh_link,sh_info specially */ + +/* Symbol types. */ + +#define STT_REGISTER 13 /* global reg reserved to app. */ + +#include "elf/reloc-macros.h" + +/* Relocation types. */ +START_RELOC_NUMBERS (elf_sparc_reloc_type) + RELOC_NUMBER (R_SPARC_NONE, 0) + RELOC_NUMBER (R_SPARC_8, 1) + RELOC_NUMBER (R_SPARC_16, 2) + RELOC_NUMBER (R_SPARC_32, 3) + RELOC_NUMBER (R_SPARC_DISP8, 4) + RELOC_NUMBER (R_SPARC_DISP16, 5) + RELOC_NUMBER (R_SPARC_DISP32, 6) + RELOC_NUMBER (R_SPARC_WDISP30, 7) + RELOC_NUMBER (R_SPARC_WDISP22, 8) + RELOC_NUMBER (R_SPARC_HI22, 9) + RELOC_NUMBER (R_SPARC_22, 10) + RELOC_NUMBER (R_SPARC_13, 11) + RELOC_NUMBER (R_SPARC_LO10, 12) + RELOC_NUMBER (R_SPARC_GOT10, 13) + RELOC_NUMBER (R_SPARC_GOT13, 14) + RELOC_NUMBER (R_SPARC_GOT22, 15) + RELOC_NUMBER (R_SPARC_PC10, 16) + RELOC_NUMBER (R_SPARC_PC22, 17) + RELOC_NUMBER (R_SPARC_WPLT30, 18) + RELOC_NUMBER (R_SPARC_COPY, 19) + RELOC_NUMBER (R_SPARC_GLOB_DAT, 20) + RELOC_NUMBER (R_SPARC_JMP_SLOT, 21) + RELOC_NUMBER (R_SPARC_RELATIVE, 22) + RELOC_NUMBER (R_SPARC_UA32, 23) + + /* ??? These 6 relocs are new but not currently used. For binary + compatibility in the sparc64-elf toolchain, we leave them out. + A non-binary upward compatible change is expected for sparc64-elf. */ +#ifndef SPARC64_OLD_RELOCS + /* ??? New relocs on the UltraSPARC. Not sure what they're for yet. */ + RELOC_NUMBER (R_SPARC_PLT32, 24) + RELOC_NUMBER (R_SPARC_HIPLT22, 25) + RELOC_NUMBER (R_SPARC_LOPLT10, 26) + RELOC_NUMBER (R_SPARC_PCPLT32, 27) + RELOC_NUMBER (R_SPARC_PCPLT22, 28) + RELOC_NUMBER (R_SPARC_PCPLT10, 29) +#endif + + /* v9 relocs */ + RELOC_NUMBER (R_SPARC_10, 30) + RELOC_NUMBER (R_SPARC_11, 31) + RELOC_NUMBER (R_SPARC_64, 32) + RELOC_NUMBER (R_SPARC_OLO10, 33) + RELOC_NUMBER (R_SPARC_HH22, 34) + RELOC_NUMBER (R_SPARC_HM10, 35) + RELOC_NUMBER (R_SPARC_LM22, 36) + RELOC_NUMBER (R_SPARC_PC_HH22, 37) + RELOC_NUMBER (R_SPARC_PC_HM10, 38) + RELOC_NUMBER (R_SPARC_PC_LM22, 39) + RELOC_NUMBER (R_SPARC_WDISP16, 40) + RELOC_NUMBER (R_SPARC_WDISP19, 41) + RELOC_NUMBER (R_SPARC_UNUSED_42, 42) + RELOC_NUMBER (R_SPARC_7, 43) + RELOC_NUMBER (R_SPARC_5, 44) + RELOC_NUMBER (R_SPARC_6, 45) + RELOC_NUMBER (R_SPARC_DISP64, 46) + RELOC_NUMBER (R_SPARC_PLT64, 47) + RELOC_NUMBER (R_SPARC_HIX22, 48) + RELOC_NUMBER (R_SPARC_LOX10, 49) + RELOC_NUMBER (R_SPARC_H44, 50) + RELOC_NUMBER (R_SPARC_M44, 51) + RELOC_NUMBER (R_SPARC_L44, 52) + RELOC_NUMBER (R_SPARC_REGISTER, 53) + RELOC_NUMBER (R_SPARC_UA64, 54) + RELOC_NUMBER (R_SPARC_UA16, 55) + + RELOC_NUMBER (R_SPARC_TLS_GD_HI22, 56) + RELOC_NUMBER (R_SPARC_TLS_GD_LO10, 57) + RELOC_NUMBER (R_SPARC_TLS_GD_ADD, 58) + RELOC_NUMBER (R_SPARC_TLS_GD_CALL, 59) + RELOC_NUMBER (R_SPARC_TLS_LDM_HI22, 60) + RELOC_NUMBER (R_SPARC_TLS_LDM_LO10, 61) + RELOC_NUMBER (R_SPARC_TLS_LDM_ADD, 62) + RELOC_NUMBER (R_SPARC_TLS_LDM_CALL, 63) + RELOC_NUMBER (R_SPARC_TLS_LDO_HIX22, 64) + RELOC_NUMBER (R_SPARC_TLS_LDO_LOX10, 65) + RELOC_NUMBER (R_SPARC_TLS_LDO_ADD, 66) + RELOC_NUMBER (R_SPARC_TLS_IE_HI22, 67) + RELOC_NUMBER (R_SPARC_TLS_IE_LO10, 68) + RELOC_NUMBER (R_SPARC_TLS_IE_LD, 69) + RELOC_NUMBER (R_SPARC_TLS_IE_LDX, 70) + RELOC_NUMBER (R_SPARC_TLS_IE_ADD, 71) + RELOC_NUMBER (R_SPARC_TLS_LE_HIX22, 72) + RELOC_NUMBER (R_SPARC_TLS_LE_LOX10, 73) + RELOC_NUMBER (R_SPARC_TLS_DTPMOD32, 74) + RELOC_NUMBER (R_SPARC_TLS_DTPMOD64, 75) + RELOC_NUMBER (R_SPARC_TLS_DTPOFF32, 76) + RELOC_NUMBER (R_SPARC_TLS_DTPOFF64, 77) + RELOC_NUMBER (R_SPARC_TLS_TPOFF32, 78) + RELOC_NUMBER (R_SPARC_TLS_TPOFF64, 79) + + EMPTY_RELOC (R_SPARC_max_std) + + RELOC_NUMBER (R_SPARC_GNU_VTINHERIT, 250) + RELOC_NUMBER (R_SPARC_GNU_VTENTRY, 251) + RELOC_NUMBER (R_SPARC_REV32, 252) + +END_RELOC_NUMBERS (R_SPARC_max) + +/* Relocation macros. */ + +#define ELF64_R_TYPE_DATA(info) \ + (((bfd_signed_vma)(ELF64_R_TYPE(info) >> 8) ^ 0x800000) - 0x800000) +#define ELF64_R_TYPE_ID(info) \ + ((info) & 0xff) +#define ELF64_R_TYPE_INFO(data, type) \ + (((bfd_vma) ((data) & 0xffffff) << 8) | (bfd_vma) (type)) + +/* Values for Elf64_Dyn.d_tag. */ + +#define DT_SPARC_REGISTER 0x70000001 + +#endif /* _ELF_SPARC_H */ diff --git a/contrib/binutils-2.14/include/elf/v850.h b/contrib/binutils-2.14/include/elf/v850.h new file mode 100644 index 0000000000..c949ab01f8 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/v850.h @@ -0,0 +1,107 @@ +/* V850 ELF support for BFD. + Copyright 1997, 1998, 2000, 2002 Free Software Foundation, Inc. + Created by Michael Meissner, 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the MIPS ELF ABI. Note + that most of this is not actually implemented by BFD. */ + +#ifndef _ELF_V850_H +#define _ELF_V850_H + +/* Processor specific flags for the ELF header e_flags field. */ + +/* Four bit V850 architecture field. */ +#define EF_V850_ARCH 0xf0000000 + +/* v850 code. */ +#define E_V850_ARCH 0x00000000 + +/* v850e code. */ +#define E_V850E_ARCH 0x10000000 + + +/* Flags for the st_other field. */ +#define V850_OTHER_SDA 0x01 /* Symbol had SDA relocations. */ +#define V850_OTHER_ZDA 0x02 /* Symbol had ZDA relocations. */ +#define V850_OTHER_TDA 0x04 /* Symbol had TDA relocations. */ +#define V850_OTHER_TDA_BYTE 0x08 /* Symbol had TDA byte relocations. */ +#define V850_OTHER_ERROR 0x80 /* Symbol had an error reported. */ + +/* V850 relocations. */ +#include "elf/reloc-macros.h" + +START_RELOC_NUMBERS (v850_reloc_type) + RELOC_NUMBER (R_V850_NONE, 0) + RELOC_NUMBER (R_V850_9_PCREL, 1) + RELOC_NUMBER (R_V850_22_PCREL, 2) + RELOC_NUMBER (R_V850_HI16_S, 3) + RELOC_NUMBER (R_V850_HI16, 4) + RELOC_NUMBER (R_V850_LO16, 5) + RELOC_NUMBER (R_V850_ABS32, 6) + RELOC_NUMBER (R_V850_16, 7) + RELOC_NUMBER (R_V850_8, 8) + RELOC_NUMBER( R_V850_SDA_16_16_OFFSET, 9) /* For ld.b, st.b, set1, clr1, not1, tst1, movea, movhi */ + RELOC_NUMBER( R_V850_SDA_15_16_OFFSET, 10) /* For ld.w, ld.h, ld.hu, st.w, st.h */ + RELOC_NUMBER( R_V850_ZDA_16_16_OFFSET, 11) /* For ld.b, st.b, set1, clr1, not1, tst1, movea, movhi */ + RELOC_NUMBER( R_V850_ZDA_15_16_OFFSET, 12) /* For ld.w, ld.h, ld.hu, st.w, st.h */ + RELOC_NUMBER( R_V850_TDA_6_8_OFFSET, 13) /* For sst.w, sld.w */ + RELOC_NUMBER( R_V850_TDA_7_8_OFFSET, 14) /* For sst.h, sld.h */ + RELOC_NUMBER( R_V850_TDA_7_7_OFFSET, 15) /* For sst.b, sld.b */ + RELOC_NUMBER( R_V850_TDA_16_16_OFFSET, 16) /* For set1, clr1, not1, tst1, movea, movhi */ + RELOC_NUMBER( R_V850_TDA_4_5_OFFSET, 17) /* For sld.hu */ + RELOC_NUMBER( R_V850_TDA_4_4_OFFSET, 18) /* For sld.bu */ + RELOC_NUMBER( R_V850_SDA_16_16_SPLIT_OFFSET, 19) /* For ld.bu */ + RELOC_NUMBER( R_V850_ZDA_16_16_SPLIT_OFFSET, 20) /* For ld.bu */ + RELOC_NUMBER( R_V850_CALLT_6_7_OFFSET, 21) /* For callt */ + RELOC_NUMBER( R_V850_CALLT_16_16_OFFSET, 22) /* For callt */ + RELOC_NUMBER (R_V850_GNU_VTINHERIT, 23) + RELOC_NUMBER (R_V850_GNU_VTENTRY, 24) + RELOC_NUMBER (R_V850_LONGCALL, 25) + RELOC_NUMBER (R_V850_LONGJUMP, 26) + RELOC_NUMBER (R_V850_ALIGN, 27) + RELOC_NUMBER (R_V850_REL32, 28) +END_RELOC_NUMBERS (R_V850_max) + + +/* Processor specific section indices. These sections do not actually + exist. Symbols with a st_shndx field corresponding to one of these + values have a special meaning. */ + +/* Small data area common symbol. */ +#define SHN_V850_SCOMMON 0xff00 + +/* Tiny data area common symbol. */ +#define SHN_V850_TCOMMON 0xff01 + +/* Zero data area common symbol. */ +#define SHN_V850_ZCOMMON 0xff02 + + +/* Processor specific section types. */ + +/* Section contains the .scommon data. */ +#define SHT_V850_SCOMMON 0x70000000 + +/* Section contains the .scommon data. */ +#define SHT_V850_TCOMMON 0x70000001 + +/* Section contains the .scommon data. */ +#define SHT_V850_ZCOMMON 0x70000002 + +#endif /* _ELF_V850_H */ diff --git a/contrib/binutils-2.14/include/elf/vax.h b/contrib/binutils-2.14/include/elf/vax.h new file mode 100644 index 0000000000..c1b5c2b30f --- /dev/null +++ b/contrib/binutils-2.14/include/elf/vax.h @@ -0,0 +1,51 @@ +/* VAX ELF support for BFD. + Copyright (C) 2002 Free Software Foundation, Inc. + Contributed by Matt Thomas . + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_VAX_H +#define _ELF_VAX_H + +#include "elf/reloc-macros.h" + +/* Relocation types. */ +START_RELOC_NUMBERS (elf_vax_reloc_type) + RELOC_NUMBER (R_VAX_NONE, 0) /* No reloc */ + RELOC_NUMBER (R_VAX_32, 1) /* Direct 32 bit */ + RELOC_NUMBER (R_VAX_16, 2) /* Direct 16 bit */ + RELOC_NUMBER (R_VAX_8, 3) /* Direct 8 bit */ + RELOC_NUMBER (R_VAX_PC32, 4) /* PC relative 32 bit */ + RELOC_NUMBER (R_VAX_PC16, 5) /* PC relative 16 bit */ + RELOC_NUMBER (R_VAX_PC8, 6) /* PC relative 8 bit */ + RELOC_NUMBER (R_VAX_GOT32, 7) /* 32 bit PC relative GOT entry */ + RELOC_NUMBER (R_VAX_PLT32, 13) /* 32 bit PC relative PLT address */ + RELOC_NUMBER (R_VAX_COPY, 19) /* Copy symbol at runtime */ + RELOC_NUMBER (R_VAX_GLOB_DAT, 20) /* Create GOT entry */ + RELOC_NUMBER (R_VAX_JMP_SLOT, 21) /* Create PLT entry */ + RELOC_NUMBER (R_VAX_RELATIVE, 22) /* Adjust by program base */ + /* These are GNU extensions to enable C++ vtable garbage collection. */ + RELOC_NUMBER (R_VAX_GNU_VTINHERIT, 23) + RELOC_NUMBER (R_VAX_GNU_VTENTRY, 24) +END_RELOC_NUMBERS (R_VAX_max) + +/* Processor specific flags for the ELF header e_flags field. */ +#define EF_VAX_NONPIC 0x0001 /* Object contains non-PIC code */ +#define EF_VAX_DFLOAT 0x0100 /* Object contains D-Float insn. */ +#define EF_VAX_GFLOAT 0x0200 /* Object contains G-Float insn. */ + +#endif diff --git a/contrib/binutils-2.14/include/elf/x86-64.h b/contrib/binutils-2.14/include/elf/x86-64.h new file mode 100644 index 0000000000..7e9100dba4 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/x86-64.h @@ -0,0 +1,56 @@ +/* x86_64 ELF support for BFD. + Copyright (C) 2000, 2002 Free Software Foundation, Inc. + Contributed by Jan Hubicka + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_X86_64_H +#define _ELF_X86_64_H + +#include "elf/reloc-macros.h" + +START_RELOC_NUMBERS (elf_x86_64_reloc_type) + RELOC_NUMBER (R_X86_64_NONE, 0) /* No reloc */ + RELOC_NUMBER (R_X86_64_64, 1) /* Direct 64 bit */ + RELOC_NUMBER (R_X86_64_PC32, 2) /* PC relative 32 bit signed */ + RELOC_NUMBER (R_X86_64_GOT32, 3) /* 32 bit GOT entry */ + RELOC_NUMBER (R_X86_64_PLT32, 4) /* 32 bit PLT address */ + RELOC_NUMBER (R_X86_64_COPY, 5) /* Copy symbol at runtime */ + RELOC_NUMBER (R_X86_64_GLOB_DAT, 6) /* Create GOT entry */ + RELOC_NUMBER (R_X86_64_JUMP_SLOT,7) /* Create PLT entry */ + RELOC_NUMBER (R_X86_64_RELATIVE, 8) /* Adjust by program base */ + RELOC_NUMBER (R_X86_64_GOTPCREL, 9) /* 32 bit signed pc relative + offset to GOT */ + RELOC_NUMBER (R_X86_64_32, 10) /* Direct 32 bit zero extended */ + RELOC_NUMBER (R_X86_64_32S, 11) /* Direct 32 bit sign extended */ + RELOC_NUMBER (R_X86_64_16, 12) /* Direct 16 bit zero extended */ + RELOC_NUMBER (R_X86_64_PC16, 13) /* 16 bit sign extended pc relative*/ + RELOC_NUMBER (R_X86_64_8, 14) /* Direct 8 bit sign extended */ + RELOC_NUMBER (R_X86_64_PC8, 15) /* 8 bit sign extended pc relative*/ + RELOC_NUMBER (R_X86_64_DTPMOD64, 16) /* ID of module containing symbol */ + RELOC_NUMBER (R_X86_64_DTPOFF64, 17) /* Offset in TLS block */ + RELOC_NUMBER (R_X86_64_TPOFF64, 18) /* Offset in initial TLS block */ + RELOC_NUMBER (R_X86_64_TLSGD, 19) /* PC relative offset to GD GOT block */ + RELOC_NUMBER (R_X86_64_TLSLD, 20) /* PC relative offset to LD GOT block */ + RELOC_NUMBER (R_X86_64_DTPOFF32, 21) /* Offset in TLS block */ + RELOC_NUMBER (R_X86_64_GOTTPOFF, 22) /* PC relative offset to IE GOT entry */ + RELOC_NUMBER (R_X86_64_TPOFF32, 23) /* Offset in initial TLS block */ + RELOC_NUMBER (R_X86_64_GNU_VTINHERIT, 250) /* GNU C++ hack */ + RELOC_NUMBER (R_X86_64_GNU_VTENTRY, 251) /* GNU C++ hack */ +END_RELOC_NUMBERS (R_X86_64_max) + +#endif diff --git a/contrib/binutils-2.14/include/elf/xstormy16.h b/contrib/binutils-2.14/include/elf/xstormy16.h new file mode 100644 index 0000000000..6b1e98f577 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/xstormy16.h @@ -0,0 +1,57 @@ +/* XSTORMY16 ELF support for BFD. + Copyright (C) 2001, 2002 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _ELF_XSTORMY16_H +#define _ELF_XSTORMY16_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_xstormy16_reloc_type) + RELOC_NUMBER (R_XSTORMY16_NONE, 0) + + RELOC_NUMBER (R_XSTORMY16_32, 1) + RELOC_NUMBER (R_XSTORMY16_16, 2) + RELOC_NUMBER (R_XSTORMY16_8, 3) + RELOC_NUMBER (R_XSTORMY16_PC32, 4) + RELOC_NUMBER (R_XSTORMY16_PC16, 5) + RELOC_NUMBER (R_XSTORMY16_PC8, 6) + + RELOC_NUMBER (R_XSTORMY16_REL_12, 7) + RELOC_NUMBER (R_XSTORMY16_24, 8) + RELOC_NUMBER (R_XSTORMY16_FPTR16, 9) + + RELOC_NUMBER (R_XSTORMY16_LO16, 10) + RELOC_NUMBER (R_XSTORMY16_HI16, 11) + RELOC_NUMBER (R_XSTORMY16_12, 12) + + RELOC_NUMBER (R_XSTORMY16_GNU_VTINHERIT, 128) + RELOC_NUMBER (R_XSTORMY16_GNU_VTENTRY, 129) +END_RELOC_NUMBERS (R_XSTORMY16_max) + +/* Define the data & instruction memory discriminator. In a linked + executable, an symbol should be deemed to point to an instruction + if ((address & XSTORMY16_INSN_MASK) == XSTORMY16_INSN_VALUE), and similarly + for the data space. See also `ld/emulparams/elf32xstormy16.sh'. */ +#define XSTORMY16_DATA_MASK 0xffc00000 +#define XSTORMY16_DATA_VALUE 0x00000000 +#define XSTORMY16_INSN_MASK 0xffc00000 +#define XSTORMY16_INSN_VALUE 0x00400000 + +#endif /* _ELF_XSTORMY16_H */ diff --git a/contrib/binutils-2.14/include/elf/xtensa.h b/contrib/binutils-2.14/include/elf/xtensa.h new file mode 100644 index 0000000000..394ee41381 --- /dev/null +++ b/contrib/binutils-2.14/include/elf/xtensa.h @@ -0,0 +1,87 @@ +/* Xtensa ELF support for BFD. + Copyright 2003 Free Software Foundation, Inc. + Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica. + + 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 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds definitions specific to the Xtensa ELF ABI. */ + +#ifndef _ELF_XTENSA_H +#define _ELF_XTENSA_H + +#include "elf/reloc-macros.h" + +/* Relocations. */ +START_RELOC_NUMBERS (elf_xtensa_reloc_type) + RELOC_NUMBER (R_XTENSA_NONE, 0) + RELOC_NUMBER (R_XTENSA_32, 1) + RELOC_NUMBER (R_XTENSA_RTLD, 2) + RELOC_NUMBER (R_XTENSA_GLOB_DAT, 3) + RELOC_NUMBER (R_XTENSA_JMP_SLOT, 4) + RELOC_NUMBER (R_XTENSA_RELATIVE, 5) + RELOC_NUMBER (R_XTENSA_PLT, 6) + RELOC_NUMBER (R_XTENSA_OP0, 8) + RELOC_NUMBER (R_XTENSA_OP1, 9) + RELOC_NUMBER (R_XTENSA_OP2, 10) + RELOC_NUMBER (R_XTENSA_ASM_EXPAND, 11) + RELOC_NUMBER (R_XTENSA_ASM_SIMPLIFY, 12) + RELOC_NUMBER (R_XTENSA_GNU_VTINHERIT, 15) + RELOC_NUMBER (R_XTENSA_GNU_VTENTRY, 16) +END_RELOC_NUMBERS (R_XTENSA_max) + +/* Processor-specific flags for the ELF header e_flags field. */ + +/* Four-bit Xtensa machine type field. */ +#define EF_XTENSA_MACH 0x0000000f + +/* Various CPU types. */ +#define E_XTENSA_MACH 0x00000000 + +/* Leave bits 0xf0 alone in case we ever have more than 16 cpu types. + Highly unlikely, but what the heck. */ + +#define EF_XTENSA_XT_INSN 0x00000100 +#define EF_XTENSA_XT_LIT 0x00000200 + + +/* Processor-specific dynamic array tags. */ + +/* Offset of the table that records the GOT location(s). */ +#define DT_XTENSA_GOT_LOC_OFF 0x70000000 + +/* Number of entries in the GOT location table. */ +#define DT_XTENSA_GOT_LOC_SZ 0x70000001 + + +/* Definitions for instruction and literal property tables. The + instruction tables for ".gnu.linkonce.t.*" sections are placed in + the following sections: + + instruction tables: .gnu.linkonce.x.* + literal tables: .gnu.linkonce.p.* +*/ + +#define XTENSA_INSN_SEC_NAME ".xt.insn" +#define XTENSA_LIT_SEC_NAME ".xt.lit" + +typedef struct property_table_entry_t +{ + bfd_vma address; + bfd_vma size; +} property_table_entry; + +#endif /* _ELF_XTENSA_H */ diff --git a/contrib/binutils-2.14/include/filenames.h b/contrib/binutils-2.14/include/filenames.h new file mode 100644 index 0000000000..ca9e2732a3 --- /dev/null +++ b/contrib/binutils-2.14/include/filenames.h @@ -0,0 +1,51 @@ +/* Macros for taking apart, interpreting and processing file names. + + These are here because some non-Posix (a.k.a. DOSish) systems have + drive letter brain-damage at the beginning of an absolute file name, + use forward- and back-slash in path names interchangeably, and + some of them have case-insensitive file names. + + Copyright 2000, 2001 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef FILENAMES_H +#define FILENAMES_H + +#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__) + +#ifndef HAVE_DOS_BASED_FILE_SYSTEM +#define HAVE_DOS_BASED_FILE_SYSTEM 1 +#endif + +#define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\') +/* Note that IS_ABSOLUTE_PATH accepts d:foo as well, although it is + only semi-absolute. This is because the users of IS_ABSOLUTE_PATH + want to know whether to prepend the current working directory to + a file name, which should not be done with a name like d:foo. */ +#define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0]) || (((f)[0]) && ((f)[1] == ':'))) +#define FILENAME_CMP(s1, s2) strcasecmp(s1, s2) + +#else /* not DOSish */ + +#define IS_DIR_SEPARATOR(c) ((c) == '/') +#define IS_ABSOLUTE_PATH(f) (IS_DIR_SEPARATOR((f)[0])) +#define FILENAME_CMP(s1, s2) strcmp(s1, s2) + +#endif /* not DOSish */ + +#endif /* FILENAMES_H */ diff --git a/contrib/binutils-2.14/include/floatformat.h b/contrib/binutils-2.14/include/floatformat.h new file mode 100644 index 0000000000..53ead3eee6 --- /dev/null +++ b/contrib/binutils-2.14/include/floatformat.h @@ -0,0 +1,121 @@ +/* IEEE floating point support declarations, for GDB, the GNU Debugger. + Copyright 1991, 1994, 1995, 1997, 2000 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 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if !defined (FLOATFORMAT_H) +#define FLOATFORMAT_H 1 + +#include "ansidecl.h" + +/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the + bytes are concatenated according to the byteorder flag, then each of those + fields is contiguous. We number the bits with 0 being the most significant + (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field + contains with the *_start and *_len fields. */ + +/* What is the order of the bytes. */ + +enum floatformat_byteorders { + + /* Standard little endian byte order. + EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */ + + floatformat_little, + + /* Standard big endian byte order. + EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */ + + floatformat_big, + + /* Little endian byte order but big endian word order. + EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */ + + floatformat_littlebyte_bigword + +}; + +enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no }; + +struct floatformat +{ + enum floatformat_byteorders byteorder; + unsigned int totalsize; /* Total size of number in bits */ + + /* Sign bit is always one bit long. 1 means negative, 0 means positive. */ + unsigned int sign_start; + + unsigned int exp_start; + unsigned int exp_len; + /* Amount added to "true" exponent. 0x3fff for many IEEE extendeds. */ + unsigned int exp_bias; + /* Exponent value which indicates NaN. This is the actual value stored in + the float, not adjusted by the exp_bias. This usually consists of all + one bits. */ + unsigned int exp_nan; + + unsigned int man_start; + unsigned int man_len; + + /* Is the integer bit explicit or implicit? */ + enum floatformat_intbit intbit; + + /* Internal name for debugging. */ + const char *name; +}; + +/* floatformats for IEEE single and double, big and little endian. */ + +extern const struct floatformat floatformat_ieee_single_big; +extern const struct floatformat floatformat_ieee_single_little; +extern const struct floatformat floatformat_ieee_double_big; +extern const struct floatformat floatformat_ieee_double_little; + +/* floatformat for ARM IEEE double, little endian bytes and big endian words */ + +extern const struct floatformat floatformat_ieee_double_littlebyte_bigword; + +/* floatformats for various extendeds. */ + +extern const struct floatformat floatformat_i387_ext; +extern const struct floatformat floatformat_m68881_ext; +extern const struct floatformat floatformat_i960_ext; +extern const struct floatformat floatformat_m88110_ext; +extern const struct floatformat floatformat_m88110_harris_ext; +extern const struct floatformat floatformat_arm_ext_big; +extern const struct floatformat floatformat_arm_ext_littlebyte_bigword; +/* IA-64 Floating Point register spilt into memory. */ +extern const struct floatformat floatformat_ia64_spill_big; +extern const struct floatformat floatformat_ia64_spill_little; +extern const struct floatformat floatformat_ia64_quad_big; +extern const struct floatformat floatformat_ia64_quad_little; + +/* Convert from FMT to a double. + FROM is the address of the extended float. + Store the double in *TO. */ + +extern void +floatformat_to_double PARAMS ((const struct floatformat *, char *, double *)); + +/* The converse: convert the double *FROM to FMT + and store where TO points. */ + +extern void +floatformat_from_double PARAMS ((const struct floatformat *, + double *, char *)); + +#endif /* defined (FLOATFORMAT_H) */ diff --git a/contrib/binutils-2.14/include/fnmatch.h b/contrib/binutils-2.14/include/fnmatch.h new file mode 100644 index 0000000000..37d23ee1b3 --- /dev/null +++ b/contrib/binutils-2.14/include/fnmatch.h @@ -0,0 +1,70 @@ +/* Copyright 1991, 1992, 1993, 1996 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef _FNMATCH_H + +#define _FNMATCH_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#undef __P +#define __P(args) args +#else /* Not C++ or ANSI C. */ +#undef __P +#define __P(args) () +/* We can get away without defining `const' here only because in this file + it is used only inside the prototype for `fnmatch', which is elided in + non-ANSI C where `const' is problematical. */ +#endif /* C++ or ANSI C. */ + + +/* We #undef these before defining them because some losing systems + (HP-UX A.08.07 for example) define these in . */ +#undef FNM_PATHNAME +#undef FNM_NOESCAPE +#undef FNM_PERIOD + +/* Bits set in the FLAGS argument to `fnmatch'. */ +#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */ +#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ +#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ + +#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) +#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#endif + +/* Value returned by `fnmatch' if STRING does not match PATTERN. */ +#define FNM_NOMATCH 1 + +/* Match STRING against the filename pattern PATTERN, + returning zero if it matches, FNM_NOMATCH if not. */ +extern int fnmatch __P ((const char *__pattern, const char *__string, + int __flags)); + +#ifdef __cplusplus +} +#endif + +#endif /* fnmatch.h */ diff --git a/contrib/binutils-2.14/include/fopen-same.h b/contrib/binutils-2.14/include/fopen-same.h new file mode 100644 index 0000000000..0f37529d33 --- /dev/null +++ b/contrib/binutils-2.14/include/fopen-same.h @@ -0,0 +1,27 @@ +/* Macros for the 'type' part of an fopen, freopen or fdopen. + + [Update] + + This version is for "same" systems, where text and binary files are + the same. An example is Unix. Many Unix systems could also add a + "b" to the string, indicating binary files, but some reject this + (and thereby don't conform to ANSI C, but what else is new?). + + This file is designed for inclusion by host-dependent .h files. No + user application should include it directly, since that would make + the application unable to be configured for both "same" and "binary" + variant systems. */ + +#define FOPEN_RB "r" +#define FOPEN_WB "w" +#define FOPEN_AB "a" +#define FOPEN_RUB "r+" +#define FOPEN_WUB "w+" +#define FOPEN_AUB "a+" + +#define FOPEN_RT "r" +#define FOPEN_WT "w" +#define FOPEN_AT "a" +#define FOPEN_RUT "r+" +#define FOPEN_WUT "w+" +#define FOPEN_AUT "a+" diff --git a/contrib/binutils-2.14/include/getopt.h b/contrib/binutils-2.14/include/getopt.h new file mode 100644 index 0000000000..a99a229015 --- /dev/null +++ b/contrib/binutils-2.14/include/getopt.h @@ -0,0 +1,144 @@ +/* Declarations for getopt. + Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 2000, + 2002 Free Software Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#ifndef _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns -1, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is + undefined, we haven't run the autoconf check so provide the + declaration without arguments. If it is 0, we checked and failed + to find the declaration so provide a fully prototyped one. If it + is 1, we found it so don't provide any declaration at all. */ +#if !HAVE_DECL_GETOPT +#if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT) +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in unistd.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else +#ifndef __cplusplus +extern int getopt (); +#endif /* __cplusplus */ +#endif +#endif /* !HAVE_DECL_GETOPT */ + +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* getopt.h */ diff --git a/contrib/binutils-2.14/include/hashtab.h b/contrib/binutils-2.14/include/hashtab.h new file mode 100644 index 0000000000..7acb5eb285 --- /dev/null +++ b/contrib/binutils-2.14/include/hashtab.h @@ -0,0 +1,190 @@ +/* An expandable hash tables datatype. + Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc. + Contributed by Vladimir Makarov (vmakarov@cygnus.com). + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This package implements basic hash table functionality. It is possible + to search for an entry, create an entry and destroy an entry. + + Elements in the table are generic pointers. + + The size of the table is not fixed; if the occupancy of the table + grows too high the hash table will be expanded. + + The abstract data implementation is based on generalized Algorithm D + from Knuth's book "The art of computer programming". Hash table is + expanded by creation of new hash table and transferring elements from + the old table to the new table. */ + +#ifndef __HASHTAB_H__ +#define __HASHTAB_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "ansidecl.h" + +#ifndef GTY +#define GTY(X) +#endif + +/* The type for a hash code. */ +typedef unsigned int hashval_t; + +/* Callback function pointer types. */ + +/* Calculate hash of a table entry. */ +typedef hashval_t (*htab_hash) PARAMS ((const void *)); + +/* Compare a table entry with a possible entry. The entry already in + the table always comes first, so the second element can be of a + different type (but in this case htab_find and htab_find_slot + cannot be used; instead the variants that accept a hash value + must be used). */ +typedef int (*htab_eq) PARAMS ((const void *, const void *)); + +/* Cleanup function called whenever a live element is removed from + the hash table. */ +typedef void (*htab_del) PARAMS ((void *)); + +/* Function called by htab_traverse for each live element. The first + arg is the slot of the element (which can be passed to htab_clear_slot + if desired), the second arg is the auxiliary pointer handed to + htab_traverse. Return 1 to continue scan, 0 to stop. */ +typedef int (*htab_trav) PARAMS ((void **, void *)); + +/* Memory-allocation function, with the same functionality as calloc(). + Iff it returns NULL, the hash table implementation will pass an error + code back to the user, so if your code doesn't handle errors, + best if you use xcalloc instead. */ +typedef PTR (*htab_alloc) PARAMS ((size_t, size_t)); + +/* We also need a free() routine. */ +typedef void (*htab_free) PARAMS ((PTR)); + +/* Memory allocation and deallocation; variants which take an extra + argument. */ +typedef PTR (*htab_alloc_with_arg) PARAMS ((void *, size_t, size_t)); +typedef void (*htab_free_with_arg) PARAMS ((void *, void *)); + +/* Hash tables are of the following type. The structure + (implementation) of this type is not needed for using the hash + tables. All work with hash table should be executed only through + functions mentioned below. The size of this structure is subject to + change. */ + +struct htab GTY(()) +{ + /* Pointer to hash function. */ + htab_hash hash_f; + + /* Pointer to comparison function. */ + htab_eq eq_f; + + /* Pointer to cleanup function. */ + htab_del del_f; + + /* Table itself. */ + PTR * GTY ((use_param (""), length ("%h.size"))) entries; + + /* Current size (in entries) of the hash table */ + size_t size; + + /* Current number of elements including also deleted elements */ + size_t n_elements; + + /* Current number of deleted elements in the table */ + size_t n_deleted; + + /* The following member is used for debugging. Its value is number + of all calls of `htab_find_slot' for the hash table. */ + unsigned int searches; + + /* The following member is used for debugging. Its value is number + of collisions fixed for time of work with the hash table. */ + unsigned int collisions; + + /* Pointers to allocate/free functions. */ + htab_alloc alloc_f; + htab_free free_f; + + /* Alternate allocate/free functions, which take an extra argument. */ + PTR GTY((skip (""))) alloc_arg; + htab_alloc_with_arg alloc_with_arg_f; + htab_free_with_arg free_with_arg_f; +}; + +typedef struct htab *htab_t; + +/* An enum saying whether we insert into the hash table or not. */ +enum insert_option {NO_INSERT, INSERT}; + +/* The prototypes of the package functions. */ + +extern htab_t htab_create_alloc PARAMS ((size_t, htab_hash, + htab_eq, htab_del, + htab_alloc, htab_free)); + +extern htab_t htab_create_alloc_ex PARAMS ((size_t, htab_hash, + htab_eq, htab_del, + PTR, htab_alloc_with_arg, + htab_free_with_arg)); + +/* Backward-compatibility functions. */ +extern htab_t htab_create PARAMS ((size_t, htab_hash, htab_eq, htab_del)); +extern htab_t htab_try_create PARAMS ((size_t, htab_hash, htab_eq, htab_del)); + +extern void htab_set_functions_ex PARAMS ((htab_t, htab_hash, + htab_eq, htab_del, + PTR, htab_alloc_with_arg, + htab_free_with_arg)); + +extern void htab_delete PARAMS ((htab_t)); +extern void htab_empty PARAMS ((htab_t)); + +extern PTR htab_find PARAMS ((htab_t, const void *)); +extern PTR *htab_find_slot PARAMS ((htab_t, const void *, + enum insert_option)); +extern PTR htab_find_with_hash PARAMS ((htab_t, const void *, + hashval_t)); +extern PTR *htab_find_slot_with_hash PARAMS ((htab_t, const void *, + hashval_t, + enum insert_option)); +extern void htab_clear_slot PARAMS ((htab_t, void **)); +extern void htab_remove_elt PARAMS ((htab_t, void *)); + +extern void htab_traverse PARAMS ((htab_t, htab_trav, void *)); +extern void htab_traverse_noresize PARAMS ((htab_t, htab_trav, void *)); + +extern size_t htab_size PARAMS ((htab_t)); +extern size_t htab_elements PARAMS ((htab_t)); +extern double htab_collisions PARAMS ((htab_t)); + +/* A hash function for pointers. */ +extern htab_hash htab_hash_pointer; + +/* An equality function for pointers. */ +extern htab_eq htab_eq_pointer; + +/* A hash function for null-terminated strings. */ +extern hashval_t htab_hash_string PARAMS ((const PTR)); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __HASHTAB_H */ diff --git a/contrib/binutils-2.14/include/ieee.h b/contrib/binutils-2.14/include/ieee.h new file mode 100644 index 0000000000..5abc32b62d --- /dev/null +++ b/contrib/binutils-2.14/include/ieee.h @@ -0,0 +1,165 @@ +/* IEEE Standard 695-1980 "Universal Format for Object Modules" header file + + Copyright 2001 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Contributed by Cygnus Support. */ + +#define N_W_VARIABLES 8 +#define Module_Beginning 0xe0 + +typedef struct ieee_module + { + char *processor; + char *module_name; + } +ieee_module_begin_type; + +#define Address_Descriptor 0xec +typedef struct ieee_address + { + bfd_vma number_of_bits_mau; + bfd_vma number_of_maus_in_address; + + unsigned char byte_order; +#define IEEE_LITTLE 0xcc +#define IEEE_BIG 0xcd + } +ieee_address_descriptor_type; + +typedef union ieee_w_variable + { + file_ptr offset[N_W_VARIABLES]; + + struct + { + file_ptr extension_record; + file_ptr environmental_record; + file_ptr section_part; + file_ptr external_part; + file_ptr debug_information_part; + file_ptr data_part; + file_ptr trailer_part; + file_ptr me_record; + } + r; + } +ieee_w_variable_type; + +typedef enum ieee_record + { + ieee_number_start_enum = 0x00, + ieee_number_end_enum=0x7f, + ieee_number_repeat_start_enum = 0x80, + ieee_number_repeat_end_enum = 0x88, + ieee_number_repeat_4_enum = 0x84, + ieee_number_repeat_3_enum = 0x83, + ieee_number_repeat_2_enum = 0x82, + ieee_number_repeat_1_enum = 0x81, + ieee_module_beginning_enum = 0xe0, + ieee_module_end_enum = 0xe1, + ieee_extension_length_1_enum = 0xde, + ieee_extension_length_2_enum = 0xdf, + ieee_section_type_enum = 0xe6, + ieee_section_alignment_enum = 0xe7, + ieee_external_symbol_enum = 0xe8, + ieee_comma = 0x90, + ieee_external_reference_enum = 0xe9, + ieee_set_current_section_enum = 0xe5, + ieee_address_descriptor_enum = 0xec, + ieee_load_constant_bytes_enum = 0xed, + ieee_load_with_relocation_enum = 0xe4, + + ieee_variable_A_enum = 0xc1, + ieee_variable_B_enum = 0xc2, + ieee_variable_C_enum = 0xc3, + ieee_variable_D_enum = 0xc4, + ieee_variable_E_enum = 0xc5, + ieee_variable_F_enum = 0xc6, + ieee_variable_G_enum = 0xc7, + ieee_variable_H_enum = 0xc8, + ieee_variable_I_enum = 0xc9, + ieee_variable_J_enum = 0xca, + ieee_variable_K_enum = 0xcb, + ieee_variable_L_enum = 0xcc, + ieee_variable_M_enum = 0xcd, + ieee_variable_N_enum = 0xce, + ieee_variable_O_enum = 0xcf, + ieee_variable_P_enum = 0xd0, + ieee_variable_Q_enum = 0xd1, + ieee_variable_R_enum = 0xd2, + ieee_variable_S_enum = 0xd3, + ieee_variable_T_enum = 0xd4, + ieee_variable_U_enum = 0xd5, + ieee_variable_V_enum = 0xd6, + ieee_variable_W_enum = 0xd7, + ieee_variable_X_enum = 0xd8, + ieee_variable_Y_enum = 0xd9, + ieee_variable_Z_enum = 0xda, + ieee_function_plus_enum = 0xa5, + ieee_function_minus_enum = 0xa6, + ieee_function_signed_open_b_enum = 0xba, + ieee_function_signed_close_b_enum = 0xbb, + + ieee_function_unsigned_open_b_enum = 0xbc, + ieee_function_unsigned_close_b_enum = 0xbd, + + ieee_function_either_open_b_enum = 0xbe, + ieee_function_either_close_b_enum = 0xbf, + ieee_record_seperator_enum = 0xdb, + + ieee_e2_first_byte_enum = 0xe2, + ieee_section_size_enum = 0xe2d3, + ieee_physical_region_size_enum = 0xe2c1, + ieee_region_base_address_enum = 0xe2c2, + ieee_mau_size_enum = 0xe2c6, + ieee_m_value_enum = 0xe2cd, + ieee_section_base_address_enum = 0xe2cc, + ieee_asn_record_enum = 0xe2ce, + ieee_section_offset_enum = 0xe2d2, + ieee_value_starting_address_enum = 0xe2c7, + ieee_assign_value_to_variable_enum = 0xe2d7, + ieee_set_current_pc_enum = 0xe2d0, + ieee_value_record_enum = 0xe2c9, + ieee_nn_record = 0xf0, + ieee_at_record_enum = 0xf1, + ieee_ty_record_enum = 0xf2, + ieee_attribute_record_enum = 0xf1c9, + ieee_atn_record_enum = 0xf1ce, + ieee_external_reference_info_record_enum = 0xf1d8, + ieee_weak_external_reference_enum= 0xf4, + ieee_repeat_data_enum = 0xf7, + ieee_bb_record_enum = 0xf8, + ieee_be_record_enum = 0xf9 + } +ieee_record_enum_type; + +typedef struct ieee_section + { + unsigned int section_index; + unsigned int section_type; + char * section_name; + unsigned int parent_section_index; + unsigned int sibling_section_index; + unsigned int context_index; + } +ieee_section_type; + +#define IEEE_REFERENCE_BASE 11 +#define IEEE_PUBLIC_BASE 32 +#define IEEE_SECTION_NUMBER_BASE 1 + diff --git a/contrib/binutils-2.14/include/libiberty.h b/contrib/binutils-2.14/include/libiberty.h new file mode 100644 index 0000000000..676ceaba4a --- /dev/null +++ b/contrib/binutils-2.14/include/libiberty.h @@ -0,0 +1,335 @@ +/* Function declarations for libiberty. + + Copyright 2001, 2002 Free Software Foundation, Inc. + + Note - certain prototypes declared in this header file are for + functions whoes implementation copyright does not belong to the + FSF. Those prototypes are present in this file for reference + purposes only and their presence in this file should not construed + as an indication of ownership by the FSF of the implementation of + those functions in any way or form whatsoever. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Written by Cygnus Support, 1994. + + The libiberty library provides a number of functions which are + missing on some operating systems. We do not declare those here, + to avoid conflicts with the system header files on operating + systems that do support those functions. In this file we only + declare those functions which are specific to libiberty. */ + +#ifndef LIBIBERTY_H +#define LIBIBERTY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ansidecl.h" + +#ifdef ANSI_PROTOTYPES +/* Get a definition for size_t. */ +#include +/* Get a definition for va_list. */ +#include +#endif + +/* Build an argument vector from a string. Allocates memory using + malloc. Use freeargv to free the vector. */ + +extern char **buildargv PARAMS ((const char *)) ATTRIBUTE_MALLOC; + +/* Free a vector returned by buildargv. */ + +extern void freeargv PARAMS ((char **)); + +/* Duplicate an argument vector. Allocates memory using malloc. Use + freeargv to free the vector. */ + +extern char **dupargv PARAMS ((char **)) ATTRIBUTE_MALLOC; + + +/* Return the last component of a path name. Note that we can't use a + prototype here because the parameter is declared inconsistently + across different systems, sometimes as "char *" and sometimes as + "const char *" */ + +/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is + undefined, we haven't run the autoconf check so provide the + declaration without arguments. If it is 0, we checked and failed + to find the declaration so provide a fully prototyped one. If it + is 1, we found it so don't provide any declaration at all. */ +#if !HAVE_DECL_BASENAME +#if defined (__GNU_LIBRARY__ ) || defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__NetBSD__) || defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (HAVE_DECL_BASENAME) +extern char *basename PARAMS ((const char *)); +#else +extern char *basename (); +#endif +#endif + +/* A well-defined basename () that is always compiled in. */ + +extern const char *lbasename PARAMS ((const char *)); + +/* A well-defined realpath () that is always compiled in. */ + +extern char *lrealpath PARAMS ((const char *)); + +/* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using xmalloc. */ + +extern char *concat PARAMS ((const char *, ...)) ATTRIBUTE_MALLOC; + +/* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using xmalloc. The first argument is + not one of the strings to be concatenated, but if not NULL is a + pointer to be freed after the new string is created, similar to the + way xrealloc works. */ + +extern char *reconcat PARAMS ((char *, const char *, ...)) ATTRIBUTE_MALLOC; + +/* Determine the length of concatenating an arbitrary number of + strings. You must pass NULL as the last argument of this function, + to terminate the list of strings. */ + +extern unsigned long concat_length PARAMS ((const char *, ...)); + +/* Concatenate an arbitrary number of strings into a SUPPLIED area of + memory. You must pass NULL as the last argument of this function, + to terminate the list of strings. The supplied memory is assumed + to be large enough. */ + +extern char *concat_copy PARAMS ((char *, const char *, ...)); + +/* Concatenate an arbitrary number of strings into a GLOBAL area of + memory. You must pass NULL as the last argument of this function, + to terminate the list of strings. The supplied memory is assumed + to be large enough. */ + +extern char *concat_copy2 PARAMS ((const char *, ...)); + +/* This is the global area used by concat_copy2. */ + +extern char *libiberty_concat_ptr; + +/* Concatenate an arbitrary number of strings. You must pass NULL as + the last argument of this function, to terminate the list of + strings. Allocates memory using alloca. The arguments are + evaluated twice! */ +#define ACONCAT(ACONCAT_PARAMS) \ + (libiberty_concat_ptr = alloca (concat_length ACONCAT_PARAMS + 1), \ + concat_copy2 ACONCAT_PARAMS) + +/* Check whether two file descriptors refer to the same file. */ + +extern int fdmatch PARAMS ((int fd1, int fd2)); + +/* Get the working directory. The result is cached, so don't call + chdir() between calls to getpwd(). */ + +extern char * getpwd PARAMS ((void)); + +/* Get the amount of time the process has run, in microseconds. */ + +extern long get_run_time PARAMS ((void)); + +/* Generate a relocated path to some installation directory. Allocates + return value using malloc. */ + +extern char *make_relative_prefix PARAMS ((const char *, const char *, + const char *)); + +/* Choose a temporary directory to use for scratch files. */ + +extern char *choose_temp_base PARAMS ((void)) ATTRIBUTE_MALLOC; + +/* Return a temporary file name or NULL if unable to create one. */ + +extern char *make_temp_file PARAMS ((const char *)) ATTRIBUTE_MALLOC; + +/* Allocate memory filled with spaces. Allocates using malloc. */ + +extern const char *spaces PARAMS ((int count)); + +/* Return the maximum error number for which strerror will return a + string. */ + +extern int errno_max PARAMS ((void)); + +/* Return the name of an errno value (e.g., strerrno (EINVAL) returns + "EINVAL"). */ + +extern const char *strerrno PARAMS ((int)); + +/* Given the name of an errno value, return the value. */ + +extern int strtoerrno PARAMS ((const char *)); + +/* ANSI's strerror(), but more robust. */ + +extern char *xstrerror PARAMS ((int)); + +/* Return the maximum signal number for which strsignal will return a + string. */ + +extern int signo_max PARAMS ((void)); + +/* Return a signal message string for a signal number + (e.g., strsignal (SIGHUP) returns something like "Hangup"). */ +/* This is commented out as it can conflict with one in system headers. + We still document its existence though. */ + +/*extern const char *strsignal PARAMS ((int));*/ + +/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns + "SIGHUP"). */ + +extern const char *strsigno PARAMS ((int)); + +/* Given the name of a signal, return its number. */ + +extern int strtosigno PARAMS ((const char *)); + +/* Register a function to be run by xexit. Returns 0 on success. */ + +extern int xatexit PARAMS ((void (*fn) (void))); + +/* Exit, calling all the functions registered with xatexit. */ + +extern void xexit PARAMS ((int status)) ATTRIBUTE_NORETURN; + +/* Set the program name used by xmalloc. */ + +extern void xmalloc_set_program_name PARAMS ((const char *)); + +/* Report an allocation failure. */ +extern void xmalloc_failed PARAMS ((size_t)) ATTRIBUTE_NORETURN; + +/* Allocate memory without fail. If malloc fails, this will print a + message to stderr (using the name set by xmalloc_set_program_name, + if any) and then call xexit. */ + +extern PTR xmalloc PARAMS ((size_t)) ATTRIBUTE_MALLOC; + +/* Reallocate memory without fail. This works like xmalloc. Note, + realloc type functions are not suitable for attribute malloc since + they may return the same address across multiple calls. */ + +extern PTR xrealloc PARAMS ((PTR, size_t)); + +/* Allocate memory without fail and set it to zero. This works like + xmalloc. */ + +extern PTR xcalloc PARAMS ((size_t, size_t)) ATTRIBUTE_MALLOC; + +/* Copy a string into a memory buffer without fail. */ + +extern char *xstrdup PARAMS ((const char *)) ATTRIBUTE_MALLOC; + +/* Copy an existing memory buffer to a new memory buffer without fail. */ + +extern PTR xmemdup PARAMS ((const PTR, size_t, size_t)) ATTRIBUTE_MALLOC; + +/* Physical memory routines. Return values are in BYTES. */ +extern double physmem_total PARAMS ((void)); +extern double physmem_available PARAMS ((void)); + +/* hex character manipulation routines */ + +#define _hex_array_size 256 +#define _hex_bad 99 +extern const char _hex_value[_hex_array_size]; +extern void hex_init PARAMS ((void)); +#define hex_p(c) (hex_value (c) != _hex_bad) +/* If you change this, note well: Some code relies on side effects in + the argument being performed exactly once. */ +#define hex_value(c) (_hex_value[(unsigned char) (c)]) + +/* Definitions used by the pexecute routine. */ + +#define PEXECUTE_FIRST 1 +#define PEXECUTE_LAST 2 +#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST) +#define PEXECUTE_SEARCH 4 +#define PEXECUTE_VERBOSE 8 + +/* Execute a program. */ + +extern int pexecute PARAMS ((const char *, char * const *, const char *, + const char *, char **, char **, int)); + +/* Wait for pexecute to finish. */ + +extern int pwait PARAMS ((int, int *, int)); + +#if !HAVE_DECL_ASPRINTF +/* Like sprintf but provides a pointer to malloc'd storage, which must + be freed by the caller. */ + +extern int asprintf PARAMS ((char **, const char *, ...)) ATTRIBUTE_PRINTF_2; +#endif + +#if !HAVE_DECL_VASPRINTF +/* Like vsprintf but provides a pointer to malloc'd storage, which + must be freed by the caller. */ + +extern int vasprintf PARAMS ((char **, const char *, va_list)) + ATTRIBUTE_PRINTF(2,0); +#endif + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +/* Drastically simplified alloca configurator. If we're using GCC, + we use __builtin_alloca; otherwise we use the C alloca. The C + alloca is always available. You can override GCC by defining + USE_C_ALLOCA yourself. The canonical autoconf macro C_ALLOCA is + also set/unset as it is often used to indicate whether code needs + to call alloca(0). */ +extern PTR C_alloca PARAMS ((size_t)) ATTRIBUTE_MALLOC; +#undef alloca +#if GCC_VERSION >= 2000 && !defined USE_C_ALLOCA +# define alloca(x) __builtin_alloca(x) +# undef C_ALLOCA +# define ASTRDUP(X) \ + (__extension__ ({ const char *const libiberty_optr = (X); \ + const unsigned long libiberty_len = strlen (libiberty_optr) + 1; \ + char *const libiberty_nptr = alloca (libiberty_len); \ + (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len); })) +#else +# define alloca(x) C_alloca(x) +# undef USE_C_ALLOCA +# define USE_C_ALLOCA 1 +# undef C_ALLOCA +# define C_ALLOCA 1 +extern const char *libiberty_optr; +extern char *libiberty_nptr; +extern unsigned long libiberty_len; +# define ASTRDUP(X) \ + (libiberty_optr = (X), \ + libiberty_len = strlen (libiberty_optr) + 1, \ + libiberty_nptr = alloca (libiberty_len), \ + (char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len)) +#endif + +#ifdef __cplusplus +} +#endif + + +#endif /* ! defined (LIBIBERTY_H) */ diff --git a/contrib/binutils-2.14/include/mpw/README b/contrib/binutils-2.14/include/mpw/README new file mode 100644 index 0000000000..10e92de79f --- /dev/null +++ b/contrib/binutils-2.14/include/mpw/README @@ -0,0 +1 @@ +This is a collection of include files that help imitate Posix in MPW. diff --git a/contrib/binutils-2.14/include/objalloc.h b/contrib/binutils-2.14/include/objalloc.h new file mode 100644 index 0000000000..c7106478dc --- /dev/null +++ b/contrib/binutils-2.14/include/objalloc.h @@ -0,0 +1,115 @@ +/* objalloc.h -- routines to allocate memory for objects + Copyright 1997, 2001 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Solutions. + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#ifndef OBJALLOC_H +#define OBJALLOC_H + +#include "ansidecl.h" + +/* These routines allocate space for an object. The assumption is + that the object will want to allocate space as it goes along, but + will never want to free any particular block. There is a function + to free a block, which also frees all more recently allocated + blocks. There is also a function to free all the allocated space. + + This is essentially a specialization of obstacks. The main + difference is that a block may not be allocated a bit at a time. + Another difference is that these routines are always built on top + of malloc, and always pass an malloc failure back to the caller, + unlike more recent versions of obstacks. */ + +/* This is what an objalloc structure looks like. Callers should not + refer to these fields, nor should they allocate these structure + themselves. Instead, they should only create them via + objalloc_init, and only access them via the functions and macros + listed below. The structure is only defined here so that we can + access it via macros. */ + +struct objalloc +{ + char *current_ptr; + unsigned int current_space; + PTR chunks; +}; + +/* Work out the required alignment. */ + +struct objalloc_align { char x; double d; }; + +#if defined (__STDC__) && __STDC__ +#ifndef offsetof +#include +#endif +#endif +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif +#define OBJALLOC_ALIGN offsetof (struct objalloc_align, d) + +/* Create an objalloc structure. Returns NULL if malloc fails. */ + +extern struct objalloc *objalloc_create PARAMS ((void)); + +/* Allocate space from an objalloc structure. Returns NULL if malloc + fails. */ + +extern PTR _objalloc_alloc PARAMS ((struct objalloc *, unsigned long)); + +/* The macro version of objalloc_alloc. We only define this if using + gcc, because otherwise we would have to evaluate the arguments + multiple times, or use a temporary field as obstack.h does. */ + +#if defined (__GNUC__) && defined (__STDC__) && __STDC__ + +/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and + does not implement __extension__. But that compiler doesn't define + __GNUC_MINOR__. */ +#if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) +#define __extension__ +#endif + +#define objalloc_alloc(o, l) \ + __extension__ \ + ({ struct objalloc *__o = (o); \ + unsigned long __len = (l); \ + if (__len == 0) \ + __len = 1; \ + __len = (__len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1); \ + (__len <= __o->current_space \ + ? (__o->current_ptr += __len, \ + __o->current_space -= __len, \ + (PTR) (__o->current_ptr - __len)) \ + : _objalloc_alloc (__o, __len)); }) + +#else /* ! __GNUC__ */ + +#define objalloc_alloc(o, l) _objalloc_alloc ((o), (l)) + +#endif /* ! __GNUC__ */ + +/* Free an entire objalloc structure. */ + +extern void objalloc_free PARAMS ((struct objalloc *)); + +/* Free a block allocated by objalloc_alloc. This also frees all more + recently allocated blocks. */ + +extern void objalloc_free_block PARAMS ((struct objalloc *, PTR)); + +#endif /* OBJALLOC_H */ diff --git a/contrib/binutils-2.14/include/obstack.h b/contrib/binutils-2.14/include/obstack.h new file mode 100644 index 0000000000..d86d9f2c42 --- /dev/null +++ b/contrib/binutils-2.14/include/obstack.h @@ -0,0 +1,599 @@ +/* obstack.h - object stack macros + Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, + 1999, 2000 + Free Software Foundation, Inc. + + + NOTE: The canonical source of this file is maintained with the GNU C Library. + Bugs can be reported to bug-glibc@gnu.org. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +/* Summary: + +All the apparent functions defined here are macros. The idea +is that you would use these pre-tested macros to solve a +very specific set of problems, and they would run fast. +Caution: no side-effects in arguments please!! They may be +evaluated MANY times!! + +These macros operate a stack of objects. Each object starts life +small, and may grow to maturity. (Consider building a word syllable +by syllable.) An object can move while it is growing. Once it has +been "finished" it never changes address again. So the "top of the +stack" is typically an immature growing object, while the rest of the +stack is of mature, fixed size and fixed address objects. + +These routines grab large chunks of memory, using a function you +supply, called `obstack_chunk_alloc'. On occasion, they free chunks, +by calling `obstack_chunk_free'. You must define them and declare +them before using any obstack macros. + +Each independent stack is represented by a `struct obstack'. +Each of the obstack macros expects a pointer to such a structure +as the first argument. + +One motivation for this package is the problem of growing char strings +in symbol tables. Unless you are "fascist pig with a read-only mind" +--Gosper's immortal quote from HAKMEM item 154, out of context--you +would not like to put any arbitrary upper limit on the length of your +symbols. + +In practice this often means you will build many short symbols and a +few long symbols. At the time you are reading a symbol you don't know +how long it is. One traditional method is to read a symbol into a +buffer, realloc()ating the buffer every time you try to read a symbol +that is longer than the buffer. This is beaut, but you still will +want to copy the symbol from the buffer to a more permanent +symbol-table entry say about half the time. + +With obstacks, you can work differently. Use one obstack for all symbol +names. As you read a symbol, grow the name in the obstack gradually. +When the name is complete, finalize it. Then, if the symbol exists already, +free the newly read name. + +The way we do this is to take a large chunk, allocating memory from +low addresses. When you want to build a symbol in the chunk you just +add chars above the current "high water mark" in the chunk. When you +have finished adding chars, because you got to the end of the symbol, +you know how long the chars are, and you can create a new object. +Mostly the chars will not burst over the highest address of the chunk, +because you would typically expect a chunk to be (say) 100 times as +long as an average object. + +In case that isn't clear, when we have enough chars to make up +the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed) +so we just point to it where it lies. No moving of chars is +needed and this is the second win: potentially long strings need +never be explicitly shuffled. Once an object is formed, it does not +change its address during its lifetime. + +When the chars burst over a chunk boundary, we allocate a larger +chunk, and then copy the partly formed object from the end of the old +chunk to the beginning of the new larger chunk. We then carry on +accreting characters to the end of the object as we normally would. + +A special macro is provided to add a single char at a time to a +growing object. This allows the use of register variables, which +break the ordinary 'growth' macro. + +Summary: + We allocate large chunks. + We carve out one object at a time from the current chunk. + Once carved, an object never moves. + We are free to append data of any size to the currently + growing object. + Exactly one object is growing in an obstack at any one time. + You can run one obstack per control block. + You may have as many control blocks as you dare. + Because of the way we do it, you can `unwind' an obstack + back to a previous state. (You may remove objects much + as you would with a stack.) +*/ + + +/* Don't do the contents of this file more than once. */ + +#ifndef _OBSTACK_H +#define _OBSTACK_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* We use subtraction of (char *) 0 instead of casting to int + because on word-addressable machines a simple cast to int + may ignore the byte-within-word field of the pointer. */ + +#ifndef __PTR_TO_INT +# define __PTR_TO_INT(P) ((P) - (char *) 0) +#endif + +#ifndef __INT_TO_PTR +# define __INT_TO_PTR(P) ((P) + (char *) 0) +#endif + +/* We need the type of the resulting object. If __PTRDIFF_TYPE__ is + defined, as with GNU C, use that; that way we don't pollute the + namespace with 's symbols. Otherwise, if is + available, include it and use ptrdiff_t. In traditional C, long is + the best that we can do. */ + +#ifdef __PTRDIFF_TYPE__ +# define PTR_INT_TYPE __PTRDIFF_TYPE__ +#else +# ifdef HAVE_STDDEF_H +# include +# define PTR_INT_TYPE ptrdiff_t +# else +# define PTR_INT_TYPE long +# endif +#endif + +#if defined _LIBC || defined HAVE_STRING_H +# include +# if defined __STDC__ && __STDC__ +# define _obstack_memcpy(To, From, N) memcpy ((To), (From), (N)) +# else +# define _obstack_memcpy(To, From, N) memcpy ((To), (char *)(From), (N)) +# endif +#else +# ifdef memcpy +# define _obstack_memcpy(To, From, N) memcpy ((To), (char *)(From), (N)) +# else +# define _obstack_memcpy(To, From, N) bcopy ((char *)(From), (To), (N)) +# endif +#endif + +struct _obstack_chunk /* Lives at front of each chunk. */ +{ + char *limit; /* 1 past end of this chunk */ + struct _obstack_chunk *prev; /* address of prior chunk or NULL */ + char contents[4]; /* objects begin here */ +}; + +struct obstack /* control current object in current chunk */ +{ + long chunk_size; /* preferred size to allocate chunks in */ + struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */ + char *object_base; /* address of object we are building */ + char *next_free; /* where to add next char to current object */ + char *chunk_limit; /* address of char after current chunk */ + PTR_INT_TYPE temp; /* Temporary for some macros. */ + int alignment_mask; /* Mask of alignment for each object. */ +#if defined __STDC__ && __STDC__ + /* These prototypes vary based on `use_extra_arg', and we use + casts to the prototypeless function type in all assignments, + but having prototypes here quiets -Wstrict-prototypes. */ + struct _obstack_chunk *(*chunkfun) (void *, long); + void (*freefun) (void *, struct _obstack_chunk *); + void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ +#else + struct _obstack_chunk *(*chunkfun) (); /* User's fcn to allocate a chunk. */ + void (*freefun) (); /* User's function to free a chunk. */ + char *extra_arg; /* first arg for chunk alloc/dealloc funcs */ +#endif + unsigned use_extra_arg:1; /* chunk alloc/dealloc funcs take extra arg */ + unsigned maybe_empty_object:1;/* There is a possibility that the current + chunk contains a zero-length object. This + prevents freeing the chunk if we allocate + a bigger chunk to replace it. */ + unsigned alloc_failed:1; /* No longer used, as we now call the failed + handler on error, but retained for binary + compatibility. */ +}; + +/* Declare the external functions we use; they are in obstack.c. */ + +#if defined __STDC__ && __STDC__ +extern void _obstack_newchunk (struct obstack *, int); +extern void _obstack_free (struct obstack *, void *); +extern int _obstack_begin (struct obstack *, int, int, + void *(*) (long), void (*) (void *)); +extern int _obstack_begin_1 (struct obstack *, int, int, + void *(*) (void *, long), + void (*) (void *, void *), void *); +extern int _obstack_memory_used (struct obstack *); +#else +extern void _obstack_newchunk (); +extern void _obstack_free (); +extern int _obstack_begin (); +extern int _obstack_begin_1 (); +extern int _obstack_memory_used (); +#endif + +#if defined __STDC__ && __STDC__ + +/* Do the function-declarations after the structs + but before defining the macros. */ + +void obstack_init (struct obstack *obstack); + +void * obstack_alloc (struct obstack *obstack, int size); + +void * obstack_copy (struct obstack *obstack, void *address, int size); +void * obstack_copy0 (struct obstack *obstack, void *address, int size); + +void obstack_free (struct obstack *obstack, void *block); + +void obstack_blank (struct obstack *obstack, int size); + +void obstack_grow (struct obstack *obstack, void *data, int size); +void obstack_grow0 (struct obstack *obstack, void *data, int size); + +void obstack_1grow (struct obstack *obstack, int data_char); +void obstack_ptr_grow (struct obstack *obstack, void *data); +void obstack_int_grow (struct obstack *obstack, int data); + +void * obstack_finish (struct obstack *obstack); + +int obstack_object_size (struct obstack *obstack); + +int obstack_room (struct obstack *obstack); +void obstack_make_room (struct obstack *obstack, int size); +void obstack_1grow_fast (struct obstack *obstack, int data_char); +void obstack_ptr_grow_fast (struct obstack *obstack, void *data); +void obstack_int_grow_fast (struct obstack *obstack, int data); +void obstack_blank_fast (struct obstack *obstack, int size); + +void * obstack_base (struct obstack *obstack); +void * obstack_next_free (struct obstack *obstack); +int obstack_alignment_mask (struct obstack *obstack); +int obstack_chunk_size (struct obstack *obstack); +int obstack_memory_used (struct obstack *obstack); + +#endif /* __STDC__ */ + +/* Non-ANSI C cannot really support alternative functions for these macros, + so we do not declare them. */ + +/* Error handler called when `obstack_chunk_alloc' failed to allocate + more memory. This can be set to a user defined function. The + default action is to print a message and abort. */ +#if defined __STDC__ && __STDC__ +extern void (*obstack_alloc_failed_handler) (void); +#else +extern void (*obstack_alloc_failed_handler) (); +#endif + +/* Exit value used when `print_and_abort' is used. */ +extern int obstack_exit_failure; + +/* Pointer to beginning of object being allocated or to be allocated next. + Note that this might not be the final address of the object + because a new chunk might be needed to hold the final size. */ + +#define obstack_base(h) ((h)->object_base) + +/* Size for allocating ordinary chunks. */ + +#define obstack_chunk_size(h) ((h)->chunk_size) + +/* Pointer to next byte not yet allocated in current chunk. */ + +#define obstack_next_free(h) ((h)->next_free) + +/* Mask specifying low bits that should be clear in address of an object. */ + +#define obstack_alignment_mask(h) ((h)->alignment_mask) + +/* To prevent prototype warnings provide complete argument list in + standard C version. */ +#if defined __STDC__ && __STDC__ + +# define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free) + +# define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) (long)) obstack_chunk_alloc, (void (*) (void *)) obstack_chunk_free) + +# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) (long)) (chunkfun), (void (*) (void *)) (freefun)) + +# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) (void *, long)) (chunkfun), \ + (void (*) (void *, void *)) (freefun), (arg)) + +# define obstack_chunkfun(h, newchunkfun) \ + ((h) -> chunkfun = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun)) + +# define obstack_freefun(h, newfreefun) \ + ((h) -> freefun = (void (*)(void *, struct _obstack_chunk *)) (newfreefun)) + +#else + +# define obstack_init(h) \ + _obstack_begin ((h), 0, 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free) + +# define obstack_begin(h, size) \ + _obstack_begin ((h), (size), 0, \ + (void *(*) ()) obstack_chunk_alloc, (void (*) ()) obstack_chunk_free) + +# define obstack_specify_allocation(h, size, alignment, chunkfun, freefun) \ + _obstack_begin ((h), (size), (alignment), \ + (void *(*) ()) (chunkfun), (void (*) ()) (freefun)) + +# define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \ + _obstack_begin_1 ((h), (size), (alignment), \ + (void *(*) ()) (chunkfun), (void (*) ()) (freefun), (arg)) + +# define obstack_chunkfun(h, newchunkfun) \ + ((h) -> chunkfun = (struct _obstack_chunk *(*)()) (newchunkfun)) + +# define obstack_freefun(h, newfreefun) \ + ((h) -> freefun = (void (*)()) (newfreefun)) + +#endif + +#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = achar) + +#define obstack_blank_fast(h,n) ((h)->next_free += (n)) + +#define obstack_memory_used(h) _obstack_memory_used (h) + +#if defined __GNUC__ && defined __STDC__ && __STDC__ +/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and + does not implement __extension__. But that compiler doesn't define + __GNUC_MINOR__. */ +# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) +# define __extension__ +# endif + +/* For GNU C, if not -traditional, + we can define these macros to compute all args only once + without using a global variable. + Also, we can avoid using the `temp' slot, to make faster code. */ + +# define obstack_object_size(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->next_free - __o->object_base); }) + +# define obstack_room(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (unsigned) (__o->chunk_limit - __o->next_free); }) + +# define obstack_make_room(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + (void) 0; }) + +# define obstack_empty_p(OBSTACK) \ + __extension__ \ + ({ struct obstack *__o = (OBSTACK); \ + (__o->chunk->prev == 0 && __o->next_free - __o->chunk->contents == 0); }) + +# define obstack_grow(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len > __o->chunk_limit) \ + _obstack_newchunk (__o, __len); \ + _obstack_memcpy (__o->next_free, (where), __len); \ + __o->next_free += __len; \ + (void) 0; }) + +# define obstack_grow0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->next_free + __len + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, __len + 1); \ + _obstack_memcpy (__o->next_free, (where), __len); \ + __o->next_free += __len; \ + *(__o->next_free)++ = 0; \ + (void) 0; }) + +# define obstack_1grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + 1 > __o->chunk_limit) \ + _obstack_newchunk (__o, 1); \ + *(__o->next_free)++ = (datum); \ + (void) 0; }) + +/* These assume that the obstack alignment is good enough for pointers or ints, + and that the data added so far to the current object + shares that much alignment. */ + +# define obstack_ptr_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (void *) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (void *)); \ + *((void **)__o->next_free)++ = ((void *)datum); \ + (void) 0; }) + +# define obstack_int_grow(OBSTACK,datum) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + if (__o->next_free + sizeof (int) > __o->chunk_limit) \ + _obstack_newchunk (__o, sizeof (int)); \ + *((int *)__o->next_free)++ = ((int)datum); \ + (void) 0; }) + +# define obstack_ptr_grow_fast(h,aptr) (*((void **) (h)->next_free)++ = (void *)aptr) +# define obstack_int_grow_fast(h,aint) (*((int *) (h)->next_free)++ = (int) aint) + +# define obstack_blank(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + int __len = (length); \ + if (__o->chunk_limit - __o->next_free < __len) \ + _obstack_newchunk (__o, __len); \ + __o->next_free += __len; \ + (void) 0; }) + +# define obstack_alloc(OBSTACK,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_blank (__h, (length)); \ + obstack_finish (__h); }) + +# define obstack_copy(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow (__h, (where), (length)); \ + obstack_finish (__h); }) + +# define obstack_copy0(OBSTACK,where,length) \ +__extension__ \ +({ struct obstack *__h = (OBSTACK); \ + obstack_grow0 (__h, (where), (length)); \ + obstack_finish (__h); }) + +/* The local variable is named __o1 to avoid a name conflict + when obstack_blank is called. */ +# define obstack_finish(OBSTACK) \ +__extension__ \ +({ struct obstack *__o1 = (OBSTACK); \ + void *value; \ + value = (void *) __o1->object_base; \ + if (__o1->next_free == value) \ + __o1->maybe_empty_object = 1; \ + __o1->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT (__o1->next_free)+__o1->alignment_mask)\ + & ~ (__o1->alignment_mask)); \ + if (__o1->next_free - (char *)__o1->chunk \ + > __o1->chunk_limit - (char *)__o1->chunk) \ + __o1->next_free = __o1->chunk_limit; \ + __o1->object_base = __o1->next_free; \ + value; }) + +# define obstack_free(OBSTACK, OBJ) \ +__extension__ \ +({ struct obstack *__o = (OBSTACK); \ + void *__obj = (OBJ); \ + if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit) \ + __o->next_free = __o->object_base = __obj; \ + else (obstack_free) (__o, __obj); }) + +#else /* not __GNUC__ or not __STDC__ */ + +# define obstack_object_size(h) \ + (unsigned) ((h)->next_free - (h)->object_base) + +# define obstack_room(h) \ + (unsigned) ((h)->chunk_limit - (h)->next_free) + +# define obstack_empty_p(h) \ + ((h)->chunk->prev == 0 && (h)->next_free - (h)->chunk->contents == 0) + +/* Note that the call to _obstack_newchunk is enclosed in (..., 0) + so that we can avoid having void expressions + in the arms of the conditional expression. + Casting the third operand to void was tried before, + but some compilers won't accept it. */ + +# define obstack_make_room(h,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0)) + +# define obstack_grow(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + _obstack_memcpy ((h)->next_free, (where), (h)->temp), \ + (h)->next_free += (h)->temp) + +# define obstack_grow0(h,where,length) \ +( (h)->temp = (length), \ + (((h)->next_free + (h)->temp + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), (h)->temp + 1), 0) : 0), \ + _obstack_memcpy ((h)->next_free, (where), (h)->temp), \ + (h)->next_free += (h)->temp, \ + *((h)->next_free)++ = 0) + +# define obstack_1grow(h,datum) \ +( (((h)->next_free + 1 > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), 1), 0) : 0), \ + (*((h)->next_free)++ = (datum))) + +# define obstack_ptr_grow(h,datum) \ +( (((h)->next_free + sizeof (char *) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0), \ + (*((char **) (((h)->next_free+=sizeof(char *))-sizeof(char *))) = ((char *) datum))) + +# define obstack_int_grow(h,datum) \ +( (((h)->next_free + sizeof (int) > (h)->chunk_limit) \ + ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0), \ + (*((int *) (((h)->next_free+=sizeof(int))-sizeof(int))) = ((int) datum))) + +# define obstack_ptr_grow_fast(h,aptr) (*((char **) (h)->next_free)++ = (char *) aptr) +# define obstack_int_grow_fast(h,aint) (*((int *) (h)->next_free)++ = (int) aint) + +# define obstack_blank(h,length) \ +( (h)->temp = (length), \ + (((h)->chunk_limit - (h)->next_free < (h)->temp) \ + ? (_obstack_newchunk ((h), (h)->temp), 0) : 0), \ + ((h)->next_free += (h)->temp)) + +# define obstack_alloc(h,length) \ + (obstack_blank ((h), (length)), obstack_finish ((h))) + +# define obstack_copy(h,where,length) \ + (obstack_grow ((h), (where), (length)), obstack_finish ((h))) + +# define obstack_copy0(h,where,length) \ + (obstack_grow0 ((h), (where), (length)), obstack_finish ((h))) + +# define obstack_finish(h) \ +( ((h)->next_free == (h)->object_base \ + ? (((h)->maybe_empty_object = 1), 0) \ + : 0), \ + (h)->temp = __PTR_TO_INT ((h)->object_base), \ + (h)->next_free \ + = __INT_TO_PTR ((__PTR_TO_INT ((h)->next_free)+(h)->alignment_mask) \ + & ~ ((h)->alignment_mask)), \ + (((h)->next_free - (char *) (h)->chunk \ + > (h)->chunk_limit - (char *) (h)->chunk) \ + ? ((h)->next_free = (h)->chunk_limit) : 0), \ + (h)->object_base = (h)->next_free, \ + __INT_TO_PTR ((h)->temp)) + +# if defined __STDC__ && __STDC__ +# define obstack_free(h,obj) \ +( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (((obstack_free) ((h), (h)->temp + (char *) (h)->chunk), 0), 0))) +# else +# define obstack_free(h,obj) \ +( (h)->temp = (char *) (obj) - (char *) (h)->chunk, \ + (((h)->temp > 0 && (h)->temp < (h)->chunk_limit - (char *) (h)->chunk)\ + ? (int) ((h)->next_free = (h)->object_base \ + = (h)->temp + (char *) (h)->chunk) \ + : (_obstack_free ((h), (h)->temp + (char *) (h)->chunk), 0))) +# endif + +#endif /* not __GNUC__ or not __STDC__ */ + +#ifdef __cplusplus +} /* C++ */ +#endif + +#endif /* obstack.h */ diff --git a/contrib/binutils-2.14/include/opcode/i386.h b/contrib/binutils-2.14/include/opcode/i386.h new file mode 100644 index 0000000000..71c204c81f --- /dev/null +++ b/contrib/binutils-2.14/include/opcode/i386.h @@ -0,0 +1,1565 @@ +/* opcode/i386.h -- Intel 80386 opcode table + Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001 + Free Software Foundation, Inc. + +This file is part of GAS, the GNU Assembler, and GDB, the GNU Debugger. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The SystemV/386 SVR3.2 assembler, and probably all AT&T derived + ix86 Unix assemblers, generate floating point instructions with + reversed source and destination registers in certain cases. + Unfortunately, gcc and possibly many other programs use this + reversed syntax, so we're stuck with it. + + eg. `fsub %st(3),%st' results in st = st - st(3) as expected, but + `fsub %st,%st(3)' results in st(3) = st - st(3), rather than + the expected st(3) = st(3) - st + + This happens with all the non-commutative arithmetic floating point + operations with two register operands, where the source register is + %st, and destination register is %st(i). See FloatDR below. + + The affected opcode map is dceX, dcfX, deeX, defX. */ + +#ifndef SYSV386_COMPAT +/* Set non-zero for broken, compatible instructions. Set to zero for + non-broken opcodes at your peril. gcc generates SystemV/386 + compatible instructions. */ +#define SYSV386_COMPAT 1 +#endif +#ifndef OLDGCC_COMPAT +/* Set non-zero to cater for old (<= 2.8.1) versions of gcc that could + generate nonsense fsubp, fsubrp, fdivp and fdivrp with operands + reversed. */ +#define OLDGCC_COMPAT SYSV386_COMPAT +#endif + +static const template i386_optab[] = { + +#define X None +#define NoSuf (No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_xSuf|No_qSuf) +#define b_Suf (No_wSuf|No_lSuf|No_sSuf|No_xSuf|No_qSuf) +#define w_Suf (No_bSuf|No_lSuf|No_sSuf|No_xSuf|No_qSuf) +#define l_Suf (No_bSuf|No_wSuf|No_sSuf|No_xSuf|No_qSuf) +#define q_Suf (No_bSuf|No_wSuf|No_sSuf|No_lSuf|No_xSuf) +#define x_Suf (No_bSuf|No_wSuf|No_sSuf|No_lSuf|No_qSuf) +#define bw_Suf (No_lSuf|No_sSuf|No_xSuf|No_qSuf) +#define bl_Suf (No_wSuf|No_sSuf|No_xSuf|No_qSuf) +#define wl_Suf (No_bSuf|No_sSuf|No_xSuf|No_qSuf) +#define wlq_Suf (No_bSuf|No_sSuf|No_xSuf) +#define lq_Suf (No_bSuf|No_wSuf|No_sSuf|No_xSuf) +#define wq_Suf (No_bSuf|No_lSuf|No_sSuf|No_xSuf) +#define sl_Suf (No_bSuf|No_wSuf|No_xSuf|No_qSuf) +#define sldx_Suf (No_bSuf|No_wSuf|No_qSuf) +#define bwl_Suf (No_sSuf|No_xSuf|No_qSuf) +#define bwlq_Suf (No_sSuf|No_xSuf) +#define FP (NoSuf|IgnoreSize) +#define l_FP (l_Suf|IgnoreSize) +#define x_FP (x_Suf|IgnoreSize) +#define sl_FP (sl_Suf|IgnoreSize) +#if SYSV386_COMPAT +/* Someone forgot that the FloatR bit reverses the operation when not + equal to the FloatD bit. ie. Changing only FloatD results in the + destination being swapped *and* the direction being reversed. */ +#define FloatDR FloatD +#else +#define FloatDR (FloatD|FloatR) +#endif + +/* Move instructions. */ +#define MOV_AX_DISP32 0xa0 +/* In the 64bit mode the short form mov immediate is redefined to have + 64bit displacement value. */ +{ "mov", 2, 0xa0, X, CpuNo64,bwlq_Suf|D|W, { Disp16|Disp32, Acc, 0 } }, +{ "mov", 2, 0x88, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +/* In the 64bit mode the short form mov immediate is redefined to have + 64bit displacement value. */ +{ "mov", 2, 0xb0, X, 0, bwl_Suf|W|ShortForm, { EncImm, Reg8|Reg16|Reg32, 0 } }, +{ "mov", 2, 0xc6, 0, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0 } }, +{ "mov", 2, 0xb0, X, Cpu64, q_Suf|W|ShortForm, { Imm64, Reg64, 0 } }, +/* The segment register moves accept WordReg so that a segment register + can be copied to a 32 bit register, and vice versa, without using a + size prefix. When moving to a 32 bit register, the upper 16 bits + are set to an implementation defined value (on the Pentium Pro, + the implementation defined value is zero). */ +{ "mov", 2, 0x8c, X, 0, wl_Suf|Modrm, { SReg2, WordReg|WordMem, 0 } }, +{ "mov", 2, 0x8c, X, Cpu386, wl_Suf|Modrm, { SReg3, WordReg|WordMem, 0 } }, +{ "mov", 2, 0x8e, X, 0, wl_Suf|Modrm|IgnoreSize, { WordReg|WordMem, SReg2, 0 } }, +{ "mov", 2, 0x8e, X, Cpu386, wl_Suf|Modrm|IgnoreSize, { WordReg|WordMem, SReg3, 0 } }, +/* Move to/from control debug registers. In the 16 or 32bit modes they are 32bit. In the 64bit + mode they are 64bit.*/ +{ "mov", 2, 0x0f20, X, Cpu386|CpuNo64, l_Suf|D|Modrm|IgnoreSize,{ Control, Reg32|InvMem, 0} }, +{ "mov", 2, 0x0f20, X, Cpu64, q_Suf|D|Modrm|IgnoreSize|NoRex64,{ Control, Reg64|InvMem, 0} }, +{ "mov", 2, 0x0f21, X, Cpu386|CpuNo64, l_Suf|D|Modrm|IgnoreSize,{ Debug, Reg32|InvMem, 0} }, +{ "mov", 2, 0x0f21, X, Cpu64, q_Suf|D|Modrm|IgnoreSize|NoRex64,{ Debug, Reg64|InvMem, 0} }, +{ "mov", 2, 0x0f24, X, Cpu386, l_Suf|D|Modrm|IgnoreSize, { Test, Reg32|InvMem, 0} }, +{ "movabs",2, 0xa0, X, Cpu64, bwlq_Suf|D|W, { Disp64, Acc, 0 } }, +{ "movabs",2, 0xb0, X, Cpu64, q_Suf|W|ShortForm, { Imm64, Reg64, 0 } }, + +/* Move with sign extend. */ +/* "movsbl" & "movsbw" must not be unified into "movsb" to avoid + conflict with the "movs" string move instruction. */ +{"movsbl", 2, 0x0fbe, X, Cpu386, NoSuf|Modrm, { Reg8|ByteMem, Reg32, 0} }, +{"movsbw", 2, 0x0fbe, X, Cpu386, NoSuf|Modrm, { Reg8|ByteMem, Reg16, 0} }, +{"movswl", 2, 0x0fbf, X, Cpu386, NoSuf|Modrm, { Reg16|ShortMem,Reg32, 0} }, +{"movsbq", 2, 0x0fbe, X, Cpu64, NoSuf|Modrm|Rex64, { Reg8|ByteMem, Reg64, 0} }, +{"movswq", 2, 0x0fbf, X, Cpu64, NoSuf|Modrm|Rex64, { Reg16|ShortMem,Reg64, 0} }, +{"movslq", 2, 0x63, X, Cpu64, NoSuf|Modrm|Rex64, { Reg32|WordMem, Reg64, 0} }, +/* Intel Syntax next 5 insns */ +{"movsx", 2, 0x0fbe, X, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, WordReg, 0} }, +{"movsx", 2, 0x0fbf, X, Cpu386, w_Suf|Modrm, { Reg16|ShortMem, Reg32, 0} }, +{"movsx", 2, 0x0fbe, X, Cpu64, b_Suf|Modrm|Rex64, { Reg8|ByteMem, Reg64, 0} }, +{"movsx", 2, 0x0fbf, X, Cpu64, w_Suf|Modrm|Rex64, { Reg16|ShortMem, Reg64, 0} }, +{"movsx", 2, 0x63, X, Cpu64, l_Suf|Modrm|Rex64, { Reg32|WordMem, Reg64, 0} }, + +/* Move with zero extend. */ +{"movzb", 2, 0x0fb6, X, Cpu386, wl_Suf|Modrm, { Reg8|ByteMem, WordReg, 0} }, +{"movzwl", 2, 0x0fb7, X, Cpu386, NoSuf|Modrm, { Reg16|ShortMem, Reg32, 0} }, +/* These instructions are not particulary usefull, since the zero extend + 32->64 is implicit, but we can encode them. */ +{"movzbq", 2, 0x0fb6, X, Cpu64, NoSuf|Modrm|Rex64, { Reg8|ByteMem, Reg64, 0} }, +{"movzwq", 2, 0x0fb7, X, Cpu64, NoSuf|Modrm|Rex64, { Reg16|ShortMem, Reg64, 0} }, +/* Intel Syntax next 4 insns */ +{"movzx", 2, 0x0fb6, X, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, WordReg, 0} }, +{"movzx", 2, 0x0fb7, X, Cpu386, w_Suf|Modrm, { Reg16|ShortMem, Reg32, 0} }, +/* These instructions are not particulary usefull, since the zero extend + 32->64 is implicit, but we can encode them. */ +{"movzx", 2, 0x0fb6, X, Cpu386, b_Suf|Modrm|Rex64, { Reg8|ByteMem, Reg64, 0} }, +{"movzx", 2, 0x0fb7, X, Cpu386, w_Suf|Modrm|Rex64, { Reg16|ShortMem, Reg64, 0} }, + +/* Push instructions. */ +{"push", 1, 0x50, X, CpuNo64, wl_Suf|ShortForm|DefaultSize, { WordReg, 0, 0 } }, +{"push", 1, 0xff, 6, CpuNo64, wl_Suf|Modrm|DefaultSize, { WordReg|WordMem, 0, 0 } }, +{"push", 1, 0x6a, X, Cpu186|CpuNo64, wl_Suf|DefaultSize, { Imm8S, 0, 0} }, +{"push", 1, 0x68, X, Cpu186|CpuNo64, wl_Suf|DefaultSize, { Imm16|Imm32, 0, 0} }, +{"push", 1, 0x06, X, 0|CpuNo64, wl_Suf|Seg2ShortForm|DefaultSize, { SReg2, 0, 0 } }, +{"push", 1, 0x0fa0, X, Cpu386|CpuNo64, wl_Suf|Seg3ShortForm|DefaultSize, { SReg3, 0, 0 } }, +/* In 64bit mode, the operand size is implicitly 64bit. */ +{"push", 1, 0x50, X, Cpu64, wq_Suf|ShortForm|DefaultSize|NoRex64, { WordReg, 0, 0 } }, +{"push", 1, 0xff, 6, Cpu64, wq_Suf|Modrm|DefaultSize|NoRex64, { WordReg|WordMem, 0, 0 } }, +{"push", 1, 0x6a, X, Cpu186|Cpu64, wq_Suf|DefaultSize|NoRex64, { Imm8S, 0, 0} }, +{"push", 1, 0x68, X, Cpu186|Cpu64, wq_Suf|DefaultSize|NoRex64, { Imm32S|Imm16, 0, 0} }, +{"push", 1, 0x06, X, Cpu64, wq_Suf|Seg2ShortForm|DefaultSize|NoRex64, { SReg2, 0, 0 } }, +{"push", 1, 0x0fa0, X, Cpu386|Cpu64, wq_Suf|Seg3ShortForm|DefaultSize|NoRex64, { SReg3, 0, 0 } }, + +{"pusha", 0, 0x60, X, Cpu186|CpuNo64, wl_Suf|DefaultSize, { 0, 0, 0 } }, + +/* Pop instructions. */ +{"pop", 1, 0x58, X, CpuNo64, wl_Suf|ShortForm|DefaultSize, { WordReg, 0, 0 } }, +{"pop", 1, 0x8f, 0, CpuNo64, wl_Suf|Modrm|DefaultSize, { WordReg|WordMem, 0, 0 } }, +#define POP_SEG_SHORT 0x07 +{"pop", 1, 0x07, X, CpuNo64, wl_Suf|Seg2ShortForm|DefaultSize, { SReg2, 0, 0 } }, +{"pop", 1, 0x0fa1, X, Cpu386|CpuNo64, wl_Suf|Seg3ShortForm|DefaultSize, { SReg3, 0, 0 } }, +/* In 64bit mode, the operand size is implicitly 64bit. */ +{"pop", 1, 0x58, X, Cpu64, wq_Suf|ShortForm|DefaultSize|NoRex64, { WordReg, 0, 0 } }, +{"pop", 1, 0x8f, 0, Cpu64, wq_Suf|Modrm|DefaultSize|NoRex64, { WordReg|WordMem, 0, 0 } }, +{"pop", 1, 0x07, X, Cpu64, wq_Suf|Seg2ShortForm|DefaultSize|NoRex64, { SReg2, 0, 0 } }, +{"pop", 1, 0x0fa1, X, Cpu64, wq_Suf|Seg3ShortForm|DefaultSize|NoRex64, { SReg3, 0, 0 } }, + +{"popa", 0, 0x61, X, Cpu186|CpuNo64, wl_Suf|DefaultSize, { 0, 0, 0 } }, + +/* Exchange instructions. + xchg commutes: we allow both operand orders. + + In the 64bit code, xchg eax, eax is reused for new nop instruction. + */ +{"xchg", 2, 0x90, X, 0, wlq_Suf|ShortForm, { WordReg, Acc, 0 } }, +{"xchg", 2, 0x90, X, 0, wlq_Suf|ShortForm, { Acc, WordReg, 0 } }, +{"xchg", 2, 0x86, X, 0, bwlq_Suf|W|Modrm, { Reg, Reg|AnyMem, 0 } }, +{"xchg", 2, 0x86, X, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, Reg, 0 } }, + +/* In/out from ports. */ +{"in", 2, 0xe4, X, 0, bwl_Suf|W, { Imm8, Acc, 0 } }, +{"in", 2, 0xec, X, 0, bwl_Suf|W, { InOutPortReg, Acc, 0 } }, +{"in", 1, 0xe4, X, 0, bwl_Suf|W, { Imm8, 0, 0 } }, +{"in", 1, 0xec, X, 0, bwl_Suf|W, { InOutPortReg, 0, 0 } }, +{"out", 2, 0xe6, X, 0, bwl_Suf|W, { Acc, Imm8, 0 } }, +{"out", 2, 0xee, X, 0, bwl_Suf|W, { Acc, InOutPortReg, 0 } }, +{"out", 1, 0xe6, X, 0, bwl_Suf|W, { Imm8, 0, 0 } }, +{"out", 1, 0xee, X, 0, bwl_Suf|W, { InOutPortReg, 0, 0 } }, + +/* Load effective address. */ +{"lea", 2, 0x8d, X, 0, wlq_Suf|Modrm, { WordMem, WordReg, 0 } }, + +/* Load segment registers from memory. */ +{"lds", 2, 0xc5, X, CpuNo64, wlq_Suf|Modrm, { WordMem, WordReg, 0} }, +{"les", 2, 0xc4, X, CpuNo64, wlq_Suf|Modrm, { WordMem, WordReg, 0} }, +{"lfs", 2, 0x0fb4, X, Cpu386, wlq_Suf|Modrm, { WordMem, WordReg, 0} }, +{"lgs", 2, 0x0fb5, X, Cpu386, wlq_Suf|Modrm, { WordMem, WordReg, 0} }, +{"lss", 2, 0x0fb2, X, Cpu386, wlq_Suf|Modrm, { WordMem, WordReg, 0} }, + +/* Flags register instructions. */ +{"clc", 0, 0xf8, X, 0, NoSuf, { 0, 0, 0} }, +{"cld", 0, 0xfc, X, 0, NoSuf, { 0, 0, 0} }, +{"cli", 0, 0xfa, X, 0, NoSuf, { 0, 0, 0} }, +{"clts", 0, 0x0f06, X, Cpu286, NoSuf, { 0, 0, 0} }, +{"cmc", 0, 0xf5, X, 0, NoSuf, { 0, 0, 0} }, +{"lahf", 0, 0x9f, X, CpuNo64,NoSuf, { 0, 0, 0} }, +{"sahf", 0, 0x9e, X, CpuNo64,NoSuf, { 0, 0, 0} }, +{"pushf", 0, 0x9c, X, CpuNo64,wlq_Suf|DefaultSize, { 0, 0, 0} }, +{"pushf", 0, 0x9c, X, Cpu64, wq_Suf|DefaultSize|NoRex64,{ 0, 0, 0} }, +{"popf", 0, 0x9d, X, CpuNo64,wlq_Suf|DefaultSize, { 0, 0, 0} }, +{"popf", 0, 0x9d, X, Cpu64, wq_Suf|DefaultSize|NoRex64,{ 0, 0, 0} }, +{"stc", 0, 0xf9, X, 0, NoSuf, { 0, 0, 0} }, +{"std", 0, 0xfd, X, 0, NoSuf, { 0, 0, 0} }, +{"sti", 0, 0xfb, X, 0, NoSuf, { 0, 0, 0} }, + +/* Arithmetic. */ +{"add", 2, 0x00, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"add", 2, 0x83, 0, 0, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"add", 2, 0x04, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"add", 2, 0x80, 0, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +{"inc", 1, 0x40, X, CpuNo64,wl_Suf|ShortForm, { WordReg, 0, 0} }, +{"inc", 1, 0xfe, 0, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"sub", 2, 0x28, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"sub", 2, 0x83, 5, 0, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"sub", 2, 0x2c, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"sub", 2, 0x80, 5, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +{"dec", 1, 0x48, X, CpuNo64, wl_Suf|ShortForm, { WordReg, 0, 0} }, +{"dec", 1, 0xfe, 1, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"sbb", 2, 0x18, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"sbb", 2, 0x83, 3, 0, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"sbb", 2, 0x1c, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"sbb", 2, 0x80, 3, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +{"cmp", 2, 0x38, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"cmp", 2, 0x83, 7, 0, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"cmp", 2, 0x3c, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"cmp", 2, 0x80, 7, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +{"test", 2, 0x84, X, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, Reg, 0} }, +{"test", 2, 0x84, X, 0, bwlq_Suf|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"test", 2, 0xa8, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"test", 2, 0xf6, 0, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +{"and", 2, 0x20, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"and", 2, 0x83, 4, 0, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"and", 2, 0x24, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"and", 2, 0x80, 4, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +{"or", 2, 0x08, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"or", 2, 0x83, 1, 0, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"or", 2, 0x0c, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"or", 2, 0x80, 1, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +{"xor", 2, 0x30, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"xor", 2, 0x83, 6, 0, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"xor", 2, 0x34, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"xor", 2, 0x80, 6, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +/* clr with 1 operand is really xor with 2 operands. */ +{"clr", 1, 0x30, X, 0, bwlq_Suf|W|Modrm|regKludge, { Reg, 0, 0 } }, + +{"adc", 2, 0x10, X, 0, bwlq_Suf|D|W|Modrm, { Reg, Reg|AnyMem, 0} }, +{"adc", 2, 0x83, 2, 0, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, 0} }, +{"adc", 2, 0x14, X, 0, bwlq_Suf|W, { EncImm, Acc, 0} }, +{"adc", 2, 0x80, 2, 0, bwlq_Suf|W|Modrm, { EncImm, Reg|AnyMem, 0} }, + +{"neg", 1, 0xf6, 3, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, +{"not", 1, 0xf6, 2, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"aaa", 0, 0x37, X, 0, NoSuf, { 0, 0, 0} }, +{"aas", 0, 0x3f, X, 0, NoSuf, { 0, 0, 0} }, +{"daa", 0, 0x27, X, 0, NoSuf, { 0, 0, 0} }, +{"das", 0, 0x2f, X, 0, NoSuf, { 0, 0, 0} }, +{"aad", 0, 0xd50a, X, 0, NoSuf, { 0, 0, 0} }, +{"aad", 1, 0xd5, X, 0, NoSuf, { Imm8S, 0, 0} }, +{"aam", 0, 0xd40a, X, 0, NoSuf, { 0, 0, 0} }, +{"aam", 1, 0xd4, X, 0, NoSuf, { Imm8S, 0, 0} }, + +/* Conversion insns. */ +/* Intel naming */ +{"cbw", 0, 0x98, X, 0, NoSuf|Size16, { 0, 0, 0} }, +{"cdqe", 0, 0x98, X, Cpu64, NoSuf|Size64, { 0, 0, 0} }, +{"cwde", 0, 0x98, X, 0, NoSuf|Size32, { 0, 0, 0} }, +{"cwd", 0, 0x99, X, 0, NoSuf|Size16, { 0, 0, 0} }, +{"cdq", 0, 0x99, X, 0, NoSuf|Size32, { 0, 0, 0} }, +{"cqo", 0, 0x99, X, Cpu64, NoSuf|Size64, { 0, 0, 0} }, +/* AT&T naming */ +{"cbtw", 0, 0x98, X, 0, NoSuf|Size16, { 0, 0, 0} }, +{"cltq", 0, 0x98, X, Cpu64, NoSuf|Size64, { 0, 0, 0} }, +{"cwtl", 0, 0x98, X, 0, NoSuf|Size32, { 0, 0, 0} }, +{"cwtd", 0, 0x99, X, 0, NoSuf|Size16, { 0, 0, 0} }, +{"cltd", 0, 0x99, X, 0, NoSuf|Size32, { 0, 0, 0} }, +{"cqto", 0, 0x99, X, Cpu64, NoSuf|Size64, { 0, 0, 0} }, + +/* Warning! the mul/imul (opcode 0xf6) must only have 1 operand! They are + expanding 64-bit multiplies, and *cannot* be selected to accomplish + 'imul %ebx, %eax' (opcode 0x0faf must be used in this case) + These multiplies can only be selected with single operand forms. */ +{"mul", 1, 0xf6, 4, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, +{"imul", 1, 0xf6, 5, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, +{"imul", 2, 0x0faf, X, Cpu386, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"imul", 3, 0x6b, X, Cpu186, wlq_Suf|Modrm, { Imm8S, WordReg|WordMem, WordReg} }, +{"imul", 3, 0x69, X, Cpu186, wlq_Suf|Modrm, { Imm16|Imm32S|Imm32, WordReg|WordMem, WordReg} }, +/* imul with 2 operands mimics imul with 3 by putting the register in + both i.rm.reg & i.rm.regmem fields. regKludge enables this + transformation. */ +{"imul", 2, 0x6b, X, Cpu186, wlq_Suf|Modrm|regKludge,{ Imm8S, WordReg, 0} }, +{"imul", 2, 0x69, X, Cpu186, wlq_Suf|Modrm|regKludge,{ Imm16|Imm32S|Imm32, WordReg, 0} }, + +{"div", 1, 0xf6, 6, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, +{"div", 2, 0xf6, 6, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, Acc, 0} }, +{"idiv", 1, 0xf6, 7, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, +{"idiv", 2, 0xf6, 7, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, Acc, 0} }, + +{"rol", 2, 0xd0, 0, 0, bwlq_Suf|W|Modrm, { Imm1, Reg|AnyMem, 0} }, +{"rol", 2, 0xc0, 0, Cpu186, bwlq_Suf|W|Modrm, { Imm8, Reg|AnyMem, 0} }, +{"rol", 2, 0xd2, 0, 0, bwlq_Suf|W|Modrm, { ShiftCount, Reg|AnyMem, 0} }, +{"rol", 1, 0xd0, 0, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"ror", 2, 0xd0, 1, 0, bwlq_Suf|W|Modrm, { Imm1, Reg|AnyMem, 0} }, +{"ror", 2, 0xc0, 1, Cpu186, bwlq_Suf|W|Modrm, { Imm8, Reg|AnyMem, 0} }, +{"ror", 2, 0xd2, 1, 0, bwlq_Suf|W|Modrm, { ShiftCount, Reg|AnyMem, 0} }, +{"ror", 1, 0xd0, 1, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"rcl", 2, 0xd0, 2, 0, bwlq_Suf|W|Modrm, { Imm1, Reg|AnyMem, 0} }, +{"rcl", 2, 0xc0, 2, Cpu186, bwlq_Suf|W|Modrm, { Imm8, Reg|AnyMem, 0} }, +{"rcl", 2, 0xd2, 2, 0, bwlq_Suf|W|Modrm, { ShiftCount, Reg|AnyMem, 0} }, +{"rcl", 1, 0xd0, 2, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"rcr", 2, 0xd0, 3, 0, bwlq_Suf|W|Modrm, { Imm1, Reg|AnyMem, 0} }, +{"rcr", 2, 0xc0, 3, Cpu186, bwlq_Suf|W|Modrm, { Imm8, Reg|AnyMem, 0} }, +{"rcr", 2, 0xd2, 3, 0, bwlq_Suf|W|Modrm, { ShiftCount, Reg|AnyMem, 0} }, +{"rcr", 1, 0xd0, 3, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"sal", 2, 0xd0, 4, 0, bwlq_Suf|W|Modrm, { Imm1, Reg|AnyMem, 0} }, +{"sal", 2, 0xc0, 4, Cpu186, bwlq_Suf|W|Modrm, { Imm8, Reg|AnyMem, 0} }, +{"sal", 2, 0xd2, 4, 0, bwlq_Suf|W|Modrm, { ShiftCount, Reg|AnyMem, 0} }, +{"sal", 1, 0xd0, 4, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"shl", 2, 0xd0, 4, 0, bwlq_Suf|W|Modrm, { Imm1, Reg|AnyMem, 0} }, +{"shl", 2, 0xc0, 4, Cpu186, bwlq_Suf|W|Modrm, { Imm8, Reg|AnyMem, 0} }, +{"shl", 2, 0xd2, 4, 0, bwlq_Suf|W|Modrm, { ShiftCount, Reg|AnyMem, 0} }, +{"shl", 1, 0xd0, 4, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"shr", 2, 0xd0, 5, 0, bwlq_Suf|W|Modrm, { Imm1, Reg|AnyMem, 0} }, +{"shr", 2, 0xc0, 5, Cpu186, bwlq_Suf|W|Modrm, { Imm8, Reg|AnyMem, 0} }, +{"shr", 2, 0xd2, 5, 0, bwlq_Suf|W|Modrm, { ShiftCount, Reg|AnyMem, 0} }, +{"shr", 1, 0xd0, 5, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"sar", 2, 0xd0, 7, 0, bwlq_Suf|W|Modrm, { Imm1, Reg|AnyMem, 0} }, +{"sar", 2, 0xc0, 7, Cpu186, bwlq_Suf|W|Modrm, { Imm8, Reg|AnyMem, 0} }, +{"sar", 2, 0xd2, 7, 0, bwlq_Suf|W|Modrm, { ShiftCount, Reg|AnyMem, 0} }, +{"sar", 1, 0xd0, 7, 0, bwlq_Suf|W|Modrm, { Reg|AnyMem, 0, 0} }, + +{"shld", 3, 0x0fa4, X, Cpu386, wlq_Suf|Modrm, { Imm8, WordReg, WordReg|WordMem} }, +{"shld", 3, 0x0fa5, X, Cpu386, wlq_Suf|Modrm, { ShiftCount, WordReg, WordReg|WordMem} }, +{"shld", 2, 0x0fa5, X, Cpu386, wlq_Suf|Modrm, { WordReg, WordReg|WordMem, 0} }, + +{"shrd", 3, 0x0fac, X, Cpu386, wlq_Suf|Modrm, { Imm8, WordReg, WordReg|WordMem} }, +{"shrd", 3, 0x0fad, X, Cpu386, wlq_Suf|Modrm, { ShiftCount, WordReg, WordReg|WordMem} }, +{"shrd", 2, 0x0fad, X, Cpu386, wlq_Suf|Modrm, { WordReg, WordReg|WordMem, 0} }, + +/* Control transfer instructions. */ +{"call", 1, 0xe8, X, 0, wlq_Suf|JumpDword|DefaultSize, { Disp16|Disp32, 0, 0} }, +{"call", 1, 0xff, 2, CpuNo64, wl_Suf|Modrm|DefaultSize, { WordReg|WordMem|JumpAbsolute, 0, 0} }, +{"call", 1, 0xff, 2, Cpu64, wq_Suf|Modrm|DefaultSize|NoRex64,{ WordReg|WordMem|JumpAbsolute, 0, 0} }, +/* Intel Syntax */ +{"call", 2, 0x9a, X, CpuNo64,wlq_Suf|JumpInterSegment|DefaultSize, { Imm16, Imm16|Imm32, 0} }, +/* Intel Syntax */ +{"call", 1, 0xff, 3, 0, x_Suf|Modrm|DefaultSize, { WordMem, 0, 0} }, +{"lcall", 2, 0x9a, X, CpuNo64, wl_Suf|JumpInterSegment|DefaultSize, { Imm16, Imm16|Imm32, 0} }, +{"lcall", 1, 0xff, 3, CpuNo64, wl_Suf|Modrm|DefaultSize, { WordMem|JumpAbsolute, 0, 0} }, +{"lcall", 1, 0xff, 3, Cpu64, q_Suf|Modrm|DefaultSize|NoRex64,{ WordMem|JumpAbsolute, 0, 0} }, + +#define JUMP_PC_RELATIVE 0xeb +{"jmp", 1, 0xeb, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jmp", 1, 0xff, 4, CpuNo64, wl_Suf|Modrm, { WordReg|WordMem|JumpAbsolute, 0, 0} }, +{"jmp", 1, 0xff, 4, Cpu64, wq_Suf|Modrm|NoRex64, { WordReg|WordMem|JumpAbsolute, 0, 0} }, +/* Intel Syntax */ +{"jmp", 2, 0xea, X, CpuNo64,wl_Suf|JumpInterSegment, { Imm16, Imm16|Imm32, 0} }, +/* Intel Syntax */ +{"jmp", 1, 0xff, 5, 0, x_Suf|Modrm, { WordMem, 0, 0} }, +{"ljmp", 2, 0xea, X, CpuNo64, wl_Suf|JumpInterSegment, { Imm16, Imm16|Imm32, 0} }, +{"ljmp", 1, 0xff, 5, CpuNo64, wl_Suf|Modrm, { WordMem|JumpAbsolute, 0, 0} }, +{"ljmp", 1, 0xff, 5, Cpu64, q_Suf|Modrm|NoRex64, { WordMem|JumpAbsolute, 0, 0} }, + +{"ret", 0, 0xc3, X, CpuNo64,wlq_Suf|DefaultSize, { 0, 0, 0} }, +{"ret", 1, 0xc2, X, CpuNo64,wlq_Suf|DefaultSize, { Imm16, 0, 0} }, +{"ret", 0, 0xc3, X, Cpu64, q_Suf|DefaultSize|NoRex64,{ 0, 0, 0} }, +{"ret", 1, 0xc2, X, Cpu64, q_Suf|DefaultSize|NoRex64,{ Imm16, 0, 0} }, +{"lret", 0, 0xcb, X, 0, wlq_Suf|DefaultSize, { 0, 0, 0} }, +{"lret", 1, 0xca, X, 0, wlq_Suf|DefaultSize, { Imm16, 0, 0} }, +{"enter", 2, 0xc8, X, Cpu186, wlq_Suf|DefaultSize, { Imm16, Imm8, 0} }, +{"leave", 0, 0xc9, X, Cpu186, wlq_Suf|DefaultSize, { 0, 0, 0} }, + +/* Conditional jumps. */ +{"jo", 1, 0x70, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jno", 1, 0x71, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jb", 1, 0x72, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jc", 1, 0x72, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnae", 1, 0x72, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnb", 1, 0x73, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnc", 1, 0x73, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jae", 1, 0x73, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"je", 1, 0x74, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jz", 1, 0x74, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jne", 1, 0x75, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnz", 1, 0x75, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jbe", 1, 0x76, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jna", 1, 0x76, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnbe", 1, 0x77, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"ja", 1, 0x77, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"js", 1, 0x78, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jns", 1, 0x79, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jp", 1, 0x7a, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jpe", 1, 0x7a, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnp", 1, 0x7b, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jpo", 1, 0x7b, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jl", 1, 0x7c, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnge", 1, 0x7c, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnl", 1, 0x7d, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jge", 1, 0x7d, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jle", 1, 0x7e, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jng", 1, 0x7e, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jnle", 1, 0x7f, X, 0, NoSuf|Jump, { Disp, 0, 0} }, +{"jg", 1, 0x7f, X, 0, NoSuf|Jump, { Disp, 0, 0} }, + +/* jcxz vs. jecxz is chosen on the basis of the address size prefix. */ +{"jcxz", 1, 0xe3, X, CpuNo64,NoSuf|JumpByte|Size16, { Disp, 0, 0} }, +{"jecxz", 1, 0xe3, X, CpuNo64,NoSuf|JumpByte|Size32, { Disp, 0, 0} }, +{"jecxz", 1, 0x67e3, X, Cpu64,NoSuf|JumpByte|Size32, { Disp, 0, 0} }, +{"jrcxz", 1, 0xe3, X, Cpu64, NoSuf|JumpByte|Size64|NoRex64, { Disp, 0, 0} }, + +/* The loop instructions also use the address size prefix to select + %cx rather than %ecx for the loop count, so the `w' form of these + instructions emit an address size prefix rather than a data size + prefix. */ +{"loop", 1, 0xe2, X, CpuNo64,wl_Suf|JumpByte,{ Disp, 0, 0} }, +{"loop", 1, 0xe2, X, Cpu64, lq_Suf|JumpByte|NoRex64,{ Disp, 0, 0} }, +{"loopz", 1, 0xe1, X, CpuNo64,wl_Suf|JumpByte,{ Disp, 0, 0} }, +{"loopz", 1, 0xe1, X, Cpu64, lq_Suf|JumpByte|NoRex64,{ Disp, 0, 0} }, +{"loope", 1, 0xe1, X, CpuNo64,wl_Suf|JumpByte,{ Disp, 0, 0} }, +{"loope", 1, 0xe1, X, Cpu64, lq_Suf|JumpByte|NoRex64,{ Disp, 0, 0} }, +{"loopnz", 1, 0xe0, X, CpuNo64,wl_Suf|JumpByte,{ Disp, 0, 0} }, +{"loopnz", 1, 0xe0, X, Cpu64, lq_Suf|JumpByte|NoRex64,{ Disp, 0, 0} }, +{"loopne", 1, 0xe0, X, CpuNo64,wl_Suf|JumpByte,{ Disp, 0, 0} }, +{"loopne", 1, 0xe0, X, Cpu64, lq_Suf|JumpByte|NoRex64,{ Disp, 0, 0} }, + +/* Set byte on flag instructions. */ +{"seto", 1, 0x0f90, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setno", 1, 0x0f91, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setb", 1, 0x0f92, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setc", 1, 0x0f92, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnae", 1, 0x0f92, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnb", 1, 0x0f93, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnc", 1, 0x0f93, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setae", 1, 0x0f93, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"sete", 1, 0x0f94, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setz", 1, 0x0f94, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setne", 1, 0x0f95, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnz", 1, 0x0f95, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setbe", 1, 0x0f96, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setna", 1, 0x0f96, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnbe", 1, 0x0f97, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"seta", 1, 0x0f97, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"sets", 1, 0x0f98, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setns", 1, 0x0f99, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setp", 1, 0x0f9a, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setpe", 1, 0x0f9a, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnp", 1, 0x0f9b, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setpo", 1, 0x0f9b, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setl", 1, 0x0f9c, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnge", 1, 0x0f9c, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnl", 1, 0x0f9d, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setge", 1, 0x0f9d, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setle", 1, 0x0f9e, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setng", 1, 0x0f9e, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setnle", 1, 0x0f9f, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, +{"setg", 1, 0x0f9f, 0, Cpu386, b_Suf|Modrm, { Reg8|ByteMem, 0, 0} }, + +/* String manipulation. */ +{"cmps", 0, 0xa6, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"cmps", 2, 0xa6, X, 0, bwlq_Suf|W|IsString, { AnyMem|EsSeg, AnyMem, 0} }, +{"scmp", 0, 0xa6, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"scmp", 2, 0xa6, X, 0, bwlq_Suf|W|IsString, { AnyMem|EsSeg, AnyMem, 0} }, +{"ins", 0, 0x6c, X, Cpu186, bwl_Suf|W|IsString, { 0, 0, 0} }, +{"ins", 2, 0x6c, X, Cpu186, bwl_Suf|W|IsString, { InOutPortReg, AnyMem|EsSeg, 0} }, +{"outs", 0, 0x6e, X, Cpu186, bwl_Suf|W|IsString, { 0, 0, 0} }, +{"outs", 2, 0x6e, X, Cpu186, bwl_Suf|W|IsString, { AnyMem, InOutPortReg, 0} }, +{"lods", 0, 0xac, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"lods", 1, 0xac, X, 0, bwlq_Suf|W|IsString, { AnyMem, 0, 0} }, +{"lods", 2, 0xac, X, 0, bwlq_Suf|W|IsString, { AnyMem, Acc, 0} }, +{"slod", 0, 0xac, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"slod", 1, 0xac, X, 0, bwlq_Suf|W|IsString, { AnyMem, 0, 0} }, +{"slod", 2, 0xac, X, 0, bwlq_Suf|W|IsString, { AnyMem, Acc, 0} }, +{"movs", 0, 0xa4, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"movs", 2, 0xa4, X, 0, bwlq_Suf|W|IsString, { AnyMem, AnyMem|EsSeg, 0} }, +{"smov", 0, 0xa4, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"smov", 2, 0xa4, X, 0, bwlq_Suf|W|IsString, { AnyMem, AnyMem|EsSeg, 0} }, +{"scas", 0, 0xae, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"scas", 1, 0xae, X, 0, bwlq_Suf|W|IsString, { AnyMem|EsSeg, 0, 0} }, +{"scas", 2, 0xae, X, 0, bwlq_Suf|W|IsString, { AnyMem|EsSeg, Acc, 0} }, +{"ssca", 0, 0xae, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"ssca", 1, 0xae, X, 0, bwlq_Suf|W|IsString, { AnyMem|EsSeg, 0, 0} }, +{"ssca", 2, 0xae, X, 0, bwlq_Suf|W|IsString, { AnyMem|EsSeg, Acc, 0} }, +{"stos", 0, 0xaa, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"stos", 1, 0xaa, X, 0, bwlq_Suf|W|IsString, { AnyMem|EsSeg, 0, 0} }, +{"stos", 2, 0xaa, X, 0, bwlq_Suf|W|IsString, { Acc, AnyMem|EsSeg, 0} }, +{"ssto", 0, 0xaa, X, 0, bwlq_Suf|W|IsString, { 0, 0, 0} }, +{"ssto", 1, 0xaa, X, 0, bwlq_Suf|W|IsString, { AnyMem|EsSeg, 0, 0} }, +{"ssto", 2, 0xaa, X, 0, bwlq_Suf|W|IsString, { Acc, AnyMem|EsSeg, 0} }, +{"xlat", 0, 0xd7, X, 0, b_Suf|IsString, { 0, 0, 0} }, +{"xlat", 1, 0xd7, X, 0, b_Suf|IsString, { AnyMem, 0, 0} }, + +/* Bit manipulation. */ +{"bsf", 2, 0x0fbc, X, Cpu386, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"bsr", 2, 0x0fbd, X, Cpu386, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"bt", 2, 0x0fa3, X, Cpu386, wlq_Suf|Modrm, { WordReg, WordReg|WordMem, 0} }, +{"bt", 2, 0x0fba, 4, Cpu386, wlq_Suf|Modrm, { Imm8, WordReg|WordMem, 0} }, +{"btc", 2, 0x0fbb, X, Cpu386, wlq_Suf|Modrm, { WordReg, WordReg|WordMem, 0} }, +{"btc", 2, 0x0fba, 7, Cpu386, wlq_Suf|Modrm, { Imm8, WordReg|WordMem, 0} }, +{"btr", 2, 0x0fb3, X, Cpu386, wlq_Suf|Modrm, { WordReg, WordReg|WordMem, 0} }, +{"btr", 2, 0x0fba, 6, Cpu386, wlq_Suf|Modrm, { Imm8, WordReg|WordMem, 0} }, +{"bts", 2, 0x0fab, X, Cpu386, wlq_Suf|Modrm, { WordReg, WordReg|WordMem, 0} }, +{"bts", 2, 0x0fba, 5, Cpu386, wlq_Suf|Modrm, { Imm8, WordReg|WordMem, 0} }, + +/* Interrupts & op. sys insns. */ +/* See gas/config/tc-i386.c for conversion of 'int $3' into the special + int 3 insn. */ +#define INT_OPCODE 0xcd +#define INT3_OPCODE 0xcc +{"int", 1, 0xcd, X, 0, NoSuf, { Imm8, 0, 0} }, +{"int3", 0, 0xcc, X, 0, NoSuf, { 0, 0, 0} }, +{"into", 0, 0xce, X, 0, NoSuf, { 0, 0, 0} }, +{"iret", 0, 0xcf, X, 0, wlq_Suf|DefaultSize, { 0, 0, 0} }, +/* i386sl, i486sl, later 486, and Pentium. */ +{"rsm", 0, 0x0faa, X, Cpu386, NoSuf, { 0, 0, 0} }, + +{"bound", 2, 0x62, X, Cpu186, wlq_Suf|Modrm, { WordReg, WordMem, 0} }, + +{"hlt", 0, 0xf4, X, 0, NoSuf, { 0, 0, 0} }, +/* nop is actually 'xchgl %eax, %eax'. */ +{"nop", 0, 0x90, X, 0, NoSuf, { 0, 0, 0} }, + +/* Protection control. */ +{"arpl", 2, 0x63, X, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16, Reg16|ShortMem, 0} }, +{"lar", 2, 0x0f02, X, Cpu286, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"lgdt", 1, 0x0f01, 2, Cpu286, wlq_Suf|Modrm, { WordMem, 0, 0} }, +{"lidt", 1, 0x0f01, 3, Cpu286, wlq_Suf|Modrm, { WordMem, 0, 0} }, +{"lldt", 1, 0x0f00, 2, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16|ShortMem, 0, 0} }, +{"lmsw", 1, 0x0f01, 6, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16|ShortMem, 0, 0} }, +{"lsl", 2, 0x0f03, X, Cpu286, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"ltr", 1, 0x0f00, 3, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16|ShortMem, 0, 0} }, + +{"sgdt", 1, 0x0f01, 0, Cpu286, wlq_Suf|Modrm, { WordMem, 0, 0} }, +{"sidt", 1, 0x0f01, 1, Cpu286, wlq_Suf|Modrm, { WordMem, 0, 0} }, +{"sldt", 1, 0x0f00, 0, Cpu286, wlq_Suf|Modrm, { WordReg|InvMem, 0, 0} }, +{"sldt", 1, 0x0f00, 0, Cpu286, w_Suf|Modrm|IgnoreSize,{ ShortMem, 0, 0} }, +{"smsw", 1, 0x0f01, 4, Cpu286, wlq_Suf|Modrm, { WordReg|InvMem, 0, 0} }, +{"smsw", 1, 0x0f01, 4, Cpu286, w_Suf|Modrm|IgnoreSize,{ ShortMem, 0, 0} }, +{"str", 1, 0x0f00, 1, Cpu286, wlq_Suf|Modrm, { WordReg|InvMem, 0, 0} }, +{"str", 1, 0x0f00, 1, Cpu286, w_Suf|Modrm|IgnoreSize,{ ShortMem, 0, 0} }, + +{"verr", 1, 0x0f00, 4, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16|ShortMem, 0, 0} }, +{"verw", 1, 0x0f00, 5, Cpu286, w_Suf|Modrm|IgnoreSize,{ Reg16|ShortMem, 0, 0} }, + +/* Floating point instructions. */ + +/* load */ +{"fld", 1, 0xd9c0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fld", 1, 0xd9, 0, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fld", 1, 0xd9c0, X, 0, l_FP|ShortForm|Ugh, { FloatReg, 0, 0} }, +/* Intel Syntax */ +{"fld", 1, 0xdb, 5, 0, x_FP|Modrm, { LLongMem, 0, 0} }, +{"fild", 1, 0xdf, 0, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, +/* Intel Syntax */ +{"fildd", 1, 0xdf, 5, 0, FP|Modrm, { LLongMem, 0, 0} }, +{"fildq", 1, 0xdf, 5, 0, FP|Modrm, { LLongMem, 0, 0} }, +{"fildll", 1, 0xdf, 5, 0, FP|Modrm, { LLongMem, 0, 0} }, +{"fldt", 1, 0xdb, 5, 0, FP|Modrm, { LLongMem, 0, 0} }, +{"fbld", 1, 0xdf, 4, 0, FP|Modrm, { LLongMem, 0, 0} }, + +/* store (no pop) */ +{"fst", 1, 0xddd0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fst", 1, 0xd9, 2, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fst", 1, 0xddd0, X, 0, l_FP|ShortForm|Ugh, { FloatReg, 0, 0} }, +{"fist", 1, 0xdf, 2, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, + +/* store (with pop) */ +{"fstp", 1, 0xddd8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fstp", 1, 0xd9, 3, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fstp", 1, 0xddd8, X, 0, l_FP|ShortForm|Ugh, { FloatReg, 0, 0} }, +/* Intel Syntax */ +{"fstp", 1, 0xdb, 7, 0, x_FP|Modrm, { LLongMem, 0, 0} }, +{"fistp", 1, 0xdf, 3, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, +/* Intel Syntax */ +{"fistpd", 1, 0xdf, 7, 0, FP|Modrm, { LLongMem, 0, 0} }, +{"fistpq", 1, 0xdf, 7, 0, FP|Modrm, { LLongMem, 0, 0} }, +{"fistpll",1, 0xdf, 7, 0, FP|Modrm, { LLongMem, 0, 0} }, +{"fstpt", 1, 0xdb, 7, 0, FP|Modrm, { LLongMem, 0, 0} }, +{"fbstp", 1, 0xdf, 6, 0, FP|Modrm, { LLongMem, 0, 0} }, + +/* exchange %st with %st0 */ +{"fxch", 1, 0xd9c8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +/* alias for fxch %st(1) */ +{"fxch", 0, 0xd9c9, X, 0, FP, { 0, 0, 0} }, + +/* comparison (without pop) */ +{"fcom", 1, 0xd8d0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +/* alias for fcom %st(1) */ +{"fcom", 0, 0xd8d1, X, 0, FP, { 0, 0, 0} }, +{"fcom", 1, 0xd8, 2, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fcom", 1, 0xd8d0, X, 0, l_FP|ShortForm|Ugh, { FloatReg, 0, 0} }, +{"ficom", 1, 0xde, 2, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, + +/* comparison (with pop) */ +{"fcomp", 1, 0xd8d8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +/* alias for fcomp %st(1) */ +{"fcomp", 0, 0xd8d9, X, 0, FP, { 0, 0, 0} }, +{"fcomp", 1, 0xd8, 3, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fcomp", 1, 0xd8d8, X, 0, l_FP|ShortForm|Ugh, { FloatReg, 0, 0} }, +{"ficomp", 1, 0xde, 3, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, +{"fcompp", 0, 0xded9, X, 0, FP, { 0, 0, 0} }, + +/* unordered comparison (with pop) */ +{"fucom", 1, 0xdde0, X, Cpu286, FP|ShortForm, { FloatReg, 0, 0} }, +/* alias for fucom %st(1) */ +{"fucom", 0, 0xdde1, X, Cpu286, FP, { 0, 0, 0} }, +{"fucomp", 1, 0xdde8, X, Cpu286, FP|ShortForm, { FloatReg, 0, 0} }, +/* alias for fucomp %st(1) */ +{"fucomp", 0, 0xdde9, X, Cpu286, FP, { 0, 0, 0} }, +{"fucompp",0, 0xdae9, X, Cpu286, FP, { 0, 0, 0} }, + +{"ftst", 0, 0xd9e4, X, 0, FP, { 0, 0, 0} }, +{"fxam", 0, 0xd9e5, X, 0, FP, { 0, 0, 0} }, + +/* load constants into %st0 */ +{"fld1", 0, 0xd9e8, X, 0, FP, { 0, 0, 0} }, +{"fldl2t", 0, 0xd9e9, X, 0, FP, { 0, 0, 0} }, +{"fldl2e", 0, 0xd9ea, X, 0, FP, { 0, 0, 0} }, +{"fldpi", 0, 0xd9eb, X, 0, FP, { 0, 0, 0} }, +{"fldlg2", 0, 0xd9ec, X, 0, FP, { 0, 0, 0} }, +{"fldln2", 0, 0xd9ed, X, 0, FP, { 0, 0, 0} }, +{"fldz", 0, 0xd9ee, X, 0, FP, { 0, 0, 0} }, + +/* arithmetic */ + +/* add */ +{"fadd", 2, 0xd8c0, X, 0, FP|ShortForm|FloatD, { FloatReg, FloatAcc, 0} }, +/* alias for fadd %st(i), %st */ +{"fadd", 1, 0xd8c0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +#if SYSV386_COMPAT +/* alias for faddp */ +{"fadd", 0, 0xdec1, X, 0, FP|Ugh, { 0, 0, 0} }, +#endif +{"fadd", 1, 0xd8, 0, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fiadd", 1, 0xde, 0, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, + +{"faddp", 2, 0xdec0, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"faddp", 1, 0xdec0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +/* alias for faddp %st, %st(1) */ +{"faddp", 0, 0xdec1, X, 0, FP, { 0, 0, 0} }, +{"faddp", 2, 0xdec0, X, 0, FP|ShortForm|Ugh, { FloatReg, FloatAcc, 0} }, + +/* subtract */ +{"fsub", 2, 0xd8e0, X, 0, FP|ShortForm|FloatDR, { FloatReg, FloatAcc, 0} }, +{"fsub", 1, 0xd8e0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +#if SYSV386_COMPAT +/* alias for fsubp */ +{"fsub", 0, 0xdee1, X, 0, FP|Ugh, { 0, 0, 0} }, +#endif +{"fsub", 1, 0xd8, 4, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fisub", 1, 0xde, 4, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, + +#if SYSV386_COMPAT +{"fsubp", 2, 0xdee0, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fsubp", 1, 0xdee0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fsubp", 0, 0xdee1, X, 0, FP, { 0, 0, 0} }, +#if OLDGCC_COMPAT +{"fsubp", 2, 0xdee0, X, 0, FP|ShortForm|Ugh, { FloatReg, FloatAcc, 0} }, +#endif +#else +{"fsubp", 2, 0xdee8, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fsubp", 1, 0xdee8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fsubp", 0, 0xdee9, X, 0, FP, { 0, 0, 0} }, +#endif + +/* subtract reverse */ +{"fsubr", 2, 0xd8e8, X, 0, FP|ShortForm|FloatDR, { FloatReg, FloatAcc, 0} }, +{"fsubr", 1, 0xd8e8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +#if SYSV386_COMPAT +/* alias for fsubrp */ +{"fsubr", 0, 0xdee9, X, 0, FP|Ugh, { 0, 0, 0} }, +#endif +{"fsubr", 1, 0xd8, 5, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fisubr", 1, 0xde, 5, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, + +#if SYSV386_COMPAT +{"fsubrp", 2, 0xdee8, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fsubrp", 1, 0xdee8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fsubrp", 0, 0xdee9, X, 0, FP, { 0, 0, 0} }, +#if OLDGCC_COMPAT +{"fsubrp", 2, 0xdee8, X, 0, FP|ShortForm|Ugh, { FloatReg, FloatAcc, 0} }, +#endif +#else +{"fsubrp", 2, 0xdee0, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fsubrp", 1, 0xdee0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fsubrp", 0, 0xdee1, X, 0, FP, { 0, 0, 0} }, +#endif + +/* multiply */ +{"fmul", 2, 0xd8c8, X, 0, FP|ShortForm|FloatD, { FloatReg, FloatAcc, 0} }, +{"fmul", 1, 0xd8c8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +#if SYSV386_COMPAT +/* alias for fmulp */ +{"fmul", 0, 0xdec9, X, 0, FP|Ugh, { 0, 0, 0} }, +#endif +{"fmul", 1, 0xd8, 1, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fimul", 1, 0xde, 1, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, + +{"fmulp", 2, 0xdec8, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fmulp", 1, 0xdec8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fmulp", 0, 0xdec9, X, 0, FP, { 0, 0, 0} }, +{"fmulp", 2, 0xdec8, X, 0, FP|ShortForm|Ugh, { FloatReg, FloatAcc, 0} }, + +/* divide */ +{"fdiv", 2, 0xd8f0, X, 0, FP|ShortForm|FloatDR, { FloatReg, FloatAcc, 0} }, +{"fdiv", 1, 0xd8f0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +#if SYSV386_COMPAT +/* alias for fdivp */ +{"fdiv", 0, 0xdef1, X, 0, FP|Ugh, { 0, 0, 0} }, +#endif +{"fdiv", 1, 0xd8, 6, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fidiv", 1, 0xde, 6, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, + +#if SYSV386_COMPAT +{"fdivp", 2, 0xdef0, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fdivp", 1, 0xdef0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fdivp", 0, 0xdef1, X, 0, FP, { 0, 0, 0} }, +#if OLDGCC_COMPAT +{"fdivp", 2, 0xdef0, X, 0, FP|ShortForm|Ugh, { FloatReg, FloatAcc, 0} }, +#endif +#else +{"fdivp", 2, 0xdef8, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fdivp", 1, 0xdef8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fdivp", 0, 0xdef9, X, 0, FP, { 0, 0, 0} }, +#endif + +/* divide reverse */ +{"fdivr", 2, 0xd8f8, X, 0, FP|ShortForm|FloatDR, { FloatReg, FloatAcc, 0} }, +{"fdivr", 1, 0xd8f8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +#if SYSV386_COMPAT +/* alias for fdivrp */ +{"fdivr", 0, 0xdef9, X, 0, FP|Ugh, { 0, 0, 0} }, +#endif +{"fdivr", 1, 0xd8, 7, 0, sl_FP|FloatMF|Modrm, { LongMem|LLongMem, 0, 0} }, +{"fidivr", 1, 0xde, 7, 0, sl_FP|FloatMF|Modrm, { ShortMem|LongMem, 0, 0} }, + +#if SYSV386_COMPAT +{"fdivrp", 2, 0xdef8, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fdivrp", 1, 0xdef8, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fdivrp", 0, 0xdef9, X, 0, FP, { 0, 0, 0} }, +#if OLDGCC_COMPAT +{"fdivrp", 2, 0xdef8, X, 0, FP|ShortForm|Ugh, { FloatReg, FloatAcc, 0} }, +#endif +#else +{"fdivrp", 2, 0xdef0, X, 0, FP|ShortForm, { FloatAcc, FloatReg, 0} }, +{"fdivrp", 1, 0xdef0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +{"fdivrp", 0, 0xdef1, X, 0, FP, { 0, 0, 0} }, +#endif + +{"f2xm1", 0, 0xd9f0, X, 0, FP, { 0, 0, 0} }, +{"fyl2x", 0, 0xd9f1, X, 0, FP, { 0, 0, 0} }, +{"fptan", 0, 0xd9f2, X, 0, FP, { 0, 0, 0} }, +{"fpatan", 0, 0xd9f3, X, 0, FP, { 0, 0, 0} }, +{"fxtract",0, 0xd9f4, X, 0, FP, { 0, 0, 0} }, +{"fprem1", 0, 0xd9f5, X, Cpu286, FP, { 0, 0, 0} }, +{"fdecstp",0, 0xd9f6, X, 0, FP, { 0, 0, 0} }, +{"fincstp",0, 0xd9f7, X, 0, FP, { 0, 0, 0} }, +{"fprem", 0, 0xd9f8, X, 0, FP, { 0, 0, 0} }, +{"fyl2xp1",0, 0xd9f9, X, 0, FP, { 0, 0, 0} }, +{"fsqrt", 0, 0xd9fa, X, 0, FP, { 0, 0, 0} }, +{"fsincos",0, 0xd9fb, X, Cpu286, FP, { 0, 0, 0} }, +{"frndint",0, 0xd9fc, X, 0, FP, { 0, 0, 0} }, +{"fscale", 0, 0xd9fd, X, 0, FP, { 0, 0, 0} }, +{"fsin", 0, 0xd9fe, X, Cpu286, FP, { 0, 0, 0} }, +{"fcos", 0, 0xd9ff, X, Cpu286, FP, { 0, 0, 0} }, +{"fchs", 0, 0xd9e0, X, 0, FP, { 0, 0, 0} }, +{"fabs", 0, 0xd9e1, X, 0, FP, { 0, 0, 0} }, + +/* processor control */ +{"fninit", 0, 0xdbe3, X, 0, FP, { 0, 0, 0} }, +{"finit", 0, 0xdbe3, X, 0, FP|FWait, { 0, 0, 0} }, +{"fldcw", 1, 0xd9, 5, 0, FP|Modrm, { ShortMem, 0, 0} }, +{"fnstcw", 1, 0xd9, 7, 0, FP|Modrm, { ShortMem, 0, 0} }, +{"fstcw", 1, 0xd9, 7, 0, FP|FWait|Modrm, { ShortMem, 0, 0} }, +{"fnstsw", 1, 0xdfe0, X, 0, FP, { Acc, 0, 0} }, +{"fnstsw", 1, 0xdd, 7, 0, FP|Modrm, { ShortMem, 0, 0} }, +{"fnstsw", 0, 0xdfe0, X, 0, FP, { 0, 0, 0} }, +{"fstsw", 1, 0xdfe0, X, 0, FP|FWait, { Acc, 0, 0} }, +{"fstsw", 1, 0xdd, 7, 0, FP|FWait|Modrm, { ShortMem, 0, 0} }, +{"fstsw", 0, 0xdfe0, X, 0, FP|FWait, { 0, 0, 0} }, +{"fnclex", 0, 0xdbe2, X, 0, FP, { 0, 0, 0} }, +{"fclex", 0, 0xdbe2, X, 0, FP|FWait, { 0, 0, 0} }, +/* Short forms of fldenv, fstenv use data size prefix. */ +{"fnstenv",1, 0xd9, 6, 0, sl_Suf|Modrm, { LLongMem, 0, 0} }, +{"fstenv", 1, 0xd9, 6, 0, sl_Suf|FWait|Modrm, { LLongMem, 0, 0} }, +{"fldenv", 1, 0xd9, 4, 0, sl_Suf|Modrm, { LLongMem, 0, 0} }, +{"fnsave", 1, 0xdd, 6, 0, sl_Suf|Modrm, { LLongMem, 0, 0} }, +{"fsave", 1, 0xdd, 6, 0, sl_Suf|FWait|Modrm, { LLongMem, 0, 0} }, +{"frstor", 1, 0xdd, 4, 0, sl_Suf|Modrm, { LLongMem, 0, 0} }, + +{"ffree", 1, 0xddc0, X, 0, FP|ShortForm, { FloatReg, 0, 0} }, +/* P6:free st(i), pop st */ +{"ffreep", 1, 0xdfc0, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} }, +{"fnop", 0, 0xd9d0, X, 0, FP, { 0, 0, 0} }, +#define FWAIT_OPCODE 0x9b +{"fwait", 0, 0x9b, X, 0, FP, { 0, 0, 0} }, + +/* Opcode prefixes; we allow them as separate insns too. */ + +#define ADDR_PREFIX_OPCODE 0x67 +{"addr16", 0, 0x67, X, Cpu386, NoSuf|IsPrefix|Size16|IgnoreSize, { 0, 0, 0} }, +{"addr32", 0, 0x67, X, Cpu386, NoSuf|IsPrefix|Size32|IgnoreSize, { 0, 0, 0} }, +{"aword", 0, 0x67, X, Cpu386, NoSuf|IsPrefix|Size16|IgnoreSize, { 0, 0, 0} }, +{"adword", 0, 0x67, X, Cpu386, NoSuf|IsPrefix|Size32|IgnoreSize, { 0, 0, 0} }, +#define DATA_PREFIX_OPCODE 0x66 +{"data16", 0, 0x66, X, Cpu386, NoSuf|IsPrefix|Size16|IgnoreSize, { 0, 0, 0} }, +{"data32", 0, 0x66, X, Cpu386, NoSuf|IsPrefix|Size32|IgnoreSize, { 0, 0, 0} }, +{"word", 0, 0x66, X, Cpu386, NoSuf|IsPrefix|Size16|IgnoreSize, { 0, 0, 0} }, +{"dword", 0, 0x66, X, Cpu386, NoSuf|IsPrefix|Size32|IgnoreSize, { 0, 0, 0} }, +#define LOCK_PREFIX_OPCODE 0xf0 +{"lock", 0, 0xf0, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +{"wait", 0, 0x9b, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +#define CS_PREFIX_OPCODE 0x2e +{"cs", 0, 0x2e, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +#define DS_PREFIX_OPCODE 0x3e +{"ds", 0, 0x3e, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +#define ES_PREFIX_OPCODE 0x26 +{"es", 0, 0x26, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +#define FS_PREFIX_OPCODE 0x64 +{"fs", 0, 0x64, X, Cpu386, NoSuf|IsPrefix, { 0, 0, 0} }, +#define GS_PREFIX_OPCODE 0x65 +{"gs", 0, 0x65, X, Cpu386, NoSuf|IsPrefix, { 0, 0, 0} }, +#define SS_PREFIX_OPCODE 0x36 +{"ss", 0, 0x36, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +#define REPNE_PREFIX_OPCODE 0xf2 +#define REPE_PREFIX_OPCODE 0xf3 +{"rep", 0, 0xf3, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +{"repe", 0, 0xf3, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +{"repz", 0, 0xf3, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +{"repne", 0, 0xf2, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +{"repnz", 0, 0xf2, X, 0, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex", 0, 0x40, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rexz", 0, 0x41, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rexy", 0, 0x42, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rexyz", 0, 0x43, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rexx", 0, 0x44, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rexxz", 0, 0x45, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rexxy", 0, 0x46, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rexxyz", 0, 0x47, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex64", 0, 0x48, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex64z", 0, 0x49, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex64y", 0, 0x4a, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex64yz",0, 0x4b, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex64x", 0, 0x4c, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex64xz",0, 0x4d, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex64xy",0, 0x4e, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, +{"rex64xyz",0, 0x4f, X, Cpu64, NoSuf|IsPrefix, { 0, 0, 0} }, + +/* 486 extensions. */ + +{"bswap", 1, 0x0fc8, X, Cpu486, lq_Suf|ShortForm, { Reg32|Reg64, 0, 0 } }, +{"xadd", 2, 0x0fc0, X, Cpu486, bwlq_Suf|W|Modrm, { Reg, Reg|AnyMem, 0 } }, +{"cmpxchg", 2, 0x0fb0, X, Cpu486, bwlq_Suf|W|Modrm, { Reg, Reg|AnyMem, 0 } }, +{"invd", 0, 0x0f08, X, Cpu486, NoSuf, { 0, 0, 0} }, +{"wbinvd", 0, 0x0f09, X, Cpu486, NoSuf, { 0, 0, 0} }, +{"invlpg", 1, 0x0f01, 7, Cpu486, NoSuf|Modrm, { AnyMem, 0, 0} }, + +/* 586 and late 486 extensions. */ +{"cpuid", 0, 0x0fa2, X, Cpu486, NoSuf, { 0, 0, 0} }, + +/* Pentium extensions. */ +{"wrmsr", 0, 0x0f30, X, Cpu586, NoSuf, { 0, 0, 0} }, +{"rdtsc", 0, 0x0f31, X, Cpu586, NoSuf, { 0, 0, 0} }, +{"rdmsr", 0, 0x0f32, X, Cpu586, NoSuf, { 0, 0, 0} }, +{"cmpxchg8b",1,0x0fc7, 1, Cpu586, NoSuf|Modrm, { LLongMem, 0, 0} }, + +/* Pentium II/Pentium Pro extensions. */ +{"sysenter",0, 0x0f34, X, Cpu686|CpuNo64, NoSuf, { 0, 0, 0} }, +{"sysexit", 0, 0x0f35, X, Cpu686|CpuNo64, NoSuf, { 0, 0, 0} }, +{"fxsave", 1, 0x0fae, 0, Cpu686, FP|Modrm, { LLongMem, 0, 0} }, +{"fxrstor", 1, 0x0fae, 1, Cpu686, FP|Modrm, { LLongMem, 0, 0} }, +{"rdpmc", 0, 0x0f33, X, Cpu686, NoSuf, { 0, 0, 0} }, +/* official undefined instr. */ +{"ud2", 0, 0x0f0b, X, Cpu686, NoSuf, { 0, 0, 0} }, +/* alias for ud2 */ +{"ud2a", 0, 0x0f0b, X, Cpu686, NoSuf, { 0, 0, 0} }, +/* 2nd. official undefined instr. */ +{"ud2b", 0, 0x0fb9, X, Cpu686, NoSuf, { 0, 0, 0} }, + +{"cmovo", 2, 0x0f40, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovno", 2, 0x0f41, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovb", 2, 0x0f42, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovc", 2, 0x0f42, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnae", 2, 0x0f42, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovae", 2, 0x0f43, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnc", 2, 0x0f43, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnb", 2, 0x0f43, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmove", 2, 0x0f44, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovz", 2, 0x0f44, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovne", 2, 0x0f45, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnz", 2, 0x0f45, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovbe", 2, 0x0f46, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovna", 2, 0x0f46, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmova", 2, 0x0f47, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnbe", 2, 0x0f47, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovs", 2, 0x0f48, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovns", 2, 0x0f49, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovp", 2, 0x0f4a, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnp", 2, 0x0f4b, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovl", 2, 0x0f4c, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnge", 2, 0x0f4c, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovge", 2, 0x0f4d, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnl", 2, 0x0f4d, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovle", 2, 0x0f4e, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovng", 2, 0x0f4e, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovg", 2, 0x0f4f, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, +{"cmovnle", 2, 0x0f4f, X, Cpu686, wlq_Suf|Modrm, { WordReg|WordMem, WordReg, 0} }, + +{"fcmovb", 2, 0xdac0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovnae",2, 0xdac0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmove", 2, 0xdac8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovbe", 2, 0xdad0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovna", 2, 0xdad0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovu", 2, 0xdad8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovae", 2, 0xdbc0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovnb", 2, 0xdbc0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovne", 2, 0xdbc8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmova", 2, 0xdbd0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovnbe",2, 0xdbd0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcmovnu", 2, 0xdbd8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, + +{"fcomi", 2, 0xdbf0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcomi", 0, 0xdbf1, X, Cpu686, FP|ShortForm, { 0, 0, 0} }, +{"fcomi", 1, 0xdbf0, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} }, +{"fucomi", 2, 0xdbe8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fucomi", 0, 0xdbe9, X, Cpu686, FP|ShortForm, { 0, 0, 0} }, +{"fucomi", 1, 0xdbe8, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} }, +{"fcomip", 2, 0xdff0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcompi", 2, 0xdff0, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fcompi", 0, 0xdff1, X, Cpu686, FP|ShortForm, { 0, 0, 0} }, +{"fcompi", 1, 0xdff0, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} }, +{"fucomip", 2, 0xdfe8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fucompi", 2, 0xdfe8, X, Cpu686, FP|ShortForm, { FloatReg, FloatAcc, 0} }, +{"fucompi", 0, 0xdfe9, X, Cpu686, FP|ShortForm, { 0, 0, 0} }, +{"fucompi", 1, 0xdfe8, X, Cpu686, FP|ShortForm, { FloatReg, 0, 0} }, + +/* Pentium4 extensions. */ + +{"movnti", 2, 0x0fc3, X, CpuP4, FP|Modrm, { WordReg, WordMem, 0 } }, +{"clflush", 1, 0x0fae, 7, CpuP4, FP|Modrm, { ByteMem, 0, 0 } }, +{"lfence", 0, 0x0fae, 0xe8, CpuP4, FP|ImmExt, { 0, 0, 0 } }, +{"mfence", 0, 0x0fae, 0xf0, CpuP4, FP|ImmExt, { 0, 0, 0 } }, +{"pause", 0, 0xf390, X, CpuP4, FP, { 0, 0, 0 } }, + +/* MMX/SSE2 instructions. */ + +{"emms", 0, 0x0f77, X, CpuMMX, FP, { 0, 0, 0 } }, +{"movd", 2, 0x0f6e, X, CpuMMX, FP|Modrm, { Reg32|LongMem, RegMMX, 0 } }, +{"movd", 2, 0x0f7e, X, CpuMMX, FP|Modrm, { RegMMX, Reg32|LongMem, 0 } }, +{"movd", 2, 0x660f6e,X,CpuSSE2,FP|Modrm, { Reg32|LLongMem, RegXMM, 0 } }, +{"movd", 2, 0x660f7e,X,CpuSSE2,FP|Modrm, { RegXMM, Reg32|LLongMem, 0 } }, +/* Real MMX instructions. */ +{"movd", 2, 0x0f6e, X, CpuMMX, FP|Modrm, { Reg64|LLongMem, RegMMX, 0 } }, +{"movd", 2, 0x0f7e, X, CpuMMX, FP|Modrm, { RegMMX, Reg64|LLongMem, 0 } }, +{"movd", 2, 0x660f6e,X,CpuSSE2,FP|Modrm, { Reg64|LLongMem, RegXMM, 0 } }, +{"movd", 2, 0x660f7e,X,CpuSSE2,FP|Modrm, { RegXMM, Reg64|LLongMem, 0 } }, +/* In the 64bit mode the short form mov immediate is redefined to have + 64bit displacement value. */ +{"movq", 2, 0x0f6f, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"movq", 2, 0x0f7f, X, CpuMMX, FP|Modrm, { RegMMX, RegMMX|LongMem, 0 } }, +{"movq", 2, 0xf30f7e,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"movq", 2, 0x660fd6,X,CpuSSE2,FP|Modrm, { RegXMM, RegXMM|LLongMem, 0 } }, +{"movq", 2, 0x88, X, Cpu64, NoSuf|D|W|Modrm|Size64,{ Reg64, Reg64|AnyMem, 0 } }, +{"movq", 2, 0xc6, 0, Cpu64, NoSuf|W|Modrm|Size64, { Imm32S, Reg64|WordMem, 0 } }, +{"movq", 2, 0xb0, X, Cpu64, NoSuf|W|ShortForm|Size64,{ Imm64, Reg64, 0 } }, +/* Move to/from control debug registers. In the 16 or 32bit modes they are 32bit. In the 64bit + mode they are 64bit.*/ +{"movq", 2, 0x0f20, X, Cpu64, NoSuf|D|Modrm|IgnoreSize|NoRex64|Size64,{ Control, Reg64|InvMem, 0} }, +{"movq", 2, 0x0f21, X, Cpu64, NoSuf|D|Modrm|IgnoreSize|NoRex64|Size64,{ Debug, Reg64|InvMem, 0} }, +{"packssdw", 2, 0x0f6b, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"packssdw", 2, 0x660f6b,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"packsswb", 2, 0x0f63, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"packsswb", 2, 0x660f63,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"packuswb", 2, 0x0f67, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"packuswb", 2, 0x660f67,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"paddb", 2, 0x0ffc, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"paddb", 2, 0x660ffc,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"paddw", 2, 0x0ffd, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"paddw", 2, 0x660ffd,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"paddd", 2, 0x0ffe, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"paddd", 2, 0x660ffe,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"paddq", 2, 0x0fd4, X, CpuMMX, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"paddq", 2, 0x660fd4,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"paddsb", 2, 0x0fec, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"paddsb", 2, 0x660fec,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"paddsw", 2, 0x0fed, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"paddsw", 2, 0x660fed,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"paddusb", 2, 0x0fdc, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"paddusb", 2, 0x660fdc,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"paddusw", 2, 0x0fdd, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"paddusw", 2, 0x660fdd,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pand", 2, 0x0fdb, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pand", 2, 0x660fdb,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pandn", 2, 0x0fdf, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pandn", 2, 0x660fdf,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pcmpeqb", 2, 0x0f74, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pcmpeqb", 2, 0x660f74,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pcmpeqw", 2, 0x0f75, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pcmpeqw", 2, 0x660f75,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pcmpeqd", 2, 0x0f76, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pcmpeqd", 2, 0x660f76,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pcmpgtb", 2, 0x0f64, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pcmpgtb", 2, 0x660f64,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pcmpgtw", 2, 0x0f65, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pcmpgtw", 2, 0x660f65,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pcmpgtd", 2, 0x0f66, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pcmpgtd", 2, 0x660f66,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pmaddwd", 2, 0x0ff5, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pmaddwd", 2, 0x660ff5,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pmulhw", 2, 0x0fe5, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pmulhw", 2, 0x660fe5,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pmullw", 2, 0x0fd5, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pmullw", 2, 0x660fd5,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"por", 2, 0x0feb, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"por", 2, 0x660feb,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psllw", 2, 0x0ff1, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psllw", 2, 0x660ff1,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psllw", 2, 0x0f71, 6, CpuMMX, FP|Modrm, { Imm8, RegMMX, 0 } }, +{"psllw", 2, 0x660f71,6,CpuSSE2,FP|Modrm, { Imm8, RegXMM, 0 } }, +{"pslld", 2, 0x0ff2, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pslld", 2, 0x660ff2,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pslld", 2, 0x0f72, 6, CpuMMX, FP|Modrm, { Imm8, RegMMX, 0 } }, +{"pslld", 2, 0x660f72,6,CpuSSE2,FP|Modrm, { Imm8, RegXMM, 0 } }, +{"psllq", 2, 0x0ff3, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psllq", 2, 0x660ff3,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psllq", 2, 0x0f73, 6, CpuMMX, FP|Modrm, { Imm8, RegMMX, 0 } }, +{"psllq", 2, 0x660f73,6,CpuSSE2,FP|Modrm, { Imm8, RegXMM, 0 } }, +{"psraw", 2, 0x0fe1, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psraw", 2, 0x660fe1,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psraw", 2, 0x0f71, 4, CpuMMX, FP|Modrm, { Imm8, RegMMX, 0 } }, +{"psraw", 2, 0x660f71,4,CpuSSE2,FP|Modrm, { Imm8, RegXMM, 0 } }, +{"psrad", 2, 0x0fe2, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psrad", 2, 0x660fe2,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psrad", 2, 0x0f72, 4, CpuMMX, FP|Modrm, { Imm8, RegMMX, 0 } }, +{"psrad", 2, 0x660f72,4,CpuSSE2,FP|Modrm, { Imm8, RegXMM, 0 } }, +{"psrlw", 2, 0x0fd1, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psrlw", 2, 0x660fd1,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psrlw", 2, 0x0f71, 2, CpuMMX, FP|Modrm, { Imm8, RegMMX, 0 } }, +{"psrlw", 2, 0x660f71,2,CpuSSE2,FP|Modrm, { Imm8, RegXMM, 0 } }, +{"psrld", 2, 0x0fd2, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psrld", 2, 0x660fd2,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psrld", 2, 0x0f72, 2, CpuMMX, FP|Modrm, { Imm8, RegMMX, 0 } }, +{"psrld", 2, 0x660f72,2,CpuSSE2,FP|Modrm, { Imm8, RegXMM, 0 } }, +{"psrlq", 2, 0x0fd3, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psrlq", 2, 0x660fd3,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psrlq", 2, 0x0f73, 2, CpuMMX, FP|Modrm, { Imm8, RegMMX, 0 } }, +{"psrlq", 2, 0x660f73,2,CpuSSE2,FP|Modrm, { Imm8, RegXMM, 0 } }, +{"psubb", 2, 0x0ff8, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psubb", 2, 0x660ff8,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psubw", 2, 0x0ff9, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psubw", 2, 0x660ff9,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psubd", 2, 0x0ffa, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psubd", 2, 0x660ffa,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psubq", 2, 0x0ffb, X, CpuMMX, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"psubq", 2, 0x660ffb,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psubsb", 2, 0x0fe8, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psubsb", 2, 0x660fe8,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psubsw", 2, 0x0fe9, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psubsw", 2, 0x660fe9,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psubusb", 2, 0x0fd8, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psubusb", 2, 0x660fd8,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"psubusw", 2, 0x0fd9, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"psubusw", 2, 0x660fd9,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"punpckhbw",2, 0x0f68, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"punpckhbw",2, 0x660f68,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"punpckhwd",2, 0x0f69, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"punpckhwd",2, 0x660f69,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"punpckhdq",2, 0x0f6a, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"punpckhdq",2, 0x660f6a,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"punpcklbw",2, 0x0f60, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"punpcklbw",2, 0x660f60,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"punpcklwd",2, 0x0f61, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"punpcklwd",2, 0x660f61,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"punpckldq",2, 0x0f62, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"punpckldq",2, 0x660f62,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pxor", 2, 0x0fef, X, CpuMMX, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pxor", 2, 0x660fef,X,CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, + +/* PIII Katmai New Instructions / SIMD instructions. */ + +{"addps", 2, 0x0f58, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"addss", 2, 0xf30f58, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"andnps", 2, 0x0f55, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"andps", 2, 0x0f54, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpeqps", 2, 0x0fc2, 0, CpuSSE, FP|Modrm|ImmExt, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpeqss", 2, 0xf30fc2, 0, CpuSSE, FP|Modrm|ImmExt, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpleps", 2, 0x0fc2, 2, CpuSSE, FP|Modrm|ImmExt, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpless", 2, 0xf30fc2, 2, CpuSSE, FP|Modrm|ImmExt, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpltps", 2, 0x0fc2, 1, CpuSSE, FP|Modrm|ImmExt, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpltss", 2, 0xf30fc2, 1, CpuSSE, FP|Modrm|ImmExt, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpneqps", 2, 0x0fc2, 4, CpuSSE, FP|Modrm|ImmExt, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpneqss", 2, 0xf30fc2, 4, CpuSSE, FP|Modrm|ImmExt, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpnleps", 2, 0x0fc2, 6, CpuSSE, FP|Modrm|ImmExt, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpnless", 2, 0xf30fc2, 6, CpuSSE, FP|Modrm|ImmExt, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpnltps", 2, 0x0fc2, 5, CpuSSE, FP|Modrm|ImmExt, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpnltss", 2, 0xf30fc2, 5, CpuSSE, FP|Modrm|ImmExt, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpordps", 2, 0x0fc2, 7, CpuSSE, FP|Modrm|ImmExt, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpordss", 2, 0xf30fc2, 7, CpuSSE, FP|Modrm|ImmExt, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpunordps",2, 0x0fc2, 3, CpuSSE, FP|Modrm|ImmExt, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpunordss",2, 0xf30fc2, 3, CpuSSE, FP|Modrm|ImmExt, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpps", 3, 0x0fc2, X, CpuSSE, FP|Modrm, { Imm8, RegXMM|LLongMem, RegXMM } }, +{"cmpss", 3, 0xf30fc2, X, CpuSSE, FP|Modrm, { Imm8, RegXMM|WordMem, RegXMM } }, +{"comiss", 2, 0x0f2f, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"cvtpi2ps", 2, 0x0f2a, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegXMM, 0 } }, +{"cvtps2pi", 2, 0x0f2d, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegMMX, 0 } }, +{"cvtsi2ss", 2, 0xf30f2a, X, CpuSSE, lq_Suf|IgnoreSize|Modrm,{ Reg32|Reg64|WordMem|LLongMem, RegXMM, 0 } }, +{"cvtss2si", 2, 0xf30f2d, X, CpuSSE, lq_Suf|IgnoreSize|Modrm,{ RegXMM|WordMem, Reg32|Reg64, 0 } }, +{"cvttps2pi", 2, 0x0f2c, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegMMX, 0 } }, +{"cvttss2si", 2, 0xf30f2c, X, CpuSSE, lq_Suf|IgnoreSize|Modrm, { RegXMM|WordMem, Reg32|Reg64, 0 } }, +{"divps", 2, 0x0f5e, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"divss", 2, 0xf30f5e, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"ldmxcsr", 1, 0x0fae, 2, CpuSSE, FP|Modrm, { WordMem, 0, 0 } }, +{"maskmovq", 2, 0x0ff7, X, CpuSSE, FP|Modrm, { RegMMX|InvMem, RegMMX, 0 } }, +{"maxps", 2, 0x0f5f, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"maxss", 2, 0xf30f5f, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"minps", 2, 0x0f5d, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"minss", 2, 0xf30f5d, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"movaps", 2, 0x0f28, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"movaps", 2, 0x0f29, X, CpuSSE, FP|Modrm, { RegXMM, RegXMM|LLongMem, 0 } }, +{"movhlps", 2, 0x0f12, X, CpuSSE, FP|Modrm, { RegXMM|InvMem, RegXMM, 0 } }, +{"movhps", 2, 0x0f16, X, CpuSSE, FP|Modrm, { LLongMem, RegXMM, 0 } }, +{"movhps", 2, 0x0f17, X, CpuSSE, FP|Modrm, { RegXMM, LLongMem, 0 } }, +{"movlhps", 2, 0x0f16, X, CpuSSE, FP|Modrm, { RegXMM|InvMem, RegXMM, 0 } }, +{"movlps", 2, 0x0f12, X, CpuSSE, FP|Modrm, { LLongMem, RegXMM, 0 } }, +{"movlps", 2, 0x0f13, X, CpuSSE, FP|Modrm, { RegXMM, LLongMem, 0 } }, +{"movmskps", 2, 0x0f50, X, CpuSSE, lq_Suf|IgnoreSize|Modrm, { RegXMM|InvMem, Reg32|Reg64, 0 } }, +{"movntps", 2, 0x0f2b, X, CpuSSE, FP|Modrm, { RegXMM, LLongMem, 0 } }, +{"movntq", 2, 0x0fe7, X, CpuSSE, FP|Modrm, { RegMMX, LLongMem, 0 } }, +{"movntdq", 2, 0x660fe7, X, CpuSSE2,FP|Modrm, { RegXMM, LLongMem, 0 } }, +{"movss", 2, 0xf30f10, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"movss", 2, 0xf30f11, X, CpuSSE, FP|Modrm, { RegXMM, RegXMM|WordMem, 0 } }, +{"movups", 2, 0x0f10, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"movups", 2, 0x0f11, X, CpuSSE, FP|Modrm, { RegXMM, RegXMM|LLongMem, 0 } }, +{"mulps", 2, 0x0f59, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"mulss", 2, 0xf30f59, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"orps", 2, 0x0f56, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pavgb", 2, 0x0fe0, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"pavgb", 2, 0x660fe0, X, CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pavgw", 2, 0x0fe3, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"pavgw", 2, 0x660fe3, X, CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pextrw", 3, 0x0fc5, X, CpuSSE, lq_Suf|IgnoreSize|Modrm, { Imm8, RegMMX|InvMem, Reg32|Reg64 } }, +{"pextrw", 3, 0x660fc5, X, CpuSSE2,lq_Suf|IgnoreSize|Modrm, { Imm8, RegXMM|InvMem, Reg32|Reg64 } }, +{"pinsrw", 3, 0x0fc4, X, CpuSSE, lq_Suf|IgnoreSize|Modrm, { Imm8, Reg32|Reg64|ShortMem, RegMMX } }, +{"pinsrw", 3, 0x660fc4, X, CpuSSE2, lq_Suf|IgnoreSize|Modrm, { Imm8, Reg32|Reg64|ShortMem, RegXMM } }, +{"pmaxsw", 2, 0x0fee, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"pmaxsw", 2, 0x660fee, X, CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pmaxub", 2, 0x0fde, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"pmaxub", 2, 0x660fde, X, CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pminsw", 2, 0x0fea, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"pminsw", 2, 0x660fea, X, CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pminub", 2, 0x0fda, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"pminub", 2, 0x660fda, X, CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pmovmskb", 2, 0x0fd7, X, CpuSSE, lq_Suf|IgnoreSize|Modrm, { RegMMX|InvMem, Reg32|Reg64, 0 } }, +{"pmovmskb", 2, 0x660fd7, X, CpuSSE2,lq_Suf|IgnoreSize|Modrm, { RegXMM|InvMem, Reg32|Reg64, 0 } }, +{"pmulhuw", 2, 0x0fe4, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"pmulhuw", 2, 0x660fe4, X, CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"prefetchnta", 1, 0x0f18, 0, CpuSSE, FP|Modrm, { LLongMem, 0, 0 } }, +{"prefetcht0", 1, 0x0f18, 1, CpuSSE, FP|Modrm, { LLongMem, 0, 0 } }, +{"prefetcht1", 1, 0x0f18, 2, CpuSSE, FP|Modrm, { LLongMem, 0, 0 } }, +{"prefetcht2", 1, 0x0f18, 3, CpuSSE, FP|Modrm, { LLongMem, 0, 0 } }, +{"psadbw", 2, 0x0ff6, X, CpuSSE, FP|Modrm, { RegMMX|LLongMem, RegMMX, 0 } }, +{"psadbw", 2, 0x660ff6, X, CpuSSE2,FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"pshufw", 3, 0x0f70, X, CpuSSE, FP|Modrm, { Imm8, RegMMX|LLongMem, RegMMX } }, +{"rcpps", 2, 0x0f53, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"rcpss", 2, 0xf30f53, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"rsqrtps", 2, 0x0f52, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"rsqrtss", 2, 0xf30f52, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"sfence", 0, 0x0fae, 0xf8, CpuSSE, FP|ImmExt, { 0, 0, 0 } }, +{"shufps", 3, 0x0fc6, X, CpuSSE, FP|Modrm, { Imm8, RegXMM|LLongMem, RegXMM } }, +{"sqrtps", 2, 0x0f51, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"sqrtss", 2, 0xf30f51, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"stmxcsr", 1, 0x0fae, 3, CpuSSE, FP|Modrm, { WordMem, 0, 0 } }, +{"subps", 2, 0x0f5c, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"subss", 2, 0xf30f5c, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"ucomiss", 2, 0x0f2e, X, CpuSSE, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"unpckhps", 2, 0x0f15, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"unpcklps", 2, 0x0f14, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"xorps", 2, 0x0f57, X, CpuSSE, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, + +/* SSE-2 instructions. */ + +{"addpd", 2, 0x660f58, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"addsd", 2, 0xf20f58, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"andnpd", 2, 0x660f55, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"andpd", 2, 0x660f54, X, CpuSSE2, FP|Modrm, { RegXMM|WordMem, RegXMM, 0 } }, +{"cmpeqpd", 2, 0x660fc2, 0, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpeqsd", 2, 0xf20fc2, 0, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LongMem, RegXMM, 0 } }, +{"cmplepd", 2, 0x660fc2, 2, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LLongMem, RegXMM, 0 } }, +{"cmplesd", 2, 0xf20fc2, 2, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LongMem, RegXMM, 0 } }, +{"cmpltpd", 2, 0x660fc2, 1, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpltsd", 2, 0xf20fc2, 1, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LongMem, RegXMM, 0 } }, +{"cmpneqpd", 2, 0x660fc2, 4, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpneqsd", 2, 0xf20fc2, 4, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LongMem, RegXMM, 0 } }, +{"cmpnlepd", 2, 0x660fc2, 6, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpnlesd", 2, 0xf20fc2, 6, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LongMem, RegXMM, 0 } }, +{"cmpnltpd", 2, 0x660fc2, 5, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpnltsd", 2, 0xf20fc2, 5, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LongMem, RegXMM, 0 } }, +{"cmpordpd", 2, 0x660fc2, 7, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpordsd", 2, 0xf20fc2, 7, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LongMem, RegXMM, 0 } }, +{"cmpunordpd",2, 0x660fc2, 3, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LLongMem, RegXMM, 0 } }, +{"cmpunordsd",2, 0xf20fc2, 3, CpuSSE2, FP|Modrm|ImmExt,{ RegXMM|LongMem, RegXMM, 0 } }, +{"cmppd", 3, 0x660fc2, X, CpuSSE2, FP|Modrm, { Imm8, RegXMM|LLongMem, RegXMM } }, +/* Intel mode string compare. */ +{"cmpsd", 0, 0xa7, X, 0, NoSuf|Size32|IsString, { 0, 0, 0} }, +{"cmpsd", 2, 0xa7, X, 0, NoSuf|Size32|IsString, { AnyMem, AnyMem|EsSeg, 0} }, +{"cmpsd", 3, 0xf20fc2, X, CpuSSE2, FP|Modrm, { Imm8, RegXMM|LongMem, RegXMM } }, +{"comisd", 2, 0x660f2f, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"cvtpi2pd", 2, 0x660f2a, X, CpuSSE2, FP|Modrm, { RegMMX|LLongMem, RegXMM, 0 } }, +{"cvtsi2sd", 2, 0xf20f2a, X, CpuSSE2, lq_Suf|IgnoreSize|Modrm,{ Reg32|Reg64|WordMem|LLongMem, RegXMM, 0 } }, +{"divpd", 2, 0x660f5e, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"divsd", 2, 0xf20f5e, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"maxpd", 2, 0x660f5f, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"maxsd", 2, 0xf20f5f, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"minpd", 2, 0x660f5d, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"minsd", 2, 0xf20f5d, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"movapd", 2, 0x660f28, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"movapd", 2, 0x660f29, X, CpuSSE2, FP|Modrm, { RegXMM, RegXMM|LLongMem, 0 } }, +{"movhpd", 2, 0x660f16, X, CpuSSE2, FP|Modrm, { LLongMem, RegXMM, 0 } }, +{"movhpd", 2, 0x660f17, X, CpuSSE2, FP|Modrm, { RegXMM, LLongMem, 0 } }, +{"movlpd", 2, 0x660f12, X, CpuSSE2, FP|Modrm, { LLongMem, RegXMM, 0 } }, +{"movlpd", 2, 0x660f13, X, CpuSSE2, FP|Modrm, { RegXMM, LLongMem, 0 } }, +{"movmskpd", 2, 0x660f50, X, CpuSSE2, lq_Suf|IgnoreSize|Modrm, { RegXMM|InvMem, Reg32|Reg64, 0 } }, +{"movntpd", 2, 0x660f2b, X, CpuSSE2, FP|Modrm, { RegXMM, LLongMem, 0 } }, +/* Intel mode string move. */ +{"movsd", 0, 0xa5, X, 0, NoSuf|Size32|IsString, { 0, 0, 0} }, +{"movsd", 2, 0xa5, X, 0, NoSuf|Size32|IsString, { AnyMem, AnyMem|EsSeg, 0} }, +{"movsd", 2, 0xf20f10, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"movsd", 2, 0xf20f11, X, CpuSSE2, FP|Modrm, { RegXMM, RegXMM|LongMem, 0 } }, +{"movupd", 2, 0x660f10, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"movupd", 2, 0x660f11, X, CpuSSE2, FP|Modrm, { RegXMM, RegXMM|LLongMem, 0 } }, +{"mulpd", 2, 0x660f59, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"mulsd", 2, 0xf20f59, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"orpd", 2, 0x660f56, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"shufpd", 3, 0x660fc6, X, CpuSSE2, FP|Modrm, { Imm8, RegXMM|LLongMem, RegXMM } }, +{"sqrtpd", 2, 0x660f51, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"sqrtsd", 2, 0xf20f51, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"subpd", 2, 0x660f5c, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"subsd", 2, 0xf20f5c, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"ucomisd", 2, 0x660f2e, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"unpckhpd", 2, 0x660f15, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"unpcklpd", 2, 0x660f14, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"xorpd", 2, 0x660f57, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvtdq2pd", 2, 0xf30fe6, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvtpd2dq", 2, 0xf20fe6, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvtdq2ps", 2, 0x0f5b, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvtpd2pi", 2, 0x660f2d, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegMMX, 0 } }, +{"cvtpd2ps", 2, 0x660f5a, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvtps2pd", 2, 0x0f5a, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvtps2dq", 2, 0x660f5b, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvtsd2si", 2, 0xf20f2d, X, CpuSSE2, lq_Suf|IgnoreSize|Modrm,{ RegXMM|LLongMem, Reg32|Reg64, 0 } }, +{"cvtsd2ss", 2, 0xf20f5a, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvtss2sd", 2, 0xf30f5a, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvttpd2pi", 2, 0x660f2c, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegMMX, 0 } }, +{"cvttsd2si", 2, 0xf20f2c, X, CpuSSE2, lq_Suf|IgnoreSize|Modrm,{ RegXMM|WordMem, Reg32|Reg64, 0 } }, +{"cvttpd2dq", 2, 0x660fe6, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"cvttps2dq", 2, 0xf30f5b, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"maskmovdqu",2, 0x660ff7, X, CpuSSE2, FP|Modrm, { RegXMM|InvMem, RegXMM, 0 } }, +{"movdqa", 2, 0x660f6f, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"movdqa", 2, 0x660f7f, X, CpuSSE2, FP|Modrm, { RegXMM, RegXMM|LLongMem, 0 } }, +{"movdqu", 2, 0xf30f6f, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"movdqu", 2, 0xf30f7f, X, CpuSSE2, FP|Modrm, { RegXMM, RegXMM|LLongMem, 0 } }, +{"movdq2q", 2, 0xf20fd6, X, CpuSSE2, FP|Modrm, { RegXMM|InvMem, RegMMX, 0 } }, +{"movq2dq", 2, 0xf30fd6, X, CpuSSE2, FP|Modrm, { RegMMX|InvMem, RegXMM, 0 } }, +{"pmuludq", 2, 0x0ff4, X, CpuSSE2, FP|Modrm, { RegMMX|LongMem, RegMMX, 0 } }, +{"pmuludq", 2, 0x660ff4, X, CpuSSE2, FP|Modrm, { RegXMM|LongMem, RegXMM, 0 } }, +{"pshufd", 3, 0x660f70, X, CpuSSE2, FP|Modrm, { Imm8, RegXMM|LLongMem, RegXMM } }, +{"pshufhw", 3, 0xf30f70, X, CpuSSE2, FP|Modrm, { Imm8, RegXMM|LLongMem, RegXMM } }, +{"pshuflw", 3, 0xf20f70, X, CpuSSE2, FP|Modrm, { Imm8, RegXMM|LLongMem, RegXMM } }, +{"pslldq", 2, 0x660f73, 7, CpuSSE2, FP|Modrm, { Imm8, RegXMM, 0 } }, +{"psrldq", 2, 0x660f73, 3, CpuSSE2, FP|Modrm, { Imm8, RegXMM, 0 } }, +{"punpckhqdq",2, 0x660f6d, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, +{"punpcklqdq",2, 0x660f6c, X, CpuSSE2, FP|Modrm, { RegXMM|LLongMem, RegXMM, 0 } }, + +/* AMD 3DNow! instructions. */ + +{"prefetch", 1, 0x0f0d, 0, Cpu3dnow, FP|Modrm, { ByteMem, 0, 0 } }, +{"prefetchw",1, 0x0f0d, 1, Cpu3dnow, FP|Modrm, { ByteMem, 0, 0 } }, +{"femms", 0, 0x0f0e, X, Cpu3dnow, FP, { 0, 0, 0 } }, +{"pavgusb", 2, 0x0f0f, 0xbf, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pf2id", 2, 0x0f0f, 0x1d, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pf2iw", 2, 0x0f0f, 0x1c, Cpu3dnow|Cpu686, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfacc", 2, 0x0f0f, 0xae, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfadd", 2, 0x0f0f, 0x9e, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfcmpeq", 2, 0x0f0f, 0xb0, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfcmpge", 2, 0x0f0f, 0x90, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfcmpgt", 2, 0x0f0f, 0xa0, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfmax", 2, 0x0f0f, 0xa4, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfmin", 2, 0x0f0f, 0x94, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfmul", 2, 0x0f0f, 0xb4, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfnacc", 2, 0x0f0f, 0x8a, Cpu3dnow|Cpu686, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfpnacc", 2, 0x0f0f, 0x8e, Cpu3dnow|Cpu686, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfrcp", 2, 0x0f0f, 0x96, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfrcpit1", 2, 0x0f0f, 0xa6, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfrcpit2", 2, 0x0f0f, 0xb6, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfrsqit1", 2, 0x0f0f, 0xa7, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfrsqrt", 2, 0x0f0f, 0x97, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfsub", 2, 0x0f0f, 0x9a, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pfsubr", 2, 0x0f0f, 0xaa, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pi2fd", 2, 0x0f0f, 0x0d, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pi2fw", 2, 0x0f0f, 0x0c, Cpu3dnow|Cpu686, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pmulhrw", 2, 0x0f0f, 0xb7, Cpu3dnow, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, +{"pswapd", 2, 0x0f0f, 0xbb, Cpu3dnow|Cpu686, FP|Modrm|ImmExt, { RegMMX|LongMem, RegMMX, 0 } }, + +/* AMD extensions. */ +{"syscall", 0, 0x0f05, X, CpuK6, NoSuf, { 0, 0, 0} }, +{"sysret", 0, 0x0f07, X, CpuK6, lq_Suf|DefaultSize, { 0, 0, 0} }, +{"swapgs", 0, 0x0f01, 0xf8, Cpu64, NoSuf|ImmExt, { 0, 0, 0} }, + +/* sentinel */ +{NULL, 0, 0, 0, 0, 0, { 0, 0, 0} } +}; +#undef X +#undef NoSuf +#undef b_Suf +#undef w_Suf +#undef l_Suf +#undef q_Suf +#undef x_Suf +#undef bw_Suf +#undef bl_Suf +#undef wl_Suf +#undef wlq_Suf +#undef sl_Suf +#undef bwl_Suf +#undef bwlq_Suf +#undef FP +#undef l_FP +#undef x_FP +#undef sl_FP + +#define MAX_MNEM_SIZE 16 /* for parsing insn mnemonics from input */ + + +/* 386 register table. */ + +static const reg_entry i386_regtab[] = { + /* make %st first as we test for it */ + {"st", FloatReg|FloatAcc, 0, 0}, + /* 8 bit regs */ +#define REGNAM_AL 1 /* Entry in i386_regtab. */ + {"al", Reg8|Acc, 0, 0}, + {"cl", Reg8|ShiftCount, 0, 1}, + {"dl", Reg8, 0, 2}, + {"bl", Reg8, 0, 3}, + {"ah", Reg8, 0, 4}, + {"ch", Reg8, 0, 5}, + {"dh", Reg8, 0, 6}, + {"bh", Reg8, 0, 7}, + {"axl", Reg8|Acc, RegRex64, 0}, /* Must be in the "al + 8" slot. */ + {"cxl", Reg8, RegRex64, 1}, + {"dxl", Reg8, RegRex64, 2}, + {"bxl", Reg8, RegRex64, 3}, + {"spl", Reg8, RegRex64, 4}, + {"bpl", Reg8, RegRex64, 5}, + {"sil", Reg8, RegRex64, 6}, + {"dil", Reg8, RegRex64, 7}, + {"r8b", Reg8, RegRex64|RegRex, 0}, + {"r9b", Reg8, RegRex64|RegRex, 1}, + {"r10b", Reg8, RegRex64|RegRex, 2}, + {"r11b", Reg8, RegRex64|RegRex, 3}, + {"r12b", Reg8, RegRex64|RegRex, 4}, + {"r13b", Reg8, RegRex64|RegRex, 5}, + {"r14b", Reg8, RegRex64|RegRex, 6}, + {"r15b", Reg8, RegRex64|RegRex, 7}, + /* 16 bit regs */ +#define REGNAM_AX 25 + {"ax", Reg16|Acc, 0, 0}, + {"cx", Reg16, 0, 1}, + {"dx", Reg16|InOutPortReg, 0, 2}, + {"bx", Reg16|BaseIndex, 0, 3}, + {"sp", Reg16, 0, 4}, + {"bp", Reg16|BaseIndex, 0, 5}, + {"si", Reg16|BaseIndex, 0, 6}, + {"di", Reg16|BaseIndex, 0, 7}, + {"r8w", Reg16, RegRex, 0}, + {"r9w", Reg16, RegRex, 1}, + {"r10w", Reg16, RegRex, 2}, + {"r11w", Reg16, RegRex, 3}, + {"r12w", Reg16, RegRex, 4}, + {"r13w", Reg16, RegRex, 5}, + {"r14w", Reg16, RegRex, 6}, + {"r15w", Reg16, RegRex, 7}, + /* 32 bit regs */ +#define REGNAM_EAX 41 + {"eax", Reg32|BaseIndex|Acc, 0, 0}, /* Must be in ax + 16 slot */ + {"ecx", Reg32|BaseIndex, 0, 1}, + {"edx", Reg32|BaseIndex, 0, 2}, + {"ebx", Reg32|BaseIndex, 0, 3}, + {"esp", Reg32, 0, 4}, + {"ebp", Reg32|BaseIndex, 0, 5}, + {"esi", Reg32|BaseIndex, 0, 6}, + {"edi", Reg32|BaseIndex, 0, 7}, + {"r8d", Reg32|BaseIndex, RegRex, 0}, + {"r9d", Reg32|BaseIndex, RegRex, 1}, + {"r10d", Reg32|BaseIndex, RegRex, 2}, + {"r11d", Reg32|BaseIndex, RegRex, 3}, + {"r12d", Reg32|BaseIndex, RegRex, 4}, + {"r13d", Reg32|BaseIndex, RegRex, 5}, + {"r14d", Reg32|BaseIndex, RegRex, 6}, + {"r15d", Reg32|BaseIndex, RegRex, 7}, + {"rax", Reg64|BaseIndex|Acc, 0, 0}, + {"rcx", Reg64|BaseIndex, 0, 1}, + {"rdx", Reg64|BaseIndex, 0, 2}, + {"rbx", Reg64|BaseIndex, 0, 3}, + {"rsp", Reg64, 0, 4}, + {"rbp", Reg64|BaseIndex, 0, 5}, + {"rsi", Reg64|BaseIndex, 0, 6}, + {"rdi", Reg64|BaseIndex, 0, 7}, + {"r8", Reg64|BaseIndex, RegRex, 0}, + {"r9", Reg64|BaseIndex, RegRex, 1}, + {"r10", Reg64|BaseIndex, RegRex, 2}, + {"r11", Reg64|BaseIndex, RegRex, 3}, + {"r12", Reg64|BaseIndex, RegRex, 4}, + {"r13", Reg64|BaseIndex, RegRex, 5}, + {"r14", Reg64|BaseIndex, RegRex, 6}, + {"r15", Reg64|BaseIndex, RegRex, 7}, + /* segment registers */ + {"es", SReg2, 0, 0}, + {"cs", SReg2, 0, 1}, + {"ss", SReg2, 0, 2}, + {"ds", SReg2, 0, 3}, + {"fs", SReg3, 0, 4}, + {"gs", SReg3, 0, 5}, + /* control registers */ + {"cr0", Control, 0, 0}, + {"cr1", Control, 0, 1}, + {"cr2", Control, 0, 2}, + {"cr3", Control, 0, 3}, + {"cr4", Control, 0, 4}, + {"cr5", Control, 0, 5}, + {"cr6", Control, 0, 6}, + {"cr7", Control, 0, 7}, + {"cr8", Control, RegRex, 0}, + {"cr9", Control, RegRex, 1}, + {"cr10", Control, RegRex, 2}, + {"cr11", Control, RegRex, 3}, + {"cr12", Control, RegRex, 4}, + {"cr13", Control, RegRex, 5}, + {"cr14", Control, RegRex, 6}, + {"cr15", Control, RegRex, 7}, + /* debug registers */ + {"db0", Debug, 0, 0}, + {"db1", Debug, 0, 1}, + {"db2", Debug, 0, 2}, + {"db3", Debug, 0, 3}, + {"db4", Debug, 0, 4}, + {"db5", Debug, 0, 5}, + {"db6", Debug, 0, 6}, + {"db7", Debug, 0, 7}, + {"db8", Debug, RegRex, 0}, + {"db9", Debug, RegRex, 1}, + {"db10", Debug, RegRex, 2}, + {"db11", Debug, RegRex, 3}, + {"db12", Debug, RegRex, 4}, + {"db13", Debug, RegRex, 5}, + {"db14", Debug, RegRex, 6}, + {"db15", Debug, RegRex, 7}, + {"dr0", Debug, 0, 0}, + {"dr1", Debug, 0, 1}, + {"dr2", Debug, 0, 2}, + {"dr3", Debug, 0, 3}, + {"dr4", Debug, 0, 4}, + {"dr5", Debug, 0, 5}, + {"dr6", Debug, 0, 6}, + {"dr7", Debug, 0, 7}, + {"dr8", Debug, RegRex, 0}, + {"dr9", Debug, RegRex, 1}, + {"dr10", Debug, RegRex, 2}, + {"dr11", Debug, RegRex, 3}, + {"dr12", Debug, RegRex, 4}, + {"dr13", Debug, RegRex, 5}, + {"dr14", Debug, RegRex, 6}, + {"dr15", Debug, RegRex, 7}, + /* test registers */ + {"tr0", Test, 0, 0}, + {"tr1", Test, 0, 1}, + {"tr2", Test, 0, 2}, + {"tr3", Test, 0, 3}, + {"tr4", Test, 0, 4}, + {"tr5", Test, 0, 5}, + {"tr6", Test, 0, 6}, + {"tr7", Test, 0, 7}, + /* mmx and simd registers */ + {"mm0", RegMMX, 0, 0}, + {"mm1", RegMMX, 0, 1}, + {"mm2", RegMMX, 0, 2}, + {"mm3", RegMMX, 0, 3}, + {"mm4", RegMMX, 0, 4}, + {"mm5", RegMMX, 0, 5}, + {"mm6", RegMMX, 0, 6}, + {"mm7", RegMMX, 0, 7}, + {"xmm0", RegXMM, 0, 0}, + {"xmm1", RegXMM, 0, 1}, + {"xmm2", RegXMM, 0, 2}, + {"xmm3", RegXMM, 0, 3}, + {"xmm4", RegXMM, 0, 4}, + {"xmm5", RegXMM, 0, 5}, + {"xmm6", RegXMM, 0, 6}, + {"xmm7", RegXMM, 0, 7}, + {"xmm8", RegXMM, RegRex, 0}, + {"xmm9", RegXMM, RegRex, 1}, + {"xmm10", RegXMM, RegRex, 2}, + {"xmm11", RegXMM, RegRex, 3}, + {"xmm12", RegXMM, RegRex, 4}, + {"xmm13", RegXMM, RegRex, 5}, + {"xmm14", RegXMM, RegRex, 6}, + {"xmm15", RegXMM, RegRex, 7}, + /* no type will make this register rejected for all purposes except + for addressing. This saves creating one extra type for RIP. */ + {"rip", BaseIndex, 0, 0} +}; + +static const reg_entry i386_float_regtab[] = { + {"st(0)", FloatReg|FloatAcc, 0, 0}, + {"st(1)", FloatReg, 0, 1}, + {"st(2)", FloatReg, 0, 2}, + {"st(3)", FloatReg, 0, 3}, + {"st(4)", FloatReg, 0, 4}, + {"st(5)", FloatReg, 0, 5}, + {"st(6)", FloatReg, 0, 6}, + {"st(7)", FloatReg, 0, 7} +}; + +#define MAX_REG_NAME_SIZE 8 /* for parsing register names from input */ + +/* segment stuff */ +static const seg_entry cs = { "cs", 0x2e }; +static const seg_entry ds = { "ds", 0x3e }; +static const seg_entry ss = { "ss", 0x36 }; +static const seg_entry es = { "es", 0x26 }; +static const seg_entry fs = { "fs", 0x64 }; +static const seg_entry gs = { "gs", 0x65 }; + +/* end of opcode/i386.h */ diff --git a/contrib/binutils-2.14/include/progress.h b/contrib/binutils-2.14/include/progress.h new file mode 100644 index 0000000000..23b0960078 --- /dev/null +++ b/contrib/binutils-2.14/include/progress.h @@ -0,0 +1,37 @@ +/* Default definitions for progress macros. + Copyright 1994 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* The default definitions below are intended to be replaced by real + definitions, if building the tools for an interactive programming + environment. */ + +#ifndef _PROGRESS_H +#define _PROGRESS_H + +#ifndef START_PROGRESS +#define START_PROGRESS(STR,N) +#endif + +#ifndef PROGRESS +#define PROGRESS(X) +#endif + +#ifndef END_PROGRESS +#define END_PROGRESS(STR) +#endif + +#endif /* _PROGRESS_H */ diff --git a/contrib/binutils-2.14/include/safe-ctype.h b/contrib/binutils-2.14/include/safe-ctype.h new file mode 100644 index 0000000000..b2ad8490bd --- /dev/null +++ b/contrib/binutils-2.14/include/safe-ctype.h @@ -0,0 +1,103 @@ +/* replacement macros. + + Copyright (C) 2000, 2001 Free Software Foundation, Inc. + Contributed by Zack Weinberg . + +This file is part of the libiberty library. +Libiberty is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +Libiberty is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with libiberty; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* This is a compatible replacement of the standard C library's + with the following properties: + + - Implements all isxxx() macros required by C99. + - Also implements some character classes useful when + parsing C-like languages. + - Does not change behavior depending on the current locale. + - Behaves properly for all values in the range of a signed or + unsigned char. + + To avoid conflicts, this header defines the isxxx functions in upper + case, e.g. ISALPHA not isalpha. */ + +#ifndef SAFE_CTYPE_H +#define SAFE_CTYPE_H + +#ifdef isalpha + #error "safe-ctype.h and ctype.h may not be used simultaneously" +#else + +/* Categories. */ + +enum { + /* In C99 */ + _sch_isblank = 0x0001, /* space \t */ + _sch_iscntrl = 0x0002, /* nonprinting characters */ + _sch_isdigit = 0x0004, /* 0-9 */ + _sch_islower = 0x0008, /* a-z */ + _sch_isprint = 0x0010, /* any printing character including ' ' */ + _sch_ispunct = 0x0020, /* all punctuation */ + _sch_isspace = 0x0040, /* space \t \n \r \f \v */ + _sch_isupper = 0x0080, /* A-Z */ + _sch_isxdigit = 0x0100, /* 0-9A-Fa-f */ + + /* Extra categories useful to cpplib. */ + _sch_isidst = 0x0200, /* A-Za-z_ */ + _sch_isvsp = 0x0400, /* \n \r */ + _sch_isnvsp = 0x0800, /* space \t \f \v \0 */ + + /* Combinations of the above. */ + _sch_isalpha = _sch_isupper|_sch_islower, /* A-Za-z */ + _sch_isalnum = _sch_isalpha|_sch_isdigit, /* A-Za-z0-9 */ + _sch_isidnum = _sch_isidst|_sch_isdigit, /* A-Za-z0-9_ */ + _sch_isgraph = _sch_isalnum|_sch_ispunct, /* isprint and not space */ + _sch_iscppsp = _sch_isvsp|_sch_isnvsp, /* isspace + \0 */ + _sch_isbasic = _sch_isprint|_sch_iscppsp /* basic charset of ISO C + (plus ` and @) */ +}; + +/* Character classification. */ +extern const unsigned short _sch_istable[256]; + +#define _sch_test(c, bit) (_sch_istable[(c) & 0xff] & (unsigned short)(bit)) + +#define ISALPHA(c) _sch_test(c, _sch_isalpha) +#define ISALNUM(c) _sch_test(c, _sch_isalnum) +#define ISBLANK(c) _sch_test(c, _sch_isblank) +#define ISCNTRL(c) _sch_test(c, _sch_iscntrl) +#define ISDIGIT(c) _sch_test(c, _sch_isdigit) +#define ISGRAPH(c) _sch_test(c, _sch_isgraph) +#define ISLOWER(c) _sch_test(c, _sch_islower) +#define ISPRINT(c) _sch_test(c, _sch_isprint) +#define ISPUNCT(c) _sch_test(c, _sch_ispunct) +#define ISSPACE(c) _sch_test(c, _sch_isspace) +#define ISUPPER(c) _sch_test(c, _sch_isupper) +#define ISXDIGIT(c) _sch_test(c, _sch_isxdigit) + +#define ISIDNUM(c) _sch_test(c, _sch_isidnum) +#define ISIDST(c) _sch_test(c, _sch_isidst) +#define IS_ISOBASIC(c) _sch_test(c, _sch_isbasic) +#define IS_VSPACE(c) _sch_test(c, _sch_isvsp) +#define IS_NVSPACE(c) _sch_test(c, _sch_isnvsp) +#define IS_SPACE_OR_NUL(c) _sch_test(c, _sch_iscppsp) + +/* Character transformation. */ +extern const unsigned char _sch_toupper[256]; +extern const unsigned char _sch_tolower[256]; +#define TOUPPER(c) _sch_toupper[(c) & 0xff] +#define TOLOWER(c) _sch_tolower[(c) & 0xff] + +#endif /* no ctype.h */ +#endif /* SAFE_CTYPE_H */ diff --git a/contrib/binutils-2.14/include/symcat.h b/contrib/binutils-2.14/include/symcat.h new file mode 100644 index 0000000000..61ce1e9b34 --- /dev/null +++ b/contrib/binutils-2.14/include/symcat.h @@ -0,0 +1,49 @@ +/* Symbol concatenation utilities. + + Copyright (C) 1998, 2000 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef SYM_CAT_H +#define SYM_CAT_H + +#if defined (__STDC__) || defined (ALMOST_STDC) || defined (HAVE_STRINGIZE) +#define CONCAT2(a,b) a##b +#define CONCAT3(a,b,c) a##b##c +#define CONCAT4(a,b,c,d) a##b##c##d +#define STRINGX(s) #s +#else +/* Note one should never pass extra whitespace to the CONCATn macros, + e.g. CONCAT2(foo, bar) because traditonal C will keep the space between + the two labels instead of concatenating them. Instead, make sure to + write CONCAT2(foo,bar). */ +#define CONCAT2(a,b) a/**/b +#define CONCAT3(a,b,c) a/**/b/**/c +#define CONCAT4(a,b,c,d) a/**/b/**/c/**/d +#define STRINGX(s) "s" +#endif + +#define XCONCAT2(a,b) CONCAT2(a,b) +#define XCONCAT3(a,b,c) CONCAT3(a,b,c) +#define XCONCAT4(a,b,c,d) CONCAT4(a,b,c,d) + +/* Note the layer of indirection here is typically used to allow + stringification of the expansion of macros. I.e. "#define foo + bar", "XSTRING(foo)", to yield "bar". Be aware that this only + works for __STDC__, not for traditional C which will still resolve + to "foo". */ +#define XSTRING(s) STRINGX(s) + +#endif /* SYM_CAT_H */ diff --git a/contrib/binutils-2.14/ld/MAINTAINERS b/contrib/binutils-2.14/ld/MAINTAINERS new file mode 100644 index 0000000000..d59a3bd7f8 --- /dev/null +++ b/contrib/binutils-2.14/ld/MAINTAINERS @@ -0,0 +1 @@ +See ../binutils/MAINTAINERS diff --git a/contrib/binutils-2.14/ld/NEWS b/contrib/binutils-2.14/ld/NEWS new file mode 100644 index 0000000000..cfaf186029 --- /dev/null +++ b/contrib/binutils-2.14/ld/NEWS @@ -0,0 +1,281 @@ +-*- text -*- + +* Added support for Xtensa architecture. + +* Added --with-sysroot configure switch to specify a target system root, for + linking against a target filesystem image. + +* Added --accept-unknown-linker-format to restore old linker behaviour (pre + 2.14) of silently accepting and linking in any files in an unknown binary + file format. + +* Added --no-omagic to undo the effects of the -N option. + +* Support for Texas Instruments TMS320C4x and TMS320C3x series of + DSP's contributed by Michael Hayes and Svein E. Seldal. + +* Added --with-lib-path configure switch to specify default value for + LIB_PATH. + +* ARM port to QNX operating system added by Graeme Peterson. + +* IP2K support added by Denis Chertykov. + +Changes in 2.13: + +* Support for the Fujitsu FRV architecture added by Red Hat. Models for FR400 + and FR500 included. + +Changes in version 2.13: + +* DEC VAX ELF support, by Matt Thomas. + +Changes in version 2.12: + +* Support for Don Knuth's MMIX, by Hans-Peter Nilsson. + +* Support for the OpenRISC 32-bit embedded processor by OpenCores. + +* Support for -z nocopyreloc in the x86 ELF linker, which disables + production of copy relocs. Warning: using this option may result in + non-sharable applications. + +* Support for -z combreloc in the ELF linker, which puts dynamic + relocations against the same symbol together, so that dynamic linker + can use an one-entry symbol lookup cache. + +* Support for ELF SHF_MERGE section merging, by Jakub Jelinek. + +Changes in version 2.11: + +* Support for AMD x86-64 architecture, by Jan Hubicka, SuSE Labs. + +* Support added for eliminating duplicate DWARF2 debug information by + having the compiler generate the information in sections called + .gnu.linkonce.wi.XXXX where XXXX is a checksum for the contents. The + linker then merges these sections together into the normal .debug_info + section. + +* The native ELF linker now searches the directories in DT_RUNPATH or + DT_RPATH of a shared library for shared libraries needed by it. + +* TI C54x support, by Timothy Wall. + +* Added command line switch --section-start to set the start address of any + specified section. + +* Added ability to emit full relocation information in linked executables, + enabled by --emit-relocs. Some post-linkage optimization tools need + this information in order to be able to correctly identify and perform + symbol relative addressing in the event of changes in section contents + (instructions being added or deleted, extending data sections, etc.) + +* Support for i860, by Jason Eckhardt (preliminary, alpha quality). + +* Support for CRIS (Axis Communications ETRAX series). + +* Support for PDP-11 and 2.11BSD a.out format, by Lars Brinkhoff. + +Changes in version 2.10: + +* Added AT> to the linker script language to allow load-time allocation of + sections into regions. + +* Added garbage collection of unused sections, enabled by --gc-sections. + It does require a bit of backend support; currently implemented are + arm-elf, avr-elf, d10v-elf, fr30-elf, i386-elf, m32r-elf, m68k-elf, + mcore-elf, mips-elf, mn10300-elf, ppc-elf, sh-elf, sparc-elf, and v850-elf. + Others will ignore the option. + +* Added SORT to the linker script language to permit sorting sections by file + name or section name. + +* Added EXTERN to the linker script language as an equivalent to the -u + command-line option. + +* Added ASSERT to the linker script language. + +* Added EXCLUDE_FILE to the linker script language for further control over + wildcard file names. + +* Added -O option to optimize linker output (as of this writing, this only + affects ELF shared library generation). + +* The -e option now accepts a number as well as a symbol name. + +* Added --no-undefined option to disallow undefined symbols when creating a + shared library. + +* The linker now issues a warning, not an error, for an undefined symbol when + using -Bsymbolic; use the new --no-undefined option to get the old + behaviour. + +* Added --demangle and --no-demangle options. + +Changes in version 2.9: + +* Added SQUAD to the linker script language. + +* New option --no-warn-mismatch. + +* The MEMORY command now parses the attributes to determine where sections that + are not placed in a specific memory region are placed. + +Changes in version 2.8: + +* Linker scripts may now contain shell wildcard characters for file and section + names. + +* The linker now supports symbol versions in ELF. + +* The NOCROSSREFS command was added to the linker script language. + +* The LOADADDR expression was added to the linker script language. + +* MAX and MIN functions were added to the linker script language. + +* The OVERLAY construct was added to the linker script language. + +* New option --warn-section-align to warn when the address of an output section + changes due to alignment of an input section. + +* New options --filter/-F and --auxiliary/-f. + +Changes in version 2.7: + +* New option --cref to print out a cross reference table. + +* New option --wrap SYMBOL. + +* New option --no-whole-archive, to turn off the effect of --whole-archive. + +* Input sections assigned to the output section /DISCARD/ in the linker script + are not included in the output file. + +* The SunOS and ELF linkers now merge stabs debugging information which uses + the N_BINCL and N_EINCL stab types. This reduces the amount of debugging + information generated. + +Changes in version 2.6: + +* When an ELF section name is representable as a C identifier (this is not true +of most ELF section names), the linker will automatically define symbols +__start_SECNAME and __stop_SECNAME, where SECNAME is the section name, at the +beginning and the end of the section. This is used by glibc. + +* When an ELF section named .gnu.warning is encountered in an input file, the +contents of the section are displayed as an error message, and the section is +not copied into the output file. This is used by glibc. + +* When an ELF section named .gnu.warning.SYMBOL is encountered in an input +file, and the symbol SYMBOL is referenced by some object file, the contents of +the section are displayed as an error message. The section is not copied into +the output file, unless doing a relocateable or shared link. This is used by +glibc. + +* New options -split-by-reloc and -split-by-file. + +* The linker now supports linking PIC compiled code on SPARC SunOS. It can +also create SPARC SunOS shared libraries, and, like the native SunOS linker, +will do so whenever there is an undefined symbol in the link and neither the -e +nor the -r option was used. + +* The -rpath option may be used on SunOS to set the list of directories to be +searched at run time. This overrides the default of building the list from the +-L options. + +* The COFF linker now combines debugging information for structs, unions, and +enums, so that even if the same type is defined in multiple input files it will +only be defined once in the output file. The --traditional-format switch will +prevent this optimization. + +Changes in version 2.5: + +* The linker now supports linking against SunOS shared libraries. It still can +not link SunOS PIC (Position Independent Code) files, so it can not be used to +generate shared libaries. + +* The linker now supports linking against ELF shared libraries for the i386 +(UnixWare) and SPARC (Solaris). It can also link ELF PIC files, and can be +used to generate shared libraries. Shared library generation is not well +tested; please report any problems encountered. The linker is now enabled for +Solaris again. + +* Eric Youngdale has contributed Linux support code, including linking against +Linux a.out shared libraries. The linker produces Linux QMAGIC binaries. + +* The ELF backend has been converted to the new linker code. To use the new +ELF linker, each particular target requires a relocation function. So far, +this function has been written for i386 (UnixWare), SPARC (Solaris) MIPS (Irix +5), and HPPA ELF targets. + +* The -( (--start-group) and -) (--end-group) options have been added to +support searching a group of archives as though they were a single archive. +This can also be used in a linker script, as GROUP ( files ). + +* When a file is named on the command line, and the linker does not recognize +it as an object file, the linker will now treat the file as a linker script +file. A linker script named in this way augments, but does not replace, the +default linker script. + +* The -warn-once option was added. It causes the linker to only warn once per +undefined symbol, rather than once per reference. + +* The COFF backend has been converted to the new linker code. As with ELF, to +use the new linker, each particular target requires a relocation function. So +far, this function has been written for the i386, m68k, a29k and SH targets. + +* The -V flag was made a synonym for -v, for SVR4 compatibility. The old -V +behaviour is available via --verbose. + +Changes in version 2.4: + +* New linker code, by Steve Chamberlain and Ian Taylor. For a.out and ecoff + formats (so far), this should result in considerable savings in time + and memory used while linking; slightly poorer performance than + before for formats not converted yet. + +* Command-line parsing is no longer done with flex. This means + oddball characters in filenames won't get treated as argument + separators. + +* HP-PA ELF support, by Jeff Law. (No SOM support yet.) + +* Mach i386 support, by David Mackenzie. + +* Irix 4 shared libraries are now supported (Irix 5 uses ELF, and ELF shared + libraries are not yet supported). + +* COFF shared libraries (as on SCO) should work as well. + +* The linker is disabled for Solaris. (Actually, it was in 2.3 also, I just + forgot to note it.) Some of their C library routines don't work when + statically linked, and the GNU linker doesn't support dynamic linking yet. + +Changes in version 2.3: + +* Weak symbols are now supported. + +* ELF support has been added. The linker has been bootstrapped on + UnixWare and Solaris. + +* Alpha OSF/1 support has been added (non dynamic linking only). + +Changes in version 2.2: + +* The `bfd' library has been updated to reduce a.out-format string + table size. The effect of this is that files linked from many input + files with duplicate symbols (`-g' debugging records, or identical + static symbols) should be much smaller. + +Changes in version 2.1: + +* The ld -ySYMBOL flag (to trace references to SYMBOL) is now implemented. + +* There is now support for writing ECOFF files, so ld and the + other utilities should work on Risc/Ultrix and Irix. + + +Local variables: +fill-column: 79 +End: diff --git a/contrib/binutils-2.14/ld/README b/contrib/binutils-2.14/ld/README new file mode 100644 index 0000000000..a953e422f7 --- /dev/null +++ b/contrib/binutils-2.14/ld/README @@ -0,0 +1,67 @@ + README for LD + +This is the GNU linker. It is distributed with other "binary +utilities" which should be in ../binutils. See ../binutils/README for +more general notes, including where to send bug reports. + +There are many features of the linker: + +* The linker uses a Binary File Descriptor library (../bfd) + that it uses to read and write object files. This helps + insulate the linker itself from the format of object files. + +* The linker supports a number of different object file + formats. It can even handle multiple formats at once: + Read two input formats and write a third. + +* The linker can be configured for cross-linking. + +* The linker supports a control language. + +* There is a user manual (ld.texinfo), as well as the + beginnings of an internals manual (ldint.texinfo). + +Installation +============ + +See ../binutils/README. + +If you want to make a cross-linker, you may want to specify +a different search path of -lfoo libraries than the default. +You can do this by setting the LIB_PATH variable in ./Makefile +or using the --with-lib-path configure switch. + +To build just the linker, make the target all-ld from the top level +directory (one directory above this one). + +Porting to a new target +======================= + +See the ldint.texinfo manual. + +Reporting bugs etc +=========================== + +See ../binutils/README. + +Known problems +============== + +The Solaris linker normally exports all dynamic symbols from an +executable. The GNU linker does not do this by default. This is +because the GNU linker tries to present the same interface for all +similar targets (in this case, all native ELF targets). This does not +matter for normal programs, but it can make a difference for programs +which try to dlopen an executable, such as PERL or Tcl. You can make +the GNU linker export all dynamic symbols with the -E or +--export-dynamic command line option. + +HP/UX 9.01 has a shell bug that causes the linker scripts to be +generated incorrectly. The symptom of this appears to be "fatal error +- scanner input buffer overflow" error messages. There are various +workarounds to this: + * Build and install bash, and build with "make SHELL=bash". + * Update to a version of HP/UX with a working shell (e.g., 9.05). + * Replace "(. ${srcdir}/scripttempl/${SCRIPT_NAME}.sc)" in + genscripts.sh with "sh ${srcdir}..." (no parens) and make sure the + emulparams script used exports any shell variables it sets. diff --git a/contrib/binutils-2.14/ld/TODO b/contrib/binutils-2.14/ld/TODO new file mode 100644 index 0000000000..31cd98ba23 --- /dev/null +++ b/contrib/binutils-2.14/ld/TODO @@ -0,0 +1,9 @@ +Volunteers to tackle some of the following would be welcome: + +Support the "traditional" BSD -A flag (incremental loading). +(There is a -A flag in ld now, but it is used to specify the +architecture. That should probably be changed.) + +Support for dynamic loading (a la dld, but bfd-based) would be nice. + +Avoid re-open (and re-seeking) output bfd and archives. diff --git a/contrib/binutils-2.14/ld/emulparams/elf_i386.sh b/contrib/binutils-2.14/ld/emulparams/elf_i386.sh new file mode 100644 index 0000000000..f1b8522fe6 --- /dev/null +++ b/contrib/binutils-2.14/ld/emulparams/elf_i386.sh @@ -0,0 +1,12 @@ +SCRIPT_NAME=elf +OUTPUT_FORMAT="elf32-i386" +TEXT_START_ADDR=0x08048000 +MAXPAGESIZE=0x1000 +COMMONPAGESIZE=0x1000 +NONPAGED_TEXT_START_ADDR=0x08048000 +ARCH=i386 +MACHINE= +NOP=0x90909090 +TEMPLATE_NAME=elf32 +GENERATE_SHLIB_SCRIPT=yes +NO_SMALL_DATA=yes diff --git a/contrib/binutils-2.14/ld/emulparams/elf_x86_64.sh b/contrib/binutils-2.14/ld/emulparams/elf_x86_64.sh new file mode 100644 index 0000000000..61e8f29f94 --- /dev/null +++ b/contrib/binutils-2.14/ld/emulparams/elf_x86_64.sh @@ -0,0 +1,30 @@ +SCRIPT_NAME=elf +ELFSIZE=64 +OUTPUT_FORMAT="elf64-x86-64" +TEXT_START_ADDR=0x400000 +MAXPAGESIZE=0x100000 +COMMONPAGESIZE=0x1000 +NONPAGED_TEXT_START_ADDR=0x400000 +ARCH="i386:x86-64" +MACHINE= +NOP=0x90909090 +TEMPLATE_NAME=elf32 +GENERATE_SHLIB_SCRIPT=yes +NO_SMALL_DATA=yes + +if [ "x${host}" = "x${target}" ]; then + case " $EMULATION_LIBPATH " in + *" ${EMULATION_NAME} "*) + NATIVE=yes + esac +fi + +# Linux modify the default library search path to first include +# a 64-bit specific directory. +case "$target" in + x86_64*-linux*) + case "$EMULATION_NAME" in + *64*) LIBPATH_SUFFIX=64 ;; + esac + ;; +esac diff --git a/contrib/binutils-2.14/ld/emultempl/astring.sed b/contrib/binutils-2.14/ld/emultempl/astring.sed new file mode 100644 index 0000000000..08bd8a6420 --- /dev/null +++ b/contrib/binutils-2.14/ld/emultempl/astring.sed @@ -0,0 +1,13 @@ +s/["\\]/\\&/g +s/$/\\n\\/ +1 s/^/"/ +25s/\\$/"/ +26s/^/"/ +50s/\\$/"/ +51s/^/"/ +75s/\\$/"/ +76s/^/"/ +100s/\\$/"/ +101s/^/"/ +$ s/$/n"/ +$ s/\\n"n"$/\\n"/ diff --git a/contrib/binutils-2.14/ld/emultempl/elf32.em b/contrib/binutils-2.14/ld/emultempl/elf32.em new file mode 100644 index 0000000000..3d94a6688a --- /dev/null +++ b/contrib/binutils-2.14/ld/emultempl/elf32.em @@ -0,0 +1,1779 @@ +# This shell script emits a C file. -*- C -*- +# It does some substitutions. +# This file is now misnamed, because it supports both 32 bit and 64 bit +# ELF emulations. +test -z "${ELFSIZE}" && ELFSIZE=32 +if [ -z "$MACHINE" ]; then + OUTPUT_ARCH=${ARCH} +else + OUTPUT_ARCH=${ARCH}:${MACHINE} +fi +cat >e${EMULATION_NAME}.c < + ELF support by Ian Lance Taylor + +This file is part of GLD, the Gnu Linker. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define TARGET_IS_${EMULATION_NAME} + +#include "bfd.h" +#include "sysdep.h" +#include "libiberty.h" +#include "safe-ctype.h" +#include "getopt.h" + +#include "bfdlink.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include +#include "elf/common.h" + +static void gld${EMULATION_NAME}_before_parse + PARAMS ((void)); +static void gld${EMULATION_NAME}_vercheck + PARAMS ((lang_input_statement_type *)); +static void gld${EMULATION_NAME}_stat_needed + PARAMS ((lang_input_statement_type *)); +static bfd_boolean gld${EMULATION_NAME}_try_needed + PARAMS ((const char *, int)); +static bfd_boolean gld${EMULATION_NAME}_search_needed + PARAMS ((const char *, const char *, int)); +static void gld${EMULATION_NAME}_check_needed + PARAMS ((lang_input_statement_type *)); +static void gld${EMULATION_NAME}_after_open + PARAMS ((void)); +static void gld${EMULATION_NAME}_find_exp_assignment + PARAMS ((etree_type *)); +static void gld${EMULATION_NAME}_find_statement_assignment + PARAMS ((lang_statement_union_type *)); +static void gld${EMULATION_NAME}_before_allocation + PARAMS ((void)); +static bfd_boolean gld${EMULATION_NAME}_open_dynamic_archive + PARAMS ((const char *, search_dirs_type *, lang_input_statement_type *)); +static lang_output_section_statement_type *output_rel_find + PARAMS ((asection *)); +static asection *output_prev_sec_find + PARAMS ((lang_output_section_statement_type *)); +static bfd_boolean gld${EMULATION_NAME}_place_orphan + PARAMS ((lang_input_statement_type *, asection *)); +static void gld${EMULATION_NAME}_finish + PARAMS ((void)); +static char *gld${EMULATION_NAME}_get_script + PARAMS ((int *isfile)); + +EOF + +# Import any needed special functions and/or overrides. +# +if test -n "$EXTRA_EM_FILE" ; then +. ${srcdir}/emultempl/${EXTRA_EM_FILE}.em +fi + +# Functions in this file can be overridden by setting the LDEMUL_* shell +# variables. If the name of the overriding function is the same as is +# defined in this file, then don't output this file's version. +# If a different overriding name is given then output the standard function +# as presumably it is called from the overriding function. +# +if test x"$LDEMUL_BEFORE_PARSE" != xgld"$EMULATION_NAME"_before_parse; then +cat >>e${EMULATION_NAME}.c <arch; + ldfile_output_machine = arch->mach; + ldfile_output_machine_name = arch->printable_name; + } + else + ldfile_output_architecture = bfd_arch_`echo ${ARCH} | sed -e 's/:.*//'`; + config.dynamic_link = ${DYNAMIC_LINK-TRUE}; + config.has_shared = `if test -n "$GENERATE_SHLIB_SCRIPT" ; then echo TRUE ; else echo FALSE ; fi`; +} + +EOF +fi + +cat >>e${EMULATION_NAME}.c <the_bfd == NULL + || (bfd_get_file_flags (s->the_bfd) & DYNAMIC) == 0) + return; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname == NULL) + soname = lbasename (bfd_get_filename (s->the_bfd)); + + for (l = global_vercheck_needed; l != NULL; l = l->next) + { + const char *suffix; + + if (strcmp (soname, l->name) == 0) + { + /* Probably can't happen, but it's an easy check. */ + continue; + } + + if (strchr (l->name, '/') != NULL) + continue; + + suffix = strstr (l->name, ".so."); + if (suffix == NULL) + continue; + + suffix += sizeof ".so." - 1; + + if (strncmp (soname, l->name, suffix - l->name) == 0) + { + /* Here we know that S is a dynamic object FOO.SO.VER1, and + the object we are considering needs a dynamic object + FOO.SO.VER2, and VER1 and VER2 are different. This + appears to be a version mismatch, so we tell the caller + to try a different version of this library. */ + global_vercheck_failed = TRUE; + return; + } + } +} + + +/* See if an input file matches a DT_NEEDED entry by running stat on + the file. */ + +static void +gld${EMULATION_NAME}_stat_needed (s) + lang_input_statement_type *s; +{ + struct stat st; + const char *suffix; + const char *soname; + + if (global_found) + return; + if (s->the_bfd == NULL) + return; + + if (bfd_stat (s->the_bfd, &st) != 0) + { + einfo ("%P:%B: bfd_stat failed: %E\n", s->the_bfd); + return; + } + + if (st.st_dev == global_stat.st_dev + && st.st_ino == global_stat.st_ino) + { + global_found = TRUE; + return; + } + + /* We issue a warning if it looks like we are including two + different versions of the same shared library. For example, + there may be a problem if -lc picks up libc.so.6 but some other + shared library has a DT_NEEDED entry of libc.so.5. This is a + heuristic test, and it will only work if the name looks like + NAME.so.VERSION. FIXME: Depending on file names is error-prone. + If we really want to issue warnings about mixing version numbers + of shared libraries, we need to find a better way. */ + + if (strchr (global_needed->name, '/') != NULL) + return; + suffix = strstr (global_needed->name, ".so."); + if (suffix == NULL) + return; + suffix += sizeof ".so." - 1; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname == NULL) + soname = lbasename (s->filename); + + if (strncmp (soname, global_needed->name, suffix - global_needed->name) == 0) + einfo ("%P: warning: %s, needed by %B, may conflict with %s\n", + global_needed->name, global_needed->by, soname); +} + + +/* This function is called for each possible name for a dynamic object + named by a DT_NEEDED entry. The FORCE parameter indicates whether + to skip the check for a conflicting version. */ + +static bfd_boolean +gld${EMULATION_NAME}_try_needed (name, force) + const char *name; + int force; +{ + bfd *abfd; + const char *soname; + + abfd = bfd_openr (name, bfd_get_target (output_bfd)); + if (abfd == NULL) + return FALSE; + if (! bfd_check_format (abfd, bfd_object)) + { + bfd_close (abfd); + return FALSE; + } + if ((bfd_get_file_flags (abfd) & DYNAMIC) == 0) + { + bfd_close (abfd); + return FALSE; + } + + /* For DT_NEEDED, they have to match. */ + if (abfd->xvec != output_bfd->xvec) + { + bfd_close (abfd); + return FALSE; + } + + /* Check whether this object would include any conflicting library + versions. If FORCE is set, then we skip this check; we use this + the second time around, if we couldn't find any compatible + instance of the shared library. */ + + if (! force) + { + struct bfd_link_needed_list *needed; + + if (! bfd_elf_get_bfd_needed_list (abfd, &needed)) + einfo ("%F%P:%B: bfd_elf_get_bfd_needed_list failed: %E\n", abfd); + + if (needed != NULL) + { + global_vercheck_needed = needed; + global_vercheck_failed = FALSE; + lang_for_each_input_file (gld${EMULATION_NAME}_vercheck); + if (global_vercheck_failed) + { + bfd_close (abfd); + /* Return FALSE to force the caller to move on to try + another file on the search path. */ + return FALSE; + } + + /* But wait! It gets much worse. On Linux, if a shared + library does not use libc at all, we are supposed to skip + it the first time around in case we encounter a shared + library later on with the same name which does use the + version of libc that we want. This is much too horrible + to use on any system other than Linux. */ + +EOF +case ${target} in + *-*-linux-gnu*) + cat >>e${EMULATION_NAME}.c <next) + if (strncmp (l->name, "libc.so", 7) == 0) + break; + if (l == NULL) + { + bfd_close (abfd); + return FALSE; + } + } + +EOF + ;; +esac +cat >>e${EMULATION_NAME}.c <filename); + + if (trace_file_tries) + info_msg (_("found %s at %s\n"), soname, name); + + global_found = FALSE; + lang_for_each_input_file (gld${EMULATION_NAME}_stat_needed); + if (global_found) + { + /* Return TRUE to indicate that we found the file, even though + we aren't going to do anything with it. */ + return TRUE; + } + + /* Tell the ELF backend that we don't want the output file to have a + DT_NEEDED entry for this file. */ + bfd_elf_set_dt_needed_name (abfd, ""); + + /* Tell the ELF backend that the output file needs a DT_NEEDED + entry for this file if it is used to resolve the reference in + a regular object. */ + bfd_elf_set_dt_needed_soname (abfd, soname); + + /* Add this file into the symbol table. */ + if (! bfd_link_add_symbols (abfd, &link_info)) + einfo ("%F%B: could not read symbols: %E\n", abfd); + + return TRUE; +} + + +/* Search for a needed file in a path. */ + +static bfd_boolean +gld${EMULATION_NAME}_search_needed (path, name, force) + const char *path; + const char *name; + int force; +{ + const char *s; + size_t len; + + if (name[0] == '/') + return gld${EMULATION_NAME}_try_needed (name, force); + + if (path == NULL || *path == '\0') + return FALSE; + len = strlen (name); + while (1) + { + char *filename, *sset; + + s = strchr (path, ':'); + if (s == NULL) + s = path + strlen (path); + + filename = (char *) xmalloc (s - path + len + 2); + if (s == path) + sset = filename; + else + { + memcpy (filename, path, s - path); + filename[s - path] = '/'; + sset = filename + (s - path) + 1; + } + strcpy (sset, name); + + if (gld${EMULATION_NAME}_try_needed (filename, force)) + return TRUE; + + free (filename); + + if (*s == '\0') + break; + path = s + 1; + } + + return FALSE; +} + +EOF +if [ "x${USE_LIBPATH}" = xyes ] ; then + cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <= alloc) + { + alloc *= 2; + b = (char *) xrealloc (b, alloc); + } + if (c != ':' + && c != ' ' + && c != '\t' + && c != '\n' + && c != ',') + { + b[len] = c; + ++len; + } + else + { + if (len > 0 && b[len - 1] != ':') + { + b[len] = ':'; + ++len; + } + } + } + + if (len > 0 && b[len - 1] == ':') + --len; + + if (len > 0) + b[len] = '\0'; + else + { + free (b); + b = NULL; + } + + fclose (f); + + if (b) + { + char *d = gld${EMULATION_NAME}_add_sysroot (b); + free (b); + b = d; + } + + ld_so_conf = b; + } + + initialized = TRUE; + } + + if (ld_so_conf == NULL) + return FALSE; + + return gld${EMULATION_NAME}_search_needed (ld_so_conf, name, force); +} + +EOF + # Linux + ;; + esac +fi +cat >>e${EMULATION_NAME}.c <filename != NULL) + { + const char *f; + + if (strcmp (s->filename, global_needed->name) == 0) + { + global_found = TRUE; + return; + } + + if (s->search_dirs_flag) + { + f = strrchr (s->filename, '/'); + if (f != NULL + && strcmp (f + 1, global_needed->name) == 0) + { + global_found = TRUE; + return; + } + } + } + + if (s->the_bfd != NULL) + { + const char *soname; + + soname = bfd_elf_get_dt_soname (s->the_bfd); + if (soname != NULL + && strcmp (soname, global_needed->name) == 0) + { + global_found = TRUE; + return; + } + } +} + +EOF + +if test x"$LDEMUL_AFTER_OPEN" != xgld"$EMULATION_NAME"_after_open; then +cat >>e${EMULATION_NAME}.c <next) + { + struct bfd_link_needed_list *ll; + int force; + + /* If we've already seen this file, skip it. */ + for (ll = needed; ll != l; ll = ll->next) + if (strcmp (ll->name, l->name) == 0) + break; + if (ll != l) + continue; + + /* See if this file was included in the link explicitly. */ + global_needed = l; + global_found = FALSE; + lang_for_each_input_file (gld${EMULATION_NAME}_check_needed); + if (global_found) + continue; + + if (trace_file_tries) + info_msg (_("%s needed by %B\n"), l->name, l->by); + + /* We need to find this file and include the symbol table. We + want to search for the file in the same way that the dynamic + linker will search. That means that we want to use + rpath_link, rpath, then the environment variable + LD_LIBRARY_PATH (native only), then the DT_RPATH/DT_RUNPATH + entries (native only), then the linker script LIB_SEARCH_DIRS. + We do not search using the -L arguments. + + We search twice. The first time, we skip objects which may + introduce version mismatches. The second time, we force + their use. See gld${EMULATION_NAME}_vercheck comment. */ + for (force = 0; force < 2; force++) + { + size_t len; + search_dirs_type *search; +EOF +if [ "x${USE_LIBPATH}" = xyes ] ; then +cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <name, force)) + break; +EOF +if [ "x${USE_LIBPATH}" = xyes ] ; then +cat >>e${EMULATION_NAME}.c <name, force)) + break; +EOF +fi +if [ "x${NATIVE}" = xyes ] ; then +cat >>e${EMULATION_NAME}.c <name, + force)) + break; + } + lib_path = (const char *) getenv ("LD_LIBRARY_PATH"); + if (gld${EMULATION_NAME}_search_needed (lib_path, l->name, force)) + break; +EOF +fi +if [ "x${USE_LIBPATH}" = xyes ] ; then +cat >>e${EMULATION_NAME}.c <next) + { + char *tmpname = gld${EMULATION_NAME}_add_sysroot (rp->name); + found = (rp->by == l->by + && gld${EMULATION_NAME}_search_needed (tmpname, + l->name, + force)); + free (tmpname); + } + if (found) + break; + +EOF +fi +cat >>e${EMULATION_NAME}.c <name); + for (search = search_head; search != NULL; search = search->next) + { + char *filename; + + if (search->cmdline) + continue; + filename = (char *) xmalloc (strlen (search->name) + len + 2); + sprintf (filename, "%s/%s", search->name, l->name); + if (gld${EMULATION_NAME}_try_needed (filename, force)) + break; + free (filename); + } + if (search != NULL) + break; +EOF +if [ "x${USE_LIBPATH}" = xyes ] ; then + case ${target} in + *-*-linux-gnu*) + cat >>e${EMULATION_NAME}.c <name, force)) + break; +EOF + # Linux + ;; + esac +fi +cat >>e${EMULATION_NAME}.c <name, l->by); + } +} + +EOF +fi + +cat >>e${EMULATION_NAME}.c <type.node_class) + { + case etree_provide: + h = bfd_link_hash_lookup (link_info.hash, exp->assign.dst, + FALSE, FALSE, FALSE); + if (h == NULL) + break; + + /* We call record_link_assignment even if the symbol is defined. + This is because if it is defined by a dynamic object, we + actually want to use the value defined by the linker script, + not the value from the dynamic object (because we are setting + symbols like etext). If the symbol is defined by a regular + object, then, as it happens, calling record_link_assignment + will do no harm. */ + + /* Fall through. */ + case etree_assign: + if (strcmp (exp->assign.dst, ".") != 0) + { + if (! (bfd_elf${ELFSIZE}_record_link_assignment + (output_bfd, &link_info, exp->assign.dst, + exp->type.node_class == etree_provide ? TRUE : FALSE))) + einfo ("%P%F: failed to record assignment to %s: %E\n", + exp->assign.dst); + } + gld${EMULATION_NAME}_find_exp_assignment (exp->assign.src); + break; + + case etree_binary: + gld${EMULATION_NAME}_find_exp_assignment (exp->binary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->binary.rhs); + break; + + case etree_trinary: + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.cond); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.lhs); + gld${EMULATION_NAME}_find_exp_assignment (exp->trinary.rhs); + break; + + case etree_unary: + gld${EMULATION_NAME}_find_exp_assignment (exp->unary.child); + break; + + default: + break; + } +} + + +/* This is called by the before_allocation routine via + lang_for_each_statement. It locates any assignment statements, and + tells the ELF backend about them, in case they are assignments to + symbols which are referred to by dynamic objects. */ + +static void +gld${EMULATION_NAME}_find_statement_assignment (s) + lang_statement_union_type *s; +{ + if (s->header.type == lang_assignment_statement_enum) + gld${EMULATION_NAME}_find_exp_assignment (s->assignment_statement.exp); +} + +EOF + +if test x"$LDEMUL_BEFORE_ALLOCATION" != xgld"$EMULATION_NAME"_before_allocation; then + if test x"${ELF_INTERPRETER_NAME+set}" = xset; then + ELF_INTERPRETER_SET_DEFAULT=" + if (sinterp != NULL) + { + sinterp->contents = ${ELF_INTERPRETER_NAME}; + sinterp->_raw_size = strlen (sinterp->contents) + 1; + } + +" + else + ELF_INTERPRETER_SET_DEFAULT= + fi +cat >>e${EMULATION_NAME}.c <contents = (bfd_byte *) command_line.interpreter; + sinterp->_raw_size = strlen (command_line.interpreter) + 1; + } + + /* Look for any sections named .gnu.warning. As a GNU extensions, + we treat such sections as containing warning messages. We print + out the warning message, and then zero out the section size so + that it does not get copied into the output file. */ + + { + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + asection *s; + bfd_size_type sz; + char *msg; + bfd_boolean ret; + + if (is->just_syms_flag) + continue; + + s = bfd_get_section_by_name (is->the_bfd, ".gnu.warning"); + if (s == NULL) + continue; + + sz = bfd_section_size (is->the_bfd, s); + msg = xmalloc ((size_t) sz + 1); + if (! bfd_get_section_contents (is->the_bfd, s, msg, (file_ptr) 0, sz)) + einfo ("%F%B: Can't read contents of section .gnu.warning: %E\n", + is->the_bfd); + msg[sz] = '\0'; + ret = link_info.callbacks->warning (&link_info, msg, + (const char *) NULL, + is->the_bfd, (asection *) NULL, + (bfd_vma) 0); + ASSERT (ret); + free (msg); + + /* Clobber the section size, so that we don't waste copying the + warning into the output file. */ + s->_raw_size = 0; + } + } +} + +EOF +fi + +if test x"$LDEMUL_OPEN_DYNAMIC_ARCHIVE" != xgld"$EMULATION_NAME"_open_dynamic_archive; then +cat >>e${EMULATION_NAME}.c <is_archive) + return FALSE; + + filename = entry->filename; + + /* This allocates a few bytes too many when EXTRA_SHLIB_EXTENSION + is defined, but it does not seem worth the headache to optimize + away those two bytes of space. */ + string = (char *) xmalloc (strlen (search->name) + + strlen (filename) + + strlen (arch) +#ifdef EXTRA_SHLIB_EXTENSION + + strlen (EXTRA_SHLIB_EXTENSION) +#endif + + sizeof "/lib.so"); + + sprintf (string, "%s/lib%s%s.so", search->name, filename, arch); + +#ifdef EXTRA_SHLIB_EXTENSION + /* Try the .so extension first. If that fails build a new filename + using EXTRA_SHLIB_EXTENSION. */ + if (! ldfile_try_open_bfd (string, entry)) + sprintf (string, "%s/lib%s%s%s", search->name, + filename, arch, EXTRA_SHLIB_EXTENSION); +#endif + + if (! ldfile_try_open_bfd (string, entry)) + { + free (string); + return FALSE; + } + + entry->filename = string; + + /* We have found a dynamic object to include in the link. The ELF + backend linker will create a DT_NEEDED entry in the .dynamic + section naming this file. If this file includes a DT_SONAME + entry, it will be used. Otherwise, the ELF linker will just use + the name of the file. For an archive found by searching, like + this one, the DT_NEEDED entry should consist of just the name of + the file, without the path information used to find it. Note + that we only need to do this if we have a dynamic object; an + archive will never be referenced by a DT_NEEDED entry. + + FIXME: This approach--using bfd_elf_set_dt_needed_name--is not + very pretty. I haven't been able to think of anything that is + pretty, though. */ + if (bfd_check_format (entry->the_bfd, bfd_object) + && (entry->the_bfd->flags & DYNAMIC) != 0) + { + ASSERT (entry->is_archive && entry->search_dirs_flag); + + /* Rather than duplicating the logic above. Just use the + filename we recorded earlier. */ + + filename = lbasename (entry->filename); + bfd_elf_set_dt_needed_name (entry->the_bfd, filename); + } + + return TRUE; +} + +EOF +fi + +if test x"$LDEMUL_PLACE_ORPHAN" != xgld"$EMULATION_NAME"_place_orphan; then +cat >>e${EMULATION_NAME}.c <name[4] == 'a'; + + for (u = lang_output_section_statement.head; u; u = lookup->next) + { + lookup = &u->output_section_statement; + if (strncmp (".rel", lookup->name, 4) == 0) + { + /* Don't place after .rel.plt as doing so results in wrong + dynamic tags. Also, place allocated reloc sections before + non-allocated. */ + int lookrela = lookup->name[4] == 'a'; + + if (strcmp (".plt", lookup->name + 4 + lookrela) == 0 + || (lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_ALLOC) == 0)) + break; + last = lookup; + if (rela == lookrela) + last_rel = lookup; + if (lookup->bfd_section != NULL + && (lookup->bfd_section->flags & SEC_ALLOC) != 0) + last_rel_alloc = lookup; + } + } + + if (last_rel_alloc) + return last_rel_alloc; + + if (last_rel) + return last_rel; + + return last; +} + +/* Find the last output section before given output statement. + Used by place_orphan. */ + +static asection * +output_prev_sec_find (os) + lang_output_section_statement_type *os; +{ + asection *s = (asection *) NULL; + lang_statement_union_type *u; + lang_output_section_statement_type *lookup; + + for (u = lang_output_section_statement.head; + u != (lang_statement_union_type *) NULL; + u = lookup->next) + { + lookup = &u->output_section_statement; + if (lookup == os) + return s; + + if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) + s = lookup->bfd_section; + } + + return NULL; +} + +/* Place an orphan section. We use this to put random SHF_ALLOC + sections in the right segment. */ + +struct orphan_save { + lang_output_section_statement_type *os; + asection **section; + lang_statement_union_type **stmt; + lang_statement_union_type **os_tail; +}; + +static bfd_boolean +gld${EMULATION_NAME}_place_orphan (file, s) + lang_input_statement_type *file; + asection *s; +{ + static struct orphan_save hold_text; + static struct orphan_save hold_rodata; + static struct orphan_save hold_data; + static struct orphan_save hold_bss; + static struct orphan_save hold_rel; + static struct orphan_save hold_interp; + static struct orphan_save hold_sdata; + static int count = 1; + struct orphan_save *place; + lang_statement_list_type *old; + lang_statement_list_type add; + etree_type *address; + const char *secname; + const char *ps = NULL; + lang_output_section_statement_type *os; + lang_statement_union_type **os_tail; + etree_type *load_base; + int isdyn = 0; + + secname = bfd_get_section_name (s->owner, s); + if (! link_info.relocateable + && link_info.combreloc + && (s->flags & SEC_ALLOC) + && strncmp (secname, ".rel", 4) == 0) + { + if (secname[4] == 'a') + secname = ".rela.dyn"; + else + secname = ".rel.dyn"; + isdyn = 1; + } + + if (isdyn || (!config.unique_orphan_sections && !unique_section_p (secname))) + { + /* Look through the script to see where to place this section. */ + os = lang_output_section_find (secname); + + if (os != NULL + && (os->bfd_section == NULL + || ((s->flags ^ os->bfd_section->flags) + & (SEC_LOAD | SEC_ALLOC)) == 0)) + { + /* We already have an output section statement with this + name, and its bfd section, if any, has compatible flags. */ + lang_add_section (&os->children, s, os, file); + return TRUE; + } + } + + if (hold_text.os == NULL) + hold_text.os = lang_output_section_find (".text"); + + /* If this is a final link, then always put .gnu.warning.SYMBOL + sections into the .text section to get them out of the way. */ + if (! link_info.shared + && ! link_info.relocateable + && strncmp (secname, ".gnu.warning.", sizeof ".gnu.warning." - 1) == 0 + && hold_text.os != NULL) + { + lang_add_section (&hold_text.os->children, s, hold_text.os, file); + return TRUE; + } + + /* Decide which segment the section should go in based on the + section name and section flags. We put loadable .note sections + right after the .interp section, so that the PT_NOTE segment is + stored right after the program headers where the OS can read it + in the first page. */ +#define HAVE_SECTION(hold, name) \ +(hold.os != NULL || (hold.os = lang_output_section_find (name)) != NULL) + + if ((s->flags & SEC_EXCLUDE) != 0 && !link_info.relocateable) + { + if (s->output_section == NULL) + s->output_section = bfd_abs_section_ptr; + return TRUE; + } + + place = NULL; + if ((s->flags & SEC_ALLOC) == 0) + ; + else if ((s->flags & SEC_LOAD) != 0 + && strncmp (secname, ".note", 5) == 0 + && HAVE_SECTION (hold_interp, ".interp")) + place = &hold_interp; + else if ((s->flags & SEC_HAS_CONTENTS) == 0 + && HAVE_SECTION (hold_bss, ".bss")) + place = &hold_bss; + else if ((s->flags & SEC_SMALL_DATA) != 0 + && HAVE_SECTION (hold_sdata, ".sdata")) + place = &hold_sdata; + else if ((s->flags & SEC_READONLY) == 0 + && HAVE_SECTION (hold_data, ".data")) + place = &hold_data; + else if (strncmp (secname, ".rel", 4) == 0 + && (s->flags & SEC_LOAD) != 0 + && (hold_rel.os != NULL + || (hold_rel.os = output_rel_find (s)) != NULL)) + place = &hold_rel; + else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY + && HAVE_SECTION (hold_rodata, ".rodata")) + place = &hold_rodata; + else if ((s->flags & (SEC_CODE | SEC_READONLY)) == (SEC_CODE | SEC_READONLY) + && hold_text.os != NULL) + place = &hold_text; + +#undef HAVE_SECTION + + /* Choose a unique name for the section. This will be needed if the + same section name appears in the input file with different + loadable or allocatable characteristics. */ + if (bfd_get_section_by_name (output_bfd, secname) != NULL) + { + secname = bfd_get_unique_section_name (output_bfd, secname, &count); + if (secname == NULL) + einfo ("%F%P: place_orphan failed: %E\n"); + } + + /* Start building a list of statements for this section. + First save the current statement pointer. */ + old = stat_ptr; + + /* If we have found an appropriate place for the output section + statements for this orphan, add them to our own private list, + inserting them later into the global statement list. */ + if (place != NULL) + { + stat_ptr = &add; + lang_list_init (stat_ptr); + } + + if (config.build_constructors) + { + /* If the name of the section is representable in C, then create + symbols to mark the start and the end of the section. */ + for (ps = secname; *ps != '\0'; ps++) + if (! ISALNUM (*ps) && *ps != '_') + break; + if (*ps == '\0') + { + char *symname; + etree_type *e_align; + + symname = (char *) xmalloc (ps - secname + sizeof "__start_"); + sprintf (symname, "__start_%s", secname); + e_align = exp_unop (ALIGN_K, + exp_intop ((bfd_vma) 1 << s->alignment_power)); + lang_add_assignment (exp_assop ('=', symname, e_align)); + } + } + + address = NULL; + if (link_info.relocateable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) + address = exp_intop ((bfd_vma) 0); + + load_base = NULL; + if (place != NULL && place->os->load_base != NULL) + { + etree_type *lma_from_vma; + lma_from_vma = exp_binop ('-', place->os->load_base, + exp_nameop (ADDR, place->os->name)); + load_base = exp_binop ('+', lma_from_vma, + exp_nameop (ADDR, secname)); + } + + os_tail = lang_output_section_statement.tail; + os = lang_enter_output_section_statement (secname, address, 0, + (bfd_vma) 0, + (etree_type *) NULL, + (etree_type *) NULL, + load_base); + + lang_add_section (&os->children, s, os, file); + + lang_leave_output_section_statement + ((bfd_vma) 0, "*default*", + (struct lang_output_section_phdr_list *) NULL, NULL); + + if (config.build_constructors && *ps == '\0') + { + char *symname; + + /* lang_leave_ouput_section_statement resets stat_ptr. Put + stat_ptr back where we want it. */ + if (place != NULL) + stat_ptr = &add; + + symname = (char *) xmalloc (ps - secname + sizeof "__stop_"); + sprintf (symname, "__stop_%s", secname); + lang_add_assignment (exp_assop ('=', symname, + exp_nameop (NAME, "."))); + } + + /* Restore the global list pointer. */ + stat_ptr = old; + + if (place != NULL && os->bfd_section != NULL) + { + asection *snew, **pps; + + snew = os->bfd_section; + + /* Shuffle the bfd section list to make the output file look + neater. This is really only cosmetic. */ + if (place->section == NULL) + { + asection *bfd_section = place->os->bfd_section; + + /* If the output statement hasn't been used to place + any input sections (and thus doesn't have an output + bfd_section), look for the closest prior output statement + having an output section. */ + if (bfd_section == NULL) + bfd_section = output_prev_sec_find (place->os); + + if (bfd_section != NULL && bfd_section != snew) + place->section = &bfd_section->next; + } + + if (place->section != NULL) + { + /* Unlink the section. */ + for (pps = &output_bfd->sections; *pps != snew; pps = &(*pps)->next) + ; + bfd_section_list_remove (output_bfd, pps); + + /* Now tack it on to the "place->os" section list. */ + bfd_section_list_insert (output_bfd, place->section, snew); + } + + /* Save the end of this list. Further ophans of this type will + follow the one we've just added. */ + place->section = &snew->next; + + /* The following is non-cosmetic. We try to put the output + statements in some sort of reasonable order here, because + they determine the final load addresses of the orphan + sections. In addition, placing output statements in the + wrong order may require extra segments. For instance, + given a typical situation of all read-only sections placed + in one segment and following that a segment containing all + the read-write sections, we wouldn't want to place an orphan + read/write section before or amongst the read-only ones. */ + if (add.head != NULL) + { + lang_statement_union_type *newly_added_os; + + if (place->stmt == NULL) + { + /* Put the new statement list right at the head. */ + *add.tail = place->os->header.next; + place->os->header.next = add.head; + + place->os_tail = &place->os->next; + } + else + { + /* Put it after the last orphan statement we added. */ + *add.tail = *place->stmt; + *place->stmt = add.head; + } + + /* Fix the global list pointer if we happened to tack our + new list at the tail. */ + if (*old->tail == add.head) + old->tail = add.tail; + + /* Save the end of this list. */ + place->stmt = add.tail; + + /* Do the same for the list of output section statements. */ + newly_added_os = *os_tail; + *os_tail = NULL; + newly_added_os->output_section_statement.next = *place->os_tail; + *place->os_tail = newly_added_os; + place->os_tail = &newly_added_os->output_section_statement.next; + + /* Fixing the global list pointer here is a little different. + We added to the list in lang_enter_output_section_statement, + trimmed off the new output_section_statment above when + assigning *os_tail = NULL, but possibly added it back in + the same place when assigning *place->os_tail. */ + if (*os_tail == NULL) + lang_output_section_statement.tail = os_tail; + } + } + + return TRUE; +} +EOF +fi + +if test x"$LDEMUL_FINISH" != xgld"$EMULATION_NAME"_finish; then +cat >>e${EMULATION_NAME}.c <head, abs_output_section, + &stat_ptr->head, 0, (bfd_vma) 0, NULL, TRUE); + + /* Redo special stuff. */ + ldemul_after_allocation (); + + /* Do the assignments again. */ + lang_do_assignments (stat_ptr->head, abs_output_section, + (fill_type *) 0, (bfd_vma) 0); + } +} +EOF +fi + +if test x"$LDEMUL_GET_SCRIPT" != xgld"$EMULATION_NAME"_get_script; then +cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <> e${EMULATION_NAME}.c +echo ' ; else if (link_info.relocateable) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xr >> e${EMULATION_NAME}.c +echo ' ; else if (!config.text_read_only) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xbn >> e${EMULATION_NAME}.c +if cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then : ; else +echo ' ; else if (!config.magic_demand_paged) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xn >> e${EMULATION_NAME}.c +fi +if test -n "$GENERATE_SHLIB_SCRIPT" ; then +if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then +echo ' ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xsc >> e${EMULATION_NAME}.c +fi +echo ' ; else if (link_info.shared) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xs >> e${EMULATION_NAME}.c +fi +if test -n "$GENERATE_COMBRELOC_SCRIPT" ; then +echo ' ; else if (link_info.combreloc) return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.xc >> e${EMULATION_NAME}.c +fi +echo ' ; else return' >> e${EMULATION_NAME}.c +sed $sc ldscripts/${EMULATION_NAME}.x >> e${EMULATION_NAME}.c +echo '; }' >> e${EMULATION_NAME}.c + +else +# Scripts read from the filesystem. + +cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <.sh file or default. + +DATA_ALIGNMENT_="${DATA_ALIGNMENT_-${DATA_ALIGNMENT-ALIGN(${SEGMENT_SIZE})}}" +DATA_ALIGNMENT_n="${DATA_ALIGNMENT_n-${DATA_ALIGNMENT_}}" +DATA_ALIGNMENT_N="${DATA_ALIGNMENT_N-${DATA_ALIGNMENT-.}}" +DATA_ALIGNMENT_r="${DATA_ALIGNMENT_r-${DATA_ALIGNMENT-}}" +DATA_ALIGNMENT_u="${DATA_ALIGNMENT_u-${DATA_ALIGNMENT_r}}" + +LD_FLAG=r +DATA_ALIGNMENT=${DATA_ALIGNMENT_r} +DEFAULT_DATA_ALIGNMENT="ALIGN(${SEGMENT_SIZE})" +( echo "/* Script for ld -r: link without relocation */" + . ${srcdir}/emulparams/${EMULATION_NAME}.sh + . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc +) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xr + +LD_FLAG=u +DATA_ALIGNMENT=${DATA_ALIGNMENT_u} +CONSTRUCTING=" " +( echo "/* Script for ld -Ur: link w/out relocation, do create constructors */" + . ${srcdir}/emulparams/${EMULATION_NAME}.sh + . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc +) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xu + +LD_FLAG= +DATA_ALIGNMENT=${DATA_ALIGNMENT_} +RELOCATING=" " +( echo "/* Default linker script, for normal executables */" + . ${srcdir}/emulparams/${EMULATION_NAME}.sh + . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc +) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.x + +LD_FLAG=n +DATA_ALIGNMENT=${DATA_ALIGNMENT_n} +TEXT_START_ADDR=${NONPAGED_TEXT_START_ADDR-${TEXT_START_ADDR}} +( echo "/* Script for -n: mix text and data on same page */" + . ${srcdir}/emulparams/${EMULATION_NAME}.sh + . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc +) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xn + +LD_FLAG=N +DATA_ALIGNMENT=${DATA_ALIGNMENT_N} +( echo "/* Script for -N: mix text and data on same page; don't align data */" + . ${srcdir}/emulparams/${EMULATION_NAME}.sh + . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc +) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xbn + +if test -n "$GENERATE_COMBRELOC_SCRIPT"; then + DATA_ALIGNMENT=${DATA_ALIGNMENT_c-${DATA_ALIGNMENT_}} + LD_FLAG=c + COMBRELOC=ldscripts/${EMULATION_NAME}.xc.tmp + ( echo "/* Script for -z combreloc: combine and sort reloc sections */" + . ${srcdir}/emulparams/${EMULATION_NAME}.sh + . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc + ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xc + rm -f ${COMBRELOC} + COMBRELOC= +fi + +if test -n "$GENERATE_SHLIB_SCRIPT"; then + LD_FLAG=shared + DATA_ALIGNMENT=${DATA_ALIGNMENT_s-${DATA_ALIGNMENT_}} + CREATE_SHLIB=" " + # Note that TEXT_START_ADDR is set to NONPAGED_TEXT_START_ADDR. + ( + echo "/* Script for ld --shared: link shared library */" + . ${srcdir}/emulparams/${EMULATION_NAME}.sh + . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc + ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xs + if test -n "$GENERATE_COMBRELOC_SCRIPT"; then + LD_FLAG=cshared + DATA_ALIGNMENT=${DATA_ALIGNMENT_sc-${DATA_ALIGNMENT}} + COMBRELOC=ldscripts/${EMULATION_NAME}.xc.tmp + ( echo "/* Script for --shared -z combreloc: shared library, combine & sort relocs */" + . ${srcdir}/emulparams/${EMULATION_NAME}.sh + . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc + ) | sed -e '/^ *$/d;s/[ ]*$//' > ldscripts/${EMULATION_NAME}.xsc + rm -f ${COMBRELOC} + COMBRELOC= + fi +fi + +case " $EMULATION_LIBPATH " in + *" ${EMULATION_NAME} "*) COMPILE_IN=true;; +esac + +# Generate e${EMULATION_NAME}.c. +. ${srcdir}/emultempl/${TEMPLATE_NAME-generic}.em diff --git a/contrib/binutils-2.14/ld/ld.1 b/contrib/binutils-2.14/ld/ld.1 new file mode 100644 index 0000000000..b26897633f --- /dev/null +++ b/contrib/binutils-2.14/ld/ld.1 @@ -0,0 +1,1816 @@ +.\" Automatically generated by Pod::Man v1.34, Pod::Parser v1.13 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "LD 1" +.TH LD 1 "2003-06-12" "binutils-2.14" "GNU Development Tools" +.SH "NAME" +ld \- Using LD, the GNU linker +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +ld [\fBoptions\fR] \fIobjfile\fR ... +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\fBld\fR combines a number of object and archive files, relocates +their data and ties up symbol references. Usually the last step in +compiling a program is to run \fBld\fR. +.PP +\&\fBld\fR accepts Linker Command Language files written in +a superset of \s-1AT&T\s0's Link Editor Command Language syntax, +to provide explicit and total control over the linking process. +.PP +This man page does not describe the command language; see the +\&\fBld\fR entry in \f(CW\*(C`info\*(C'\fR, or the manual +ld: the \s-1GNU\s0 linker, for full details on the command language and +on other aspects of the \s-1GNU\s0 linker. +.PP +This version of \fBld\fR uses the general purpose \s-1BFD\s0 libraries +to operate on object files. This allows \fBld\fR to read, combine, and +write object files in many different formats\-\-\-for example, \s-1COFF\s0 or +\&\f(CW\*(C`a.out\*(C'\fR. Different formats may be linked together to produce any +available kind of object file. +.PP +Aside from its flexibility, the \s-1GNU\s0 linker is more helpful than other +linkers in providing diagnostic information. Many linkers abandon +execution immediately upon encountering an error; whenever possible, +\&\fBld\fR continues executing, allowing you to identify other errors +(or, in some cases, to get an output file in spite of the error). +.PP +The \s-1GNU\s0 linker \fBld\fR is meant to cover a broad range of situations, +and to be as compatible as possible with other linkers. As a result, +you have many choices to control its behavior. +.SH "OPTIONS" +.IX Header "OPTIONS" +The linker supports a plethora of command-line options, but in actual +practice few of them are used in any particular context. +For instance, a frequent use of \fBld\fR is to link standard Unix +object files on a standard, supported Unix system. On such a system, to +link a file \f(CW\*(C`hello.o\*(C'\fR: +.PP +.Vb 1 +\& ld -o /lib/crt0.o hello.o -lc +.Ve +.PP +This tells \fBld\fR to produce a file called \fIoutput\fR as the +result of linking the file \f(CW\*(C`/lib/crt0.o\*(C'\fR with \f(CW\*(C`hello.o\*(C'\fR and +the library \f(CW\*(C`libc.a\*(C'\fR, which will come from the standard search +directories. (See the discussion of the \fB\-l\fR option below.) +.PP +Some of the command-line options to \fBld\fR may be specified at any +point in the command line. However, options which refer to files, such +as \fB\-l\fR or \fB\-T\fR, cause the file to be read at the point at +which the option appears in the command line, relative to the object +files and other file options. Repeating non-file options with a +different argument will either have no further effect, or override prior +occurrences (those further to the left on the command line) of that +option. Options which may be meaningfully specified more than once are +noted in the descriptions below. +.PP +Non-option arguments are object files or archives which are to be linked +together. They may follow, precede, or be mixed in with command-line +options, except that an object file argument may not be placed between +an option and its argument. +.PP +Usually the linker is invoked with at least one object file, but you can +specify other forms of binary input files using \fB\-l\fR, \fB\-R\fR, +and the script command language. If \fIno\fR binary input files at all +are specified, the linker does not produce any output, and issues the +message \fBNo input files\fR. +.PP +If the linker cannot recognize the format of an object file, it will +assume that it is a linker script. A script specified in this way +augments the main linker script used for the link (either the default +linker script or the one specified by using \fB\-T\fR). This feature +permits the linker to link against a file which appears to be an object +or an archive, but actually merely defines some symbol values, or uses +\&\f(CW\*(C`INPUT\*(C'\fR or \f(CW\*(C`GROUP\*(C'\fR to load other objects. Note that +specifying a script in this way merely augments the main linker script; +use the \fB\-T\fR option to replace the default linker script entirely. +.PP +For options whose names are a single letter, +option arguments must either follow the option letter without intervening +whitespace, or be given as separate arguments immediately following the +option that requires them. +.PP +For options whose names are multiple letters, either one dash or two can +precede the option name; for example, \fB\-trace\-symbol\fR and +\&\fB\-\-trace\-symbol\fR are equivalent. Note\-\-\-there is one exception to +this rule. Multiple letter options that start with a lower case 'o' can +only be preceeded by two dashes. This is to reduce confusion with the +\&\fB\-o\fR option. So for example \fB\-omagic\fR sets the output file +name to \fBmagic\fR whereas \fB\-\-omagic\fR sets the \s-1NMAGIC\s0 flag on the +output. +.PP +Arguments to multiple-letter options must either be separated from the +option name by an equals sign, or be given as separate arguments +immediately following the option that requires them. For example, +\&\fB\-\-trace\-symbol foo\fR and \fB\-\-trace\-symbol=foo\fR are equivalent. +Unique abbreviations of the names of multiple-letter options are +accepted. +.PP +Note\-\-\-if the linker is being invoked indirectly, via a compiler driver +(e.g. \fBgcc\fR) then all the linker command line options should be +prefixed by \fB\-Wl,\fR (or whatever is appropriate for the particular +compiler driver) like this: +.PP +.Vb 1 +\& gcc -Wl,--startgroup foo.o bar.o -Wl,--endgroup +.Ve +.PP +This is important, because otherwise the compiler driver program may +silently drop the linker options, resulting in a bad link. +.PP +Here is a table of the generic command line switches accepted by the \s-1GNU\s0 +linker: +.IP "\fB\-a\fR\fIkeyword\fR" 4 +.IX Item "-akeyword" +This option is supported for \s-1HP/UX\s0 compatibility. The \fIkeyword\fR +argument must be one of the strings \fBarchive\fR, \fBshared\fR, or +\&\fBdefault\fR. \fB\-aarchive\fR is functionally equivalent to +\&\fB\-Bstatic\fR, and the other two keywords are functionally equivalent +to \fB\-Bdynamic\fR. This option may be used any number of times. +.IP "\fB\-A\fR\fIarchitecture\fR" 4 +.IX Item "-Aarchitecture" +.PD 0 +.IP "\fB\-\-architecture=\fR\fIarchitecture\fR" 4 +.IX Item "--architecture=architecture" +.PD +In the current release of \fBld\fR, this option is useful only for the +Intel 960 family of architectures. In that \fBld\fR configuration, the +\&\fIarchitecture\fR argument identifies the particular architecture in +the 960 family, enabling some safeguards and modifying the +archive-library search path. +.Sp +Future releases of \fBld\fR may support similar functionality for +other architecture families. +.IP "\fB\-b\fR \fIinput-format\fR" 4 +.IX Item "-b input-format" +.PD 0 +.IP "\fB\-\-format=\fR\fIinput-format\fR" 4 +.IX Item "--format=input-format" +.PD +\&\fBld\fR may be configured to support more than one kind of object +file. If your \fBld\fR is configured this way, you can use the +\&\fB\-b\fR option to specify the binary format for input object files +that follow this option on the command line. Even when \fBld\fR is +configured to support alternative object formats, you don't usually need +to specify this, as \fBld\fR should be configured to expect as a +default input format the most usual format on each machine. +\&\fIinput-format\fR is a text string, the name of a particular format +supported by the \s-1BFD\s0 libraries. (You can list the available binary +formats with \fBobjdump \-i\fR.) +.Sp +You may want to use this option if you are linking files with an unusual +binary format. You can also use \fB\-b\fR to switch formats explicitly (when +linking object files of different formats), by including +\&\fB\-b\fR \fIinput-format\fR before each group of object files in a +particular format. +.Sp +The default format is taken from the environment variable +\&\f(CW\*(C`GNUTARGET\*(C'\fR. +.Sp +You can also define the input format from a script, using the command +\&\f(CW\*(C`TARGET\*(C'\fR; +.IP "\fB\-c\fR \fIMRI-commandfile\fR" 4 +.IX Item "-c MRI-commandfile" +.PD 0 +.IP "\fB\-\-mri\-script=\fR\fIMRI-commandfile\fR" 4 +.IX Item "--mri-script=MRI-commandfile" +.PD +For compatibility with linkers produced by \s-1MRI\s0, \fBld\fR accepts script +files written in an alternate, restricted command language, described in +the \s-1MRI\s0 Compatible Script Files section of \s-1GNU\s0 ld documentation. +Introduce \s-1MRI\s0 script files with +the option \fB\-c\fR; use the \fB\-T\fR option to run linker +scripts written in the general-purpose \fBld\fR scripting language. +If \fIMRI-cmdfile\fR does not exist, \fBld\fR looks for it in the directories +specified by any \fB\-L\fR options. +.IP "\fB\-d\fR" 4 +.IX Item "-d" +.PD 0 +.IP "\fB\-dc\fR" 4 +.IX Item "-dc" +.IP "\fB\-dp\fR" 4 +.IX Item "-dp" +.PD +These three options are equivalent; multiple forms are supported for +compatibility with other linkers. They assign space to common symbols +even if a relocatable output file is specified (with \fB\-r\fR). The +script command \f(CW\*(C`FORCE_COMMON_ALLOCATION\*(C'\fR has the same effect. +.IP "\fB\-e\fR \fIentry\fR" 4 +.IX Item "-e entry" +.PD 0 +.IP "\fB\-\-entry=\fR\fIentry\fR" 4 +.IX Item "--entry=entry" +.PD +Use \fIentry\fR as the explicit symbol for beginning execution of your +program, rather than the default entry point. If there is no symbol +named \fIentry\fR, the linker will try to parse \fIentry\fR as a number, +and use that as the entry address (the number will be interpreted in +base 10; you may use a leading \fB0x\fR for base 16, or a leading +\&\fB0\fR for base 8). +.IP "\fB\-E\fR" 4 +.IX Item "-E" +.PD 0 +.IP "\fB\-\-export\-dynamic\fR" 4 +.IX Item "--export-dynamic" +.PD +When creating a dynamically linked executable, add all symbols to the +dynamic symbol table. The dynamic symbol table is the set of symbols +which are visible from dynamic objects at run time. +.Sp +If you do not use this option, the dynamic symbol table will normally +contain only those symbols which are referenced by some dynamic object +mentioned in the link. +.Sp +If you use \f(CW\*(C`dlopen\*(C'\fR to load a dynamic object which needs to refer +back to the symbols defined by the program, rather than some other +dynamic object, then you will probably need to use this option when +linking the program itself. +.Sp +You can also use the version script to control what symbols should +be added to the dynamic symbol table if the output format supports it. +See the description of \fB\-\-version\-script\fR in \f(CW@ref\fR{\s-1VERSION\s0}. +.IP "\fB\-EB\fR" 4 +.IX Item "-EB" +Link big-endian objects. This affects the default output format. +.IP "\fB\-EL\fR" 4 +.IX Item "-EL" +Link little-endian objects. This affects the default output format. +.IP "\fB\-f\fR" 4 +.IX Item "-f" +.PD 0 +.IP "\fB\-\-auxiliary\fR \fIname\fR" 4 +.IX Item "--auxiliary name" +.PD +When creating an \s-1ELF\s0 shared object, set the internal \s-1DT_AUXILIARY\s0 field +to the specified name. This tells the dynamic linker that the symbol +table of the shared object should be used as an auxiliary filter on the +symbol table of the shared object \fIname\fR. +.Sp +If you later link a program against this filter object, then, when you +run the program, the dynamic linker will see the \s-1DT_AUXILIARY\s0 field. If +the dynamic linker resolves any symbols from the filter object, it will +first check whether there is a definition in the shared object +\&\fIname\fR. If there is one, it will be used instead of the definition +in the filter object. The shared object \fIname\fR need not exist. +Thus the shared object \fIname\fR may be used to provide an alternative +implementation of certain functions, perhaps for debugging or for +machine specific performance. +.Sp +This option may be specified more than once. The \s-1DT_AUXILIARY\s0 entries +will be created in the order in which they appear on the command line. +.IP "\fB\-F\fR \fIname\fR" 4 +.IX Item "-F name" +.PD 0 +.IP "\fB\-\-filter\fR \fIname\fR" 4 +.IX Item "--filter name" +.PD +When creating an \s-1ELF\s0 shared object, set the internal \s-1DT_FILTER\s0 field to +the specified name. This tells the dynamic linker that the symbol table +of the shared object which is being created should be used as a filter +on the symbol table of the shared object \fIname\fR. +.Sp +If you later link a program against this filter object, then, when you +run the program, the dynamic linker will see the \s-1DT_FILTER\s0 field. The +dynamic linker will resolve symbols according to the symbol table of the +filter object as usual, but it will actually link to the definitions +found in the shared object \fIname\fR. Thus the filter object can be +used to select a subset of the symbols provided by the object +\&\fIname\fR. +.Sp +Some older linkers used the \fB\-F\fR option throughout a compilation +toolchain for specifying object-file format for both input and output +object files. +The \s-1GNU\s0 linker uses other mechanisms for this purpose: the +\&\fB\-b\fR, \fB\-\-format\fR, \fB\-\-oformat\fR options, the +\&\f(CW\*(C`TARGET\*(C'\fR command in linker scripts, and the \f(CW\*(C`GNUTARGET\*(C'\fR +environment variable. +The \s-1GNU\s0 linker will ignore the \fB\-F\fR option when not +creating an \s-1ELF\s0 shared object. +.IP "\fB\-fini\fR \fIname\fR" 4 +.IX Item "-fini name" +When creating an \s-1ELF\s0 executable or shared object, call \s-1NAME\s0 when the +executable or shared object is unloaded, by setting \s-1DT_FINI\s0 to the +address of the function. By default, the linker uses \f(CW\*(C`_fini\*(C'\fR as +the function to call. +.IP "\fB\-g\fR" 4 +.IX Item "-g" +Ignored. Provided for compatibility with other tools. +.IP "\fB\-G\fR\fIvalue\fR" 4 +.IX Item "-Gvalue" +.PD 0 +.IP "\fB\-\-gpsize=\fR\fIvalue\fR" 4 +.IX Item "--gpsize=value" +.PD +Set the maximum size of objects to be optimized using the \s-1GP\s0 register to +\&\fIsize\fR. This is only meaningful for object file formats such as +\&\s-1MIPS\s0 \s-1ECOFF\s0 which supports putting large and small objects into different +sections. This is ignored for other object file formats. +.IP "\fB\-h\fR\fIname\fR" 4 +.IX Item "-hname" +.PD 0 +.IP "\fB\-soname=\fR\fIname\fR" 4 +.IX Item "-soname=name" +.PD +When creating an \s-1ELF\s0 shared object, set the internal \s-1DT_SONAME\s0 field to +the specified name. When an executable is linked with a shared object +which has a \s-1DT_SONAME\s0 field, then when the executable is run the dynamic +linker will attempt to load the shared object specified by the \s-1DT_SONAME\s0 +field rather than the using the file name given to the linker. +.IP "\fB\-i\fR" 4 +.IX Item "-i" +Perform an incremental link (same as option \fB\-r\fR). +.IP "\fB\-init\fR \fIname\fR" 4 +.IX Item "-init name" +When creating an \s-1ELF\s0 executable or shared object, call \s-1NAME\s0 when the +executable or shared object is loaded, by setting \s-1DT_INIT\s0 to the address +of the function. By default, the linker uses \f(CW\*(C`_init\*(C'\fR as the +function to call. +.IP "\fB\-l\fR\fIarchive\fR" 4 +.IX Item "-larchive" +.PD 0 +.IP "\fB\-\-library=\fR\fIarchive\fR" 4 +.IX Item "--library=archive" +.PD +Add archive file \fIarchive\fR to the list of files to link. This +option may be used any number of times. \fBld\fR will search its +path-list for occurrences of \f(CW\*(C`lib\f(CIarchive\f(CW.a\*(C'\fR for every +\&\fIarchive\fR specified. +.Sp +On systems which support shared libraries, \fBld\fR may also search for +libraries with extensions other than \f(CW\*(C`.a\*(C'\fR. Specifically, on \s-1ELF\s0 +and SunOS systems, \fBld\fR will search a directory for a library with +an extension of \f(CW\*(C`.so\*(C'\fR before searching for one with an extension of +\&\f(CW\*(C`.a\*(C'\fR. By convention, a \f(CW\*(C`.so\*(C'\fR extension indicates a shared +library. +.Sp +The linker will search an archive only once, at the location where it is +specified on the command line. If the archive defines a symbol which +was undefined in some object which appeared before the archive on the +command line, the linker will include the appropriate file(s) from the +archive. However, an undefined symbol in an object appearing later on +the command line will not cause the linker to search the archive again. +.Sp +See the \fB\-(\fR option for a way to force the linker to search +archives multiple times. +.Sp +You may list the same archive multiple times on the command line. +.Sp +This type of archive searching is standard for Unix linkers. However, +if you are using \fBld\fR on \s-1AIX\s0, note that it is different from the +behaviour of the \s-1AIX\s0 linker. +.IP "\fB\-L\fR\fIsearchdir\fR" 4 +.IX Item "-Lsearchdir" +.PD 0 +.IP "\fB\-\-library\-path=\fR\fIsearchdir\fR" 4 +.IX Item "--library-path=searchdir" +.PD +Add path \fIsearchdir\fR to the list of paths that \fBld\fR will search +for archive libraries and \fBld\fR control scripts. You may use this +option any number of times. The directories are searched in the order +in which they are specified on the command line. Directories specified +on the command line are searched before the default directories. All +\&\fB\-L\fR options apply to all \fB\-l\fR options, regardless of the +order in which the options appear. +.Sp +If \fIsearchdir\fR begins with \f(CW\*(C`=\*(C'\fR, then the \f(CW\*(C`=\*(C'\fR will be replaced +by the \fIsysroot prefix\fR, a path specified when the linker is configured. +.Sp +The default set of paths searched (without being specified with +\&\fB\-L\fR) depends on which emulation mode \fBld\fR is using, and in +some cases also on how it was configured. +.Sp +The paths can also be specified in a link script with the +\&\f(CW\*(C`SEARCH_DIR\*(C'\fR command. Directories specified this way are searched +at the point in which the linker script appears in the command line. +.IP "\fB\-m\fR\fIemulation\fR" 4 +.IX Item "-memulation" +Emulate the \fIemulation\fR linker. You can list the available +emulations with the \fB\-\-verbose\fR or \fB\-V\fR options. +.Sp +If the \fB\-m\fR option is not used, the emulation is taken from the +\&\f(CW\*(C`LDEMULATION\*(C'\fR environment variable, if that is defined. +.Sp +Otherwise, the default emulation depends upon how the linker was +configured. +.IP "\fB\-M\fR" 4 +.IX Item "-M" +.PD 0 +.IP "\fB\-\-print\-map\fR" 4 +.IX Item "--print-map" +.PD +Print a link map to the standard output. A link map provides +information about the link, including the following: +.RS 4 +.IP "\(bu" 4 +Where object files and symbols are mapped into memory. +.IP "\(bu" 4 +How common symbols are allocated. +.IP "\(bu" 4 +All archive members included in the link, with a mention of the symbol +which caused the archive member to be brought in. +.RE +.RS 4 +.RE +.IP "\fB\-n\fR" 4 +.IX Item "-n" +.PD 0 +.IP "\fB\-\-nmagic\fR" 4 +.IX Item "--nmagic" +.PD +Turn off page alignment of sections, and mark the output as +\&\f(CW\*(C`NMAGIC\*(C'\fR if possible. +.IP "\fB\-N\fR" 4 +.IX Item "-N" +.PD 0 +.IP "\fB\-\-omagic\fR" 4 +.IX Item "--omagic" +.PD +Set the text and data sections to be readable and writable. Also, do +not page-align the data segment, and disable linking against shared +libraries. If the output format supports Unix style magic numbers, +mark the output as \f(CW\*(C`OMAGIC\*(C'\fR. +.IP "\fB\-\-no\-omagic\fR" 4 +.IX Item "--no-omagic" +This option negates most of the effects of the \fB\-N\fR option. It +sets the text section to be read\-only, and forces the data segment to +be page\-aligned. Note \- this option does not enable linking against +shared libraries. Use \fB\-Bdynamic\fR for this. +.IP "\fB\-o\fR \fIoutput\fR" 4 +.IX Item "-o output" +.PD 0 +.IP "\fB\-\-output=\fR\fIoutput\fR" 4 +.IX Item "--output=output" +.PD +Use \fIoutput\fR as the name for the program produced by \fBld\fR; if this +option is not specified, the name \fIa.out\fR is used by default. The +script command \f(CW\*(C`OUTPUT\*(C'\fR can also specify the output file name. +.IP "\fB\-O\fR \fIlevel\fR" 4 +.IX Item "-O level" +If \fIlevel\fR is a numeric values greater than zero \fBld\fR optimizes +the output. This might take significantly longer and therefore probably +should only be enabled for the final binary. +.IP "\fB\-q\fR" 4 +.IX Item "-q" +.PD 0 +.IP "\fB\-\-emit\-relocs\fR" 4 +.IX Item "--emit-relocs" +.PD +Leave relocation sections and contents in fully linked exececutables. +Post link analysis and optimization tools may need this information in +order to perform correct modifications of executables. This results +in larger executables. +.Sp +This option is currently only supported on \s-1ELF\s0 platforms. +.IP "\fB\-r\fR" 4 +.IX Item "-r" +.PD 0 +.IP "\fB\-\-relocateable\fR" 4 +.IX Item "--relocateable" +.PD +Generate relocatable output\-\-\-i.e., generate an output file that can in +turn serve as input to \fBld\fR. This is often called \fIpartial +linking\fR. As a side effect, in environments that support standard Unix +magic numbers, this option also sets the output file's magic number to +\&\f(CW\*(C`OMAGIC\*(C'\fR. +If this option is not specified, an absolute file is produced. When +linking \*(C+ programs, this option \fIwill not\fR resolve references to +constructors; to do that, use \fB\-Ur\fR. +.Sp +When an input file does not have the same format as the output file, +partial linking is only supported if that input file does not contain any +relocations. Different output formats can have further restrictions; for +example some \f(CW\*(C`a.out\*(C'\fR\-based formats do not support partial linking +with input files in other formats at all. +.Sp +This option does the same thing as \fB\-i\fR. +.IP "\fB\-R\fR \fIfilename\fR" 4 +.IX Item "-R filename" +.PD 0 +.IP "\fB\-\-just\-symbols=\fR\fIfilename\fR" 4 +.IX Item "--just-symbols=filename" +.PD +Read symbol names and their addresses from \fIfilename\fR, but do not +relocate it or include it in the output. This allows your output file +to refer symbolically to absolute locations of memory defined in other +programs. You may use this option more than once. +.Sp +For compatibility with other \s-1ELF\s0 linkers, if the \fB\-R\fR option is +followed by a directory name, rather than a file name, it is treated as +the \fB\-rpath\fR option. +.IP "\fB\-s\fR" 4 +.IX Item "-s" +.PD 0 +.IP "\fB\-\-strip\-all\fR" 4 +.IX Item "--strip-all" +.PD +Omit all symbol information from the output file. +.IP "\fB\-S\fR" 4 +.IX Item "-S" +.PD 0 +.IP "\fB\-\-strip\-debug\fR" 4 +.IX Item "--strip-debug" +.PD +Omit debugger symbol information (but not all symbols) from the output file. +.IP "\fB\-t\fR" 4 +.IX Item "-t" +.PD 0 +.IP "\fB\-\-trace\fR" 4 +.IX Item "--trace" +.PD +Print the names of the input files as \fBld\fR processes them. +.IP "\fB\-T\fR \fIscriptfile\fR" 4 +.IX Item "-T scriptfile" +.PD 0 +.IP "\fB\-\-script=\fR\fIscriptfile\fR" 4 +.IX Item "--script=scriptfile" +.PD +Use \fIscriptfile\fR as the linker script. This script replaces +\&\fBld\fR's default linker script (rather than adding to it), so +\&\fIcommandfile\fR must specify everything necessary to describe the +output file. If \fIscriptfile\fR does not exist in +the current directory, \f(CW\*(C`ld\*(C'\fR looks for it in the directories +specified by any preceding \fB\-L\fR options. Multiple \fB\-T\fR +options accumulate. +.IP "\fB\-u\fR \fIsymbol\fR" 4 +.IX Item "-u symbol" +.PD 0 +.IP "\fB\-\-undefined=\fR\fIsymbol\fR" 4 +.IX Item "--undefined=symbol" +.PD +Force \fIsymbol\fR to be entered in the output file as an undefined +symbol. Doing this may, for example, trigger linking of additional +modules from standard libraries. \fB\-u\fR may be repeated with +different option arguments to enter additional undefined symbols. This +option is equivalent to the \f(CW\*(C`EXTERN\*(C'\fR linker script command. +.IP "\fB\-Ur\fR" 4 +.IX Item "-Ur" +For anything other than \*(C+ programs, this option is equivalent to +\&\fB\-r\fR: it generates relocatable output\-\-\-i.e., an output file that can in +turn serve as input to \fBld\fR. When linking \*(C+ programs, \fB\-Ur\fR +\&\fIdoes\fR resolve references to constructors, unlike \fB\-r\fR. +It does not work to use \fB\-Ur\fR on files that were themselves linked +with \fB\-Ur\fR; once the constructor table has been built, it cannot +be added to. Use \fB\-Ur\fR only for the last partial link, and +\&\fB\-r\fR for the others. +.IP "\fB\-\-unique[=\fR\fI\s-1SECTION\s0\fR\fB]\fR" 4 +.IX Item "--unique[=SECTION]" +Creates a separate output section for every input section matching +\&\fI\s-1SECTION\s0\fR, or if the optional wildcard \fI\s-1SECTION\s0\fR argument is +missing, for every orphan input section. An orphan section is one not +specifically mentioned in a linker script. You may use this option +multiple times on the command line; It prevents the normal merging of +input sections with the same name, overriding output section assignments +in a linker script. +.IP "\fB\-v\fR" 4 +.IX Item "-v" +.PD 0 +.IP "\fB\-\-version\fR" 4 +.IX Item "--version" +.IP "\fB\-V\fR" 4 +.IX Item "-V" +.PD +Display the version number for \fBld\fR. The \fB\-V\fR option also +lists the supported emulations. +.IP "\fB\-x\fR" 4 +.IX Item "-x" +.PD 0 +.IP "\fB\-\-discard\-all\fR" 4 +.IX Item "--discard-all" +.PD +Delete all local symbols. +.IP "\fB\-X\fR" 4 +.IX Item "-X" +.PD 0 +.IP "\fB\-\-discard\-locals\fR" 4 +.IX Item "--discard-locals" +.PD +Delete all temporary local symbols. For most targets, this is all local +symbols whose names begin with \fBL\fR. +.IP "\fB\-y\fR \fIsymbol\fR" 4 +.IX Item "-y symbol" +.PD 0 +.IP "\fB\-\-trace\-symbol=\fR\fIsymbol\fR" 4 +.IX Item "--trace-symbol=symbol" +.PD +Print the name of each linked file in which \fIsymbol\fR appears. This +option may be given any number of times. On many systems it is necessary +to prepend an underscore. +.Sp +This option is useful when you have an undefined symbol in your link but +don't know where the reference is coming from. +.IP "\fB\-Y\fR \fIpath\fR" 4 +.IX Item "-Y path" +Add \fIpath\fR to the default library search path. This option exists +for Solaris compatibility. +.IP "\fB\-z\fR \fIkeyword\fR" 4 +.IX Item "-z keyword" +The recognized keywords are \f(CW\*(C`initfirst\*(C'\fR, \f(CW\*(C`interpose\*(C'\fR, +\&\f(CW\*(C`loadfltr\*(C'\fR, \f(CW\*(C`nodefaultlib\*(C'\fR, \f(CW\*(C`nodelete\*(C'\fR, \f(CW\*(C`nodlopen\*(C'\fR, +\&\f(CW\*(C`nodump\*(C'\fR, \f(CW\*(C`now\*(C'\fR, \f(CW\*(C`origin\*(C'\fR, \f(CW\*(C`combreloc\*(C'\fR, \f(CW\*(C`nocombreloc\*(C'\fR +and \f(CW\*(C`nocopyreloc\*(C'\fR. +The other keywords are +ignored for Solaris compatibility. \f(CW\*(C`initfirst\*(C'\fR marks the object +to be initialized first at runtime before any other objects. +\&\f(CW\*(C`interpose\*(C'\fR marks the object that its symbol table interposes +before all symbols but the primary executable. \f(CW\*(C`loadfltr\*(C'\fR marks +the object that its filtees be processed immediately at runtime. +\&\f(CW\*(C`nodefaultlib\*(C'\fR marks the object that the search for dependencies +of this object will ignore any default library search paths. +\&\f(CW\*(C`nodelete\*(C'\fR marks the object shouldn't be unloaded at runtime. +\&\f(CW\*(C`nodlopen\*(C'\fR marks the object not available to \f(CW\*(C`dlopen\*(C'\fR. +\&\f(CW\*(C`nodump\*(C'\fR marks the object can not be dumped by \f(CW\*(C`dldump\*(C'\fR. +\&\f(CW\*(C`now\*(C'\fR marks the object with the non-lazy runtime binding. +\&\f(CW\*(C`origin\*(C'\fR marks the object may contain \f(CW$ORIGIN\fR. +\&\f(CW\*(C`defs\*(C'\fR disallows undefined symbols. +\&\f(CW\*(C`muldefs\*(C'\fR allows multiple definitions. +\&\f(CW\*(C`combreloc\*(C'\fR combines multiple reloc sections and sorts them +to make dynamic symbol lookup caching possible. +\&\f(CW\*(C`nocombreloc\*(C'\fR disables multiple reloc sections combining. +\&\f(CW\*(C`nocopyreloc\*(C'\fR disables production of copy relocs. +.IP "\fB\-(\fR \fIarchives\fR \fB\-)\fR" 4 +.IX Item "-( archives -)" +.PD 0 +.IP "\fB\-\-start\-group\fR \fIarchives\fR \fB\-\-end\-group\fR" 4 +.IX Item "--start-group archives --end-group" +.PD +The \fIarchives\fR should be a list of archive files. They may be +either explicit file names, or \fB\-l\fR options. +.Sp +The specified archives are searched repeatedly until no new undefined +references are created. Normally, an archive is searched only once in +the order that it is specified on the command line. If a symbol in that +archive is needed to resolve an undefined symbol referred to by an +object in an archive that appears later on the command line, the linker +would not be able to resolve that reference. By grouping the archives, +they all be searched repeatedly until all possible references are +resolved. +.Sp +Using this option has a significant performance cost. It is best to use +it only when there are unavoidable circular references between two or +more archives. +.IP "\fB\-\-accept\-unknown\-input\-arch\fR" 4 +.IX Item "--accept-unknown-input-arch" +.PD 0 +.IP "\fB\-\-no\-accept\-unknown\-input\-arch\fR" 4 +.IX Item "--no-accept-unknown-input-arch" +.PD +Tells the linker to accept input files whose architecture cannot be +recognised. The assumption is that the user knows what they are doing +and deliberately wants to link in these unknown input files. This was +the default behaviour of the linker, before release 2.14. The default +behaviour from release 2.14 onwards is to reject such input files, and +so the \fB\-\-accept\-unknown\-input\-arch\fR option has been added to +restore the old behaviour. +.IP "\fB\-assert\fR \fIkeyword\fR" 4 +.IX Item "-assert keyword" +This option is ignored for SunOS compatibility. +.IP "\fB\-Bdynamic\fR" 4 +.IX Item "-Bdynamic" +.PD 0 +.IP "\fB\-dy\fR" 4 +.IX Item "-dy" +.IP "\fB\-call_shared\fR" 4 +.IX Item "-call_shared" +.PD +Link against dynamic libraries. This is only meaningful on platforms +for which shared libraries are supported. This option is normally the +default on such platforms. The different variants of this option are +for compatibility with various systems. You may use this option +multiple times on the command line: it affects library searching for +\&\fB\-l\fR options which follow it. +.IP "\fB\-Bgroup\fR" 4 +.IX Item "-Bgroup" +Set the \f(CW\*(C`DF_1_GROUP\*(C'\fR flag in the \f(CW\*(C`DT_FLAGS_1\*(C'\fR entry in the dynamic +section. This causes the runtime linker to handle lookups in this +object and its dependencies to be performed only inside the group. +\&\fB\-\-no\-undefined\fR is implied. This option is only meaningful on \s-1ELF\s0 +platforms which support shared libraries. +.IP "\fB\-Bstatic\fR" 4 +.IX Item "-Bstatic" +.PD 0 +.IP "\fB\-dn\fR" 4 +.IX Item "-dn" +.IP "\fB\-non_shared\fR" 4 +.IX Item "-non_shared" +.IP "\fB\-static\fR" 4 +.IX Item "-static" +.PD +Do not link against shared libraries. This is only meaningful on +platforms for which shared libraries are supported. The different +variants of this option are for compatibility with various systems. You +may use this option multiple times on the command line: it affects +library searching for \fB\-l\fR options which follow it. +.IP "\fB\-Bsymbolic\fR" 4 +.IX Item "-Bsymbolic" +When creating a shared library, bind references to global symbols to the +definition within the shared library, if any. Normally, it is possible +for a program linked against a shared library to override the definition +within the shared library. This option is only meaningful on \s-1ELF\s0 +platforms which support shared libraries. +.IP "\fB\-\-check\-sections\fR" 4 +.IX Item "--check-sections" +.PD 0 +.IP "\fB\-\-no\-check\-sections\fR" 4 +.IX Item "--no-check-sections" +.PD +Asks the linker \fInot\fR to check section addresses after they have +been assigned to see if there any overlaps. Normally the linker will +perform this check, and if it finds any overlaps it will produce +suitable error messages. The linker does know about, and does make +allowances for sections in overlays. The default behaviour can be +restored by using the command line switch \fB\-\-check\-sections\fR. +.IP "\fB\-\-cref\fR" 4 +.IX Item "--cref" +Output a cross reference table. If a linker map file is being +generated, the cross reference table is printed to the map file. +Otherwise, it is printed on the standard output. +.Sp +The format of the table is intentionally simple, so that it may be +easily processed by a script if necessary. The symbols are printed out, +sorted by name. For each symbol, a list of file names is given. If the +symbol is defined, the first file listed is the location of the +definition. The remaining files contain references to the symbol. +.IP "\fB\-\-no\-define\-common\fR" 4 +.IX Item "--no-define-common" +This option inhibits the assignment of addresses to common symbols. +The script command \f(CW\*(C`INHIBIT_COMMON_ALLOCATION\*(C'\fR has the same effect. +.Sp +The \fB\-\-no\-define\-common\fR option allows decoupling +the decision to assign addresses to Common symbols from the choice +of the output file type; otherwise a non-Relocatable output type +forces assigning addresses to Common symbols. +Using \fB\-\-no\-define\-common\fR allows Common symbols that are referenced +from a shared library to be assigned addresses only in the main program. +This eliminates the unused duplicate space in the shared library, +and also prevents any possible confusion over resolving to the wrong +duplicate when there are many dynamic modules with specialized search +paths for runtime symbol resolution. +.IP "\fB\-\-defsym\fR \fIsymbol\fR\fB=\fR\fIexpression\fR" 4 +.IX Item "--defsym symbol=expression" +Create a global symbol in the output file, containing the absolute +address given by \fIexpression\fR. You may use this option as many +times as necessary to define multiple symbols in the command line. A +limited form of arithmetic is supported for the \fIexpression\fR in this +context: you may give a hexadecimal constant or the name of an existing +symbol, or use \f(CW\*(C`+\*(C'\fR and \f(CW\*(C`\-\*(C'\fR to add or subtract hexadecimal +constants or symbols. If you need more elaborate expressions, consider +using the linker command language from a script. \fINote:\fR there should be no white +space between \fIsymbol\fR, the equals sign (``\fB=\fR''), and +\&\fIexpression\fR. +.IP "\fB\-\-demangle[=\fR\fIstyle\fR\fB]\fR" 4 +.IX Item "--demangle[=style]" +.PD 0 +.IP "\fB\-\-no\-demangle\fR" 4 +.IX Item "--no-demangle" +.PD +These options control whether to demangle symbol names in error messages +and other output. When the linker is told to demangle, it tries to +present symbol names in a readable fashion: it strips leading +underscores if they are used by the object file format, and converts \*(C+ +mangled symbol names into user readable names. Different compilers have +different mangling styles. The optional demangling style argument can be used +to choose an appropriate demangling style for your compiler. The linker will +demangle by default unless the environment variable \fB\s-1COLLECT_NO_DEMANGLE\s0\fR +is set. These options may be used to override the default. +.IP "\fB\-\-dynamic\-linker\fR \fIfile\fR" 4 +.IX Item "--dynamic-linker file" +Set the name of the dynamic linker. This is only meaningful when +generating dynamically linked \s-1ELF\s0 executables. The default dynamic +linker is normally correct; don't use this unless you know what you are +doing. +.IP "\fB\-\-embedded\-relocs\fR" 4 +.IX Item "--embedded-relocs" +This option is only meaningful when linking \s-1MIPS\s0 embedded \s-1PIC\s0 code, +generated by the \-membedded\-pic option to the \s-1GNU\s0 compiler and +assembler. It causes the linker to create a table which may be used at +runtime to relocate any data which was statically initialized to pointer +values. See the code in testsuite/ld\-empic for details. +.IP "\fB\-\-fatal\-warnings\fR" 4 +.IX Item "--fatal-warnings" +Treat all warnings as errors. +.IP "\fB\-\-force\-exe\-suffix\fR" 4 +.IX Item "--force-exe-suffix" +Make sure that an output file has a .exe suffix. +.Sp +If a successfully built fully linked output file does not have a +\&\f(CW\*(C`.exe\*(C'\fR or \f(CW\*(C`.dll\*(C'\fR suffix, this option forces the linker to copy +the output file to one of the same name with a \f(CW\*(C`.exe\*(C'\fR suffix. This +option is useful when using unmodified Unix makefiles on a Microsoft +Windows host, since some versions of Windows won't run an image unless +it ends in a \f(CW\*(C`.exe\*(C'\fR suffix. +.IP "\fB\-\-no\-gc\-sections\fR" 4 +.IX Item "--no-gc-sections" +.PD 0 +.IP "\fB\-\-gc\-sections\fR" 4 +.IX Item "--gc-sections" +.PD +Enable garbage collection of unused input sections. It is ignored on +targets that do not support this option. This option is not compatible +with \fB\-r\fR, nor should it be used with dynamic linking. The default +behaviour (of not performing this garbage collection) can be restored by +specifying \fB\-\-no\-gc\-sections\fR on the command line. +.IP "\fB\-\-help\fR" 4 +.IX Item "--help" +Print a summary of the command-line options on the standard output and exit. +.IP "\fB\-\-target\-help\fR" 4 +.IX Item "--target-help" +Print a summary of all target specific options on the standard output and exit. +.IP "\fB\-Map\fR \fImapfile\fR" 4 +.IX Item "-Map mapfile" +Print a link map to the file \fImapfile\fR. See the description of the +\&\fB\-M\fR option, above. +.IP "\fB\-\-no\-keep\-memory\fR" 4 +.IX Item "--no-keep-memory" +\&\fBld\fR normally optimizes for speed over memory usage by caching the +symbol tables of input files in memory. This option tells \fBld\fR to +instead optimize for memory usage, by rereading the symbol tables as +necessary. This may be required if \fBld\fR runs out of memory space +while linking a large executable. +.IP "\fB\-\-no\-undefined\fR" 4 +.IX Item "--no-undefined" +.PD 0 +.IP "\fB\-z defs\fR" 4 +.IX Item "-z defs" +.PD +Normally when creating a non-symbolic shared library, undefined symbols +are allowed and left to be resolved by the runtime loader. This option +disallows such undefined symbols if they come from regular object +files. The switch \fB\-\-no\-allow\-shlib\-undefined\fR controls the +behaviour for shared objects being linked into the shared library. +.IP "\fB\-\-allow\-multiple\-definition\fR" 4 +.IX Item "--allow-multiple-definition" +.PD 0 +.IP "\fB\-z muldefs\fR" 4 +.IX Item "-z muldefs" +.PD +Normally when a symbol is defined multiple times, the linker will +report a fatal error. These options allow multiple definitions and the +first definition will be used. +.IP "\fB\-\-allow\-shlib\-undefined\fR" 4 +.IX Item "--allow-shlib-undefined" +.PD 0 +.IP "\fB\-\-no\-allow\-shlib\-undefined\fR" 4 +.IX Item "--no-allow-shlib-undefined" +.PD +Allow (the default) or disallow undefined symbols in shared objects. +The setting of this switch overrides \fB\-\-no\-undefined\fR where +shared objects are concerned. Thus if \fB\-\-no\-undefined\fR is set +but \fB\-\-no\-allow\-shlib\-undefined\fR is not, the net result will be +that undefined symbols in regular object files will trigger an error, +but undefined symbols in shared objects will be ignored. +.Sp +The reason that \fB\-\-allow\-shlib\-undefined\fR is the default is that +the shared object being specified at link time may not be the same one +that is available at load time, so the symbols might actually be +resolvable at load time. Plus there are some systems, (eg BeOS) where +undefined symbols in shared libraries is normal since the kernel +patches them at load time to select which function is most appropriate +for the current architecture. eg. to dynamically select an appropriate +memset function. Apparently it is also normal for \s-1HPPA\s0 shared +libraries to have undefined symbols. +.IP "\fB\-\-no\-undefined\-version\fR" 4 +.IX Item "--no-undefined-version" +Normally when a symbol has an undefined version, the linker will ignore +it. This option disallows symbols with undefined version and a fatal error +will be issued instead. +.IP "\fB\-\-no\-warn\-mismatch\fR" 4 +.IX Item "--no-warn-mismatch" +Normally \fBld\fR will give an error if you try to link together input +files that are mismatched for some reason, perhaps because they have +been compiled for different processors or for different endiannesses. +This option tells \fBld\fR that it should silently permit such possible +errors. This option should only be used with care, in cases when you +have taken some special action that ensures that the linker errors are +inappropriate. +.IP "\fB\-\-no\-whole\-archive\fR" 4 +.IX Item "--no-whole-archive" +Turn off the effect of the \fB\-\-whole\-archive\fR option for subsequent +archive files. +.IP "\fB\-\-noinhibit\-exec\fR" 4 +.IX Item "--noinhibit-exec" +Retain the executable output file whenever it is still usable. +Normally, the linker will not produce an output file if it encounters +errors during the link process; it exits without writing an output file +when it issues any error whatsoever. +.IP "\fB\-nostdlib\fR" 4 +.IX Item "-nostdlib" +Only search library directories explicitly specified on the +command line. Library directories specified in linker scripts +(including linker scripts specified on the command line) are ignored. +.IP "\fB\-\-oformat\fR \fIoutput-format\fR" 4 +.IX Item "--oformat output-format" +\&\fBld\fR may be configured to support more than one kind of object +file. If your \fBld\fR is configured this way, you can use the +\&\fB\-\-oformat\fR option to specify the binary format for the output +object file. Even when \fBld\fR is configured to support alternative +object formats, you don't usually need to specify this, as \fBld\fR +should be configured to produce as a default output format the most +usual format on each machine. \fIoutput-format\fR is a text string, the +name of a particular format supported by the \s-1BFD\s0 libraries. (You can +list the available binary formats with \fBobjdump \-i\fR.) The script +command \f(CW\*(C`OUTPUT_FORMAT\*(C'\fR can also specify the output format, but +this option overrides it. +.IP "\fB\-qmagic\fR" 4 +.IX Item "-qmagic" +This option is ignored for Linux compatibility. +.IP "\fB\-Qy\fR" 4 +.IX Item "-Qy" +This option is ignored for \s-1SVR4\s0 compatibility. +.IP "\fB\-\-relax\fR" 4 +.IX Item "--relax" +An option with machine dependent effects. +This option is only supported on a few targets. +.Sp +On some platforms, the \fB\-\-relax\fR option performs global +optimizations that become possible when the linker resolves addressing +in the program, such as relaxing address modes and synthesizing new +instructions in the output object file. +.Sp +On some platforms these link time global optimizations may make symbolic +debugging of the resulting executable impossible. +This is known to be +the case for the Matsushita \s-1MN10200\s0 and \s-1MN10300\s0 family of processors. +.Sp +On platforms where this is not supported, \fB\-\-relax\fR is accepted, +but ignored. +.IP "\fB\-\-retain\-symbols\-file\fR \fIfilename\fR" 4 +.IX Item "--retain-symbols-file filename" +Retain \fIonly\fR the symbols listed in the file \fIfilename\fR, +discarding all others. \fIfilename\fR is simply a flat file, with one +symbol name per line. This option is especially useful in environments +(such as VxWorks) +where a large global symbol table is accumulated gradually, to conserve +run-time memory. +.Sp +\&\fB\-\-retain\-symbols\-file\fR does \fInot\fR discard undefined symbols, +or symbols needed for relocations. +.Sp +You may only specify \fB\-\-retain\-symbols\-file\fR once in the command +line. It overrides \fB\-s\fR and \fB\-S\fR. +.IP "\fB\-rpath\fR \fIdir\fR" 4 +.IX Item "-rpath dir" +Add a directory to the runtime library search path. This is used when +linking an \s-1ELF\s0 executable with shared objects. All \fB\-rpath\fR +arguments are concatenated and passed to the runtime linker, which uses +them to locate shared objects at runtime. The \fB\-rpath\fR option is +also used when locating shared objects which are needed by shared +objects explicitly included in the link; see the description of the +\&\fB\-rpath\-link\fR option. If \fB\-rpath\fR is not used when linking an +\&\s-1ELF\s0 executable, the contents of the environment variable +\&\f(CW\*(C`LD_RUN_PATH\*(C'\fR will be used if it is defined. +.Sp +The \fB\-rpath\fR option may also be used on SunOS. By default, on +SunOS, the linker will form a runtime search patch out of all the +\&\fB\-L\fR options it is given. If a \fB\-rpath\fR option is used, the +runtime search path will be formed exclusively using the \fB\-rpath\fR +options, ignoring the \fB\-L\fR options. This can be useful when using +gcc, which adds many \fB\-L\fR options which may be on \s-1NFS\s0 mounted +filesystems. +.Sp +For compatibility with other \s-1ELF\s0 linkers, if the \fB\-R\fR option is +followed by a directory name, rather than a file name, it is treated as +the \fB\-rpath\fR option. +.IP "\fB\-rpath\-link\fR \fI\s-1DIR\s0\fR" 4 +.IX Item "-rpath-link DIR" +When using \s-1ELF\s0 or SunOS, one shared library may require another. This +happens when an \f(CW\*(C`ld \-shared\*(C'\fR link includes a shared library as one +of the input files. +.Sp +When the linker encounters such a dependency when doing a non\-shared, +non-relocatable link, it will automatically try to locate the required +shared library and include it in the link, if it is not included +explicitly. In such a case, the \fB\-rpath\-link\fR option +specifies the first set of directories to search. The +\&\fB\-rpath\-link\fR option may specify a sequence of directory names +either by specifying a list of names separated by colons, or by +appearing multiple times. +.Sp +This option should be used with caution as it overrides the search path +that may have been hard compiled into a shared library. In such a case it +is possible to use unintentionally a different search path than the +runtime linker would do. +.Sp +The linker uses the following search paths to locate required shared +libraries. +.RS 4 +.IP "1." 4 +Any directories specified by \fB\-rpath\-link\fR options. +.IP "2." 4 +Any directories specified by \fB\-rpath\fR options. The difference +between \fB\-rpath\fR and \fB\-rpath\-link\fR is that directories +specified by \fB\-rpath\fR options are included in the executable and +used at runtime, whereas the \fB\-rpath\-link\fR option is only effective +at link time. It is for the native linker only. +.IP "3." 4 +On an \s-1ELF\s0 system, if the \fB\-rpath\fR and \f(CW\*(C`rpath\-link\*(C'\fR options +were not used, search the contents of the environment variable +\&\f(CW\*(C`LD_RUN_PATH\*(C'\fR. It is for the native linker only. +.IP "4." 4 +On SunOS, if the \fB\-rpath\fR option was not used, search any +directories specified using \fB\-L\fR options. +.IP "5." 4 +For a native linker, the contents of the environment variable +\&\f(CW\*(C`LD_LIBRARY_PATH\*(C'\fR. +.IP "6." 4 +For a native \s-1ELF\s0 linker, the directories in \f(CW\*(C`DT_RUNPATH\*(C'\fR or +\&\f(CW\*(C`DT_RPATH\*(C'\fR of a shared library are searched for shared +libraries needed by it. The \f(CW\*(C`DT_RPATH\*(C'\fR entries are ignored if +\&\f(CW\*(C`DT_RUNPATH\*(C'\fR entries exist. +.IP "7." 4 +The default directories, normally \fI/lib\fR and \fI/usr/lib\fR. +.IP "8." 4 +For a native linker on an \s-1ELF\s0 system, if the file \fI/etc/ld.so.conf\fR +exists, the list of directories found in that file. +.RE +.RS 4 +.Sp +If the required shared library is not found, the linker will issue a +warning and continue with the link. +.RE +.IP "\fB\-shared\fR" 4 +.IX Item "-shared" +.PD 0 +.IP "\fB\-Bshareable\fR" 4 +.IX Item "-Bshareable" +.PD +Create a shared library. This is currently only supported on \s-1ELF\s0, \s-1XCOFF\s0 +and SunOS platforms. On SunOS, the linker will automatically create a +shared library if the \fB\-e\fR option is not used and there are +undefined symbols in the link. +.IP "\fB\-\-sort\-common\fR" 4 +.IX Item "--sort-common" +This option tells \fBld\fR to sort the common symbols by size when it +places them in the appropriate output sections. First come all the one +byte symbols, then all the two byte, then all the four byte, and then +everything else. This is to prevent gaps between symbols due to +alignment constraints. +.IP "\fB\-\-split\-by\-file [\fR\fIsize\fR\fB]\fR" 4 +.IX Item "--split-by-file [size]" +Similar to \fB\-\-split\-by\-reloc\fR but creates a new output section for +each input file when \fIsize\fR is reached. \fIsize\fR defaults to a +size of 1 if not given. +.IP "\fB\-\-split\-by\-reloc [\fR\fIcount\fR\fB]\fR" 4 +.IX Item "--split-by-reloc [count]" +Tries to creates extra sections in the output file so that no single +output section in the file contains more than \fIcount\fR relocations. +This is useful when generating huge relocatable files for downloading into +certain real time kernels with the \s-1COFF\s0 object file format; since \s-1COFF\s0 +cannot represent more than 65535 relocations in a single section. Note +that this will fail to work with object file formats which do not +support arbitrary sections. The linker will not split up individual +input sections for redistribution, so if a single input section contains +more than \fIcount\fR relocations one output section will contain that +many relocations. \fIcount\fR defaults to a value of 32768. +.IP "\fB\-\-stats\fR" 4 +.IX Item "--stats" +Compute and display statistics about the operation of the linker, such +as execution time and memory usage. +.IP "\fB\-\-traditional\-format\fR" 4 +.IX Item "--traditional-format" +For some targets, the output of \fBld\fR is different in some ways from +the output of some existing linker. This switch requests \fBld\fR to +use the traditional format instead. +.Sp +For example, on SunOS, \fBld\fR combines duplicate entries in the +symbol string table. This can reduce the size of an output file with +full debugging information by over 30 percent. Unfortunately, the SunOS +\&\f(CW\*(C`dbx\*(C'\fR program can not read the resulting program (\f(CW\*(C`gdb\*(C'\fR has no +trouble). The \fB\-\-traditional\-format\fR switch tells \fBld\fR to not +combine duplicate entries. +.IP "\fB\-\-section\-start\fR \fIsectionname\fR\fB=\fR\fIorg\fR" 4 +.IX Item "--section-start sectionname=org" +Locate a section in the output file at the absolute +address given by \fIorg\fR. You may use this option as many +times as necessary to locate multiple sections in the command +line. +\&\fIorg\fR must be a single hexadecimal integer; +for compatibility with other linkers, you may omit the leading +\&\fB0x\fR usually associated with hexadecimal values. \fINote:\fR there +should be no white space between \fIsectionname\fR, the equals +sign (``\fB=\fR''), and \fIorg\fR. +.IP "\fB\-Tbss\fR \fIorg\fR" 4 +.IX Item "-Tbss org" +.PD 0 +.IP "\fB\-Tdata\fR \fIorg\fR" 4 +.IX Item "-Tdata org" +.IP "\fB\-Ttext\fR \fIorg\fR" 4 +.IX Item "-Ttext org" +.PD +Same as \-\-section\-start, with \f(CW\*(C`.bss\*(C'\fR, \f(CW\*(C`.data\*(C'\fR or +\&\f(CW\*(C`.text\*(C'\fR as the \fIsectionname\fR. +.IP "\fB\-\-dll\-verbose\fR" 4 +.IX Item "--dll-verbose" +.PD 0 +.IP "\fB\-\-verbose\fR" 4 +.IX Item "--verbose" +.PD +Display the version number for \fBld\fR and list the linker emulations +supported. Display which input files can and cannot be opened. Display +the linker script being used by the linker. +.IP "\fB\-\-version\-script=\fR\fIversion-scriptfile\fR" 4 +.IX Item "--version-script=version-scriptfile" +Specify the name of a version script to the linker. This is typically +used when creating shared libraries to specify additional information +about the version hierarchy for the library being created. This option +is only meaningful on \s-1ELF\s0 platforms which support shared libraries. +.IP "\fB\-\-warn\-common\fR" 4 +.IX Item "--warn-common" +Warn when a common symbol is combined with another common symbol or with +a symbol definition. Unix linkers allow this somewhat sloppy practice, +but linkers on some other operating systems do not. This option allows +you to find potential problems from combining global symbols. +Unfortunately, some C libraries use this practice, so you may get some +warnings about symbols in the libraries as well as in your programs. +.Sp +There are three kinds of global symbols, illustrated here by C examples: +.RS 4 +.IP "\fBint i = 1;\fR" 4 +.IX Item "int i = 1;" +A definition, which goes in the initialized data section of the output +file. +.IP "\fBextern int i;\fR" 4 +.IX Item "extern int i;" +An undefined reference, which does not allocate space. +There must be either a definition or a common symbol for the +variable somewhere. +.IP "\fBint i;\fR" 4 +.IX Item "int i;" +A common symbol. If there are only (one or more) common symbols for a +variable, it goes in the uninitialized data area of the output file. +The linker merges multiple common symbols for the same variable into a +single symbol. If they are of different sizes, it picks the largest +size. The linker turns a common symbol into a declaration, if there is +a definition of the same variable. +.RE +.RS 4 +.Sp +The \fB\-\-warn\-common\fR option can produce five kinds of warnings. +Each warning consists of a pair of lines: the first describes the symbol +just encountered, and the second describes the previous symbol +encountered with the same name. One or both of the two symbols will be +a common symbol. +.IP "1." 4 +Turning a common symbol into a reference, because there is already a +definition for the symbol. +.Sp +.Vb 3 +\& (
): warning: common of `' +\& overridden by definition +\& (
): warning: defined here +.Ve +.IP "2." 4 +Turning a common symbol into a reference, because a later definition for +the symbol is encountered. This is the same as the previous case, +except that the symbols are encountered in a different order. +.Sp +.Vb 3 +\& (
): warning: definition of `' +\& overriding common +\& (
): warning: common is here +.Ve +.IP "3." 4 +Merging a common symbol with a previous same-sized common symbol. +.Sp +.Vb 3 +\& (
): warning: multiple common +\& of `' +\& (
): warning: previous common is here +.Ve +.IP "4." 4 +Merging a common symbol with a previous larger common symbol. +.Sp +.Vb 3 +\& (
): warning: common of `' +\& overridden by larger common +\& (
): warning: larger common is here +.Ve +.IP "5." 4 +Merging a common symbol with a previous smaller common symbol. This is +the same as the previous case, except that the symbols are +encountered in a different order. +.Sp +.Vb 3 +\& (
): warning: common of `' +\& overriding smaller common +\& (
): warning: smaller common is here +.Ve +.RE +.RS 4 +.RE +.IP "\fB\-\-warn\-constructors\fR" 4 +.IX Item "--warn-constructors" +Warn if any global constructors are used. This is only useful for a few +object file formats. For formats like \s-1COFF\s0 or \s-1ELF\s0, the linker can not +detect the use of global constructors. +.IP "\fB\-\-warn\-multiple\-gp\fR" 4 +.IX Item "--warn-multiple-gp" +Warn if multiple global pointer values are required in the output file. +This is only meaningful for certain processors, such as the Alpha. +Specifically, some processors put large-valued constants in a special +section. A special register (the global pointer) points into the middle +of this section, so that constants can be loaded efficiently via a +base-register relative addressing mode. Since the offset in +base-register relative mode is fixed and relatively small (e.g., 16 +bits), this limits the maximum size of the constant pool. Thus, in +large programs, it is often necessary to use multiple global pointer +values in order to be able to address all possible constants. This +option causes a warning to be issued whenever this case occurs. +.IP "\fB\-\-warn\-once\fR" 4 +.IX Item "--warn-once" +Only warn once for each undefined symbol, rather than once per module +which refers to it. +.IP "\fB\-\-warn\-section\-align\fR" 4 +.IX Item "--warn-section-align" +Warn if the address of an output section is changed because of +alignment. Typically, the alignment will be set by an input section. +The address will only be changed if it not explicitly specified; that +is, if the \f(CW\*(C`SECTIONS\*(C'\fR command does not specify a start address for +the section. +.IP "\fB\-\-whole\-archive\fR" 4 +.IX Item "--whole-archive" +For each archive mentioned on the command line after the +\&\fB\-\-whole\-archive\fR option, include every object file in the archive +in the link, rather than searching the archive for the required object +files. This is normally used to turn an archive file into a shared +library, forcing every object to be included in the resulting shared +library. This option may be used more than once. +.Sp +Two notes when using this option from gcc: First, gcc doesn't know +about this option, so you have to use \fB\-Wl,\-whole\-archive\fR. +Second, don't forget to use \fB\-Wl,\-no\-whole\-archive\fR after your +list of archives, because gcc will add its own list of archives to +your link and you may not want this flag to affect those as well. +.IP "\fB\-\-wrap\fR \fIsymbol\fR" 4 +.IX Item "--wrap symbol" +Use a wrapper function for \fIsymbol\fR. Any undefined reference to +\&\fIsymbol\fR will be resolved to \f(CW\*(C`_\|_wrap_\f(CIsymbol\f(CW\*(C'\fR. Any +undefined reference to \f(CW\*(C`_\|_real_\f(CIsymbol\f(CW\*(C'\fR will be resolved to +\&\fIsymbol\fR. +.Sp +This can be used to provide a wrapper for a system function. The +wrapper function should be called \f(CW\*(C`_\|_wrap_\f(CIsymbol\f(CW\*(C'\fR. If it +wishes to call the system function, it should call +\&\f(CW\*(C`_\|_real_\f(CIsymbol\f(CW\*(C'\fR. +.Sp +Here is a trivial example: +.Sp +.Vb 6 +\& void * +\& __wrap_malloc (int c) +\& { +\& printf ("malloc called with %ld\en", c); +\& return __real_malloc (c); +\& } +.Ve +.Sp +If you link other code with this file using \fB\-\-wrap malloc\fR, then +all calls to \f(CW\*(C`malloc\*(C'\fR will call the function \f(CW\*(C`_\|_wrap_malloc\*(C'\fR +instead. The call to \f(CW\*(C`_\|_real_malloc\*(C'\fR in \f(CW\*(C`_\|_wrap_malloc\*(C'\fR will +call the real \f(CW\*(C`malloc\*(C'\fR function. +.Sp +You may wish to provide a \f(CW\*(C`_\|_real_malloc\*(C'\fR function as well, so that +links without the \fB\-\-wrap\fR option will succeed. If you do this, +you should not put the definition of \f(CW\*(C`_\|_real_malloc\*(C'\fR in the same +file as \f(CW\*(C`_\|_wrap_malloc\*(C'\fR; if you do, the assembler may resolve the +call before the linker has a chance to wrap it to \f(CW\*(C`malloc\*(C'\fR. +.IP "\fB\-\-enable\-new\-dtags\fR" 4 +.IX Item "--enable-new-dtags" +.PD 0 +.IP "\fB\-\-disable\-new\-dtags\fR" 4 +.IX Item "--disable-new-dtags" +.PD +This linker can create the new dynamic tags in \s-1ELF\s0. But the older \s-1ELF\s0 +systems may not understand them. If you specify +\&\fB\-\-enable\-new\-dtags\fR, the dynamic tags will be created as needed. +If you specify \fB\-\-disable\-new\-dtags\fR, no new dynamic tags will be +created. By default, the new dynamic tags are not created. Note that +those options are only available for \s-1ELF\s0 systems. +.PP +The i386 \s-1PE\s0 linker supports the \fB\-shared\fR option, which causes +the output to be a dynamically linked library (\s-1DLL\s0) instead of a +normal executable. You should name the output \f(CW\*(C`*.dll\*(C'\fR when you +use this option. In addition, the linker fully supports the standard +\&\f(CW\*(C`*.def\*(C'\fR files, which may be specified on the linker command line +like an object file (in fact, it should precede archives it exports +symbols from, to ensure that they get linked in, just like a normal +object file). +.PP +In addition to the options common to all targets, the i386 \s-1PE\s0 linker +support additional command line options that are specific to the i386 +\&\s-1PE\s0 target. Options that take values may be separated from their +values by either a space or an equals sign. +.IP "\fB\-\-add\-stdcall\-alias\fR" 4 +.IX Item "--add-stdcall-alias" +If given, symbols with a stdcall suffix (@\fInn\fR) will be exported +as-is and also with the suffix stripped. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-base\-file\fR \fIfile\fR" 4 +.IX Item "--base-file file" +Use \fIfile\fR as the name of a file in which to save the base +addresses of all the relocations needed for generating DLLs with +\&\fIdlltool\fR. +[This is an i386 \s-1PE\s0 specific option] +.IP "\fB\-\-dll\fR" 4 +.IX Item "--dll" +Create a \s-1DLL\s0 instead of a regular executable. You may also use +\&\fB\-shared\fR or specify a \f(CW\*(C`LIBRARY\*(C'\fR in a given \f(CW\*(C`.def\*(C'\fR +file. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-enable\-stdcall\-fixup\fR" 4 +.IX Item "--enable-stdcall-fixup" +.PD 0 +.IP "\fB\-\-disable\-stdcall\-fixup\fR" 4 +.IX Item "--disable-stdcall-fixup" +.PD +If the link finds a symbol that it cannot resolve, it will attempt to +do ``fuzzy linking'' by looking for another defined symbol that differs +only in the format of the symbol name (cdecl vs stdcall) and will +resolve that symbol by linking to the match. For example, the +undefined symbol \f(CW\*(C`_foo\*(C'\fR might be linked to the function +\&\f(CW\*(C`_foo@12\*(C'\fR, or the undefined symbol \f(CW\*(C`_bar@16\*(C'\fR might be linked +to the function \f(CW\*(C`_bar\*(C'\fR. When the linker does this, it prints a +warning, since it normally should have failed to link, but sometimes +import libraries generated from third-party dlls may need this feature +to be usable. If you specify \fB\-\-enable\-stdcall\-fixup\fR, this +feature is fully enabled and warnings are not printed. If you specify +\&\fB\-\-disable\-stdcall\-fixup\fR, this feature is disabled and such +mismatches are considered to be errors. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-export\-all\-symbols\fR" 4 +.IX Item "--export-all-symbols" +If given, all global symbols in the objects used to build a \s-1DLL\s0 will +be exported by the \s-1DLL\s0. Note that this is the default if there +otherwise wouldn't be any exported symbols. When symbols are +explicitly exported via \s-1DEF\s0 files or implicitly exported via function +attributes, the default is to not export anything else unless this +option is given. Note that the symbols \f(CW\*(C`DllMain@12\*(C'\fR, +\&\f(CW\*(C`DllEntryPoint@0\*(C'\fR, \f(CW\*(C`DllMainCRTStartup@12\*(C'\fR, and +\&\f(CW\*(C`impure_ptr\*(C'\fR will not be automatically +exported. Also, symbols imported from other DLLs will not be +re\-exported, nor will symbols specifying the \s-1DLL\s0's internal layout +such as those beginning with \f(CW\*(C`_head_\*(C'\fR or ending with +\&\f(CW\*(C`_iname\*(C'\fR. In addition, no symbols from \f(CW\*(C`libgcc\*(C'\fR, +\&\f(CW\*(C`libstd++\*(C'\fR, \f(CW\*(C`libmingw32\*(C'\fR, or \f(CW\*(C`crtX.o\*(C'\fR will be exported. +Symbols whose names begin with \f(CW\*(C`_\|_rtti_\*(C'\fR or \f(CW\*(C`_\|_builtin_\*(C'\fR will +not be exported, to help with \*(C+ DLLs. Finally, there is an +extensive list of cygwin-private symbols that are not exported +(obviously, this applies on when building DLLs for cygwin targets). +These cygwin-excludes are: \f(CW\*(C`_cygwin_dll_entry@12\*(C'\fR, +\&\f(CW\*(C`_cygwin_crt0_common@8\*(C'\fR, \f(CW\*(C`_cygwin_noncygwin_dll_entry@12\*(C'\fR, +\&\f(CW\*(C`_fmode\*(C'\fR, \f(CW\*(C`_impure_ptr\*(C'\fR, \f(CW\*(C`cygwin_attach_dll\*(C'\fR, +\&\f(CW\*(C`cygwin_premain0\*(C'\fR, \f(CW\*(C`cygwin_premain1\*(C'\fR, \f(CW\*(C`cygwin_premain2\*(C'\fR, +\&\f(CW\*(C`cygwin_premain3\*(C'\fR, and \f(CW\*(C`environ\*(C'\fR. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-exclude\-symbols\fR \fIsymbol\fR\fB,\fR\fIsymbol\fR\fB,...\fR" 4 +.IX Item "--exclude-symbols symbol,symbol,..." +Specifies a list of symbols which should not be automatically +exported. The symbol names may be delimited by commas or colons. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-exclude\-libs\fR \fIlib\fR\fB,\fR\fIlib\fR\fB,...\fR" 4 +.IX Item "--exclude-libs lib,lib,..." +Specifies a list of archive libraries from which symbols should not be automatically +exported. The library names may be delimited by commas or colons. Specifying +\&\f(CW\*(C`\-\-exclude\-libs ALL\*(C'\fR excludes symbols in all archive libraries from +automatic export. Symbols explicitly listed in a .def file are still exported, +regardless of this option. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-file\-alignment\fR" 4 +.IX Item "--file-alignment" +Specify the file alignment. Sections in the file will always begin at +file offsets which are multiples of this number. This defaults to +512. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-heap\fR \fIreserve\fR" 4 +.IX Item "--heap reserve" +.PD 0 +.IP "\fB\-\-heap\fR \fIreserve\fR\fB,\fR\fIcommit\fR" 4 +.IX Item "--heap reserve,commit" +.PD +Specify the amount of memory to reserve (and optionally commit) to be +used as heap for this program. The default is 1Mb reserved, 4K +committed. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-image\-base\fR \fIvalue\fR" 4 +.IX Item "--image-base value" +Use \fIvalue\fR as the base address of your program or dll. This is +the lowest memory location that will be used when your program or dll +is loaded. To reduce the need to relocate and improve performance of +your dlls, each should have a unique base address and not overlap any +other dlls. The default is 0x400000 for executables, and 0x10000000 +for dlls. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-kill\-at\fR" 4 +.IX Item "--kill-at" +If given, the stdcall suffixes (@\fInn\fR) will be stripped from +symbols before they are exported. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-major\-image\-version\fR \fIvalue\fR" 4 +.IX Item "--major-image-version value" +Sets the major number of the ``image version''. Defaults to 1. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-major\-os\-version\fR \fIvalue\fR" 4 +.IX Item "--major-os-version value" +Sets the major number of the ``os version''. Defaults to 4. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-major\-subsystem\-version\fR \fIvalue\fR" 4 +.IX Item "--major-subsystem-version value" +Sets the major number of the ``subsystem version''. Defaults to 4. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-minor\-image\-version\fR \fIvalue\fR" 4 +.IX Item "--minor-image-version value" +Sets the minor number of the ``image version''. Defaults to 0. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-minor\-os\-version\fR \fIvalue\fR" 4 +.IX Item "--minor-os-version value" +Sets the minor number of the ``os version''. Defaults to 0. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-minor\-subsystem\-version\fR \fIvalue\fR" 4 +.IX Item "--minor-subsystem-version value" +Sets the minor number of the ``subsystem version''. Defaults to 0. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-output\-def\fR \fIfile\fR" 4 +.IX Item "--output-def file" +The linker will create the file \fIfile\fR which will contain a \s-1DEF\s0 +file corresponding to the \s-1DLL\s0 the linker is generating. This \s-1DEF\s0 file +(which should be called \f(CW\*(C`*.def\*(C'\fR) may be used to create an import +library with \f(CW\*(C`dlltool\*(C'\fR or may be used as a reference to +automatically or implicitly exported symbols. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-out\-implib\fR \fIfile\fR" 4 +.IX Item "--out-implib file" +The linker will create the file \fIfile\fR which will contain an +import lib corresponding to the \s-1DLL\s0 the linker is generating. This +import lib (which should be called \f(CW\*(C`*.dll.a\*(C'\fR or \f(CW\*(C`*.a\*(C'\fR +may be used to link clients against the generated \s-1DLL\s0; this behavior +makes it possible to skip a separate \f(CW\*(C`dlltool\*(C'\fR import library +creation step. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-enable\-auto\-image\-base\fR" 4 +.IX Item "--enable-auto-image-base" +Automatically choose the image base for DLLs, unless one is specified +using the \f(CW\*(C`\-\-image\-base\*(C'\fR argument. By using a hash generated +from the dllname to create unique image bases for each \s-1DLL\s0, in-memory +collisions and relocations which can delay program execution are +avoided. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-disable\-auto\-image\-base\fR" 4 +.IX Item "--disable-auto-image-base" +Do not automatically generate a unique image base. If there is no +user-specified image base (\f(CW\*(C`\-\-image\-base\*(C'\fR) then use the platform +default. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-dll\-search\-prefix\fR \fIstring\fR" 4 +.IX Item "--dll-search-prefix string" +When linking dynamically to a dll without an import library, +search for \f(CW\*(C`.dll\*(C'\fR in preference to +\&\f(CW\*(C`lib.dll\*(C'\fR. This behavior allows easy distinction +between DLLs built for the various \*(L"subplatforms\*(R": native, cygwin, +uwin, pw, etc. For instance, cygwin DLLs typically use +\&\f(CW\*(C`\-\-dll\-search\-prefix=cyg\*(C'\fR. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-enable\-auto\-import\fR" 4 +.IX Item "--enable-auto-import" +Do sophisticated linking of \f(CW\*(C`_symbol\*(C'\fR to \f(CW\*(C`_\|_imp_\|_symbol\*(C'\fR for +\&\s-1DATA\s0 imports from DLLs, and create the necessary thunking symbols when +building the import libraries with those \s-1DATA\s0 exports. This generally +will 'just work' \*(-- but sometimes you may see this message: +.Sp +"variable '' can't be auto\-imported. Please read the +documentation for ld's \f(CW\*(C`\-\-enable\-auto\-import\*(C'\fR for details." +.Sp +This message occurs when some (sub)expression accesses an address +ultimately given by the sum of two constants (Win32 import tables only +allow one). Instances where this may occur include accesses to member +fields of struct variables imported from a \s-1DLL\s0, as well as using a +constant index into an array variable imported from a \s-1DLL\s0. Any +multiword variable (arrays, structs, long long, etc) may trigger +this error condition. However, regardless of the exact data type +of the offending exported variable, ld will always detect it, issue +the warning, and exit. +.Sp +There are several ways to address this difficulty, regardless of the +data type of the exported variable: +.Sp +One way is to use \-\-enable\-runtime\-pseudo\-reloc switch. This leaves the task +of adjusting references in your client code for runtime environment, so +this method works only when runtime environtment supports this feature. +.Sp +A second solution is to force one of the 'constants' to be a variable \*(-- +that is, unknown and un-optimizable at compile time. For arrays, +there are two possibilities: a) make the indexee (the array's address) +a variable, or b) make the 'constant' index a variable. Thus: +.Sp +.Vb 3 +\& extern type extern_array[]; +\& extern_array[1] --> +\& { volatile type *t=extern_array; t[1] } +.Ve +.Sp +or +.Sp +.Vb 3 +\& extern type extern_array[]; +\& extern_array[1] --> +\& { volatile int t=1; extern_array[t] } +.Ve +.Sp +For structs (and most other multiword data types) the only option +is to make the struct itself (or the long long, or the ...) variable: +.Sp +.Vb 3 +\& extern struct s extern_struct; +\& extern_struct.field --> +\& { volatile struct s *t=&extern_struct; t->field } +.Ve +.Sp +or +.Sp +.Vb 3 +\& extern long long extern_ll; +\& extern_ll --> +\& { volatile long long * local_ll=&extern_ll; *local_ll } +.Ve +.Sp +A third method of dealing with this difficulty is to abandon +\&'auto\-import' for the offending symbol and mark it with +\&\f(CW\*(C`_\|_declspec(dllimport)\*(C'\fR. However, in practice that +requires using compile-time #defines to indicate whether you are +building a \s-1DLL\s0, building client code that will link to the \s-1DLL\s0, or +merely building/linking to a static library. In making the choice +between the various methods of resolving the 'direct address with +constant offset' problem, you should consider typical real-world usage: +.Sp +Original: +.Sp +.Vb 7 +\& --foo.h +\& extern int arr[]; +\& --foo.c +\& #include "foo.h" +\& void main(int argc, char **argv){ +\& printf("%d\en",arr[1]); +\& } +.Ve +.Sp +Solution 1: +.Sp +.Vb 9 +\& --foo.h +\& extern int arr[]; +\& --foo.c +\& #include "foo.h" +\& void main(int argc, char **argv){ +\& /* This workaround is for win32 and cygwin; do not "optimize" */ +\& volatile int *parr = arr; +\& printf("%d\en",parr[1]); +\& } +.Ve +.Sp +Solution 2: +.Sp +.Vb 14 +\& --foo.h +\& /* Note: auto-export is assumed (no __declspec(dllexport)) */ +\& #if (defined(_WIN32) || defined(__CYGWIN__)) && \e +\& !(defined(FOO_BUILD_DLL) || defined(FOO_STATIC)) +\& #define FOO_IMPORT __declspec(dllimport) +\& #else +\& #define FOO_IMPORT +\& #endif +\& extern FOO_IMPORT int arr[]; +\& --foo.c +\& #include "foo.h" +\& void main(int argc, char **argv){ +\& printf("%d\en",arr[1]); +\& } +.Ve +.Sp +A fourth way to avoid this problem is to re-code your +library to use a functional interface rather than a data interface +for the offending variables (e.g. \fIset_foo()\fR and \fIget_foo()\fR accessor +functions). +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-disable\-auto\-import\fR" 4 +.IX Item "--disable-auto-import" +Do not attempt to do sophisticalted linking of \f(CW\*(C`_symbol\*(C'\fR to +\&\f(CW\*(C`_\|_imp_\|_symbol\*(C'\fR for \s-1DATA\s0 imports from DLLs. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-enable\-runtime\-pseudo\-reloc\fR" 4 +.IX Item "--enable-runtime-pseudo-reloc" +If your code contains expressions described in \-\-enable\-auto\-import section, +that is, \s-1DATA\s0 imports from \s-1DLL\s0 with non-zero offset, this switch will create +a vector of 'runtime pseudo relocations' which can be used by runtime +environment to adjust references to such data in your client code. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-disable\-runtime\-pseudo\-reloc\fR" 4 +.IX Item "--disable-runtime-pseudo-reloc" +Do not create pseudo relocations for non-zero offset \s-1DATA\s0 imports from +DLLs. This is the default. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-enable\-extra\-pe\-debug\fR" 4 +.IX Item "--enable-extra-pe-debug" +Show additional debug info related to auto-import symbol thunking. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-section\-alignment\fR" 4 +.IX Item "--section-alignment" +Sets the section alignment. Sections in memory will always begin at +addresses which are a multiple of this number. Defaults to 0x1000. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-stack\fR \fIreserve\fR" 4 +.IX Item "--stack reserve" +.PD 0 +.IP "\fB\-\-stack\fR \fIreserve\fR\fB,\fR\fIcommit\fR" 4 +.IX Item "--stack reserve,commit" +.PD +Specify the amount of memory to reserve (and optionally commit) to be +used as stack for this program. The default is 2Mb reserved, 4K +committed. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.IP "\fB\-\-subsystem\fR \fIwhich\fR" 4 +.IX Item "--subsystem which" +.PD 0 +.IP "\fB\-\-subsystem\fR \fIwhich\fR\fB:\fR\fImajor\fR" 4 +.IX Item "--subsystem which:major" +.IP "\fB\-\-subsystem\fR \fIwhich\fR\fB:\fR\fImajor\fR\fB.\fR\fIminor\fR" 4 +.IX Item "--subsystem which:major.minor" +.PD +Specifies the subsystem under which your program will execute. The +legal values for \fIwhich\fR are \f(CW\*(C`native\*(C'\fR, \f(CW\*(C`windows\*(C'\fR, +\&\f(CW\*(C`console\*(C'\fR, and \f(CW\*(C`posix\*(C'\fR. You may optionally set the +subsystem version also. +[This option is specific to the i386 \s-1PE\s0 targeted port of the linker] +.SH "ENVIRONMENT" +.IX Header "ENVIRONMENT" +You can change the behavior of \fBld\fR with the environment variables +\&\f(CW\*(C`GNUTARGET\*(C'\fR, +\&\f(CW\*(C`LDEMULATION\*(C'\fR and \f(CW\*(C`COLLECT_NO_DEMANGLE\*(C'\fR. +.PP +\&\f(CW\*(C`GNUTARGET\*(C'\fR determines the input-file object format if you don't +use \fB\-b\fR (or its synonym \fB\-\-format\fR). Its value should be one +of the \s-1BFD\s0 names for an input format. If there is no +\&\f(CW\*(C`GNUTARGET\*(C'\fR in the environment, \fBld\fR uses the natural format +of the target. If \f(CW\*(C`GNUTARGET\*(C'\fR is set to \f(CW\*(C`default\*(C'\fR then \s-1BFD\s0 +attempts to discover the input format by examining binary input files; +this method often succeeds, but there are potential ambiguities, since +there is no method of ensuring that the magic number used to specify +object-file formats is unique. However, the configuration procedure for +\&\s-1BFD\s0 on each system places the conventional format for that system first +in the search\-list, so ambiguities are resolved in favor of convention. +.PP +\&\f(CW\*(C`LDEMULATION\*(C'\fR determines the default emulation if you don't use the +\&\fB\-m\fR option. The emulation can affect various aspects of linker +behaviour, particularly the default linker script. You can list the +available emulations with the \fB\-\-verbose\fR or \fB\-V\fR options. If +the \fB\-m\fR option is not used, and the \f(CW\*(C`LDEMULATION\*(C'\fR environment +variable is not defined, the default emulation depends upon how the +linker was configured. +.PP +Normally, the linker will default to demangling symbols. However, if +\&\f(CW\*(C`COLLECT_NO_DEMANGLE\*(C'\fR is set in the environment, then it will +default to not demangling symbols. This environment variable is used in +a similar fashion by the \f(CW\*(C`gcc\*(C'\fR linker wrapper program. The default +may be overridden by the \fB\-\-demangle\fR and \fB\-\-no\-demangle\fR +options. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIar\fR\|(1), \fInm\fR\|(1), \fIobjcopy\fR\|(1), \fIobjdump\fR\|(1), \fIreadelf\fR\|(1) and +the Info entries for \fIbinutils\fR and +\&\fIld\fR. +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, +2002, 2003 Free Software Foundation, Inc. +.PP +Permission is granted to copy, distribute and/or modify this document +under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``\s-1GNU\s0 Free Documentation License''. diff --git a/contrib/binutils-2.14/ld/ld.h b/contrib/binutils-2.14/ld/ld.h new file mode 100644 index 0000000000..75c054e775 --- /dev/null +++ b/contrib/binutils-2.14/ld/ld.h @@ -0,0 +1,252 @@ +/* ld.h -- general linker header file + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2002 + Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GLD; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef LD_H +#define LD_H + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef ENABLE_NLS +# include +# define _(String) gettext (String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define gettext(Msgid) (Msgid) +# define dgettext(Domainname, Msgid) (Msgid) +# define dcgettext(Domainname, Msgid, Category) (Msgid) +# define textdomain(Domainname) while (0) /* nothing */ +# define bindtextdomain(Domainname, Dirname) while (0) /* nothing */ +# define _(String) (String) +# define N_(String) (String) +#endif + +#include "bin-bugs.h" + +/* Look in this environment name for the linker to pretend to be */ +#define EMULATION_ENVIRON "LDEMULATION" +/* If in there look for the strings: */ + +/* Look in this variable for a target format */ +#define TARGET_ENVIRON "GNUTARGET" + +/* Input sections which are put in a section of this name are actually + discarded. */ +#define DISCARD_SECTION_NAME "/DISCARD/" + +/* A file name list */ +typedef struct name_list { + const char *name; + struct name_list *next; +} +name_list; + +/* A wildcard specification. This is only used in ldgram.y, but it + winds up in ldgram.h, so we need to define it outside. */ + +struct wildcard_spec { + const char *name; + struct name_list *exclude_name_list; + bfd_boolean sorted; +}; + +struct wildcard_list { + struct wildcard_list *next; + struct wildcard_spec spec; +}; + +/* Extra information we hold on sections */ +typedef struct user_section_struct { + /* Pointer to the section where this data will go */ + struct lang_input_statement_struct *file; +} section_userdata_type; + +#define get_userdata(x) ((x)->userdata) + +#define BYTE_SIZE (1) +#define SHORT_SIZE (2) +#define LONG_SIZE (4) +#define QUAD_SIZE (8) + +typedef struct { + /* 1 => assign space to common symbols even if `relocatable_output'. */ + bfd_boolean force_common_definition; + + /* 1 => do not assign addresses to common symbols. */ + bfd_boolean inhibit_common_definition; + bfd_boolean relax; + + /* Name of runtime interpreter to invoke. */ + char *interpreter; + + /* Name to give runtime libary from the -soname argument. */ + char *soname; + + /* Runtime library search path from the -rpath argument. */ + char *rpath; + + /* Link time runtime library search path from the -rpath-link + argument. */ + char *rpath_link; + + /* Big or little endian as set on command line. */ + enum { ENDIAN_UNSET = 0, ENDIAN_BIG, ENDIAN_LITTLE } endian; + + /* If TRUE, build MIPS embedded PIC relocation tables in the output + file. */ + bfd_boolean embedded_relocs; + + /* If TRUE, force generation of a file with a .exe file. */ + bfd_boolean force_exe_suffix; + + /* If TRUE, generate a cross reference report. */ + bfd_boolean cref; + + /* If TRUE (which is the default), warn about mismatched input + files. */ + bfd_boolean warn_mismatch; + + /* Remove unreferenced sections? */ + bfd_boolean gc_sections; + + /* Name of shared object whose symbol table should be filtered with + this shared object. From the --filter option. */ + char *filter_shlib; + + /* Name of shared object for whose symbol table this shared object + is an auxiliary filter. From the --auxiliary option. */ + char **auxiliary_filters; + + /* A version symbol to be applied to the symbol names found in the + .exports sections. */ + char *version_exports_section; + + /* If TRUE (the default) check section addresses, once compute, + fpor overlaps. */ + bfd_boolean check_section_addresses; + + /* If TRUE allow the linking of input files in an unknown architecture + assuming that the user knows what they are doing. This was the old + behaviour of the linker. The new default behaviour is to reject such + input files. */ + bfd_boolean accept_unknown_input_arch; + +} args_type; + +extern args_type command_line; + +typedef int token_code_type; + +typedef struct { + bfd_size_type specified_data_size; + bfd_boolean magic_demand_paged; + bfd_boolean make_executable; + + /* If TRUE, doing a dynamic link. */ + bfd_boolean dynamic_link; + + /* If TRUE, -shared is supported. */ + /* ??? A better way to do this is perhaps to define this in the + ld_emulation_xfer_struct since this is really a target dependent + parameter. */ + bfd_boolean has_shared; + + /* If TRUE, build constructors. */ + bfd_boolean build_constructors; + + /* If TRUE, warn about any constructors. */ + bfd_boolean warn_constructors; + + /* If TRUE, warn about merging common symbols with others. */ + bfd_boolean warn_common; + + /* If TRUE, only warn once about a particular undefined symbol. */ + bfd_boolean warn_once; + + /* If TRUE, warn if multiple global-pointers are needed (Alpha + only). */ + bfd_boolean warn_multiple_gp; + + /* If TRUE, warn if the starting address of an output section + changes due to the alignment of an input section. */ + bfd_boolean warn_section_align; + + /* If TRUE, warning messages are fatal */ + bfd_boolean fatal_warnings; + + bfd_boolean sort_common; + + bfd_boolean text_read_only; + + char *map_filename; + FILE *map_file; + + bfd_boolean stats; + + /* If set, orphan input sections will be mapped to separate output + sections. */ + bfd_boolean unique_orphan_sections; + + unsigned int split_by_reloc; + bfd_size_type split_by_file; + + /* If set, only search library directories explicitly selected + on the command line. */ + bfd_boolean only_cmd_line_lib_dirs; +} ld_config_type; + +extern ld_config_type config; + +typedef enum { + lang_first_phase_enum, + lang_allocating_phase_enum, + lang_final_phase_enum +} lang_phase_type; + +extern FILE * saved_script_handle; +extern bfd_boolean force_make_executable; + +/* Non-zero if we are processing a --defsym from the command line. */ +extern int parsing_defsym; + +extern int yyparse PARAMS ((void)); + +extern void add_cref PARAMS ((const char *, bfd *, asection *, bfd_vma)); +extern void output_cref PARAMS ((FILE *)); +extern void check_nocrossrefs PARAMS ((void)); + +extern void ld_abort PARAMS ((const char *, int, const char *)) + ATTRIBUTE_NORETURN; + +/* If gcc >= 2.6, we can give a function name, too. */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 6) +#define __PRETTY_FUNCTION__ ((char*) NULL) +#endif + +#undef abort +#define abort() ld_abort (__FILE__, __LINE__, __PRETTY_FUNCTION__) + +#endif diff --git a/contrib/binutils-2.14/ld/ld.texinfo b/contrib/binutils-2.14/ld/ld.texinfo new file mode 100644 index 0000000000..cfebf096e4 --- /dev/null +++ b/contrib/binutils-2.14/ld/ld.texinfo @@ -0,0 +1,5599 @@ +\input texinfo +@setfilename ld.info +@c Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +@c 2001, 2002, 2003 Free Software Foundation, Inc. +@syncodeindex ky cp +@include configdoc.texi +@c (configdoc.texi is generated by the Makefile) +@include ldver.texi + +@c @smallbook + +@macro gcctabopt{body} +@code{\body\} +@end macro + +@c man begin NAME +@ifset man +@c Configure for the generation of man pages +@set UsesEnvVars +@set GENERIC +@set A29K +@set ARC +@set ARM +@set D10V +@set D30V +@set H8/300 +@set H8/500 +@set HPPA +@set I370 +@set I80386 +@set I860 +@set I960 +@set M32R +@set M68HC11 +@set M680X0 +@set MCORE +@set MIPS +@set MMIX +@set MSP430 +@set PDP11 +@set PJ +@set SH +@set SPARC +@set TIC54X +@set V850 +@set VAX +@set WIN32 +@set XTENSA +@end ifset +@c man end + +@ifinfo +@format +START-INFO-DIR-ENTRY +* Ld: (ld). The GNU linker. +END-INFO-DIR-ENTRY +@end format +@end ifinfo + +@ifinfo +This file documents the @sc{gnu} linker LD version @value{VERSION}. + +Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, +2001, 2002, 2003 Free Software Foundation, Inc. + +@ignore + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``GNU Free Documentation License''. + +Permission is granted to process this file through Tex and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +@end ifinfo +@iftex +@finalout +@setchapternewpage odd +@settitle Using LD, the GNU linker +@titlepage +@title Using ld +@subtitle The GNU linker +@sp 1 +@subtitle @code{ld} version 2 +@subtitle Version @value{VERSION} +@author Steve Chamberlain +@author Ian Lance Taylor +@page + +@tex +{\parskip=0pt +\hfill Red Hat Inc\par +\hfill nickc\@credhat.com, doc\@redhat.com\par +\hfill {\it Using LD, the GNU linker}\par +\hfill Edited by Jeffrey Osier (jeffrey\@cygnus.com)\par +} +\global\parindent=0pt % Steve likes it this way. +@end tex + +@vskip 0pt plus 1filll +@c man begin COPYRIGHT +Copyright @copyright{} 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, +2002, 2003 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.1 +or any later version published by the Free Software Foundation; +with no Invariant Sections, with no Front-Cover Texts, and with no +Back-Cover Texts. A copy of the license is included in the +section entitled ``GNU Free Documentation License''. +@c man end + +@end titlepage +@end iftex +@c FIXME: Talk about importance of *order* of args, cmds to linker! + +@ifnottex +@node Top +@top Using ld +This file documents the @sc{gnu} linker ld version @value{VERSION}. + +This document is distributed under the terms of the GNU Free +Documentation License. A copy of the license is included in the +section entitled ``GNU Free Documentation License''. + +@menu +* Overview:: Overview +* Invocation:: Invocation +* Scripts:: Linker Scripts +@ifset GENERIC +* Machine Dependent:: Machine Dependent Features +@end ifset +@ifclear GENERIC +@ifset H8300 +* H8/300:: ld and the H8/300 +@end ifset +@ifset Renesas +* Renesas:: ld and other Renesas micros +@end ifset +@ifset I960 +* i960:: ld and the Intel 960 family +@end ifset +@ifset ARM +* ARM:: ld and the ARM family +@end ifset +@ifset HPPA +* HPPA ELF32:: ld and HPPA 32-bit ELF +@end ifset +@ifset TICOFF +* TI COFF:: ld and the TI COFF +@end ifset +@ifset WIN32 +* Win32:: ld and WIN32 (cygwin/mingw) +@end ifset +@ifset XTENSA +* Xtensa:: ld and Xtensa Processors +@end ifset +@end ifclear +@ifclear SingleFormat +* BFD:: BFD +@end ifclear +@c Following blank line required for remaining bug in makeinfo conds/menus + +* Reporting Bugs:: Reporting Bugs +* MRI:: MRI Compatible Script Files +* GNU Free Documentation License:: GNU Free Documentation License +* Index:: Index +@end menu +@end ifnottex + +@node Overview +@chapter Overview + +@cindex @sc{gnu} linker +@cindex what is this? + +@ifset man +@c man begin SYNOPSIS +ld [@b{options}] @var{objfile} @dots{} +@c man end + +@c man begin SEEALSO +ar(1), nm(1), objcopy(1), objdump(1), readelf(1) and +the Info entries for @file{binutils} and +@file{ld}. +@c man end +@end ifset + +@c man begin DESCRIPTION + +@command{ld} combines a number of object and archive files, relocates +their data and ties up symbol references. Usually the last step in +compiling a program is to run @command{ld}. + +@command{ld} accepts Linker Command Language files written in +a superset of AT&T's Link Editor Command Language syntax, +to provide explicit and total control over the linking process. + +@ifset man +@c For the man only +This man page does not describe the command language; see the +@command{ld} entry in @code{info}, or the manual +ld: the GNU linker, for full details on the command language and +on other aspects of the GNU linker. +@end ifset + +@ifclear SingleFormat +This version of @command{ld} uses the general purpose BFD libraries +to operate on object files. This allows @command{ld} to read, combine, and +write object files in many different formats---for example, COFF or +@code{a.out}. Different formats may be linked together to produce any +available kind of object file. @xref{BFD}, for more information. +@end ifclear + +Aside from its flexibility, the @sc{gnu} linker is more helpful than other +linkers in providing diagnostic information. Many linkers abandon +execution immediately upon encountering an error; whenever possible, +@command{ld} continues executing, allowing you to identify other errors +(or, in some cases, to get an output file in spite of the error). + +@c man end + +@node Invocation +@chapter Invocation + +@c man begin DESCRIPTION + +The @sc{gnu} linker @command{ld} is meant to cover a broad range of situations, +and to be as compatible as possible with other linkers. As a result, +you have many choices to control its behavior. + +@c man end + +@ifset UsesEnvVars +@menu +* Options:: Command Line Options +* Environment:: Environment Variables +@end menu + +@node Options +@section Command Line Options +@end ifset + +@cindex command line +@cindex options + +@c man begin OPTIONS + +The linker supports a plethora of command-line options, but in actual +practice few of them are used in any particular context. +@cindex standard Unix system +For instance, a frequent use of @command{ld} is to link standard Unix +object files on a standard, supported Unix system. On such a system, to +link a file @code{hello.o}: + +@smallexample +ld -o @var{output} /lib/crt0.o hello.o -lc +@end smallexample + +This tells @command{ld} to produce a file called @var{output} as the +result of linking the file @code{/lib/crt0.o} with @code{hello.o} and +the library @code{libc.a}, which will come from the standard search +directories. (See the discussion of the @samp{-l} option below.) + +Some of the command-line options to @command{ld} may be specified at any +point in the command line. However, options which refer to files, such +as @samp{-l} or @samp{-T}, cause the file to be read at the point at +which the option appears in the command line, relative to the object +files and other file options. Repeating non-file options with a +different argument will either have no further effect, or override prior +occurrences (those further to the left on the command line) of that +option. Options which may be meaningfully specified more than once are +noted in the descriptions below. + +@cindex object files +Non-option arguments are object files or archives which are to be linked +together. They may follow, precede, or be mixed in with command-line +options, except that an object file argument may not be placed between +an option and its argument. + +Usually the linker is invoked with at least one object file, but you can +specify other forms of binary input files using @samp{-l}, @samp{-R}, +and the script command language. If @emph{no} binary input files at all +are specified, the linker does not produce any output, and issues the +message @samp{No input files}. + +If the linker cannot recognize the format of an object file, it will +assume that it is a linker script. A script specified in this way +augments the main linker script used for the link (either the default +linker script or the one specified by using @samp{-T}). This feature +permits the linker to link against a file which appears to be an object +or an archive, but actually merely defines some symbol values, or uses +@code{INPUT} or @code{GROUP} to load other objects. Note that +specifying a script in this way merely augments the main linker script; +use the @samp{-T} option to replace the default linker script entirely. +@xref{Scripts}. + +For options whose names are a single letter, +option arguments must either follow the option letter without intervening +whitespace, or be given as separate arguments immediately following the +option that requires them. + +For options whose names are multiple letters, either one dash or two can +precede the option name; for example, @samp{-trace-symbol} and +@samp{--trace-symbol} are equivalent. Note---there is one exception to +this rule. Multiple letter options that start with a lower case 'o' can +only be preceeded by two dashes. This is to reduce confusion with the +@samp{-o} option. So for example @samp{-omagic} sets the output file +name to @samp{magic} whereas @samp{--omagic} sets the NMAGIC flag on the +output. + +Arguments to multiple-letter options must either be separated from the +option name by an equals sign, or be given as separate arguments +immediately following the option that requires them. For example, +@samp{--trace-symbol foo} and @samp{--trace-symbol=foo} are equivalent. +Unique abbreviations of the names of multiple-letter options are +accepted. + +Note---if the linker is being invoked indirectly, via a compiler driver +(e.g. @samp{gcc}) then all the linker command line options should be +prefixed by @samp{-Wl,} (or whatever is appropriate for the particular +compiler driver) like this: + +@smallexample + gcc -Wl,--startgroup foo.o bar.o -Wl,--endgroup +@end smallexample + +This is important, because otherwise the compiler driver program may +silently drop the linker options, resulting in a bad link. + +Here is a table of the generic command line switches accepted by the GNU +linker: + +@table @gcctabopt +@kindex -a@var{keyword} +@item -a@var{keyword} +This option is supported for HP/UX compatibility. The @var{keyword} +argument must be one of the strings @samp{archive}, @samp{shared}, or +@samp{default}. @samp{-aarchive} is functionally equivalent to +@samp{-Bstatic}, and the other two keywords are functionally equivalent +to @samp{-Bdynamic}. This option may be used any number of times. + +@ifset I960 +@cindex architectures +@kindex -A@var{arch} +@item -A@var{architecture} +@kindex --architecture=@var{arch} +@itemx --architecture=@var{architecture} +In the current release of @command{ld}, this option is useful only for the +Intel 960 family of architectures. In that @command{ld} configuration, the +@var{architecture} argument identifies the particular architecture in +the 960 family, enabling some safeguards and modifying the +archive-library search path. @xref{i960,,@command{ld} and the Intel 960 +family}, for details. + +Future releases of @command{ld} may support similar functionality for +other architecture families. +@end ifset + +@ifclear SingleFormat +@cindex binary input format +@kindex -b @var{format} +@kindex --format=@var{format} +@cindex input format +@cindex input format +@item -b @var{input-format} +@itemx --format=@var{input-format} +@command{ld} may be configured to support more than one kind of object +file. If your @command{ld} is configured this way, you can use the +@samp{-b} option to specify the binary format for input object files +that follow this option on the command line. Even when @command{ld} is +configured to support alternative object formats, you don't usually need +to specify this, as @command{ld} should be configured to expect as a +default input format the most usual format on each machine. +@var{input-format} is a text string, the name of a particular format +supported by the BFD libraries. (You can list the available binary +formats with @samp{objdump -i}.) +@xref{BFD}. + +You may want to use this option if you are linking files with an unusual +binary format. You can also use @samp{-b} to switch formats explicitly (when +linking object files of different formats), by including +@samp{-b @var{input-format}} before each group of object files in a +particular format. + +The default format is taken from the environment variable +@code{GNUTARGET}. +@ifset UsesEnvVars +@xref{Environment}. +@end ifset +You can also define the input format from a script, using the command +@code{TARGET}; +@ifclear man +see @ref{Format Commands}. +@end ifclear +@end ifclear + +@kindex -c @var{MRI-cmdfile} +@kindex --mri-script=@var{MRI-cmdfile} +@cindex compatibility, MRI +@item -c @var{MRI-commandfile} +@itemx --mri-script=@var{MRI-commandfile} +For compatibility with linkers produced by MRI, @command{ld} accepts script +files written in an alternate, restricted command language, described in +@ifclear man +@ref{MRI,,MRI Compatible Script Files}. +@end ifclear +@ifset man +the MRI Compatible Script Files section of GNU ld documentation. +@end ifset +Introduce MRI script files with +the option @samp{-c}; use the @samp{-T} option to run linker +scripts written in the general-purpose @command{ld} scripting language. +If @var{MRI-cmdfile} does not exist, @command{ld} looks for it in the directories +specified by any @samp{-L} options. + +@cindex common allocation +@kindex -d +@kindex -dc +@kindex -dp +@item -d +@itemx -dc +@itemx -dp +These three options are equivalent; multiple forms are supported for +compatibility with other linkers. They assign space to common symbols +even if a relocatable output file is specified (with @samp{-r}). The +script command @code{FORCE_COMMON_ALLOCATION} has the same effect. +@xref{Miscellaneous Commands}. + +@cindex entry point, from command line +@kindex -e @var{entry} +@kindex --entry=@var{entry} +@item -e @var{entry} +@itemx --entry=@var{entry} +Use @var{entry} as the explicit symbol for beginning execution of your +program, rather than the default entry point. If there is no symbol +named @var{entry}, the linker will try to parse @var{entry} as a number, +and use that as the entry address (the number will be interpreted in +base 10; you may use a leading @samp{0x} for base 16, or a leading +@samp{0} for base 8). @xref{Entry Point}, for a discussion of defaults +and other ways of specifying the entry point. + +@cindex dynamic symbol table +@kindex -E +@kindex --export-dynamic +@item -E +@itemx --export-dynamic +When creating a dynamically linked executable, add all symbols to the +dynamic symbol table. The dynamic symbol table is the set of symbols +which are visible from dynamic objects at run time. + +If you do not use this option, the dynamic symbol table will normally +contain only those symbols which are referenced by some dynamic object +mentioned in the link. + +If you use @code{dlopen} to load a dynamic object which needs to refer +back to the symbols defined by the program, rather than some other +dynamic object, then you will probably need to use this option when +linking the program itself. + +You can also use the version script to control what symbols should +be added to the dynamic symbol table if the output format supports it. +See the description of @samp{--version-script} in @ref{VERSION}. + +@ifclear SingleFormat +@cindex big-endian objects +@cindex endianness +@kindex -EB +@item -EB +Link big-endian objects. This affects the default output format. + +@cindex little-endian objects +@kindex -EL +@item -EL +Link little-endian objects. This affects the default output format. +@end ifclear + +@kindex -f +@kindex --auxiliary +@item -f +@itemx --auxiliary @var{name} +When creating an ELF shared object, set the internal DT_AUXILIARY field +to the specified name. This tells the dynamic linker that the symbol +table of the shared object should be used as an auxiliary filter on the +symbol table of the shared object @var{name}. + +If you later link a program against this filter object, then, when you +run the program, the dynamic linker will see the DT_AUXILIARY field. If +the dynamic linker resolves any symbols from the filter object, it will +first check whether there is a definition in the shared object +@var{name}. If there is one, it will be used instead of the definition +in the filter object. The shared object @var{name} need not exist. +Thus the shared object @var{name} may be used to provide an alternative +implementation of certain functions, perhaps for debugging or for +machine specific performance. + +This option may be specified more than once. The DT_AUXILIARY entries +will be created in the order in which they appear on the command line. + +@kindex -F +@kindex --filter +@item -F @var{name} +@itemx --filter @var{name} +When creating an ELF shared object, set the internal DT_FILTER field to +the specified name. This tells the dynamic linker that the symbol table +of the shared object which is being created should be used as a filter +on the symbol table of the shared object @var{name}. + +If you later link a program against this filter object, then, when you +run the program, the dynamic linker will see the DT_FILTER field. The +dynamic linker will resolve symbols according to the symbol table of the +filter object as usual, but it will actually link to the definitions +found in the shared object @var{name}. Thus the filter object can be +used to select a subset of the symbols provided by the object +@var{name}. + +Some older linkers used the @option{-F} option throughout a compilation +toolchain for specifying object-file format for both input and output +object files. +@ifclear SingleFormat +The @sc{gnu} linker uses other mechanisms for this purpose: the +@option{-b}, @option{--format}, @option{--oformat} options, the +@code{TARGET} command in linker scripts, and the @code{GNUTARGET} +environment variable. +@end ifclear +The @sc{gnu} linker will ignore the @option{-F} option when not +creating an ELF shared object. + +@cindex finalization function +@kindex -fini +@item -fini @var{name} +When creating an ELF executable or shared object, call NAME when the +executable or shared object is unloaded, by setting DT_FINI to the +address of the function. By default, the linker uses @code{_fini} as +the function to call. + +@kindex -g +@item -g +Ignored. Provided for compatibility with other tools. + +@kindex -G +@kindex --gpsize +@cindex object size +@item -G@var{value} +@itemx --gpsize=@var{value} +Set the maximum size of objects to be optimized using the GP register to +@var{size}. This is only meaningful for object file formats such as +MIPS ECOFF which supports putting large and small objects into different +sections. This is ignored for other object file formats. + +@cindex runtime library name +@kindex -h@var{name} +@kindex -soname=@var{name} +@item -h@var{name} +@itemx -soname=@var{name} +When creating an ELF shared object, set the internal DT_SONAME field to +the specified name. When an executable is linked with a shared object +which has a DT_SONAME field, then when the executable is run the dynamic +linker will attempt to load the shared object specified by the DT_SONAME +field rather than the using the file name given to the linker. + +@kindex -i +@cindex incremental link +@item -i +Perform an incremental link (same as option @samp{-r}). + +@cindex initialization function +@kindex -init +@item -init @var{name} +When creating an ELF executable or shared object, call NAME when the +executable or shared object is loaded, by setting DT_INIT to the address +of the function. By default, the linker uses @code{_init} as the +function to call. + +@cindex archive files, from cmd line +@kindex -l@var{archive} +@kindex --library=@var{archive} +@item -l@var{archive} +@itemx --library=@var{archive} +Add archive file @var{archive} to the list of files to link. This +option may be used any number of times. @command{ld} will search its +path-list for occurrences of @code{lib@var{archive}.a} for every +@var{archive} specified. + +On systems which support shared libraries, @command{ld} may also search for +libraries with extensions other than @code{.a}. Specifically, on ELF +and SunOS systems, @command{ld} will search a directory for a library with +an extension of @code{.so} before searching for one with an extension of +@code{.a}. By convention, a @code{.so} extension indicates a shared +library. + +The linker will search an archive only once, at the location where it is +specified on the command line. If the archive defines a symbol which +was undefined in some object which appeared before the archive on the +command line, the linker will include the appropriate file(s) from the +archive. However, an undefined symbol in an object appearing later on +the command line will not cause the linker to search the archive again. + +See the @option{-(} option for a way to force the linker to search +archives multiple times. + +You may list the same archive multiple times on the command line. + +@ifset GENERIC +This type of archive searching is standard for Unix linkers. However, +if you are using @command{ld} on AIX, note that it is different from the +behaviour of the AIX linker. +@end ifset + +@cindex search directory, from cmd line +@kindex -L@var{dir} +@kindex --library-path=@var{dir} +@item -L@var{searchdir} +@itemx --library-path=@var{searchdir} +Add path @var{searchdir} to the list of paths that @command{ld} will search +for archive libraries and @command{ld} control scripts. You may use this +option any number of times. The directories are searched in the order +in which they are specified on the command line. Directories specified +on the command line are searched before the default directories. All +@option{-L} options apply to all @option{-l} options, regardless of the +order in which the options appear. + +If @var{searchdir} begins with @code{=}, then the @code{=} will be replaced +by the @dfn{sysroot prefix}, a path specified when the linker is configured. + +@ifset UsesEnvVars +The default set of paths searched (without being specified with +@samp{-L}) depends on which emulation mode @command{ld} is using, and in +some cases also on how it was configured. @xref{Environment}. +@end ifset + +The paths can also be specified in a link script with the +@code{SEARCH_DIR} command. Directories specified this way are searched +at the point in which the linker script appears in the command line. + +@cindex emulation +@kindex -m @var{emulation} +@item -m@var{emulation} +Emulate the @var{emulation} linker. You can list the available +emulations with the @samp{--verbose} or @samp{-V} options. + +If the @samp{-m} option is not used, the emulation is taken from the +@code{LDEMULATION} environment variable, if that is defined. + +Otherwise, the default emulation depends upon how the linker was +configured. + +@cindex link map +@kindex -M +@kindex --print-map +@item -M +@itemx --print-map +Print a link map to the standard output. A link map provides +information about the link, including the following: + +@itemize @bullet +@item +Where object files and symbols are mapped into memory. +@item +How common symbols are allocated. +@item +All archive members included in the link, with a mention of the symbol +which caused the archive member to be brought in. +@end itemize + +@kindex -n +@cindex read-only text +@cindex NMAGIC +@kindex --nmagic +@item -n +@itemx --nmagic +Turn off page alignment of sections, and mark the output as +@code{NMAGIC} if possible. + +@kindex -N +@kindex --omagic +@cindex read/write from cmd line +@cindex OMAGIC +@item -N +@itemx --omagic +Set the text and data sections to be readable and writable. Also, do +not page-align the data segment, and disable linking against shared +libraries. If the output format supports Unix style magic numbers, +mark the output as @code{OMAGIC}. + +@kindex --no-omagic +@cindex OMAGIC +@item --no-omagic +This option negates most of the effects of the @option{-N} option. It +sets the text section to be read-only, and forces the data segment to +be page-aligned. Note - this option does not enable linking against +shared libraries. Use @option{-Bdynamic} for this. + +@kindex -o @var{output} +@kindex --output=@var{output} +@cindex naming the output file +@item -o @var{output} +@itemx --output=@var{output} +Use @var{output} as the name for the program produced by @command{ld}; if this +option is not specified, the name @file{a.out} is used by default. The +script command @code{OUTPUT} can also specify the output file name. + +@kindex -O @var{level} +@cindex generating optimized output +@item -O @var{level} +If @var{level} is a numeric values greater than zero @command{ld} optimizes +the output. This might take significantly longer and therefore probably +should only be enabled for the final binary. + +@kindex -q +@kindex --emit-relocs +@cindex retain relocations in final executable +@item -q +@itemx --emit-relocs +Leave relocation sections and contents in fully linked exececutables. +Post link analysis and optimization tools may need this information in +order to perform correct modifications of executables. This results +in larger executables. + +This option is currently only supported on ELF platforms. + +@cindex partial link +@cindex relocatable output +@kindex -r +@kindex --relocateable +@item -r +@itemx --relocateable +Generate relocatable output---i.e., generate an output file that can in +turn serve as input to @command{ld}. This is often called @dfn{partial +linking}. As a side effect, in environments that support standard Unix +magic numbers, this option also sets the output file's magic number to +@code{OMAGIC}. +@c ; see @option{-N}. +If this option is not specified, an absolute file is produced. When +linking C++ programs, this option @emph{will not} resolve references to +constructors; to do that, use @samp{-Ur}. + +When an input file does not have the same format as the output file, +partial linking is only supported if that input file does not contain any +relocations. Different output formats can have further restrictions; for +example some @code{a.out}-based formats do not support partial linking +with input files in other formats at all. + +This option does the same thing as @samp{-i}. + +@kindex -R @var{file} +@kindex --just-symbols=@var{file} +@cindex symbol-only input +@item -R @var{filename} +@itemx --just-symbols=@var{filename} +Read symbol names and their addresses from @var{filename}, but do not +relocate it or include it in the output. This allows your output file +to refer symbolically to absolute locations of memory defined in other +programs. You may use this option more than once. + +For compatibility with other ELF linkers, if the @option{-R} option is +followed by a directory name, rather than a file name, it is treated as +the @option{-rpath} option. + +@kindex -s +@kindex --strip-all +@cindex strip all symbols +@item -s +@itemx --strip-all +Omit all symbol information from the output file. + +@kindex -S +@kindex --strip-debug +@cindex strip debugger symbols +@item -S +@itemx --strip-debug +Omit debugger symbol information (but not all symbols) from the output file. + +@kindex -t +@kindex --trace +@cindex input files, displaying +@item -t +@itemx --trace +Print the names of the input files as @command{ld} processes them. + +@kindex -T @var{script} +@kindex --script=@var{script} +@cindex script files +@item -T @var{scriptfile} +@itemx --script=@var{scriptfile} +Use @var{scriptfile} as the linker script. This script replaces +@command{ld}'s default linker script (rather than adding to it), so +@var{commandfile} must specify everything necessary to describe the +output file. @xref{Scripts}. If @var{scriptfile} does not exist in +the current directory, @code{ld} looks for it in the directories +specified by any preceding @samp{-L} options. Multiple @samp{-T} +options accumulate. + +@kindex -u @var{symbol} +@kindex --undefined=@var{symbol} +@cindex undefined symbol +@item -u @var{symbol} +@itemx --undefined=@var{symbol} +Force @var{symbol} to be entered in the output file as an undefined +symbol. Doing this may, for example, trigger linking of additional +modules from standard libraries. @samp{-u} may be repeated with +different option arguments to enter additional undefined symbols. This +option is equivalent to the @code{EXTERN} linker script command. + +@kindex -Ur +@cindex constructors +@item -Ur +For anything other than C++ programs, this option is equivalent to +@samp{-r}: it generates relocatable output---i.e., an output file that can in +turn serve as input to @command{ld}. When linking C++ programs, @samp{-Ur} +@emph{does} resolve references to constructors, unlike @samp{-r}. +It does not work to use @samp{-Ur} on files that were themselves linked +with @samp{-Ur}; once the constructor table has been built, it cannot +be added to. Use @samp{-Ur} only for the last partial link, and +@samp{-r} for the others. + +@kindex --unique[=@var{SECTION}] +@item --unique[=@var{SECTION}] +Creates a separate output section for every input section matching +@var{SECTION}, or if the optional wildcard @var{SECTION} argument is +missing, for every orphan input section. An orphan section is one not +specifically mentioned in a linker script. You may use this option +multiple times on the command line; It prevents the normal merging of +input sections with the same name, overriding output section assignments +in a linker script. + +@kindex -v +@kindex -V +@kindex --version +@cindex version +@item -v +@itemx --version +@itemx -V +Display the version number for @command{ld}. The @option{-V} option also +lists the supported emulations. + +@kindex -x +@kindex --discard-all +@cindex deleting local symbols +@item -x +@itemx --discard-all +Delete all local symbols. + +@kindex -X +@kindex --discard-locals +@cindex local symbols, deleting +@cindex L, deleting symbols beginning +@item -X +@itemx --discard-locals +Delete all temporary local symbols. For most targets, this is all local +symbols whose names begin with @samp{L}. + +@kindex -y @var{symbol} +@kindex --trace-symbol=@var{symbol} +@cindex symbol tracing +@item -y @var{symbol} +@itemx --trace-symbol=@var{symbol} +Print the name of each linked file in which @var{symbol} appears. This +option may be given any number of times. On many systems it is necessary +to prepend an underscore. + +This option is useful when you have an undefined symbol in your link but +don't know where the reference is coming from. + +@kindex -Y @var{path} +@item -Y @var{path} +Add @var{path} to the default library search path. This option exists +for Solaris compatibility. + +@kindex -z @var{keyword} +@item -z @var{keyword} +The recognized keywords are @code{initfirst}, @code{interpose}, +@code{loadfltr}, @code{nodefaultlib}, @code{nodelete}, @code{nodlopen}, +@code{nodump}, @code{now}, @code{origin}, @code{combreloc}, @code{nocombreloc} +and @code{nocopyreloc}. +The other keywords are +ignored for Solaris compatibility. @code{initfirst} marks the object +to be initialized first at runtime before any other objects. +@code{interpose} marks the object that its symbol table interposes +before all symbols but the primary executable. @code{loadfltr} marks +the object that its filtees be processed immediately at runtime. +@code{nodefaultlib} marks the object that the search for dependencies +of this object will ignore any default library search paths. +@code{nodelete} marks the object shouldn't be unloaded at runtime. +@code{nodlopen} marks the object not available to @code{dlopen}. +@code{nodump} marks the object can not be dumped by @code{dldump}. +@code{now} marks the object with the non-lazy runtime binding. +@code{origin} marks the object may contain $ORIGIN. +@code{defs} disallows undefined symbols. +@code{muldefs} allows multiple definitions. +@code{combreloc} combines multiple reloc sections and sorts them +to make dynamic symbol lookup caching possible. +@code{nocombreloc} disables multiple reloc sections combining. +@code{nocopyreloc} disables production of copy relocs. + +@kindex -( +@cindex groups of archives +@item -( @var{archives} -) +@itemx --start-group @var{archives} --end-group +The @var{archives} should be a list of archive files. They may be +either explicit file names, or @samp{-l} options. + +The specified archives are searched repeatedly until no new undefined +references are created. Normally, an archive is searched only once in +the order that it is specified on the command line. If a symbol in that +archive is needed to resolve an undefined symbol referred to by an +object in an archive that appears later on the command line, the linker +would not be able to resolve that reference. By grouping the archives, +they all be searched repeatedly until all possible references are +resolved. + +Using this option has a significant performance cost. It is best to use +it only when there are unavoidable circular references between two or +more archives. + +@kindex --accept-unknown-input-arch +@kindex --no-accept-unknown-input-arch +@item --accept-unknown-input-arch +@itemx --no-accept-unknown-input-arch +Tells the linker to accept input files whose architecture cannot be +recognised. The assumption is that the user knows what they are doing +and deliberately wants to link in these unknown input files. This was +the default behaviour of the linker, before release 2.14. The default +behaviour from release 2.14 onwards is to reject such input files, and +so the @samp{--accept-unknown-input-arch} option has been added to +restore the old behaviour. + +@kindex -assert @var{keyword} +@item -assert @var{keyword} +This option is ignored for SunOS compatibility. + +@kindex -Bdynamic +@kindex -dy +@kindex -call_shared +@item -Bdynamic +@itemx -dy +@itemx -call_shared +Link against dynamic libraries. This is only meaningful on platforms +for which shared libraries are supported. This option is normally the +default on such platforms. The different variants of this option are +for compatibility with various systems. You may use this option +multiple times on the command line: it affects library searching for +@option{-l} options which follow it. + +@kindex -Bgroup +@item -Bgroup +Set the @code{DF_1_GROUP} flag in the @code{DT_FLAGS_1} entry in the dynamic +section. This causes the runtime linker to handle lookups in this +object and its dependencies to be performed only inside the group. +@option{--no-undefined} is implied. This option is only meaningful on ELF +platforms which support shared libraries. + +@kindex -Bstatic +@kindex -dn +@kindex -non_shared +@kindex -static +@item -Bstatic +@itemx -dn +@itemx -non_shared +@itemx -static +Do not link against shared libraries. This is only meaningful on +platforms for which shared libraries are supported. The different +variants of this option are for compatibility with various systems. You +may use this option multiple times on the command line: it affects +library searching for @option{-l} options which follow it. + +@kindex -Bsymbolic +@item -Bsymbolic +When creating a shared library, bind references to global symbols to the +definition within the shared library, if any. Normally, it is possible +for a program linked against a shared library to override the definition +within the shared library. This option is only meaningful on ELF +platforms which support shared libraries. + +@kindex --check-sections +@kindex --no-check-sections +@item --check-sections +@itemx --no-check-sections +Asks the linker @emph{not} to check section addresses after they have +been assigned to see if there any overlaps. Normally the linker will +perform this check, and if it finds any overlaps it will produce +suitable error messages. The linker does know about, and does make +allowances for sections in overlays. The default behaviour can be +restored by using the command line switch @samp{--check-sections}. + +@cindex cross reference table +@kindex --cref +@item --cref +Output a cross reference table. If a linker map file is being +generated, the cross reference table is printed to the map file. +Otherwise, it is printed on the standard output. + +The format of the table is intentionally simple, so that it may be +easily processed by a script if necessary. The symbols are printed out, +sorted by name. For each symbol, a list of file names is given. If the +symbol is defined, the first file listed is the location of the +definition. The remaining files contain references to the symbol. + +@cindex common allocation +@kindex --no-define-common +@item --no-define-common +This option inhibits the assignment of addresses to common symbols. +The script command @code{INHIBIT_COMMON_ALLOCATION} has the same effect. +@xref{Miscellaneous Commands}. + +The @samp{--no-define-common} option allows decoupling +the decision to assign addresses to Common symbols from the choice +of the output file type; otherwise a non-Relocatable output type +forces assigning addresses to Common symbols. +Using @samp{--no-define-common} allows Common symbols that are referenced +from a shared library to be assigned addresses only in the main program. +This eliminates the unused duplicate space in the shared library, +and also prevents any possible confusion over resolving to the wrong +duplicate when there are many dynamic modules with specialized search +paths for runtime symbol resolution. + +@cindex symbols, from command line +@kindex --defsym @var{symbol}=@var{exp} +@item --defsym @var{symbol}=@var{expression} +Create a global symbol in the output file, containing the absolute +address given by @var{expression}. You may use this option as many +times as necessary to define multiple symbols in the command line. A +limited form of arithmetic is supported for the @var{expression} in this +context: you may give a hexadecimal constant or the name of an existing +symbol, or use @code{+} and @code{-} to add or subtract hexadecimal +constants or symbols. If you need more elaborate expressions, consider +using the linker command language from a script (@pxref{Assignments,, +Assignment: Symbol Definitions}). @emph{Note:} there should be no white +space between @var{symbol}, the equals sign (``@key{=}''), and +@var{expression}. + +@cindex demangling, from command line +@kindex --demangle[=@var{style}] +@kindex --no-demangle +@item --demangle[=@var{style}] +@itemx --no-demangle +These options control whether to demangle symbol names in error messages +and other output. When the linker is told to demangle, it tries to +present symbol names in a readable fashion: it strips leading +underscores if they are used by the object file format, and converts C++ +mangled symbol names into user readable names. Different compilers have +different mangling styles. The optional demangling style argument can be used +to choose an appropriate demangling style for your compiler. The linker will +demangle by default unless the environment variable @samp{COLLECT_NO_DEMANGLE} +is set. These options may be used to override the default. + +@cindex dynamic linker, from command line +@kindex -I@var{file} +@kindex --dynamic-linker @var{file} +@item --dynamic-linker @var{file} +Set the name of the dynamic linker. This is only meaningful when +generating dynamically linked ELF executables. The default dynamic +linker is normally correct; don't use this unless you know what you are +doing. + +@cindex MIPS embedded PIC code +@kindex --embedded-relocs +@item --embedded-relocs +This option is only meaningful when linking MIPS embedded PIC code, +generated by the -membedded-pic option to the @sc{gnu} compiler and +assembler. It causes the linker to create a table which may be used at +runtime to relocate any data which was statically initialized to pointer +values. See the code in testsuite/ld-empic for details. + + +@kindex --fatal-warnings +@item --fatal-warnings +Treat all warnings as errors. + +@kindex --force-exe-suffix +@item --force-exe-suffix +Make sure that an output file has a .exe suffix. + +If a successfully built fully linked output file does not have a +@code{.exe} or @code{.dll} suffix, this option forces the linker to copy +the output file to one of the same name with a @code{.exe} suffix. This +option is useful when using unmodified Unix makefiles on a Microsoft +Windows host, since some versions of Windows won't run an image unless +it ends in a @code{.exe} suffix. + +@kindex --gc-sections +@kindex --no-gc-sections +@cindex garbage collection +@item --no-gc-sections +@itemx --gc-sections +Enable garbage collection of unused input sections. It is ignored on +targets that do not support this option. This option is not compatible +with @samp{-r}, nor should it be used with dynamic linking. The default +behaviour (of not performing this garbage collection) can be restored by +specifying @samp{--no-gc-sections} on the command line. + +@cindex help +@cindex usage +@kindex --help +@item --help +Print a summary of the command-line options on the standard output and exit. + +@kindex --target-help +@item --target-help +Print a summary of all target specific options on the standard output and exit. + +@kindex -Map +@item -Map @var{mapfile} +Print a link map to the file @var{mapfile}. See the description of the +@samp{-M} option, above. + +@cindex memory usage +@kindex --no-keep-memory +@item --no-keep-memory +@command{ld} normally optimizes for speed over memory usage by caching the +symbol tables of input files in memory. This option tells @command{ld} to +instead optimize for memory usage, by rereading the symbol tables as +necessary. This may be required if @command{ld} runs out of memory space +while linking a large executable. + +@kindex --no-undefined +@kindex -z defs +@item --no-undefined +@itemx -z defs +Normally when creating a non-symbolic shared library, undefined symbols +are allowed and left to be resolved by the runtime loader. This option +disallows such undefined symbols if they come from regular object +files. The switch @samp{--no-allow-shlib-undefined} controls the +behaviour for shared objects being linked into the shared library. + +@kindex --allow-multiple-definition +@kindex -z muldefs +@item --allow-multiple-definition +@itemx -z muldefs +Normally when a symbol is defined multiple times, the linker will +report a fatal error. These options allow multiple definitions and the +first definition will be used. + +@kindex --allow-shlib-undefined +@kindex --no-allow-shlib-undefined +@item --allow-shlib-undefined +@itemx --no-allow-shlib-undefined +Allow (the default) or disallow undefined symbols in shared objects. +The setting of this switch overrides @samp{--no-undefined} where +shared objects are concerned. Thus if @samp{--no-undefined} is set +but @samp{--no-allow-shlib-undefined} is not, the net result will be +that undefined symbols in regular object files will trigger an error, +but undefined symbols in shared objects will be ignored. + +The reason that @samp{--allow-shlib-undefined} is the default is that +the shared object being specified at link time may not be the same one +that is available at load time, so the symbols might actually be +resolvable at load time. Plus there are some systems, (eg BeOS) where +undefined symbols in shared libraries is normal since the kernel +patches them at load time to select which function is most appropriate +for the current architecture. eg. to dynamically select an appropriate +memset function. Apparently it is also normal for HPPA shared +libraries to have undefined symbols. + +@kindex --no-undefined-version +@item --no-undefined-version +Normally when a symbol has an undefined version, the linker will ignore +it. This option disallows symbols with undefined version and a fatal error +will be issued instead. + +@kindex --no-warn-mismatch +@item --no-warn-mismatch +Normally @command{ld} will give an error if you try to link together input +files that are mismatched for some reason, perhaps because they have +been compiled for different processors or for different endiannesses. +This option tells @command{ld} that it should silently permit such possible +errors. This option should only be used with care, in cases when you +have taken some special action that ensures that the linker errors are +inappropriate. + +@kindex --no-whole-archive +@item --no-whole-archive +Turn off the effect of the @option{--whole-archive} option for subsequent +archive files. + +@cindex output file after errors +@kindex --noinhibit-exec +@item --noinhibit-exec +Retain the executable output file whenever it is still usable. +Normally, the linker will not produce an output file if it encounters +errors during the link process; it exits without writing an output file +when it issues any error whatsoever. + +@kindex -nostdlib +@item -nostdlib +Only search library directories explicitly specified on the +command line. Library directories specified in linker scripts +(including linker scripts specified on the command line) are ignored. + +@ifclear SingleFormat +@kindex --oformat +@item --oformat @var{output-format} +@command{ld} may be configured to support more than one kind of object +file. If your @command{ld} is configured this way, you can use the +@samp{--oformat} option to specify the binary format for the output +object file. Even when @command{ld} is configured to support alternative +object formats, you don't usually need to specify this, as @command{ld} +should be configured to produce as a default output format the most +usual format on each machine. @var{output-format} is a text string, the +name of a particular format supported by the BFD libraries. (You can +list the available binary formats with @samp{objdump -i}.) The script +command @code{OUTPUT_FORMAT} can also specify the output format, but +this option overrides it. @xref{BFD}. +@end ifclear + +@kindex -qmagic +@item -qmagic +This option is ignored for Linux compatibility. + +@kindex -Qy +@item -Qy +This option is ignored for SVR4 compatibility. + +@kindex --relax +@cindex synthesizing linker +@cindex relaxing addressing modes +@item --relax +An option with machine dependent effects. +@ifset GENERIC +This option is only supported on a few targets. +@end ifset +@ifset H8300 +@xref{H8/300,,@command{ld} and the H8/300}. +@end ifset +@ifset I960 +@xref{i960,, @command{ld} and the Intel 960 family}. +@end ifset +@ifset XTENSA +@xref{Xtensa,, @command{ld} and Xtensa Processors}. +@end ifset + +On some platforms, the @samp{--relax} option performs global +optimizations that become possible when the linker resolves addressing +in the program, such as relaxing address modes and synthesizing new +instructions in the output object file. + +On some platforms these link time global optimizations may make symbolic +debugging of the resulting executable impossible. +@ifset GENERIC +This is known to be +the case for the Matsushita MN10200 and MN10300 family of processors. +@end ifset + +@ifset GENERIC +On platforms where this is not supported, @samp{--relax} is accepted, +but ignored. +@end ifset + +@cindex retaining specified symbols +@cindex stripping all but some symbols +@cindex symbols, retaining selectively +@item --retain-symbols-file @var{filename} +Retain @emph{only} the symbols listed in the file @var{filename}, +discarding all others. @var{filename} is simply a flat file, with one +symbol name per line. This option is especially useful in environments +@ifset GENERIC +(such as VxWorks) +@end ifset +where a large global symbol table is accumulated gradually, to conserve +run-time memory. + +@samp{--retain-symbols-file} does @emph{not} discard undefined symbols, +or symbols needed for relocations. + +You may only specify @samp{--retain-symbols-file} once in the command +line. It overrides @samp{-s} and @samp{-S}. + +@ifset GENERIC +@item -rpath @var{dir} +@cindex runtime library search path +@kindex -rpath +Add a directory to the runtime library search path. This is used when +linking an ELF executable with shared objects. All @option{-rpath} +arguments are concatenated and passed to the runtime linker, which uses +them to locate shared objects at runtime. The @option{-rpath} option is +also used when locating shared objects which are needed by shared +objects explicitly included in the link; see the description of the +@option{-rpath-link} option. If @option{-rpath} is not used when linking an +ELF executable, the contents of the environment variable +@code{LD_RUN_PATH} will be used if it is defined. + +The @option{-rpath} option may also be used on SunOS. By default, on +SunOS, the linker will form a runtime search patch out of all the +@option{-L} options it is given. If a @option{-rpath} option is used, the +runtime search path will be formed exclusively using the @option{-rpath} +options, ignoring the @option{-L} options. This can be useful when using +gcc, which adds many @option{-L} options which may be on NFS mounted +filesystems. + +For compatibility with other ELF linkers, if the @option{-R} option is +followed by a directory name, rather than a file name, it is treated as +the @option{-rpath} option. +@end ifset + +@ifset GENERIC +@cindex link-time runtime library search path +@kindex -rpath-link +@item -rpath-link @var{DIR} +When using ELF or SunOS, one shared library may require another. This +happens when an @code{ld -shared} link includes a shared library as one +of the input files. + +When the linker encounters such a dependency when doing a non-shared, +non-relocatable link, it will automatically try to locate the required +shared library and include it in the link, if it is not included +explicitly. In such a case, the @option{-rpath-link} option +specifies the first set of directories to search. The +@option{-rpath-link} option may specify a sequence of directory names +either by specifying a list of names separated by colons, or by +appearing multiple times. + +This option should be used with caution as it overrides the search path +that may have been hard compiled into a shared library. In such a case it +is possible to use unintentionally a different search path than the +runtime linker would do. + +The linker uses the following search paths to locate required shared +libraries. +@enumerate +@item +Any directories specified by @option{-rpath-link} options. +@item +Any directories specified by @option{-rpath} options. The difference +between @option{-rpath} and @option{-rpath-link} is that directories +specified by @option{-rpath} options are included in the executable and +used at runtime, whereas the @option{-rpath-link} option is only effective +at link time. It is for the native linker only. +@item +On an ELF system, if the @option{-rpath} and @code{rpath-link} options +were not used, search the contents of the environment variable +@code{LD_RUN_PATH}. It is for the native linker only. +@item +On SunOS, if the @option{-rpath} option was not used, search any +directories specified using @option{-L} options. +@item +For a native linker, the contents of the environment variable +@code{LD_LIBRARY_PATH}. +@item +For a native ELF linker, the directories in @code{DT_RUNPATH} or +@code{DT_RPATH} of a shared library are searched for shared +libraries needed by it. The @code{DT_RPATH} entries are ignored if +@code{DT_RUNPATH} entries exist. +@item +The default directories, normally @file{/lib} and @file{/usr/lib}. +@item +For a native linker on an ELF system, if the file @file{/etc/ld.so.conf} +exists, the list of directories found in that file. +@end enumerate + +If the required shared library is not found, the linker will issue a +warning and continue with the link. +@end ifset + +@kindex -shared +@kindex -Bshareable +@item -shared +@itemx -Bshareable +@cindex shared libraries +Create a shared library. This is currently only supported on ELF, XCOFF +and SunOS platforms. On SunOS, the linker will automatically create a +shared library if the @option{-e} option is not used and there are +undefined symbols in the link. + +@item --sort-common +@kindex --sort-common +This option tells @command{ld} to sort the common symbols by size when it +places them in the appropriate output sections. First come all the one +byte symbols, then all the two byte, then all the four byte, and then +everything else. This is to prevent gaps between symbols due to +alignment constraints. + +@kindex --split-by-file +@item --split-by-file [@var{size}] +Similar to @option{--split-by-reloc} but creates a new output section for +each input file when @var{size} is reached. @var{size} defaults to a +size of 1 if not given. + +@kindex --split-by-reloc +@item --split-by-reloc [@var{count}] +Tries to creates extra sections in the output file so that no single +output section in the file contains more than @var{count} relocations. +This is useful when generating huge relocatable files for downloading into +certain real time kernels with the COFF object file format; since COFF +cannot represent more than 65535 relocations in a single section. Note +that this will fail to work with object file formats which do not +support arbitrary sections. The linker will not split up individual +input sections for redistribution, so if a single input section contains +more than @var{count} relocations one output section will contain that +many relocations. @var{count} defaults to a value of 32768. + +@kindex --stats +@item --stats +Compute and display statistics about the operation of the linker, such +as execution time and memory usage. + +@kindex --traditional-format +@cindex traditional format +@item --traditional-format +For some targets, the output of @command{ld} is different in some ways from +the output of some existing linker. This switch requests @command{ld} to +use the traditional format instead. + +@cindex dbx +For example, on SunOS, @command{ld} combines duplicate entries in the +symbol string table. This can reduce the size of an output file with +full debugging information by over 30 percent. Unfortunately, the SunOS +@code{dbx} program can not read the resulting program (@code{gdb} has no +trouble). The @samp{--traditional-format} switch tells @command{ld} to not +combine duplicate entries. + +@kindex --section-start @var{sectionname}=@var{org} +@item --section-start @var{sectionname}=@var{org} +Locate a section in the output file at the absolute +address given by @var{org}. You may use this option as many +times as necessary to locate multiple sections in the command +line. +@var{org} must be a single hexadecimal integer; +for compatibility with other linkers, you may omit the leading +@samp{0x} usually associated with hexadecimal values. @emph{Note:} there +should be no white space between @var{sectionname}, the equals +sign (``@key{=}''), and @var{org}. + +@kindex -Tbss @var{org} +@kindex -Tdata @var{org} +@kindex -Ttext @var{org} +@cindex segment origins, cmd line +@item -Tbss @var{org} +@itemx -Tdata @var{org} +@itemx -Ttext @var{org} +Same as --section-start, with @code{.bss}, @code{.data} or +@code{.text} as the @var{sectionname}. + +@kindex --verbose +@cindex verbose +@item --dll-verbose +@itemx --verbose +Display the version number for @command{ld} and list the linker emulations +supported. Display which input files can and cannot be opened. Display +the linker script being used by the linker. + +@kindex --version-script=@var{version-scriptfile} +@cindex version script, symbol versions +@itemx --version-script=@var{version-scriptfile} +Specify the name of a version script to the linker. This is typically +used when creating shared libraries to specify additional information +about the version hierarchy for the library being created. This option +is only meaningful on ELF platforms which support shared libraries. +@xref{VERSION}. + +@kindex --warn-common +@cindex warnings, on combining symbols +@cindex combining symbols, warnings on +@item --warn-common +Warn when a common symbol is combined with another common symbol or with +a symbol definition. Unix linkers allow this somewhat sloppy practice, +but linkers on some other operating systems do not. This option allows +you to find potential problems from combining global symbols. +Unfortunately, some C libraries use this practice, so you may get some +warnings about symbols in the libraries as well as in your programs. + +There are three kinds of global symbols, illustrated here by C examples: + +@table @samp +@item int i = 1; +A definition, which goes in the initialized data section of the output +file. + +@item extern int i; +An undefined reference, which does not allocate space. +There must be either a definition or a common symbol for the +variable somewhere. + +@item int i; +A common symbol. If there are only (one or more) common symbols for a +variable, it goes in the uninitialized data area of the output file. +The linker merges multiple common symbols for the same variable into a +single symbol. If they are of different sizes, it picks the largest +size. The linker turns a common symbol into a declaration, if there is +a definition of the same variable. +@end table + +The @samp{--warn-common} option can produce five kinds of warnings. +Each warning consists of a pair of lines: the first describes the symbol +just encountered, and the second describes the previous symbol +encountered with the same name. One or both of the two symbols will be +a common symbol. + +@enumerate +@item +Turning a common symbol into a reference, because there is already a +definition for the symbol. +@smallexample +@var{file}(@var{section}): warning: common of `@var{symbol}' + overridden by definition +@var{file}(@var{section}): warning: defined here +@end smallexample + +@item +Turning a common symbol into a reference, because a later definition for +the symbol is encountered. This is the same as the previous case, +except that the symbols are encountered in a different order. +@smallexample +@var{file}(@var{section}): warning: definition of `@var{symbol}' + overriding common +@var{file}(@var{section}): warning: common is here +@end smallexample + +@item +Merging a common symbol with a previous same-sized common symbol. +@smallexample +@var{file}(@var{section}): warning: multiple common + of `@var{symbol}' +@var{file}(@var{section}): warning: previous common is here +@end smallexample + +@item +Merging a common symbol with a previous larger common symbol. +@smallexample +@var{file}(@var{section}): warning: common of `@var{symbol}' + overridden by larger common +@var{file}(@var{section}): warning: larger common is here +@end smallexample + +@item +Merging a common symbol with a previous smaller common symbol. This is +the same as the previous case, except that the symbols are +encountered in a different order. +@smallexample +@var{file}(@var{section}): warning: common of `@var{symbol}' + overriding smaller common +@var{file}(@var{section}): warning: smaller common is here +@end smallexample +@end enumerate + +@kindex --warn-constructors +@item --warn-constructors +Warn if any global constructors are used. This is only useful for a few +object file formats. For formats like COFF or ELF, the linker can not +detect the use of global constructors. + +@kindex --warn-multiple-gp +@item --warn-multiple-gp +Warn if multiple global pointer values are required in the output file. +This is only meaningful for certain processors, such as the Alpha. +Specifically, some processors put large-valued constants in a special +section. A special register (the global pointer) points into the middle +of this section, so that constants can be loaded efficiently via a +base-register relative addressing mode. Since the offset in +base-register relative mode is fixed and relatively small (e.g., 16 +bits), this limits the maximum size of the constant pool. Thus, in +large programs, it is often necessary to use multiple global pointer +values in order to be able to address all possible constants. This +option causes a warning to be issued whenever this case occurs. + +@kindex --warn-once +@cindex warnings, on undefined symbols +@cindex undefined symbols, warnings on +@item --warn-once +Only warn once for each undefined symbol, rather than once per module +which refers to it. + +@kindex --warn-section-align +@cindex warnings, on section alignment +@cindex section alignment, warnings on +@item --warn-section-align +Warn if the address of an output section is changed because of +alignment. Typically, the alignment will be set by an input section. +The address will only be changed if it not explicitly specified; that +is, if the @code{SECTIONS} command does not specify a start address for +the section (@pxref{SECTIONS}). + +@kindex --whole-archive +@cindex including an entire archive +@item --whole-archive +For each archive mentioned on the command line after the +@option{--whole-archive} option, include every object file in the archive +in the link, rather than searching the archive for the required object +files. This is normally used to turn an archive file into a shared +library, forcing every object to be included in the resulting shared +library. This option may be used more than once. + +Two notes when using this option from gcc: First, gcc doesn't know +about this option, so you have to use @option{-Wl,-whole-archive}. +Second, don't forget to use @option{-Wl,-no-whole-archive} after your +list of archives, because gcc will add its own list of archives to +your link and you may not want this flag to affect those as well. + +@kindex --wrap +@item --wrap @var{symbol} +Use a wrapper function for @var{symbol}. Any undefined reference to +@var{symbol} will be resolved to @code{__wrap_@var{symbol}}. Any +undefined reference to @code{__real_@var{symbol}} will be resolved to +@var{symbol}. + +This can be used to provide a wrapper for a system function. The +wrapper function should be called @code{__wrap_@var{symbol}}. If it +wishes to call the system function, it should call +@code{__real_@var{symbol}}. + +Here is a trivial example: + +@smallexample +void * +__wrap_malloc (int c) +@{ + printf ("malloc called with %ld\n", c); + return __real_malloc (c); +@} +@end smallexample + +If you link other code with this file using @option{--wrap malloc}, then +all calls to @code{malloc} will call the function @code{__wrap_malloc} +instead. The call to @code{__real_malloc} in @code{__wrap_malloc} will +call the real @code{malloc} function. + +You may wish to provide a @code{__real_malloc} function as well, so that +links without the @option{--wrap} option will succeed. If you do this, +you should not put the definition of @code{__real_malloc} in the same +file as @code{__wrap_malloc}; if you do, the assembler may resolve the +call before the linker has a chance to wrap it to @code{malloc}. + +@kindex --enable-new-dtags +@kindex --disable-new-dtags +@item --enable-new-dtags +@itemx --disable-new-dtags +This linker can create the new dynamic tags in ELF. But the older ELF +systems may not understand them. If you specify +@option{--enable-new-dtags}, the dynamic tags will be created as needed. +If you specify @option{--disable-new-dtags}, no new dynamic tags will be +created. By default, the new dynamic tags are not created. Note that +those options are only available for ELF systems. + +@end table + +@c man end + +@subsection Options Specific to i386 PE Targets + +@c man begin OPTIONS + +The i386 PE linker supports the @option{-shared} option, which causes +the output to be a dynamically linked library (DLL) instead of a +normal executable. You should name the output @code{*.dll} when you +use this option. In addition, the linker fully supports the standard +@code{*.def} files, which may be specified on the linker command line +like an object file (in fact, it should precede archives it exports +symbols from, to ensure that they get linked in, just like a normal +object file). + +In addition to the options common to all targets, the i386 PE linker +support additional command line options that are specific to the i386 +PE target. Options that take values may be separated from their +values by either a space or an equals sign. + +@table @gcctabopt + +@kindex --add-stdcall-alias +@item --add-stdcall-alias +If given, symbols with a stdcall suffix (@@@var{nn}) will be exported +as-is and also with the suffix stripped. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --base-file +@item --base-file @var{file} +Use @var{file} as the name of a file in which to save the base +addresses of all the relocations needed for generating DLLs with +@file{dlltool}. +[This is an i386 PE specific option] + +@kindex --dll +@item --dll +Create a DLL instead of a regular executable. You may also use +@option{-shared} or specify a @code{LIBRARY} in a given @code{.def} +file. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --enable-stdcall-fixup +@kindex --disable-stdcall-fixup +@item --enable-stdcall-fixup +@itemx --disable-stdcall-fixup +If the link finds a symbol that it cannot resolve, it will attempt to +do ``fuzzy linking'' by looking for another defined symbol that differs +only in the format of the symbol name (cdecl vs stdcall) and will +resolve that symbol by linking to the match. For example, the +undefined symbol @code{_foo} might be linked to the function +@code{_foo@@12}, or the undefined symbol @code{_bar@@16} might be linked +to the function @code{_bar}. When the linker does this, it prints a +warning, since it normally should have failed to link, but sometimes +import libraries generated from third-party dlls may need this feature +to be usable. If you specify @option{--enable-stdcall-fixup}, this +feature is fully enabled and warnings are not printed. If you specify +@option{--disable-stdcall-fixup}, this feature is disabled and such +mismatches are considered to be errors. +[This option is specific to the i386 PE targeted port of the linker] + +@cindex DLLs, creating +@kindex --export-all-symbols +@item --export-all-symbols +If given, all global symbols in the objects used to build a DLL will +be exported by the DLL. Note that this is the default if there +otherwise wouldn't be any exported symbols. When symbols are +explicitly exported via DEF files or implicitly exported via function +attributes, the default is to not export anything else unless this +option is given. Note that the symbols @code{DllMain@@12}, +@code{DllEntryPoint@@0}, @code{DllMainCRTStartup@@12}, and +@code{impure_ptr} will not be automatically +exported. Also, symbols imported from other DLLs will not be +re-exported, nor will symbols specifying the DLL's internal layout +such as those beginning with @code{_head_} or ending with +@code{_iname}. In addition, no symbols from @code{libgcc}, +@code{libstd++}, @code{libmingw32}, or @code{crtX.o} will be exported. +Symbols whose names begin with @code{__rtti_} or @code{__builtin_} will +not be exported, to help with C++ DLLs. Finally, there is an +extensive list of cygwin-private symbols that are not exported +(obviously, this applies on when building DLLs for cygwin targets). +These cygwin-excludes are: @code{_cygwin_dll_entry@@12}, +@code{_cygwin_crt0_common@@8}, @code{_cygwin_noncygwin_dll_entry@@12}, +@code{_fmode}, @code{_impure_ptr}, @code{cygwin_attach_dll}, +@code{cygwin_premain0}, @code{cygwin_premain1}, @code{cygwin_premain2}, +@code{cygwin_premain3}, and @code{environ}. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --exclude-symbols +@item --exclude-symbols @var{symbol},@var{symbol},... +Specifies a list of symbols which should not be automatically +exported. The symbol names may be delimited by commas or colons. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --exclude-libs +@item --exclude-libs @var{lib},@var{lib},... +Specifies a list of archive libraries from which symbols should not be automatically +exported. The library names may be delimited by commas or colons. Specifying +@code{--exclude-libs ALL} excludes symbols in all archive libraries from +automatic export. Symbols explicitly listed in a .def file are still exported, +regardless of this option. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --file-alignment +@item --file-alignment +Specify the file alignment. Sections in the file will always begin at +file offsets which are multiples of this number. This defaults to +512. +[This option is specific to the i386 PE targeted port of the linker] + +@cindex heap size +@kindex --heap +@item --heap @var{reserve} +@itemx --heap @var{reserve},@var{commit} +Specify the amount of memory to reserve (and optionally commit) to be +used as heap for this program. The default is 1Mb reserved, 4K +committed. +[This option is specific to the i386 PE targeted port of the linker] + +@cindex image base +@kindex --image-base +@item --image-base @var{value} +Use @var{value} as the base address of your program or dll. This is +the lowest memory location that will be used when your program or dll +is loaded. To reduce the need to relocate and improve performance of +your dlls, each should have a unique base address and not overlap any +other dlls. The default is 0x400000 for executables, and 0x10000000 +for dlls. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --kill-at +@item --kill-at +If given, the stdcall suffixes (@@@var{nn}) will be stripped from +symbols before they are exported. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --major-image-version +@item --major-image-version @var{value} +Sets the major number of the ``image version''. Defaults to 1. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --major-os-version +@item --major-os-version @var{value} +Sets the major number of the ``os version''. Defaults to 4. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --major-subsystem-version +@item --major-subsystem-version @var{value} +Sets the major number of the ``subsystem version''. Defaults to 4. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --minor-image-version +@item --minor-image-version @var{value} +Sets the minor number of the ``image version''. Defaults to 0. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --minor-os-version +@item --minor-os-version @var{value} +Sets the minor number of the ``os version''. Defaults to 0. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --minor-subsystem-version +@item --minor-subsystem-version @var{value} +Sets the minor number of the ``subsystem version''. Defaults to 0. +[This option is specific to the i386 PE targeted port of the linker] + +@cindex DEF files, creating +@cindex DLLs, creating +@kindex --output-def +@item --output-def @var{file} +The linker will create the file @var{file} which will contain a DEF +file corresponding to the DLL the linker is generating. This DEF file +(which should be called @code{*.def}) may be used to create an import +library with @code{dlltool} or may be used as a reference to +automatically or implicitly exported symbols. +[This option is specific to the i386 PE targeted port of the linker] + +@cindex DLLs, creating +@kindex --out-implib +@item --out-implib @var{file} +The linker will create the file @var{file} which will contain an +import lib corresponding to the DLL the linker is generating. This +import lib (which should be called @code{*.dll.a} or @code{*.a} +may be used to link clients against the generated DLL; this behavior +makes it possible to skip a separate @code{dlltool} import library +creation step. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --enable-auto-image-base +@item --enable-auto-image-base +Automatically choose the image base for DLLs, unless one is specified +using the @code{--image-base} argument. By using a hash generated +from the dllname to create unique image bases for each DLL, in-memory +collisions and relocations which can delay program execution are +avoided. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --disable-auto-image-base +@item --disable-auto-image-base +Do not automatically generate a unique image base. If there is no +user-specified image base (@code{--image-base}) then use the platform +default. +[This option is specific to the i386 PE targeted port of the linker] + +@cindex DLLs, linking to +@kindex --dll-search-prefix +@item --dll-search-prefix @var{string} +When linking dynamically to a dll without an import library, +search for @code{.dll} in preference to +@code{lib.dll}. This behavior allows easy distinction +between DLLs built for the various "subplatforms": native, cygwin, +uwin, pw, etc. For instance, cygwin DLLs typically use +@code{--dll-search-prefix=cyg}. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --enable-auto-import +@item --enable-auto-import +Do sophisticated linking of @code{_symbol} to @code{__imp__symbol} for +DATA imports from DLLs, and create the necessary thunking symbols when +building the import libraries with those DATA exports. This generally +will 'just work' -- but sometimes you may see this message: + +"variable '' can't be auto-imported. Please read the +documentation for ld's @code{--enable-auto-import} for details." + +This message occurs when some (sub)expression accesses an address +ultimately given by the sum of two constants (Win32 import tables only +allow one). Instances where this may occur include accesses to member +fields of struct variables imported from a DLL, as well as using a +constant index into an array variable imported from a DLL. Any +multiword variable (arrays, structs, long long, etc) may trigger +this error condition. However, regardless of the exact data type +of the offending exported variable, ld will always detect it, issue +the warning, and exit. + +There are several ways to address this difficulty, regardless of the +data type of the exported variable: + +One way is to use --enable-runtime-pseudo-reloc switch. This leaves the task +of adjusting references in your client code for runtime environment, so +this method works only when runtime environtment supports this feature. + +A second solution is to force one of the 'constants' to be a variable -- +that is, unknown and un-optimizable at compile time. For arrays, +there are two possibilities: a) make the indexee (the array's address) +a variable, or b) make the 'constant' index a variable. Thus: + +@example +extern type extern_array[]; +extern_array[1] --> + @{ volatile type *t=extern_array; t[1] @} +@end example + +or + +@example +extern type extern_array[]; +extern_array[1] --> + @{ volatile int t=1; extern_array[t] @} +@end example + +For structs (and most other multiword data types) the only option +is to make the struct itself (or the long long, or the ...) variable: + +@example +extern struct s extern_struct; +extern_struct.field --> + @{ volatile struct s *t=&extern_struct; t->field @} +@end example + +or + +@example +extern long long extern_ll; +extern_ll --> + @{ volatile long long * local_ll=&extern_ll; *local_ll @} +@end example + +A third method of dealing with this difficulty is to abandon +'auto-import' for the offending symbol and mark it with +@code{__declspec(dllimport)}. However, in practice that +requires using compile-time #defines to indicate whether you are +building a DLL, building client code that will link to the DLL, or +merely building/linking to a static library. In making the choice +between the various methods of resolving the 'direct address with +constant offset' problem, you should consider typical real-world usage: + +Original: +@example +--foo.h +extern int arr[]; +--foo.c +#include "foo.h" +void main(int argc, char **argv)@{ + printf("%d\n",arr[1]); +@} +@end example + +Solution 1: +@example +--foo.h +extern int arr[]; +--foo.c +#include "foo.h" +void main(int argc, char **argv)@{ + /* This workaround is for win32 and cygwin; do not "optimize" */ + volatile int *parr = arr; + printf("%d\n",parr[1]); +@} +@end example + +Solution 2: +@example +--foo.h +/* Note: auto-export is assumed (no __declspec(dllexport)) */ +#if (defined(_WIN32) || defined(__CYGWIN__)) && \ + !(defined(FOO_BUILD_DLL) || defined(FOO_STATIC)) +#define FOO_IMPORT __declspec(dllimport) +#else +#define FOO_IMPORT +#endif +extern FOO_IMPORT int arr[]; +--foo.c +#include "foo.h" +void main(int argc, char **argv)@{ + printf("%d\n",arr[1]); +@} +@end example + +A fourth way to avoid this problem is to re-code your +library to use a functional interface rather than a data interface +for the offending variables (e.g. set_foo() and get_foo() accessor +functions). +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --disable-auto-import +@item --disable-auto-import +Do not attempt to do sophisticalted linking of @code{_symbol} to +@code{__imp__symbol} for DATA imports from DLLs. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --enable-runtime-pseudo-reloc +@item --enable-runtime-pseudo-reloc +If your code contains expressions described in --enable-auto-import section, +that is, DATA imports from DLL with non-zero offset, this switch will create +a vector of 'runtime pseudo relocations' which can be used by runtime +environment to adjust references to such data in your client code. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --disable-runtime-pseudo-reloc +@item --disable-runtime-pseudo-reloc +Do not create pseudo relocations for non-zero offset DATA imports from +DLLs. This is the default. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --enable-extra-pe-debug +@item --enable-extra-pe-debug +Show additional debug info related to auto-import symbol thunking. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --section-alignment +@item --section-alignment +Sets the section alignment. Sections in memory will always begin at +addresses which are a multiple of this number. Defaults to 0x1000. +[This option is specific to the i386 PE targeted port of the linker] + +@cindex stack size +@kindex --stack +@item --stack @var{reserve} +@itemx --stack @var{reserve},@var{commit} +Specify the amount of memory to reserve (and optionally commit) to be +used as stack for this program. The default is 2Mb reserved, 4K +committed. +[This option is specific to the i386 PE targeted port of the linker] + +@kindex --subsystem +@item --subsystem @var{which} +@itemx --subsystem @var{which}:@var{major} +@itemx --subsystem @var{which}:@var{major}.@var{minor} +Specifies the subsystem under which your program will execute. The +legal values for @var{which} are @code{native}, @code{windows}, +@code{console}, and @code{posix}. You may optionally set the +subsystem version also. +[This option is specific to the i386 PE targeted port of the linker] + +@end table + +@c man end + +@ifset UsesEnvVars +@node Environment +@section Environment Variables + +@c man begin ENVIRONMENT + +You can change the behavior of @command{ld} with the environment variables +@ifclear SingleFormat +@code{GNUTARGET}, +@end ifclear +@code{LDEMULATION} and @code{COLLECT_NO_DEMANGLE}. + +@ifclear SingleFormat +@kindex GNUTARGET +@cindex default input format +@code{GNUTARGET} determines the input-file object format if you don't +use @samp{-b} (or its synonym @samp{--format}). Its value should be one +of the BFD names for an input format (@pxref{BFD}). If there is no +@code{GNUTARGET} in the environment, @command{ld} uses the natural format +of the target. If @code{GNUTARGET} is set to @code{default} then BFD +attempts to discover the input format by examining binary input files; +this method often succeeds, but there are potential ambiguities, since +there is no method of ensuring that the magic number used to specify +object-file formats is unique. However, the configuration procedure for +BFD on each system places the conventional format for that system first +in the search-list, so ambiguities are resolved in favor of convention. +@end ifclear + +@kindex LDEMULATION +@cindex default emulation +@cindex emulation, default +@code{LDEMULATION} determines the default emulation if you don't use the +@samp{-m} option. The emulation can affect various aspects of linker +behaviour, particularly the default linker script. You can list the +available emulations with the @samp{--verbose} or @samp{-V} options. If +the @samp{-m} option is not used, and the @code{LDEMULATION} environment +variable is not defined, the default emulation depends upon how the +linker was configured. + +@kindex COLLECT_NO_DEMANGLE +@cindex demangling, default +Normally, the linker will default to demangling symbols. However, if +@code{COLLECT_NO_DEMANGLE} is set in the environment, then it will +default to not demangling symbols. This environment variable is used in +a similar fashion by the @code{gcc} linker wrapper program. The default +may be overridden by the @samp{--demangle} and @samp{--no-demangle} +options. + +@c man end +@end ifset + +@node Scripts +@chapter Linker Scripts + +@cindex scripts +@cindex linker scripts +@cindex command files +Every link is controlled by a @dfn{linker script}. This script is +written in the linker command language. + +The main purpose of the linker script is to describe how the sections in +the input files should be mapped into the output file, and to control +the memory layout of the output file. Most linker scripts do nothing +more than this. However, when necessary, the linker script can also +direct the linker to perform many other operations, using the commands +described below. + +The linker always uses a linker script. If you do not supply one +yourself, the linker will use a default script that is compiled into the +linker executable. You can use the @samp{--verbose} command line option +to display the default linker script. Certain command line options, +such as @samp{-r} or @samp{-N}, will affect the default linker script. + +You may supply your own linker script by using the @samp{-T} command +line option. When you do this, your linker script will replace the +default linker script. + +You may also use linker scripts implicitly by naming them as input files +to the linker, as though they were files to be linked. @xref{Implicit +Linker Scripts}. + +@menu +* Basic Script Concepts:: Basic Linker Script Concepts +* Script Format:: Linker Script Format +* Simple Example:: Simple Linker Script Example +* Simple Commands:: Simple Linker Script Commands +* Assignments:: Assigning Values to Symbols +* SECTIONS:: SECTIONS Command +* MEMORY:: MEMORY Command +* PHDRS:: PHDRS Command +* VERSION:: VERSION Command +* Expressions:: Expressions in Linker Scripts +* Implicit Linker Scripts:: Implicit Linker Scripts +@end menu + +@node Basic Script Concepts +@section Basic Linker Script Concepts +@cindex linker script concepts +We need to define some basic concepts and vocabulary in order to +describe the linker script language. + +The linker combines input files into a single output file. The output +file and each input file are in a special data format known as an +@dfn{object file format}. Each file is called an @dfn{object file}. +The output file is often called an @dfn{executable}, but for our +purposes we will also call it an object file. Each object file has, +among other things, a list of @dfn{sections}. We sometimes refer to a +section in an input file as an @dfn{input section}; similarly, a section +in the output file is an @dfn{output section}. + +Each section in an object file has a name and a size. Most sections +also have an associated block of data, known as the @dfn{section +contents}. A section may be marked as @dfn{loadable}, which mean that +the contents should be loaded into memory when the output file is run. +A section with no contents may be @dfn{allocatable}, which means that an +area in memory should be set aside, but nothing in particular should be +loaded there (in some cases this memory must be zeroed out). A section +which is neither loadable nor allocatable typically contains some sort +of debugging information. + +Every loadable or allocatable output section has two addresses. The +first is the @dfn{VMA}, or virtual memory address. This is the address +the section will have when the output file is run. The second is the +@dfn{LMA}, or load memory address. This is the address at which the +section will be loaded. In most cases the two addresses will be the +same. An example of when they might be different is when a data section +is loaded into ROM, and then copied into RAM when the program starts up +(this technique is often used to initialize global variables in a ROM +based system). In this case the ROM address would be the LMA, and the +RAM address would be the VMA. + +You can see the sections in an object file by using the @code{objdump} +program with the @samp{-h} option. + +Every object file also has a list of @dfn{symbols}, known as the +@dfn{symbol table}. A symbol may be defined or undefined. Each symbol +has a name, and each defined symbol has an address, among other +information. If you compile a C or C++ program into an object file, you +will get a defined symbol for every defined function and global or +static variable. Every undefined function or global variable which is +referenced in the input file will become an undefined symbol. + +You can see the symbols in an object file by using the @code{nm} +program, or by using the @code{objdump} program with the @samp{-t} +option. + +@node Script Format +@section Linker Script Format +@cindex linker script format +Linker scripts are text files. + +You write a linker script as a series of commands. Each command is +either a keyword, possibly followed by arguments, or an assignment to a +symbol. You may separate commands using semicolons. Whitespace is +generally ignored. + +Strings such as file or format names can normally be entered directly. +If the file name contains a character such as a comma which would +otherwise serve to separate file names, you may put the file name in +double quotes. There is no way to use a double quote character in a +file name. + +You may include comments in linker scripts just as in C, delimited by +@samp{/*} and @samp{*/}. As in C, comments are syntactically equivalent +to whitespace. + +@node Simple Example +@section Simple Linker Script Example +@cindex linker script example +@cindex example of linker script +Many linker scripts are fairly simple. + +The simplest possible linker script has just one command: +@samp{SECTIONS}. You use the @samp{SECTIONS} command to describe the +memory layout of the output file. + +The @samp{SECTIONS} command is a powerful command. Here we will +describe a simple use of it. Let's assume your program consists only of +code, initialized data, and uninitialized data. These will be in the +@samp{.text}, @samp{.data}, and @samp{.bss} sections, respectively. +Let's assume further that these are the only sections which appear in +your input files. + +For this example, let's say that the code should be loaded at address +0x10000, and that the data should start at address 0x8000000. Here is a +linker script which will do that: +@smallexample +SECTIONS +@{ + . = 0x10000; + .text : @{ *(.text) @} + . = 0x8000000; + .data : @{ *(.data) @} + .bss : @{ *(.bss) @} +@} +@end smallexample + +You write the @samp{SECTIONS} command as the keyword @samp{SECTIONS}, +followed by a series of symbol assignments and output section +descriptions enclosed in curly braces. + +The first line inside the @samp{SECTIONS} command of the above example +sets the value of the special symbol @samp{.}, which is the location +counter. If you do not specify the address of an output section in some +other way (other ways are described later), the address is set from the +current value of the location counter. The location counter is then +incremented by the size of the output section. At the start of the +@samp{SECTIONS} command, the location counter has the value @samp{0}. + +The second line defines an output section, @samp{.text}. The colon is +required syntax which may be ignored for now. Within the curly braces +after the output section name, you list the names of the input sections +which should be placed into this output section. The @samp{*} is a +wildcard which matches any file name. The expression @samp{*(.text)} +means all @samp{.text} input sections in all input files. + +Since the location counter is @samp{0x10000} when the output section +@samp{.text} is defined, the linker will set the address of the +@samp{.text} section in the output file to be @samp{0x10000}. + +The remaining lines define the @samp{.data} and @samp{.bss} sections in +the output file. The linker will place the @samp{.data} output section +at address @samp{0x8000000}. After the linker places the @samp{.data} +output section, the value of the location counter will be +@samp{0x8000000} plus the size of the @samp{.data} output section. The +effect is that the linker will place the @samp{.bss} output section +immediately after the @samp{.data} output section in memory + +The linker will ensure that each output section has the required +alignment, by increasing the location counter if necessary. In this +example, the specified addresses for the @samp{.text} and @samp{.data} +sections will probably satisfy any alignment constraints, but the linker +may have to create a small gap between the @samp{.data} and @samp{.bss} +sections. + +That's it! That's a simple and complete linker script. + +@node Simple Commands +@section Simple Linker Script Commands +@cindex linker script simple commands +In this section we describe the simple linker script commands. + +@menu +* Entry Point:: Setting the entry point +* File Commands:: Commands dealing with files +@ifclear SingleFormat +* Format Commands:: Commands dealing with object file formats +@end ifclear + +* Miscellaneous Commands:: Other linker script commands +@end menu + +@node Entry Point +@subsection Setting the Entry Point +@kindex ENTRY(@var{symbol}) +@cindex start of execution +@cindex first instruction +@cindex entry point +The first instruction to execute in a program is called the @dfn{entry +point}. You can use the @code{ENTRY} linker script command to set the +entry point. The argument is a symbol name: +@smallexample +ENTRY(@var{symbol}) +@end smallexample + +There are several ways to set the entry point. The linker will set the +entry point by trying each of the following methods in order, and +stopping when one of them succeeds: +@itemize @bullet +@item +the @samp{-e} @var{entry} command-line option; +@item +the @code{ENTRY(@var{symbol})} command in a linker script; +@item +the value of the symbol @code{start}, if defined; +@item +the address of the first byte of the @samp{.text} section, if present; +@item +The address @code{0}. +@end itemize + +@node File Commands +@subsection Commands Dealing with Files +@cindex linker script file commands +Several linker script commands deal with files. + +@table @code +@item INCLUDE @var{filename} +@kindex INCLUDE @var{filename} +@cindex including a linker script +Include the linker script @var{filename} at this point. The file will +be searched for in the current directory, and in any directory specified +with the @option{-L} option. You can nest calls to @code{INCLUDE} up to +10 levels deep. + +@item INPUT(@var{file}, @var{file}, @dots{}) +@itemx INPUT(@var{file} @var{file} @dots{}) +@kindex INPUT(@var{files}) +@cindex input files in linker scripts +@cindex input object files in linker scripts +@cindex linker script input object files +The @code{INPUT} command directs the linker to include the named files +in the link, as though they were named on the command line. + +For example, if you always want to include @file{subr.o} any time you do +a link, but you can't be bothered to put it on every link command line, +then you can put @samp{INPUT (subr.o)} in your linker script. + +In fact, if you like, you can list all of your input files in the linker +script, and then invoke the linker with nothing but a @samp{-T} option. + +In case a @dfn{sysroot prefix} is configured, and the filename starts +with the @samp{/} character, and the script being processed was +located inside the @dfn{sysroot prefix}, the filename will be looked +for in the @dfn{sysroot prefix}. Otherwise, the linker will try to +open the file in the current directory. If it is not found, the +linker will search through the archive library search path. See the +description of @samp{-L} in @ref{Options,,Command Line Options}. + +If you use @samp{INPUT (-l@var{file})}, @command{ld} will transform the +name to @code{lib@var{file}.a}, as with the command line argument +@samp{-l}. + +When you use the @code{INPUT} command in an implicit linker script, the +files will be included in the link at the point at which the linker +script file is included. This can affect archive searching. + +@item GROUP(@var{file}, @var{file}, @dots{}) +@itemx GROUP(@var{file} @var{file} @dots{}) +@kindex GROUP(@var{files}) +@cindex grouping input files +The @code{GROUP} command is like @code{INPUT}, except that the named +files should all be archives, and they are searched repeatedly until no +new undefined references are created. See the description of @samp{-(} +in @ref{Options,,Command Line Options}. + +@item OUTPUT(@var{filename}) +@kindex OUTPUT(@var{filename}) +@cindex output file name in linker scripot +The @code{OUTPUT} command names the output file. Using +@code{OUTPUT(@var{filename})} in the linker script is exactly like using +@samp{-o @var{filename}} on the command line (@pxref{Options,,Command +Line Options}). If both are used, the command line option takes +precedence. + +You can use the @code{OUTPUT} command to define a default name for the +output file other than the usual default of @file{a.out}. + +@item SEARCH_DIR(@var{path}) +@kindex SEARCH_DIR(@var{path}) +@cindex library search path in linker script +@cindex archive search path in linker script +@cindex search path in linker script +The @code{SEARCH_DIR} command adds @var{path} to the list of paths where +@command{ld} looks for archive libraries. Using +@code{SEARCH_DIR(@var{path})} is exactly like using @samp{-L @var{path}} +on the command line (@pxref{Options,,Command Line Options}). If both +are used, then the linker will search both paths. Paths specified using +the command line option are searched first. + +@item STARTUP(@var{filename}) +@kindex STARTUP(@var{filename}) +@cindex first input file +The @code{STARTUP} command is just like the @code{INPUT} command, except +that @var{filename} will become the first input file to be linked, as +though it were specified first on the command line. This may be useful +when using a system in which the entry point is always the start of the +first file. +@end table + +@ifclear SingleFormat +@node Format Commands +@subsection Commands Dealing with Object File Formats +A couple of linker script commands deal with object file formats. + +@table @code +@item OUTPUT_FORMAT(@var{bfdname}) +@itemx OUTPUT_FORMAT(@var{default}, @var{big}, @var{little}) +@kindex OUTPUT_FORMAT(@var{bfdname}) +@cindex output file format in linker script +The @code{OUTPUT_FORMAT} command names the BFD format to use for the +output file (@pxref{BFD}). Using @code{OUTPUT_FORMAT(@var{bfdname})} is +exactly like using @samp{--oformat @var{bfdname}} on the command line +(@pxref{Options,,Command Line Options}). If both are used, the command +line option takes precedence. + +You can use @code{OUTPUT_FORMAT} with three arguments to use different +formats based on the @samp{-EB} and @samp{-EL} command line options. +This permits the linker script to set the output format based on the +desired endianness. + +If neither @samp{-EB} nor @samp{-EL} are used, then the output format +will be the first argument, @var{default}. If @samp{-EB} is used, the +output format will be the second argument, @var{big}. If @samp{-EL} is +used, the output format will be the third argument, @var{little}. + +For example, the default linker script for the MIPS ELF target uses this +command: +@smallexample +OUTPUT_FORMAT(elf32-bigmips, elf32-bigmips, elf32-littlemips) +@end smallexample +This says that the default format for the output file is +@samp{elf32-bigmips}, but if the user uses the @samp{-EL} command line +option, the output file will be created in the @samp{elf32-littlemips} +format. + +@item TARGET(@var{bfdname}) +@kindex TARGET(@var{bfdname}) +@cindex input file format in linker script +The @code{TARGET} command names the BFD format to use when reading input +files. It affects subsequent @code{INPUT} and @code{GROUP} commands. +This command is like using @samp{-b @var{bfdname}} on the command line +(@pxref{Options,,Command Line Options}). If the @code{TARGET} command +is used but @code{OUTPUT_FORMAT} is not, then the last @code{TARGET} +command is also used to set the format for the output file. @xref{BFD}. +@end table +@end ifclear + +@node Miscellaneous Commands +@subsection Other Linker Script Commands +There are a few other linker scripts commands. + +@table @code +@item ASSERT(@var{exp}, @var{message}) +@kindex ASSERT +@cindex assertion in linker script +Ensure that @var{exp} is non-zero. If it is zero, then exit the linker +with an error code, and print @var{message}. + +@item EXTERN(@var{symbol} @var{symbol} @dots{}) +@kindex EXTERN +@cindex undefined symbol in linker script +Force @var{symbol} to be entered in the output file as an undefined +symbol. Doing this may, for example, trigger linking of additional +modules from standard libraries. You may list several @var{symbol}s for +each @code{EXTERN}, and you may use @code{EXTERN} multiple times. This +command has the same effect as the @samp{-u} command-line option. + +@item FORCE_COMMON_ALLOCATION +@kindex FORCE_COMMON_ALLOCATION +@cindex common allocation in linker script +This command has the same effect as the @samp{-d} command-line option: +to make @command{ld} assign space to common symbols even if a relocatable +output file is specified (@samp{-r}). + +@item INHIBIT_COMMON_ALLOCATION +@kindex INHIBIT_COMMON_ALLOCATION +@cindex common allocation in linker script +This command has the same effect as the @samp{--no-define-common} +command-line option: to make @code{ld} omit the assignment of addresses +to common symbols even for a non-relocatable output file. + +@item NOCROSSREFS(@var{section} @var{section} @dots{}) +@kindex NOCROSSREFS(@var{sections}) +@cindex cross references +This command may be used to tell @command{ld} to issue an error about any +references among certain output sections. + +In certain types of programs, particularly on embedded systems when +using overlays, when one section is loaded into memory, another section +will not be. Any direct references between the two sections would be +errors. For example, it would be an error if code in one section called +a function defined in the other section. + +The @code{NOCROSSREFS} command takes a list of output section names. If +@command{ld} detects any cross references between the sections, it reports +an error and returns a non-zero exit status. Note that the +@code{NOCROSSREFS} command uses output section names, not input section +names. + +@ifclear SingleFormat +@item OUTPUT_ARCH(@var{bfdarch}) +@kindex OUTPUT_ARCH(@var{bfdarch}) +@cindex machine architecture +@cindex architecture +Specify a particular output machine architecture. The argument is one +of the names used by the BFD library (@pxref{BFD}). You can see the +architecture of an object file by using the @code{objdump} program with +the @samp{-f} option. +@end ifclear +@end table + +@node Assignments +@section Assigning Values to Symbols +@cindex assignment in scripts +@cindex symbol definition, scripts +@cindex variables, defining +You may assign a value to a symbol in a linker script. This will define +the symbol as a global symbol. + +@menu +* Simple Assignments:: Simple Assignments +* PROVIDE:: PROVIDE +@end menu + +@node Simple Assignments +@subsection Simple Assignments + +You may assign to a symbol using any of the C assignment operators: + +@table @code +@item @var{symbol} = @var{expression} ; +@itemx @var{symbol} += @var{expression} ; +@itemx @var{symbol} -= @var{expression} ; +@itemx @var{symbol} *= @var{expression} ; +@itemx @var{symbol} /= @var{expression} ; +@itemx @var{symbol} <<= @var{expression} ; +@itemx @var{symbol} >>= @var{expression} ; +@itemx @var{symbol} &= @var{expression} ; +@itemx @var{symbol} |= @var{expression} ; +@end table + +The first case will define @var{symbol} to the value of +@var{expression}. In the other cases, @var{symbol} must already be +defined, and the value will be adjusted accordingly. + +The special symbol name @samp{.} indicates the location counter. You +may only use this within a @code{SECTIONS} command. + +The semicolon after @var{expression} is required. + +Expressions are defined below; see @ref{Expressions}. + +You may write symbol assignments as commands in their own right, or as +statements within a @code{SECTIONS} command, or as part of an output +section description in a @code{SECTIONS} command. + +The section of the symbol will be set from the section of the +expression; for more information, see @ref{Expression Section}. + +Here is an example showing the three different places that symbol +assignments may be used: + +@smallexample +floating_point = 0; +SECTIONS +@{ + .text : + @{ + *(.text) + _etext = .; + @} + _bdata = (. + 3) & ~ 3; + .data : @{ *(.data) @} +@} +@end smallexample +@noindent +In this example, the symbol @samp{floating_point} will be defined as +zero. The symbol @samp{_etext} will be defined as the address following +the last @samp{.text} input section. The symbol @samp{_bdata} will be +defined as the address following the @samp{.text} output section aligned +upward to a 4 byte boundary. + +@node PROVIDE +@subsection PROVIDE +@cindex PROVIDE +In some cases, it is desirable for a linker script to define a symbol +only if it is referenced and is not defined by any object included in +the link. For example, traditional linkers defined the symbol +@samp{etext}. However, ANSI C requires that the user be able to use +@samp{etext} as a function name without encountering an error. The +@code{PROVIDE} keyword may be used to define a symbol, such as +@samp{etext}, only if it is referenced but not defined. The syntax is +@code{PROVIDE(@var{symbol} = @var{expression})}. + +Here is an example of using @code{PROVIDE} to define @samp{etext}: +@smallexample +SECTIONS +@{ + .text : + @{ + *(.text) + _etext = .; + PROVIDE(etext = .); + @} +@} +@end smallexample + +In this example, if the program defines @samp{_etext} (with a leading +underscore), the linker will give a multiple definition error. If, on +the other hand, the program defines @samp{etext} (with no leading +underscore), the linker will silently use the definition in the program. +If the program references @samp{etext} but does not define it, the +linker will use the definition in the linker script. + +@node SECTIONS +@section SECTIONS Command +@kindex SECTIONS +The @code{SECTIONS} command tells the linker how to map input sections +into output sections, and how to place the output sections in memory. + +The format of the @code{SECTIONS} command is: +@smallexample +SECTIONS +@{ + @var{sections-command} + @var{sections-command} + @dots{} +@} +@end smallexample + +Each @var{sections-command} may of be one of the following: + +@itemize @bullet +@item +an @code{ENTRY} command (@pxref{Entry Point,,Entry command}) +@item +a symbol assignment (@pxref{Assignments}) +@item +an output section description +@item +an overlay description +@end itemize + +The @code{ENTRY} command and symbol assignments are permitted inside the +@code{SECTIONS} command for convenience in using the location counter in +those commands. This can also make the linker script easier to +understand because you can use those commands at meaningful points in +the layout of the output file. + +Output section descriptions and overlay descriptions are described +below. + +If you do not use a @code{SECTIONS} command in your linker script, the +linker will place each input section into an identically named output +section in the order that the sections are first encountered in the +input files. If all input sections are present in the first file, for +example, the order of sections in the output file will match the order +in the first input file. The first section will be at address zero. + +@menu +* Output Section Description:: Output section description +* Output Section Name:: Output section name +* Output Section Address:: Output section address +* Input Section:: Input section description +* Output Section Data:: Output section data +* Output Section Keywords:: Output section keywords +* Output Section Discarding:: Output section discarding +* Output Section Attributes:: Output section attributes +* Overlay Description:: Overlay description +@end menu + +@node Output Section Description +@subsection Output Section Description +The full description of an output section looks like this: +@smallexample +@group +@var{section} [@var{address}] [(@var{type})] : [AT(@var{lma})] + @{ + @var{output-section-command} + @var{output-section-command} + @dots{} + @} [>@var{region}] [AT>@var{lma_region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}] +@end group +@end smallexample + +Most output sections do not use most of the optional section attributes. + +The whitespace around @var{section} is required, so that the section +name is unambiguous. The colon and the curly braces are also required. +The line breaks and other white space are optional. + +Each @var{output-section-command} may be one of the following: + +@itemize @bullet +@item +a symbol assignment (@pxref{Assignments}) +@item +an input section description (@pxref{Input Section}) +@item +data values to include directly (@pxref{Output Section Data}) +@item +a special output section keyword (@pxref{Output Section Keywords}) +@end itemize + +@node Output Section Name +@subsection Output Section Name +@cindex name, section +@cindex section name +The name of the output section is @var{section}. @var{section} must +meet the constraints of your output format. In formats which only +support a limited number of sections, such as @code{a.out}, the name +must be one of the names supported by the format (@code{a.out}, for +example, allows only @samp{.text}, @samp{.data} or @samp{.bss}). If the +output format supports any number of sections, but with numbers and not +names (as is the case for Oasys), the name should be supplied as a +quoted numeric string. A section name may consist of any sequence of +characters, but a name which contains any unusual characters such as +commas must be quoted. + +The output section name @samp{/DISCARD/} is special; @ref{Output Section +Discarding}. + +@node Output Section Address +@subsection Output Section Description +@cindex address, section +@cindex section address +The @var{address} is an expression for the VMA (the virtual memory +address) of the output section. If you do not provide @var{address}, +the linker will set it based on @var{region} if present, or otherwise +based on the current value of the location counter. + +If you provide @var{address}, the address of the output section will be +set to precisely that. If you provide neither @var{address} nor +@var{region}, then the address of the output section will be set to the +current value of the location counter aligned to the alignment +requirements of the output section. The alignment requirement of the +output section is the strictest alignment of any input section contained +within the output section. + +For example, +@smallexample +.text . : @{ *(.text) @} +@end smallexample +@noindent +and +@smallexample +.text : @{ *(.text) @} +@end smallexample +@noindent +are subtly different. The first will set the address of the +@samp{.text} output section to the current value of the location +counter. The second will set it to the current value of the location +counter aligned to the strictest alignment of a @samp{.text} input +section. + +The @var{address} may be an arbitrary expression; @ref{Expressions}. +For example, if you want to align the section on a 0x10 byte boundary, +so that the lowest four bits of the section address are zero, you could +do something like this: +@smallexample +.text ALIGN(0x10) : @{ *(.text) @} +@end smallexample +@noindent +This works because @code{ALIGN} returns the current location counter +aligned upward to the specified value. + +Specifying @var{address} for a section will change the value of the +location counter. + +@node Input Section +@subsection Input Section Description +@cindex input sections +@cindex mapping input sections to output sections +The most common output section command is an input section description. + +The input section description is the most basic linker script operation. +You use output sections to tell the linker how to lay out your program +in memory. You use input section descriptions to tell the linker how to +map the input files into your memory layout. + +@menu +* Input Section Basics:: Input section basics +* Input Section Wildcards:: Input section wildcard patterns +* Input Section Common:: Input section for common symbols +* Input Section Keep:: Input section and garbage collection +* Input Section Example:: Input section example +@end menu + +@node Input Section Basics +@subsubsection Input Section Basics +@cindex input section basics +An input section description consists of a file name optionally followed +by a list of section names in parentheses. + +The file name and the section name may be wildcard patterns, which we +describe further below (@pxref{Input Section Wildcards}). + +The most common input section description is to include all input +sections with a particular name in the output section. For example, to +include all input @samp{.text} sections, you would write: +@smallexample +*(.text) +@end smallexample +@noindent +Here the @samp{*} is a wildcard which matches any file name. To exclude a list +of files from matching the file name wildcard, EXCLUDE_FILE may be used to +match all files except the ones specified in the EXCLUDE_FILE list. For +example: +@smallexample +(*(EXCLUDE_FILE (*crtend.o *otherfile.o) .ctors)) +@end smallexample +will cause all .ctors sections from all files except @file{crtend.o} and +@file{otherfile.o} to be included. + +There are two ways to include more than one section: +@smallexample +*(.text .rdata) +*(.text) *(.rdata) +@end smallexample +@noindent +The difference between these is the order in which the @samp{.text} and +@samp{.rdata} input sections will appear in the output section. In the +first example, they will be intermingled, appearing in the same order as +they are found in the linker input. In the second example, all +@samp{.text} input sections will appear first, followed by all +@samp{.rdata} input sections. + +You can specify a file name to include sections from a particular file. +You would do this if one or more of your files contain special data that +needs to be at a particular location in memory. For example: +@smallexample +data.o(.data) +@end smallexample + +If you use a file name without a list of sections, then all sections in +the input file will be included in the output section. This is not +commonly done, but it may by useful on occasion. For example: +@smallexample +data.o +@end smallexample + +When you use a file name which does not contain any wild card +characters, the linker will first see if you also specified the file +name on the linker command line or in an @code{INPUT} command. If you +did not, the linker will attempt to open the file as an input file, as +though it appeared on the command line. Note that this differs from an +@code{INPUT} command, because the linker will not search for the file in +the archive search path. + +@node Input Section Wildcards +@subsubsection Input Section Wildcard Patterns +@cindex input section wildcards +@cindex wildcard file name patterns +@cindex file name wildcard patterns +@cindex section name wildcard patterns +In an input section description, either the file name or the section +name or both may be wildcard patterns. + +The file name of @samp{*} seen in many examples is a simple wildcard +pattern for the file name. + +The wildcard patterns are like those used by the Unix shell. + +@table @samp +@item * +matches any number of characters +@item ? +matches any single character +@item [@var{chars}] +matches a single instance of any of the @var{chars}; the @samp{-} +character may be used to specify a range of characters, as in +@samp{[a-z]} to match any lower case letter +@item \ +quotes the following character +@end table + +When a file name is matched with a wildcard, the wildcard characters +will not match a @samp{/} character (used to separate directory names on +Unix). A pattern consisting of a single @samp{*} character is an +exception; it will always match any file name, whether it contains a +@samp{/} or not. In a section name, the wildcard characters will match +a @samp{/} character. + +File name wildcard patterns only match files which are explicitly +specified on the command line or in an @code{INPUT} command. The linker +does not search directories to expand wildcards. + +If a file name matches more than one wildcard pattern, or if a file name +appears explicitly and is also matched by a wildcard pattern, the linker +will use the first match in the linker script. For example, this +sequence of input section descriptions is probably in error, because the +@file{data.o} rule will not be used: +@smallexample +.data : @{ *(.data) @} +.data1 : @{ data.o(.data) @} +@end smallexample + +@cindex SORT +Normally, the linker will place files and sections matched by wildcards +in the order in which they are seen during the link. You can change +this by using the @code{SORT} keyword, which appears before a wildcard +pattern in parentheses (e.g., @code{SORT(.text*)}). When the +@code{SORT} keyword is used, the linker will sort the files or sections +into ascending order by name before placing them in the output file. + +If you ever get confused about where input sections are going, use the +@samp{-M} linker option to generate a map file. The map file shows +precisely how input sections are mapped to output sections. + +This example shows how wildcard patterns might be used to partition +files. This linker script directs the linker to place all @samp{.text} +sections in @samp{.text} and all @samp{.bss} sections in @samp{.bss}. +The linker will place the @samp{.data} section from all files beginning +with an upper case character in @samp{.DATA}; for all other files, the +linker will place the @samp{.data} section in @samp{.data}. +@smallexample +@group +SECTIONS @{ + .text : @{ *(.text) @} + .DATA : @{ [A-Z]*(.data) @} + .data : @{ *(.data) @} + .bss : @{ *(.bss) @} +@} +@end group +@end smallexample + +@node Input Section Common +@subsubsection Input Section for Common Symbols +@cindex common symbol placement +@cindex uninitialized data placement +A special notation is needed for common symbols, because in many object +file formats common symbols do not have a particular input section. The +linker treats common symbols as though they are in an input section +named @samp{COMMON}. + +You may use file names with the @samp{COMMON} section just as with any +other input sections. You can use this to place common symbols from a +particular input file in one section while common symbols from other +input files are placed in another section. + +In most cases, common symbols in input files will be placed in the +@samp{.bss} section in the output file. For example: +@smallexample +.bss @{ *(.bss) *(COMMON) @} +@end smallexample + +@cindex scommon section +@cindex small common symbols +Some object file formats have more than one type of common symbol. For +example, the MIPS ELF object file format distinguishes standard common +symbols and small common symbols. In this case, the linker will use a +different special section name for other types of common symbols. In +the case of MIPS ELF, the linker uses @samp{COMMON} for standard common +symbols and @samp{.scommon} for small common symbols. This permits you +to map the different types of common symbols into memory at different +locations. + +@cindex [COMMON] +You will sometimes see @samp{[COMMON]} in old linker scripts. This +notation is now considered obsolete. It is equivalent to +@samp{*(COMMON)}. + +@node Input Section Keep +@subsubsection Input Section and Garbage Collection +@cindex KEEP +@cindex garbage collection +When link-time garbage collection is in use (@samp{--gc-sections}), +it is often useful to mark sections that should not be eliminated. +This is accomplished by surrounding an input section's wildcard entry +with @code{KEEP()}, as in @code{KEEP(*(.init))} or +@code{KEEP(SORT(*)(.ctors))}. + +@node Input Section Example +@subsubsection Input Section Example +The following example is a complete linker script. It tells the linker +to read all of the sections from file @file{all.o} and place them at the +start of output section @samp{outputa} which starts at location +@samp{0x10000}. All of section @samp{.input1} from file @file{foo.o} +follows immediately, in the same output section. All of section +@samp{.input2} from @file{foo.o} goes into output section +@samp{outputb}, followed by section @samp{.input1} from @file{foo1.o}. +All of the remaining @samp{.input1} and @samp{.input2} sections from any +files are written to output section @samp{outputc}. + +@smallexample +@group +SECTIONS @{ + outputa 0x10000 : + @{ + all.o + foo.o (.input1) + @} +@end group +@group + outputb : + @{ + foo.o (.input2) + foo1.o (.input1) + @} +@end group +@group + outputc : + @{ + *(.input1) + *(.input2) + @} +@} +@end group +@end smallexample + +@node Output Section Data +@subsection Output Section Data +@cindex data +@cindex section data +@cindex output section data +@kindex BYTE(@var{expression}) +@kindex SHORT(@var{expression}) +@kindex LONG(@var{expression}) +@kindex QUAD(@var{expression}) +@kindex SQUAD(@var{expression}) +You can include explicit bytes of data in an output section by using +@code{BYTE}, @code{SHORT}, @code{LONG}, @code{QUAD}, or @code{SQUAD} as +an output section command. Each keyword is followed by an expression in +parentheses providing the value to store (@pxref{Expressions}). The +value of the expression is stored at the current value of the location +counter. + +The @code{BYTE}, @code{SHORT}, @code{LONG}, and @code{QUAD} commands +store one, two, four, and eight bytes (respectively). After storing the +bytes, the location counter is incremented by the number of bytes +stored. + +For example, this will store the byte 1 followed by the four byte value +of the symbol @samp{addr}: +@smallexample +BYTE(1) +LONG(addr) +@end smallexample + +When using a 64 bit host or target, @code{QUAD} and @code{SQUAD} are the +same; they both store an 8 byte, or 64 bit, value. When both host and +target are 32 bits, an expression is computed as 32 bits. In this case +@code{QUAD} stores a 32 bit value zero extended to 64 bits, and +@code{SQUAD} stores a 32 bit value sign extended to 64 bits. + +If the object file format of the output file has an explicit endianness, +which is the normal case, the value will be stored in that endianness. +When the object file format does not have an explicit endianness, as is +true of, for example, S-records, the value will be stored in the +endianness of the first input object file. + +Note---these commands only work inside a section description and not +between them, so the following will produce an error from the linker: +@smallexample +SECTIONS @{@ .text : @{@ *(.text) @}@ LONG(1) .data : @{@ *(.data) @}@ @}@ +@end smallexample +whereas this will work: +@smallexample +SECTIONS @{@ .text : @{@ *(.text) ; LONG(1) @}@ .data : @{@ *(.data) @}@ @}@ +@end smallexample + +@kindex FILL(@var{expression}) +@cindex holes, filling +@cindex unspecified memory +You may use the @code{FILL} command to set the fill pattern for the +current section. It is followed by an expression in parentheses. Any +otherwise unspecified regions of memory within the section (for example, +gaps left due to the required alignment of input sections) are filled +with the value of the expression, repeated as +necessary. A @code{FILL} statement covers memory locations after the +point at which it occurs in the section definition; by including more +than one @code{FILL} statement, you can have different fill patterns in +different parts of an output section. + +This example shows how to fill unspecified regions of memory with the +value @samp{0x90}: +@smallexample +FILL(0x90909090) +@end smallexample + +The @code{FILL} command is similar to the @samp{=@var{fillexp}} output +section attribute, but it only affects the +part of the section following the @code{FILL} command, rather than the +entire section. If both are used, the @code{FILL} command takes +precedence. @xref{Output Section Fill}, for details on the fill +expression. + +@node Output Section Keywords +@subsection Output Section Keywords +There are a couple of keywords which can appear as output section +commands. + +@table @code +@kindex CREATE_OBJECT_SYMBOLS +@cindex input filename symbols +@cindex filename symbols +@item CREATE_OBJECT_SYMBOLS +The command tells the linker to create a symbol for each input file. +The name of each symbol will be the name of the corresponding input +file. The section of each symbol will be the output section in which +the @code{CREATE_OBJECT_SYMBOLS} command appears. + +This is conventional for the a.out object file format. It is not +normally used for any other object file format. + +@kindex CONSTRUCTORS +@cindex C++ constructors, arranging in link +@cindex constructors, arranging in link +@item CONSTRUCTORS +When linking using the a.out object file format, the linker uses an +unusual set construct to support C++ global constructors and +destructors. When linking object file formats which do not support +arbitrary sections, such as ECOFF and XCOFF, the linker will +automatically recognize C++ global constructors and destructors by name. +For these object file formats, the @code{CONSTRUCTORS} command tells the +linker to place constructor information in the output section where the +@code{CONSTRUCTORS} command appears. The @code{CONSTRUCTORS} command is +ignored for other object file formats. + +The symbol @w{@code{__CTOR_LIST__}} marks the start of the global +constructors, and the symbol @w{@code{__DTOR_LIST}} marks the end. The +first word in the list is the number of entries, followed by the address +of each constructor or destructor, followed by a zero word. The +compiler must arrange to actually run the code. For these object file +formats @sc{gnu} C++ normally calls constructors from a subroutine +@code{__main}; a call to @code{__main} is automatically inserted into +the startup code for @code{main}. @sc{gnu} C++ normally runs +destructors either by using @code{atexit}, or directly from the function +@code{exit}. + +For object file formats such as @code{COFF} or @code{ELF} which support +arbitrary section names, @sc{gnu} C++ will normally arrange to put the +addresses of global constructors and destructors into the @code{.ctors} +and @code{.dtors} sections. Placing the following sequence into your +linker script will build the sort of table which the @sc{gnu} C++ +runtime code expects to see. + +@smallexample + __CTOR_LIST__ = .; + LONG((__CTOR_END__ - __CTOR_LIST__) / 4 - 2) + *(.ctors) + LONG(0) + __CTOR_END__ = .; + __DTOR_LIST__ = .; + LONG((__DTOR_END__ - __DTOR_LIST__) / 4 - 2) + *(.dtors) + LONG(0) + __DTOR_END__ = .; +@end smallexample + +If you are using the @sc{gnu} C++ support for initialization priority, +which provides some control over the order in which global constructors +are run, you must sort the constructors at link time to ensure that they +are executed in the correct order. When using the @code{CONSTRUCTORS} +command, use @samp{SORT(CONSTRUCTORS)} instead. When using the +@code{.ctors} and @code{.dtors} sections, use @samp{*(SORT(.ctors))} and +@samp{*(SORT(.dtors))} instead of just @samp{*(.ctors)} and +@samp{*(.dtors)}. + +Normally the compiler and linker will handle these issues automatically, +and you will not need to concern yourself with them. However, you may +need to consider this if you are using C++ and writing your own linker +scripts. + +@end table + +@node Output Section Discarding +@subsection Output Section Discarding +@cindex discarding sections +@cindex sections, discarding +@cindex removing sections +The linker will not create output section which do not have any +contents. This is for convenience when referring to input sections that +may or may not be present in any of the input files. For example: +@smallexample +.foo @{ *(.foo) @} +@end smallexample +@noindent +will only create a @samp{.foo} section in the output file if there is a +@samp{.foo} section in at least one input file. + +If you use anything other than an input section description as an output +section command, such as a symbol assignment, then the output section +will always be created, even if there are no matching input sections. + +@cindex /DISCARD/ +The special output section name @samp{/DISCARD/} may be used to discard +input sections. Any input sections which are assigned to an output +section named @samp{/DISCARD/} are not included in the output file. + +@node Output Section Attributes +@subsection Output Section Attributes +@cindex output section attributes +We showed above that the full description of an output section looked +like this: +@smallexample +@group +@var{section} [@var{address}] [(@var{type})] : [AT(@var{lma})] + @{ + @var{output-section-command} + @var{output-section-command} + @dots{} + @} [>@var{region}] [AT>@var{lma_region}] [:@var{phdr} :@var{phdr} @dots{}] [=@var{fillexp}] +@end group +@end smallexample +We've already described @var{section}, @var{address}, and +@var{output-section-command}. In this section we will describe the +remaining section attributes. + +@menu +* Output Section Type:: Output section type +* Output Section LMA:: Output section LMA +* Output Section Region:: Output section region +* Output Section Phdr:: Output section phdr +* Output Section Fill:: Output section fill +@end menu + +@node Output Section Type +@subsubsection Output Section Type +Each output section may have a type. The type is a keyword in +parentheses. The following types are defined: + +@table @code +@item NOLOAD +The section should be marked as not loadable, so that it will not be +loaded into memory when the program is run. +@item DSECT +@itemx COPY +@itemx INFO +@itemx OVERLAY +These type names are supported for backward compatibility, and are +rarely used. They all have the same effect: the section should be +marked as not allocatable, so that no memory is allocated for the +section when the program is run. +@end table + +@kindex NOLOAD +@cindex prevent unnecessary loading +@cindex loading, preventing +The linker normally sets the attributes of an output section based on +the input sections which map into it. You can override this by using +the section type. For example, in the script sample below, the +@samp{ROM} section is addressed at memory location @samp{0} and does not +need to be loaded when the program is run. The contents of the +@samp{ROM} section will appear in the linker output file as usual. +@smallexample +@group +SECTIONS @{ + ROM 0 (NOLOAD) : @{ @dots{} @} + @dots{} +@} +@end group +@end smallexample + +@node Output Section LMA +@subsubsection Output Section LMA +@kindex AT>@var{lma_region} +@kindex AT(@var{lma}) +@cindex load address +@cindex section load address +Every section has a virtual address (VMA) and a load address (LMA); see +@ref{Basic Script Concepts}. The address expression which may appear in +an output section description sets the VMA (@pxref{Output Section +Address}). + +The linker will normally set the LMA equal to the VMA. You can change +that by using the @code{AT} keyword. The expression @var{lma} that +follows the @code{AT} keyword specifies the load address of the +section. Alternatively, with @samp{AT>@var{lma_region}} expression, +you may specify a memory region for the section's load address. @xref{MEMORY}. + +@cindex ROM initialized data +@cindex initialized data in ROM +This feature is designed to make it easy to build a ROM image. For +example, the following linker script creates three output sections: one +called @samp{.text}, which starts at @code{0x1000}, one called +@samp{.mdata}, which is loaded at the end of the @samp{.text} section +even though its VMA is @code{0x2000}, and one called @samp{.bss} to hold +uninitialized data at address @code{0x3000}. The symbol @code{_data} is +defined with the value @code{0x2000}, which shows that the location +counter holds the VMA value, not the LMA value. + +@smallexample +@group +SECTIONS + @{ + .text 0x1000 : @{ *(.text) _etext = . ; @} + .mdata 0x2000 : + AT ( ADDR (.text) + SIZEOF (.text) ) + @{ _data = . ; *(.data); _edata = . ; @} + .bss 0x3000 : + @{ _bstart = . ; *(.bss) *(COMMON) ; _bend = . ;@} +@} +@end group +@end smallexample + +The run-time initialization code for use with a program generated with +this linker script would include something like the following, to copy +the initialized data from the ROM image to its runtime address. Notice +how this code takes advantage of the symbols defined by the linker +script. + +@smallexample +@group +extern char _etext, _data, _edata, _bstart, _bend; +char *src = &_etext; +char *dst = &_data; + +/* ROM has data at end of text; copy it. */ +while (dst < &_edata) @{ + *dst++ = *src++; +@} + +/* Zero bss */ +for (dst = &_bstart; dst< &_bend; dst++) + *dst = 0; +@end group +@end smallexample + +@node Output Section Region +@subsubsection Output Section Region +@kindex >@var{region} +@cindex section, assigning to memory region +@cindex memory regions and sections +You can assign a section to a previously defined region of memory by +using @samp{>@var{region}}. @xref{MEMORY}. + +Here is a simple example: +@smallexample +@group +MEMORY @{ rom : ORIGIN = 0x1000, LENGTH = 0x1000 @} +SECTIONS @{ ROM : @{ *(.text) @} >rom @} +@end group +@end smallexample + +@node Output Section Phdr +@subsubsection Output Section Phdr +@kindex :@var{phdr} +@cindex section, assigning to program header +@cindex program headers and sections +You can assign a section to a previously defined program segment by +using @samp{:@var{phdr}}. @xref{PHDRS}. If a section is assigned to +one or more segments, then all subsequent allocated sections will be +assigned to those segments as well, unless they use an explicitly +@code{:@var{phdr}} modifier. You can use @code{:NONE} to tell the +linker to not put the section in any segment at all. + +Here is a simple example: +@smallexample +@group +PHDRS @{ text PT_LOAD ; @} +SECTIONS @{ .text : @{ *(.text) @} :text @} +@end group +@end smallexample + +@node Output Section Fill +@subsubsection Output Section Fill +@kindex =@var{fillexp} +@cindex section fill pattern +@cindex fill pattern, entire section +You can set the fill pattern for an entire section by using +@samp{=@var{fillexp}}. @var{fillexp} is an expression +(@pxref{Expressions}). Any otherwise unspecified regions of memory +within the output section (for example, gaps left due to the required +alignment of input sections) will be filled with the value, repeated as +necessary. If the fill expression is a simple hex number, ie. a string +of hex digit starting with @samp{0x} and without a trailing @samp{k} or @samp{M}, then +an arbitrarily long sequence of hex digits can be used to specify the +fill pattern; Leading zeros become part of the pattern too. For all +other cases, including extra parentheses or a unary @code{+}, the fill +pattern is the four least significant bytes of the value of the +expression. In all cases, the number is big-endian. + +You can also change the fill value with a @code{FILL} command in the +output section commands; (@pxref{Output Section Data}). + +Here is a simple example: +@smallexample +@group +SECTIONS @{ .text : @{ *(.text) @} =0x90909090 @} +@end group +@end smallexample + +@node Overlay Description +@subsection Overlay Description +@kindex OVERLAY +@cindex overlays +An overlay description provides an easy way to describe sections which +are to be loaded as part of a single memory image but are to be run at +the same memory address. At run time, some sort of overlay manager will +copy the overlaid sections in and out of the runtime memory address as +required, perhaps by simply manipulating addressing bits. This approach +can be useful, for example, when a certain region of memory is faster +than another. + +Overlays are described using the @code{OVERLAY} command. The +@code{OVERLAY} command is used within a @code{SECTIONS} command, like an +output section description. The full syntax of the @code{OVERLAY} +command is as follows: +@smallexample +@group +OVERLAY [@var{start}] : [NOCROSSREFS] [AT ( @var{ldaddr} )] + @{ + @var{secname1} + @{ + @var{output-section-command} + @var{output-section-command} + @dots{} + @} [:@var{phdr}@dots{}] [=@var{fill}] + @var{secname2} + @{ + @var{output-section-command} + @var{output-section-command} + @dots{} + @} [:@var{phdr}@dots{}] [=@var{fill}] + @dots{} + @} [>@var{region}] [:@var{phdr}@dots{}] [=@var{fill}] +@end group +@end smallexample + +Everything is optional except @code{OVERLAY} (a keyword), and each +section must have a name (@var{secname1} and @var{secname2} above). The +section definitions within the @code{OVERLAY} construct are identical to +those within the general @code{SECTIONS} contruct (@pxref{SECTIONS}), +except that no addresses and no memory regions may be defined for +sections within an @code{OVERLAY}. + +The sections are all defined with the same starting address. The load +addresses of the sections are arranged such that they are consecutive in +memory starting at the load address used for the @code{OVERLAY} as a +whole (as with normal section definitions, the load address is optional, +and defaults to the start address; the start address is also optional, +and defaults to the current value of the location counter). + +If the @code{NOCROSSREFS} keyword is used, and there any references +among the sections, the linker will report an error. Since the sections +all run at the same address, it normally does not make sense for one +section to refer directly to another. @xref{Miscellaneous Commands, +NOCROSSREFS}. + +For each section within the @code{OVERLAY}, the linker automatically +defines two symbols. The symbol @code{__load_start_@var{secname}} is +defined as the starting load address of the section. The symbol +@code{__load_stop_@var{secname}} is defined as the final load address of +the section. Any characters within @var{secname} which are not legal +within C identifiers are removed. C (or assembler) code may use these +symbols to move the overlaid sections around as necessary. + +At the end of the overlay, the value of the location counter is set to +the start address of the overlay plus the size of the largest section. + +Here is an example. Remember that this would appear inside a +@code{SECTIONS} construct. +@smallexample +@group + OVERLAY 0x1000 : AT (0x4000) + @{ + .text0 @{ o1/*.o(.text) @} + .text1 @{ o2/*.o(.text) @} + @} +@end group +@end smallexample +@noindent +This will define both @samp{.text0} and @samp{.text1} to start at +address 0x1000. @samp{.text0} will be loaded at address 0x4000, and +@samp{.text1} will be loaded immediately after @samp{.text0}. The +following symbols will be defined: @code{__load_start_text0}, +@code{__load_stop_text0}, @code{__load_start_text1}, +@code{__load_stop_text1}. + +C code to copy overlay @code{.text1} into the overlay area might look +like the following. + +@smallexample +@group + extern char __load_start_text1, __load_stop_text1; + memcpy ((char *) 0x1000, &__load_start_text1, + &__load_stop_text1 - &__load_start_text1); +@end group +@end smallexample + +Note that the @code{OVERLAY} command is just syntactic sugar, since +everything it does can be done using the more basic commands. The above +example could have been written identically as follows. + +@smallexample +@group + .text0 0x1000 : AT (0x4000) @{ o1/*.o(.text) @} + __load_start_text0 = LOADADDR (.text0); + __load_stop_text0 = LOADADDR (.text0) + SIZEOF (.text0); + .text1 0x1000 : AT (0x4000 + SIZEOF (.text0)) @{ o2/*.o(.text) @} + __load_start_text1 = LOADADDR (.text1); + __load_stop_text1 = LOADADDR (.text1) + SIZEOF (.text1); + . = 0x1000 + MAX (SIZEOF (.text0), SIZEOF (.text1)); +@end group +@end smallexample + +@node MEMORY +@section MEMORY Command +@kindex MEMORY +@cindex memory regions +@cindex regions of memory +@cindex allocating memory +@cindex discontinuous memory +The linker's default configuration permits allocation of all available +memory. You can override this by using the @code{MEMORY} command. + +The @code{MEMORY} command describes the location and size of blocks of +memory in the target. You can use it to describe which memory regions +may be used by the linker, and which memory regions it must avoid. You +can then assign sections to particular memory regions. The linker will +set section addresses based on the memory regions, and will warn about +regions that become too full. The linker will not shuffle sections +around to fit into the available regions. + +A linker script may contain at most one use of the @code{MEMORY} +command. However, you can define as many blocks of memory within it as +you wish. The syntax is: +@smallexample +@group +MEMORY + @{ + @var{name} [(@var{attr})] : ORIGIN = @var{origin}, LENGTH = @var{len} + @dots{} + @} +@end group +@end smallexample + +The @var{name} is a name used in the linker script to refer to the +region. The region name has no meaning outside of the linker script. +Region names are stored in a separate name space, and will not conflict +with symbol names, file names, or section names. Each memory region +must have a distinct name. + +@cindex memory region attributes +The @var{attr} string is an optional list of attributes that specify +whether to use a particular memory region for an input section which is +not explicitly mapped in the linker script. As described in +@ref{SECTIONS}, if you do not specify an output section for some input +section, the linker will create an output section with the same name as +the input section. If you define region attributes, the linker will use +them to select the memory region for the output section that it creates. + +The @var{attr} string must consist only of the following characters: +@table @samp +@item R +Read-only section +@item W +Read/write section +@item X +Executable section +@item A +Allocatable section +@item I +Initialized section +@item L +Same as @samp{I} +@item ! +Invert the sense of any of the preceding attributes +@end table + +If a unmapped section matches any of the listed attributes other than +@samp{!}, it will be placed in the memory region. The @samp{!} +attribute reverses this test, so that an unmapped section will be placed +in the memory region only if it does not match any of the listed +attributes. + +@kindex ORIGIN = +@kindex o = +@kindex org = +The @var{origin} is an expression for the start address of the memory +region. The expression must evaluate to a constant before memory +allocation is performed, which means that you may not use any section +relative symbols. The keyword @code{ORIGIN} may be abbreviated to +@code{org} or @code{o} (but not, for example, @code{ORG}). + +@kindex LENGTH = +@kindex len = +@kindex l = +The @var{len} is an expression for the size in bytes of the memory +region. As with the @var{origin} expression, the expression must +evaluate to a constant before memory allocation is performed. The +keyword @code{LENGTH} may be abbreviated to @code{len} or @code{l}. + +In the following example, we specify that there are two memory regions +available for allocation: one starting at @samp{0} for 256 kilobytes, +and the other starting at @samp{0x40000000} for four megabytes. The +linker will place into the @samp{rom} memory region every section which +is not explicitly mapped into a memory region, and is either read-only +or executable. The linker will place other sections which are not +explicitly mapped into a memory region into the @samp{ram} memory +region. + +@smallexample +@group +MEMORY + @{ + rom (rx) : ORIGIN = 0, LENGTH = 256K + ram (!rx) : org = 0x40000000, l = 4M + @} +@end group +@end smallexample + +Once you define a memory region, you can direct the linker to place +specific output sections into that memory region by using the +@samp{>@var{region}} output section attribute. For example, if you have +a memory region named @samp{mem}, you would use @samp{>mem} in the +output section definition. @xref{Output Section Region}. If no address +was specified for the output section, the linker will set the address to +the next available address within the memory region. If the combined +output sections directed to a memory region are too large for the +region, the linker will issue an error message. + +@node PHDRS +@section PHDRS Command +@kindex PHDRS +@cindex program headers +@cindex ELF program headers +@cindex program segments +@cindex segments, ELF +The ELF object file format uses @dfn{program headers}, also knows as +@dfn{segments}. The program headers describe how the program should be +loaded into memory. You can print them out by using the @code{objdump} +program with the @samp{-p} option. + +When you run an ELF program on a native ELF system, the system loader +reads the program headers in order to figure out how to load the +program. This will only work if the program headers are set correctly. +This manual does not describe the details of how the system loader +interprets program headers; for more information, see the ELF ABI. + +The linker will create reasonable program headers by default. However, +in some cases, you may need to specify the program headers more +precisely. You may use the @code{PHDRS} command for this purpose. When +the linker sees the @code{PHDRS} command in the linker script, it will +not create any program headers other than the ones specified. + +The linker only pays attention to the @code{PHDRS} command when +generating an ELF output file. In other cases, the linker will simply +ignore @code{PHDRS}. + +This is the syntax of the @code{PHDRS} command. The words @code{PHDRS}, +@code{FILEHDR}, @code{AT}, and @code{FLAGS} are keywords. + +@smallexample +@group +PHDRS +@{ + @var{name} @var{type} [ FILEHDR ] [ PHDRS ] [ AT ( @var{address} ) ] + [ FLAGS ( @var{flags} ) ] ; +@} +@end group +@end smallexample + +The @var{name} is used only for reference in the @code{SECTIONS} command +of the linker script. It is not put into the output file. Program +header names are stored in a separate name space, and will not conflict +with symbol names, file names, or section names. Each program header +must have a distinct name. + +Certain program header types describe segments of memory which the +system loader will load from the file. In the linker script, you +specify the contents of these segments by placing allocatable output +sections in the segments. You use the @samp{:@var{phdr}} output section +attribute to place a section in a particular segment. @xref{Output +Section Phdr}. + +It is normal to put certain sections in more than one segment. This +merely implies that one segment of memory contains another. You may +repeat @samp{:@var{phdr}}, using it once for each segment which should +contain the section. + +If you place a section in one or more segments using @samp{:@var{phdr}}, +then the linker will place all subsequent allocatable sections which do +not specify @samp{:@var{phdr}} in the same segments. This is for +convenience, since generally a whole set of contiguous sections will be +placed in a single segment. You can use @code{:NONE} to override the +default segment and tell the linker to not put the section in any +segment at all. + +@kindex FILEHDR +@kindex PHDRS +You may use the @code{FILEHDR} and @code{PHDRS} keywords appear after +the program header type to further describe the contents of the segment. +The @code{FILEHDR} keyword means that the segment should include the ELF +file header. The @code{PHDRS} keyword means that the segment should +include the ELF program headers themselves. + +The @var{type} may be one of the following. The numbers indicate the +value of the keyword. + +@table @asis +@item @code{PT_NULL} (0) +Indicates an unused program header. + +@item @code{PT_LOAD} (1) +Indicates that this program header describes a segment to be loaded from +the file. + +@item @code{PT_DYNAMIC} (2) +Indicates a segment where dynamic linking information can be found. + +@item @code{PT_INTERP} (3) +Indicates a segment where the name of the program interpreter may be +found. + +@item @code{PT_NOTE} (4) +Indicates a segment holding note information. + +@item @code{PT_SHLIB} (5) +A reserved program header type, defined but not specified by the ELF +ABI. + +@item @code{PT_PHDR} (6) +Indicates a segment where the program headers may be found. + +@item @var{expression} +An expression giving the numeric type of the program header. This may +be used for types not defined above. +@end table + +You can specify that a segment should be loaded at a particular address +in memory by using an @code{AT} expression. This is identical to the +@code{AT} command used as an output section attribute (@pxref{Output +Section LMA}). The @code{AT} command for a program header overrides the +output section attribute. + +The linker will normally set the segment flags based on the sections +which comprise the segment. You may use the @code{FLAGS} keyword to +explicitly specify the segment flags. The value of @var{flags} must be +an integer. It is used to set the @code{p_flags} field of the program +header. + +Here is an example of @code{PHDRS}. This shows a typical set of program +headers used on a native ELF system. + +@example +@group +PHDRS +@{ + headers PT_PHDR PHDRS ; + interp PT_INTERP ; + text PT_LOAD FILEHDR PHDRS ; + data PT_LOAD ; + dynamic PT_DYNAMIC ; +@} + +SECTIONS +@{ + . = SIZEOF_HEADERS; + .interp : @{ *(.interp) @} :text :interp + .text : @{ *(.text) @} :text + .rodata : @{ *(.rodata) @} /* defaults to :text */ + @dots{} + . = . + 0x1000; /* move to a new page in memory */ + .data : @{ *(.data) @} :data + .dynamic : @{ *(.dynamic) @} :data :dynamic + @dots{} +@} +@end group +@end example + +@node VERSION +@section VERSION Command +@kindex VERSION @{script text@} +@cindex symbol versions +@cindex version script +@cindex versions of symbols +The linker supports symbol versions when using ELF. Symbol versions are +only useful when using shared libraries. The dynamic linker can use +symbol versions to select a specific version of a function when it runs +a program that may have been linked against an earlier version of the +shared library. + +You can include a version script directly in the main linker script, or +you can supply the version script as an implicit linker script. You can +also use the @samp{--version-script} linker option. + +The syntax of the @code{VERSION} command is simply +@smallexample +VERSION @{ version-script-commands @} +@end smallexample + +The format of the version script commands is identical to that used by +Sun's linker in Solaris 2.5. The version script defines a tree of +version nodes. You specify the node names and interdependencies in the +version script. You can specify which symbols are bound to which +version nodes, and you can reduce a specified set of symbols to local +scope so that they are not globally visible outside of the shared +library. + +The easiest way to demonstrate the version script language is with a few +examples. + +@smallexample +VERS_1.1 @{ + global: + foo1; + local: + old*; + original*; + new*; +@}; + +VERS_1.2 @{ + foo2; +@} VERS_1.1; + +VERS_2.0 @{ + bar1; bar2; +@} VERS_1.2; +@end smallexample + +This example version script defines three version nodes. The first +version node defined is @samp{VERS_1.1}; it has no other dependencies. +The script binds the symbol @samp{foo1} to @samp{VERS_1.1}. It reduces +a number of symbols to local scope so that they are not visible outside +of the shared library; this is done using wildcard patterns, so that any +symbol whose name begins with @samp{old}, @samp{original}, or @samp{new} +is matched. The wildcard patterns available are the same as those used +in the shell when matching filenames (also known as ``globbing''). + +Next, the version script defines node @samp{VERS_1.2}. This node +depends upon @samp{VERS_1.1}. The script binds the symbol @samp{foo2} +to the version node @samp{VERS_1.2}. + +Finally, the version script defines node @samp{VERS_2.0}. This node +depends upon @samp{VERS_1.2}. The scripts binds the symbols @samp{bar1} +and @samp{bar2} are bound to the version node @samp{VERS_2.0}. + +When the linker finds a symbol defined in a library which is not +specifically bound to a version node, it will effectively bind it to an +unspecified base version of the library. You can bind all otherwise +unspecified symbols to a given version node by using @samp{global: *;} +somewhere in the version script. + +The names of the version nodes have no specific meaning other than what +they might suggest to the person reading them. The @samp{2.0} version +could just as well have appeared in between @samp{1.1} and @samp{1.2}. +However, this would be a confusing way to write a version script. + +Node name can be omited, provided it is the only version node +in the version script. Such version script doesn't assign any versions to +symbols, only selects which symbols will be globally visible out and which +won't. + +@smallexample +@{ global: foo; bar; local: *; @}; +@end smallexample + +When you link an application against a shared library that has versioned +symbols, the application itself knows which version of each symbol it +requires, and it also knows which version nodes it needs from each +shared library it is linked against. Thus at runtime, the dynamic +loader can make a quick check to make sure that the libraries you have +linked against do in fact supply all of the version nodes that the +application will need to resolve all of the dynamic symbols. In this +way it is possible for the dynamic linker to know with certainty that +all external symbols that it needs will be resolvable without having to +search for each symbol reference. + +The symbol versioning is in effect a much more sophisticated way of +doing minor version checking that SunOS does. The fundamental problem +that is being addressed here is that typically references to external +functions are bound on an as-needed basis, and are not all bound when +the application starts up. If a shared library is out of date, a +required interface may be missing; when the application tries to use +that interface, it may suddenly and unexpectedly fail. With symbol +versioning, the user will get a warning when they start their program if +the libraries being used with the application are too old. + +There are several GNU extensions to Sun's versioning approach. The +first of these is the ability to bind a symbol to a version node in the +source file where the symbol is defined instead of in the versioning +script. This was done mainly to reduce the burden on the library +maintainer. You can do this by putting something like: +@smallexample +__asm__(".symver original_foo,foo@@VERS_1.1"); +@end smallexample +@noindent +in the C source file. This renames the function @samp{original_foo} to +be an alias for @samp{foo} bound to the version node @samp{VERS_1.1}. +The @samp{local:} directive can be used to prevent the symbol +@samp{original_foo} from being exported. A @samp{.symver} directive +takes precedence over a version script. + +The second GNU extension is to allow multiple versions of the same +function to appear in a given shared library. In this way you can make +an incompatible change to an interface without increasing the major +version number of the shared library, while still allowing applications +linked against the old interface to continue to function. + +To do this, you must use multiple @samp{.symver} directives in the +source file. Here is an example: + +@smallexample +__asm__(".symver original_foo,foo@@"); +__asm__(".symver old_foo,foo@@VERS_1.1"); +__asm__(".symver old_foo1,foo@@VERS_1.2"); +__asm__(".symver new_foo,foo@@@@VERS_2.0"); +@end smallexample + +In this example, @samp{foo@@} represents the symbol @samp{foo} bound to the +unspecified base version of the symbol. The source file that contains this +example would define 4 C functions: @samp{original_foo}, @samp{old_foo}, +@samp{old_foo1}, and @samp{new_foo}. + +When you have multiple definitions of a given symbol, there needs to be +some way to specify a default version to which external references to +this symbol will be bound. You can do this with the +@samp{foo@@@@VERS_2.0} type of @samp{.symver} directive. You can only +declare one version of a symbol as the default in this manner; otherwise +you would effectively have multiple definitions of the same symbol. + +If you wish to bind a reference to a specific version of the symbol +within the shared library, you can use the aliases of convenience +(i.e., @samp{old_foo}), or you can use the @samp{.symver} directive to +specifically bind to an external version of the function in question. + +You can also specify the language in the version script: + +@smallexample +VERSION extern "lang" @{ version-script-commands @} +@end smallexample + +The supported @samp{lang}s are @samp{C}, @samp{C++}, and @samp{Java}. +The linker will iterate over the list of symbols at the link time and +demangle them according to @samp{lang} before matching them to the +patterns specified in @samp{version-script-commands}. + +@node Expressions +@section Expressions in Linker Scripts +@cindex expressions +@cindex arithmetic +The syntax for expressions in the linker script language is identical to +that of C expressions. All expressions are evaluated as integers. All +expressions are evaluated in the same size, which is 32 bits if both the +host and target are 32 bits, and is otherwise 64 bits. + +You can use and set symbol values in expressions. + +The linker defines several special purpose builtin functions for use in +expressions. + +@menu +* Constants:: Constants +* Symbols:: Symbol Names +* Location Counter:: The Location Counter +* Operators:: Operators +* Evaluation:: Evaluation +* Expression Section:: The Section of an Expression +* Builtin Functions:: Builtin Functions +@end menu + +@node Constants +@subsection Constants +@cindex integer notation +@cindex constants in linker scripts +All constants are integers. + +As in C, the linker considers an integer beginning with @samp{0} to be +octal, and an integer beginning with @samp{0x} or @samp{0X} to be +hexadecimal. The linker considers other integers to be decimal. + +@cindex scaled integers +@cindex K and M integer suffixes +@cindex M and K integer suffixes +@cindex suffixes for integers +@cindex integer suffixes +In addition, you can use the suffixes @code{K} and @code{M} to scale a +constant by +@c TEXI2ROFF-KILL +@ifnottex +@c END TEXI2ROFF-KILL +@code{1024} or @code{1024*1024} +@c TEXI2ROFF-KILL +@end ifnottex +@tex +${\rm 1024}$ or ${\rm 1024}^2$ +@end tex +@c END TEXI2ROFF-KILL +respectively. For example, the following all refer to the same quantity: +@smallexample +_fourk_1 = 4K; +_fourk_2 = 4096; +_fourk_3 = 0x1000; +@end smallexample + +@node Symbols +@subsection Symbol Names +@cindex symbol names +@cindex names +@cindex quoted symbol names +@kindex " +Unless quoted, symbol names start with a letter, underscore, or period +and may include letters, digits, underscores, periods, and hyphens. +Unquoted symbol names must not conflict with any keywords. You can +specify a symbol which contains odd characters or has the same name as a +keyword by surrounding the symbol name in double quotes: +@smallexample +"SECTION" = 9; +"with a space" = "also with a space" + 10; +@end smallexample + +Since symbols can contain many non-alphabetic characters, it is safest +to delimit symbols with spaces. For example, @samp{A-B} is one symbol, +whereas @samp{A - B} is an expression involving subtraction. + +@node Location Counter +@subsection The Location Counter +@kindex . +@cindex dot +@cindex location counter +@cindex current output location +The special linker variable @dfn{dot} @samp{.} always contains the +current output location counter. Since the @code{.} always refers to a +location in an output section, it may only appear in an expression +within a @code{SECTIONS} command. The @code{.} symbol may appear +anywhere that an ordinary symbol is allowed in an expression. + +@cindex holes +Assigning a value to @code{.} will cause the location counter to be +moved. This may be used to create holes in the output section. The +location counter may never be moved backwards. + +@smallexample +SECTIONS +@{ + output : + @{ + file1(.text) + . = . + 1000; + file2(.text) + . += 1000; + file3(.text) + @} = 0x12345678; +@} +@end smallexample +@noindent +In the previous example, the @samp{.text} section from @file{file1} is +located at the beginning of the output section @samp{output}. It is +followed by a 1000 byte gap. Then the @samp{.text} section from +@file{file2} appears, also with a 1000 byte gap following before the +@samp{.text} section from @file{file3}. The notation @samp{= 0x12345678} +specifies what data to write in the gaps (@pxref{Output Section Fill}). + +@cindex dot inside sections +Note: @code{.} actually refers to the byte offset from the start of the +current containing object. Normally this is the @code{SECTIONS} +statement, whose start address is 0, hence @code{.} can be used as an +absolute address. If @code{.} is used inside a section description +however, it refers to the byte offset from the start of that section, +not an absolute address. Thus in a script like this: + +@smallexample +SECTIONS +@{ + . = 0x100 + .text: @{ + *(.text) + . = 0x200 + @} + . = 0x500 + .data: @{ + *(.data) + . += 0x600 + @} +@} +@end smallexample + +The @samp{.text} section will be assigned a starting address of 0x100 +and a size of exactly 0x200 bytes, even if there is not enough data in +the @samp{.text} input sections to fill this area. (If there is too +much data, an error will be produced because this would be an attempt to +move @code{.} backwards). The @samp{.data} section will start at 0x500 +and it will have an extra 0x600 bytes worth of space after the end of +the values from the @samp{.data} input sections and before the end of +the @samp{.data} output section itself. + +@need 2000 +@node Operators +@subsection Operators +@cindex operators for arithmetic +@cindex arithmetic operators +@cindex precedence in expressions +The linker recognizes the standard C set of arithmetic operators, with +the standard bindings and precedence levels: +@c TEXI2ROFF-KILL +@ifnottex +@c END TEXI2ROFF-KILL +@smallexample +precedence associativity Operators Notes +(highest) +1 left ! - ~ (1) +2 left * / % +3 left + - +4 left >> << +5 left == != > < <= >= +6 left & +7 left | +8 left && +9 left || +10 right ? : +11 right &= += -= *= /= (2) +(lowest) +@end smallexample +Notes: +(1) Prefix operators +(2) @xref{Assignments}. +@c TEXI2ROFF-KILL +@end ifnottex +@tex +\vskip \baselineskip +%"lispnarrowing" is the extra indent used generally for smallexample +\hskip\lispnarrowing\vbox{\offinterlineskip +\hrule +\halign +{\vrule#&\strut\hfil\ #\ \hfil&\vrule#&\strut\hfil\ #\ \hfil&\vrule#&\strut\hfil\ {\tt #}\ \hfil&\vrule#\cr +height2pt&\omit&&\omit&&\omit&\cr +&Precedence&& Associativity &&{\rm Operators}&\cr +height2pt&\omit&&\omit&&\omit&\cr +\noalign{\hrule} +height2pt&\omit&&\omit&&\omit&\cr +&highest&&&&&\cr +% '176 is tilde, '~' in tt font +&1&&left&&\qquad- \char'176\ !\qquad\dag&\cr +&2&&left&&* / \%&\cr +&3&&left&&+ -&\cr +&4&&left&&>> <<&\cr +&5&&left&&== != > < <= >=&\cr +&6&&left&&\&&\cr +&7&&left&&|&\cr +&8&&left&&{\&\&}&\cr +&9&&left&&||&\cr +&10&&right&&? :&\cr +&11&&right&&\qquad\&= += -= *= /=\qquad\ddag&\cr +&lowest&&&&&\cr +height2pt&\omit&&\omit&&\omit&\cr} +\hrule} +@end tex +@iftex +{ +@obeylines@parskip=0pt@parindent=0pt +@dag@quad Prefix operators. +@ddag@quad @xref{Assignments}. +} +@end iftex +@c END TEXI2ROFF-KILL + +@node Evaluation +@subsection Evaluation +@cindex lazy evaluation +@cindex expression evaluation order +The linker evaluates expressions lazily. It only computes the value of +an expression when absolutely necessary. + +The linker needs some information, such as the value of the start +address of the first section, and the origins and lengths of memory +regions, in order to do any linking at all. These values are computed +as soon as possible when the linker reads in the linker script. + +However, other values (such as symbol values) are not known or needed +until after storage allocation. Such values are evaluated later, when +other information (such as the sizes of output sections) is available +for use in the symbol assignment expression. + +The sizes of sections cannot be known until after allocation, so +assignments dependent upon these are not performed until after +allocation. + +Some expressions, such as those depending upon the location counter +@samp{.}, must be evaluated during section allocation. + +If the result of an expression is required, but the value is not +available, then an error results. For example, a script like the +following +@smallexample +@group +SECTIONS + @{ + .text 9+this_isnt_constant : + @{ *(.text) @} + @} +@end group +@end smallexample +@noindent +will cause the error message @samp{non constant expression for initial +address}. + +@node Expression Section +@subsection The Section of an Expression +@cindex expression sections +@cindex absolute expressions +@cindex relative expressions +@cindex absolute and relocatable symbols +@cindex relocatable and absolute symbols +@cindex symbols, relocatable and absolute +When the linker evaluates an expression, the result is either absolute +or relative to some section. A relative expression is expressed as a +fixed offset from the base of a section. + +The position of the expression within the linker script determines +whether it is absolute or relative. An expression which appears within +an output section definition is relative to the base of the output +section. An expression which appears elsewhere will be absolute. + +A symbol set to a relative expression will be relocatable if you request +relocatable output using the @samp{-r} option. That means that a +further link operation may change the value of the symbol. The symbol's +section will be the section of the relative expression. + +A symbol set to an absolute expression will retain the same value +through any further link operation. The symbol will be absolute, and +will not have any particular associated section. + +You can use the builtin function @code{ABSOLUTE} to force an expression +to be absolute when it would otherwise be relative. For example, to +create an absolute symbol set to the address of the end of the output +section @samp{.data}: +@smallexample +SECTIONS + @{ + .data : @{ *(.data) _edata = ABSOLUTE(.); @} + @} +@end smallexample +@noindent +If @samp{ABSOLUTE} were not used, @samp{_edata} would be relative to the +@samp{.data} section. + +@node Builtin Functions +@subsection Builtin Functions +@cindex functions in expressions +The linker script language includes a number of builtin functions for +use in linker script expressions. + +@table @code +@item ABSOLUTE(@var{exp}) +@kindex ABSOLUTE(@var{exp}) +@cindex expression, absolute +Return the absolute (non-relocatable, as opposed to non-negative) value +of the expression @var{exp}. Primarily useful to assign an absolute +value to a symbol within a section definition, where symbol values are +normally section relative. @xref{Expression Section}. + +@item ADDR(@var{section}) +@kindex ADDR(@var{section}) +@cindex section address in expression +Return the absolute address (the VMA) of the named @var{section}. Your +script must previously have defined the location of that section. In +the following example, @code{symbol_1} and @code{symbol_2} are assigned +identical values: +@smallexample +@group +SECTIONS @{ @dots{} + .output1 : + @{ + start_of_output_1 = ABSOLUTE(.); + @dots{} + @} + .output : + @{ + symbol_1 = ADDR(.output1); + symbol_2 = start_of_output_1; + @} +@dots{} @} +@end group +@end smallexample + +@item ALIGN(@var{exp}) +@kindex ALIGN(@var{exp}) +@cindex round up location counter +@cindex align location counter +Return the location counter (@code{.}) aligned to the next @var{exp} +boundary. +@code{ALIGN} doesn't change the value of the location counter---it just +does arithmetic on it. Here is an example which aligns the output +@code{.data} section to the next @code{0x2000} byte boundary after the +preceding section and sets a variable within the section to the next +@code{0x8000} boundary after the input sections: +@smallexample +@group +SECTIONS @{ @dots{} + .data ALIGN(0x2000): @{ + *(.data) + variable = ALIGN(0x8000); + @} +@dots{} @} +@end group +@end smallexample +@noindent +The first use of @code{ALIGN} in this example specifies the location of +a section because it is used as the optional @var{address} attribute of +a section definition (@pxref{Output Section Address}). The second use +of @code{ALIGN} is used to defines the value of a symbol. + +The builtin function @code{NEXT} is closely related to @code{ALIGN}. + +@item BLOCK(@var{exp}) +@kindex BLOCK(@var{exp}) +This is a synonym for @code{ALIGN}, for compatibility with older linker +scripts. It is most often seen when setting the address of an output +section. + +@item DATA_SEGMENT_ALIGN(@var{maxpagesize}, @var{commonpagesize}) +@kindex DATA_SEGMENT_ALIGN(@var{maxpagesize}, @var{commonpagesize}) +This is equivalent to either +@smallexample +(ALIGN(@var{maxpagesize}) + (. & (@var{maxpagesize} - 1))) +@end smallexample +or +@smallexample +(ALIGN(@var{maxpagesize}) + (. & (@var{maxpagesize} - @var{commonpagesize}))) +@end smallexample +@noindent +depending on whether the latter uses fewer @var{commonpagesize} sized pages +for the data segment (area between the result of this expression and +@code{DATA_SEGMENT_END}) than the former or not. +If the latter form is used, it means @var{commonpagesize} bytes of runtime +memory will be saved at the expense of up to @var{commonpagesize} wasted +bytes in the on-disk file. + +This expression can only be used directly in @code{SECTIONS} commands, not in +any output section descriptions and only once in the linker script. +@var{commonpagesize} should be less or equal to @var{maxpagesize} and should +be the system page size the object wants to be optimized for (while still +working on system page sizes up to @var{maxpagesize}). + +@noindent +Example: +@smallexample + . = DATA_SEGMENT_ALIGN(0x10000, 0x2000); +@end smallexample + +@item DATA_SEGMENT_END(@var{exp}) +@kindex DATA_SEGMENT_END(@var{exp}) +This defines the end of data segment for @code{DATA_SEGMENT_ALIGN} +evaluation purposes. + +@smallexample + . = DATA_SEGMENT_END(.); +@end smallexample + +@item DEFINED(@var{symbol}) +@kindex DEFINED(@var{symbol}) +@cindex symbol defaults +Return 1 if @var{symbol} is in the linker global symbol table and is +defined, otherwise return 0. You can use this function to provide +default values for symbols. For example, the following script fragment +shows how to set a global symbol @samp{begin} to the first location in +the @samp{.text} section---but if a symbol called @samp{begin} already +existed, its value is preserved: + +@smallexample +@group +SECTIONS @{ @dots{} + .text : @{ + begin = DEFINED(begin) ? begin : . ; + @dots{} + @} + @dots{} +@} +@end group +@end smallexample + +@item LOADADDR(@var{section}) +@kindex LOADADDR(@var{section}) +@cindex section load address in expression +Return the absolute LMA of the named @var{section}. This is normally +the same as @code{ADDR}, but it may be different if the @code{AT} +attribute is used in the output section definition (@pxref{Output +Section LMA}). + +@kindex MAX +@item MAX(@var{exp1}, @var{exp2}) +Returns the maximum of @var{exp1} and @var{exp2}. + +@kindex MIN +@item MIN(@var{exp1}, @var{exp2}) +Returns the minimum of @var{exp1} and @var{exp2}. + +@item NEXT(@var{exp}) +@kindex NEXT(@var{exp}) +@cindex unallocated address, next +Return the next unallocated address that is a multiple of @var{exp}. +This function is closely related to @code{ALIGN(@var{exp})}; unless you +use the @code{MEMORY} command to define discontinuous memory for the +output file, the two functions are equivalent. + +@item SIZEOF(@var{section}) +@kindex SIZEOF(@var{section}) +@cindex section size +Return the size in bytes of the named @var{section}, if that section has +been allocated. If the section has not been allocated when this is +evaluated, the linker will report an error. In the following example, +@code{symbol_1} and @code{symbol_2} are assigned identical values: +@smallexample +@group +SECTIONS@{ @dots{} + .output @{ + .start = . ; + @dots{} + .end = . ; + @} + symbol_1 = .end - .start ; + symbol_2 = SIZEOF(.output); +@dots{} @} +@end group +@end smallexample + +@item SIZEOF_HEADERS +@itemx sizeof_headers +@kindex SIZEOF_HEADERS +@cindex header size +Return the size in bytes of the output file's headers. This is +information which appears at the start of the output file. You can use +this number when setting the start address of the first section, if you +choose, to facilitate paging. + +@cindex not enough room for program headers +@cindex program headers, not enough room +When producing an ELF output file, if the linker script uses the +@code{SIZEOF_HEADERS} builtin function, the linker must compute the +number of program headers before it has determined all the section +addresses and sizes. If the linker later discovers that it needs +additional program headers, it will report an error @samp{not enough +room for program headers}. To avoid this error, you must avoid using +the @code{SIZEOF_HEADERS} function, or you must rework your linker +script to avoid forcing the linker to use additional program headers, or +you must define the program headers yourself using the @code{PHDRS} +command (@pxref{PHDRS}). +@end table + +@node Implicit Linker Scripts +@section Implicit Linker Scripts +@cindex implicit linker scripts +If you specify a linker input file which the linker can not recognize as +an object file or an archive file, it will try to read the file as a +linker script. If the file can not be parsed as a linker script, the +linker will report an error. + +An implicit linker script will not replace the default linker script. + +Typically an implicit linker script would contain only symbol +assignments, or the @code{INPUT}, @code{GROUP}, or @code{VERSION} +commands. + +Any input files read because of an implicit linker script will be read +at the position in the command line where the implicit linker script was +read. This can affect archive searching. + +@ifset GENERIC +@node Machine Dependent +@chapter Machine Dependent Features + +@cindex machine dependencies +@command{ld} has additional features on some platforms; the following +sections describe them. Machines where @command{ld} has no additional +functionality are not listed. + +@menu +@ifset H8300 +* H8/300:: @command{ld} and the H8/300 +@end ifset +@ifset I960 +* i960:: @command{ld} and the Intel 960 family +@end ifset +@ifset ARM +* ARM:: @command{ld} and the ARM family +@end ifset +@ifset HPPA +* HPPA ELF32:: @command{ld} and HPPA 32-bit ELF +@end ifset +@ifset MMIX +* MMIX:: @command{ld} and MMIX +@end ifset +@ifset MSP430 +* MSP430:: @command{ld} and MSP430 +@end ifset +@ifset TICOFF +* TI COFF:: @command{ld} and TI COFF +@end ifset +@ifset WIN32 +* WIN32:: @command{ld} and WIN32 (cygwin/mingw) +@end ifset +@ifset XTENSA +* Xtensa:: @command{ld} and Xtensa Processors +@end ifset +@end menu +@end ifset + +@ifset H8300 +@ifclear GENERIC +@raisesections +@end ifclear + +@node H8/300 +@section @command{ld} and the H8/300 + +@cindex H8/300 support +For the H8/300, @command{ld} can perform these global optimizations when +you specify the @samp{--relax} command-line option. + +@table @emph +@cindex relaxing on H8/300 +@item relaxing address modes +@command{ld} finds all @code{jsr} and @code{jmp} instructions whose +targets are within eight bits, and turns them into eight-bit +program-counter relative @code{bsr} and @code{bra} instructions, +respectively. + +@cindex synthesizing on H8/300 +@item synthesizing instructions +@c FIXME: specifically mov.b, or any mov instructions really? +@command{ld} finds all @code{mov.b} instructions which use the +sixteen-bit absolute address form, but refer to the top +page of memory, and changes them to use the eight-bit address form. +(That is: the linker turns @samp{mov.b @code{@@}@var{aa}:16} into +@samp{mov.b @code{@@}@var{aa}:8} whenever the address @var{aa} is in the +top page of memory). +@end table + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifclear GENERIC +@ifset Renesas +@c This stuff is pointless to say unless you're especially concerned +@c with Renesas chips; don't enable it for generic case, please. +@node Renesas +@chapter @command{ld} and Other Renesas Chips + +@command{ld} also supports the Renesas (formerly Hitachi) H8/300H, +H8/500, and SH chips. No special features, commands, or command-line +options are required for these chips. +@end ifset +@end ifclear + +@ifset I960 +@ifclear GENERIC +@raisesections +@end ifclear + +@node i960 +@section @command{ld} and the Intel 960 Family + +@cindex i960 support + +You can use the @samp{-A@var{architecture}} command line option to +specify one of the two-letter names identifying members of the 960 +family; the option specifies the desired output target, and warns of any +incompatible instructions in the input files. It also modifies the +linker's search strategy for archive libraries, to support the use of +libraries specific to each particular architecture, by including in the +search loop names suffixed with the string identifying the architecture. + +For example, if your @command{ld} command line included @w{@samp{-ACA}} as +well as @w{@samp{-ltry}}, the linker would look (in its built-in search +paths, and in any paths you specify with @samp{-L}) for a library with +the names + +@smallexample +@group +try +libtry.a +tryca +libtryca.a +@end group +@end smallexample + +@noindent +The first two possibilities would be considered in any event; the last +two are due to the use of @w{@samp{-ACA}}. + +You can meaningfully use @samp{-A} more than once on a command line, since +the 960 architecture family allows combination of target architectures; each +use will add another pair of name variants to search for when @w{@samp{-l}} +specifies a library. + +@cindex @option{--relax} on i960 +@cindex relaxing on i960 +@command{ld} supports the @samp{--relax} option for the i960 family. If +you specify @samp{--relax}, @command{ld} finds all @code{balx} and +@code{calx} instructions whose targets are within 24 bits, and turns +them into 24-bit program-counter relative @code{bal} and @code{cal} +instructions, respectively. @command{ld} also turns @code{cal} +instructions into @code{bal} instructions when it determines that the +target subroutine is a leaf routine (that is, the target subroutine does +not itself call any subroutines). + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifset ARM +@ifclear GENERIC +@raisesections +@end ifclear + +@node ARM +@section @command{ld}'s Support for Interworking Between ARM and Thumb Code + +@cindex ARM interworking support +@kindex --support-old-code +For the ARM, @command{ld} will generate code stubs to allow functions calls +betweem ARM and Thumb code. These stubs only work with code that has +been compiled and assembled with the @samp{-mthumb-interwork} command +line option. If it is necessary to link with old ARM object files or +libraries, which have not been compiled with the -mthumb-interwork +option then the @samp{--support-old-code} command line switch should be +given to the linker. This will make it generate larger stub functions +which will work with non-interworking aware ARM code. Note, however, +the linker does not support generating stubs for function calls to +non-interworking aware Thumb code. + +@cindex thumb entry point +@cindex entry point, thumb +@kindex --thumb-entry=@var{entry} +The @samp{--thumb-entry} switch is a duplicate of the generic +@samp{--entry} switch, in that it sets the program's starting address. +But it also sets the bottom bit of the address, so that it can be +branched to using a BX instruction, and the program will start +executing in Thumb mode straight away. + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifset HPPA +@ifclear GENERIC +@raisesections +@end ifclear + +@node HPPA ELF32 +@section @command{ld} and HPPA 32-bit ELF Support +@cindex HPPA multiple sub-space stubs +@kindex --multi-subspace +When generating a shared library, @command{ld} will by default generate +import stubs suitable for use with a single sub-space application. +The @samp{--multi-subspace} switch causes @command{ld} to generate export +stubs, and different (larger) import stubs suitable for use with +multiple sub-spaces. + +@cindex HPPA stub grouping +@kindex --stub-group-size=@var{N} +Long branch stubs and import/export stubs are placed by @command{ld} in +stub sections located between groups of input sections. +@samp{--stub-group-size} specifies the maximum size of a group of input +sections handled by one stub section. Since branch offsets are signed, +a stub section may serve two groups of input sections, one group before +the stub section, and one group after it. However, when using +conditional branches that require stubs, it may be better (for branch +prediction) that stub sections only serve one group of input sections. +A negative value for @samp{N} chooses this scheme, ensuring that +branches to stubs always use a negative offset. Two special values of +@samp{N} are recognized, @samp{1} and @samp{-1}. These both instruct +@command{ld} to automatically size input section groups for the branch types +detected, with the same behaviour regarding stub placement as other +positive or negative values of @samp{N} respectively. + +Note that @samp{--stub-group-size} does not split input sections. A +single input section larger than the group size specified will of course +create a larger group (of one section). If input sections are too +large, it may not be possible for a branch to reach its stub. + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifset MMIX +@ifclear GENERIC +@raisesections +@end ifclear + +@node MMIX +@section @code{ld} and MMIX +For MMIX, there is a choice of generating @code{ELF} object files or +@code{mmo} object files when linking. The simulator @code{mmix} +understands the @code{mmo} format. The binutils @code{objcopy} utility +can translate between the two formats. + +There is one special section, the @samp{.MMIX.reg_contents} section. +Contents in this section is assumed to correspond to that of global +registers, and symbols referring to it are translated to special symbols, +equal to registers. In a final link, the start address of the +@samp{.MMIX.reg_contents} section corresponds to the first allocated +global register multiplied by 8. Register @code{$255} is not included in +this section; it is always set to the program entry, which is at the +symbol @code{Main} for @code{mmo} files. + +Symbols with the prefix @code{__.MMIX.start.}, for example +@code{__.MMIX.start..text} and @code{__.MMIX.start..data} are special; +there must be only one each, even if they are local. The default linker +script uses these to set the default start address of a section. + +Initial and trailing multiples of zero-valued 32-bit words in a section, +are left out from an mmo file. + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifset MSP430 +@ifclear GENERIC +@raisesections +@end ifclear + +@node MSP430 +@section @code{ld} and MSP430 +For the MSP430 it is possible to select the MPU architecture. The flag @samp{-m [mpu type]} +will select an appropriate linker script for selected MPU type. (To get a list of known MPUs +just pass @samp{-m help} option to the linker). + +@cindex MSP430 extra sections +The linker will recognize some extra sections which are MSP430 specific: + +@table @code +@item @samp{.vectors} +Defines a portion of ROM where interrupt vectors located. + +@item @samp{.bootloader} +Defines the bootloader portion of the ROM (if applicable). Any code +in this section will be uploaded to the MPU. + +@item @samp{.infomem} +Defines an information memory section (if applicable). Any code in +this section will be uploaded to the MPU. + +@item @samp{.infomemnobits} +This is the same as the @samp{.infomem} section except that any code +in this section will not be uploaded to the MPU. + +@item @samp{.noinit} +Denotes a portion of RAM located above @samp{.bss} section. + +The last two sections are used by gcc. +@end table + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifset TICOFF +@ifclear GENERIC +@raisesections +@end ifclear + +@node TI COFF +@section @command{ld}'s Support for Various TI COFF Versions +@cindex TI COFF versions +@kindex --format=@var{version} +The @samp{--format} switch allows selection of one of the various +TI COFF versions. The latest of this writing is 2; versions 0 and 1 are +also supported. The TI COFF versions also vary in header byte-order +format; @command{ld} will read any version or byte order, but the output +header format depends on the default specified by the specific target. + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifset WIN32 +@ifclear GENERIC +@raisesections +@end ifclear + +@node WIN32 +@section @command{ld} and WIN32 (cygwin/mingw) + +This section describes some of the win32 specific @command{ld} issues. +See @ref{Options,,Command Line Options} for detailed decription of the +command line options mentioned here. + +@table @emph +@cindex import libraries +@item import libraries +The standard Windows linker creates and uses so-called import +libraries, which contains information for linking to dll's. They are +regular static archives and are handled as any other static +archive. The cygwin and mingw ports of @command{ld} have specific +support for creating such libraries provided with the +@samp{--out-implib} command line option. + +@item exporting DLL symbols +@cindex exporting DLL symbols +The cygwin/mingw @command{ld} has several ways to export symbols for dll's. + +@table @emph +@item using auto-export functionality +@cindex using auto-export functionality +By default @command{ld} exports symbols with the auto-export functionality, +which is controlled by the following command line options: + +@itemize +@item --export-all-symbols [This is the default] +@item --exclude-symbols +@item --exclude-libs +@end itemize + +If, however, @samp{--export-all-symbols} is not given explicitly on the +command line, then the default auto-export behavior will be @emph{disabled} +if either of the following are true: + +@itemize +@item A DEF file is used. +@item Any symbol in any object file was marked with the __declspec(dllexport) attribute. +@end itemize + +@item using a DEF file +@cindex using a DEF file +Another way of exporting symbols is using a DEF file. A DEF file is +an ASCII file containing definitions of symbols which should be +exported when a dll is created. Usually it is named @samp{.def} and is added as any other object file to the linker's +command line. The file's name must end in @samp{.def} or @samp{.DEF}. + +@example +gcc -o .def +@end example + +Using a DEF file turns off the normal auto-export behavior, unless the +@samp{--export-all-symbols} option is also used. + +Here is an example of a DEF file for a shared library called @samp{xyz.dll}: + +@example +LIBRARY "xyz.dll" BASE=0x10000000 + +EXPORTS +foo +bar +_bar = bar +@end example + +This example defines a base address and three symbols. The third +symbol is an alias for the second. For the complete format +specification see ld/deffilep.y in the binutils sources. + +@cindex creating a DEF file +While linking a shared dll, @command{ld} is able to create a DEF file +with the @samp{--output-def } command line option. + +@item Using decorations +@cindex Using decorations +Another way of marking symbols for export is to modify the source code +itself, so that when building the DLL each symbol to be exported is +declared as: + +@example +__declspec(dllexport) int a_variable +__declspec(dllexport) void a_function(int with_args) +@end example + +All such symbols will be exported from the DLL. If, however, +any of the object files in the DLL contain symbols decorated in +this way, then the normal auto-export behavior is disabled, unless +the @samp{--export-all-symbols} option is also used. + +Note that object files that wish to access these symbols must @emph{not} +decorate them with dllexport. Instead, they should use dllimport, +instead: + +@example +__declspec(dllimport) int a_variable +__declspec(dllimport) void a_function(int with_args) +@end example + +This complicates the structure of library header files, because +when included by the library itself the header must declare the +variables and functions as dllexport, but when included by client +code the header must declare them as dllimport. There are a number +of idioms that are typically used to do this; often client code can +omit the __declspec() declaration completely. See +@samp{--enable-auto-import} and @samp{automatic data imports} for more +imformation. +@end table + +@cindex automatic data imports +@item automatic data imports +The standard Windows dll format supports data imports from dlls only +by adding special decorations (dllimport/dllexport), which let the +compiler produce specific assembler instructions to deal with this +issue. This increases the effort necessary to port existing Un*x +code to these platforms, especially for large +c++ libraries and applications. The auto-import feature, which was +initially provided by Paul Sokolovsky, allows one to omit the +decorations to archieve a behavior that conforms to that on POSIX/Un*x +platforms. This feature is enabled with the @samp{--enable-auto-import} +command-line option, although it is enabled by default on cygwin/mingw. +The @samp{--enable-auto-import} option itself now serves mainly to +suppress any warnings that are ordinarily emitted when linked objects +trigger the feature's use. + +auto-import of variables does not always work flawlessly without +additional assistance. Sometimes, you will see this message + +"variable '' can't be auto-imported. Please read the +documentation for ld's @code{--enable-auto-import} for details." + +The @samp{--enable-auto-import} documentation explains why this error +occurs, and several methods that can be used to overcome this difficulty. +One of these methods is the @emph{runtime pseudo-relocs} feature, described +below. + +@cindex runtime pseudo-relocation +For complex variables imported from DLLs (such as structs or classes), +object files typically contain a base address for the variable and an +offset (@emph{addend}) within the variable--to specify a particular +field or public member, for instance. Unfortunately, the runtime loader used +in win32 environments is incapable of fixing these references at runtime +without the additional information supplied by dllimport/dllexport decorations. +The standard auto-import feature described above is unable to resolve these +references. + +The @samp{--enable-runtime-pseudo-relocs} switch allows these references to +be resolved without error, while leaving the task of adjusting the references +themselves (with their non-zero addends) to specialized code provided by the +runtime environment. Recent versions of the cygwin and mingw environments and +compilers provide this runtime support; older versions do not. However, the +support is only necessary on the developer's platform; the compiled result will +run without error on an older system. + +@samp{--enable-runtime-pseudo-relocs} is not the default; it must be explicitly +enabled as needed. + +@cindex direct linking to a dll +@item direct linking to a dll +The cygwin/mingw ports of @command{ld} support the direct linking, +including data symbols, to a dll without the usage of any import +libraries. This is much faster and uses much less memory than does the +traditional import library method, expecially when linking large +libraries or applications. When @command{ld} creates an import lib, each +function or variable exported from the dll is stored in its own bfd, even +though a single bfd could contain many exports. The overhead involved in +storing, loading, and processing so many bfd's is quite large, and explains the +tremendous time, memory, and storage needed to link against particularly +large or complex libraries when using import libs. + +Linking directly to a dll uses no extra command-line switches other than +@samp{-L} and @samp{-l}, because @command{ld} already searches for a number +of names to match each library. All that is needed from the developer's +perspective is an understanding of this search, in order to force ld to +select the dll instead of an import library. + + +For instance, when ld is called with the argument @samp{-lxxx} it will attempt +to find, in the first directory of its search path, + +@example +libxxx.dll.a +xxx.dll.a +libxxx.a +cygxxx.dll (*) +libxxx.dll +xxx.dll +@end example + +before moving on to the next directory in the search path. + +(*) Actually, this is not @samp{cygxxx.dll} but in fact is @samp{xxx.dll}, +where @samp{} is set by the @command{ld} option +@samp{--dll-search-prefix=}. In the case of cygwin, the standard gcc spec +file includes @samp{--dll-search-prefix=cyg}, so in effect we actually search for +@samp{cygxxx.dll}. + +Other win32-based unix environments, such as mingw or pw32, may use other +@samp{}es, although at present only cygwin makes use of this feature. It +was originally intended to help avoid name conflicts among dll's built for the +various win32/un*x environments, so that (for example) two versions of a zlib dll +could coexist on the same machine. + +The generic cygwin/mingw path layout uses a @samp{bin} directory for +applications and dll's and a @samp{lib} directory for the import +libraries (using cygwin nomenclature): + +@example +bin/ + cygxxx.dll +lib/ + libxxx.dll.a (in case of dll's) + libxxx.a (in case of static archive) +@end example + +Linking directly to a dll without using the import library can be +done two ways: + +1. Use the dll directly by adding the @samp{bin} path to the link line +@example +gcc -Wl,-verbose -o a.exe -L../bin/ -lxxx +@end example + +However, as the dll's often have version numbers appended to their names +(@samp{cygncurses-5.dll}) this will often fail, unless one specifies +@samp{-L../bin -lncurses-5} to include the version. Import libs are generally +not versioned, and do not have this difficulty. + +2. Create a symbolic link from the dll to a file in the @samp{lib} +directory according to the above mentioned search pattern. This +should be used to avoid unwanted changes in the tools needed for +making the app/dll. + +@example +ln -s bin/cygxxx.dll lib/[cyg|lib|]xxx.dll[.a] +@end example + +Then you can link without any make environment changes. + +@example +gcc -Wl,-verbose -o a.exe -L../lib/ -lxxx +@end example + +This technique also avoids the version number problems, because the following is +perfectly legal + +@example +bin/ + cygxxx-5.dll +lib/ + libxxx.dll.a -> ../bin/cygxxx-5.dll +@end example + +Linking directly to a dll without using an import lib will work +even when auto-import features are exercised, and even when +@samp{--enable-runtime-pseudo-relocs} is used. + +Given the improvements in speed and memory usage, one might justifiably +wonder why import libraries are used at all. There are two reasons: + +1. Until recently, the link-directly-to-dll functionality did @emph{not} +work with auto-imported data. + +2. Sometimes it is necessary to include pure static objects within the +import library (which otherwise contains only bfd's for indirection +symbols that point to the exports of a dll). Again, the import lib +for the cygwin kernel makes use of this ability, and it is not +possible to do this without an import lib. + +So, import libs are not going away. But the ability to replace +true import libs with a simple symbolic link to (or a copy of) +a dll, in most cases, is a useful addition to the suite of tools +binutils makes available to the win32 developer. Given the +massive improvements in memory requirements during linking, storage +requirements, and linking speed, we expect that many developers +will soon begin to use this feature whenever possible. + +@item symbol aliasing +@table @emph +@item adding additional names +Sometimes, it is useful to export symbols with additional names. +A symbol @samp{foo} will be exported as @samp{foo}, but it can also be +exported as @samp{_foo} by using special directives in the DEF file +when creating the dll. This will affect also the optional created +import library. Consider the following DEF file: + +@example +LIBRARY "xyz.dll" BASE=0x61000000 + +EXPORTS +foo +_foo = foo +@end example + +The line @samp{_foo = foo} maps the symbol @samp{foo} to @samp{_foo}. + +Another method for creating a symbol alias is to create it in the +source code using the "weak" attribute: + +@example +void foo () @{ /* Do something. */; @} +void _foo () __attribute__ ((weak, alias ("foo"))); +@end example + +See the gcc manual for more information about attributes and weak +symbols. + +@item renaming symbols +Sometimes it is useful to rename exports. For instance, the cygwin +kernel does this regularly. A symbol @samp{_foo} can be exported as +@samp{foo} but not as @samp{_foo} by using special directives in the +DEF file. (This will also affect the import library, if it is +created). In the following example: + +@example +LIBRARY "xyz.dll" BASE=0x61000000 + +EXPORTS +_foo = foo +@end example + +The line @samp{_foo = foo} maps the exported symbol @samp{foo} to +@samp{_foo}. +@end table + +Note: using a DEF file disables the default auto-export behavior, +unless the @samp{--export-all-symbols} command line option is used. +If, however, you are trying to rename symbols, then you should list +@emph{all} desired exports in the DEF file, including the symbols +that are not being renamed, and do @emph{not} use the +@samp{--export-all-symbols} option. If you list only the +renamed symbols in the DEF file, and use @samp{--export-all-symbols} +to handle the other symbols, then the both the new names @emph{and} +the original names for the the renamed symbols will be exported. +In effect, you'd be aliasing those symbols, not renaming them, +which is probably not what you wanted. +@end table + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifset XTENSA +@ifclear GENERIC +@raisesections +@end ifclear + +@node Xtensa +@section @code{ld} and Xtensa Processors + +@cindex Xtensa processors +The default @command{ld} behavior for Xtensa processors is to interpret +@code{SECTIONS} commands so that lists of explicitly named sections in a +specification with a wildcard file will be interleaved when necessary to +keep literal pools within the range of PC-relative load offsets. For +example, with the command: + +@smallexample +SECTIONS +@{ + .text : @{ + *(.literal .text) + @} +@} +@end smallexample + +@noindent +@command{ld} may interleave some of the @code{.literal} +and @code{.text} sections from different object files to ensure that the +literal pools are within the range of PC-relative load offsets. A valid +interleaving might place the @code{.literal} sections from an initial +group of files followed by the @code{.text} sections of that group of +files. Then, the @code{.literal} sections from the rest of the files +and the @code{.text} sections from the rest of the files would follow. +The non-interleaved order can still be specified as: + +@smallexample +SECTIONS +@{ + .text : @{ + *(.literal) *(.text) + @} +@} +@end smallexample + +@cindex @code{--relax} on Xtensa +@cindex relaxing on Xtensa +@kindex --no-relax +The Xtensa version of @command{ld} enables the @option{--relax} option by +default to attempt to reduce space in the output image by combining +literals with identical values. It also provides the +@option{--no-relax} option to disable this optimization. When enabled, +the relaxation algorithm ensures that a literal will only be merged with +another literal when the new merged literal location is within the +offset range of all of its uses. + +The relaxation mechanism will also attempt to optimize +assembler-generated ``longcall'' sequences of +@code{L32R}/@code{CALLX@var{n}} when the target is known to fit into a +@code{CALL@var{n}} instruction encoding. The current optimization +converts the sequence into @code{NOP}/@code{CALL@var{n}} and removes the +literal referenced by the @code{L32R} instruction. + +@ifclear GENERIC +@lowersections +@end ifclear +@end ifset + +@ifclear SingleFormat +@node BFD +@chapter BFD + +@cindex back end +@cindex object file management +@cindex object formats available +@kindex objdump -i +The linker accesses object and archive files using the BFD libraries. +These libraries allow the linker to use the same routines to operate on +object files whatever the object file format. A different object file +format can be supported simply by creating a new BFD back end and adding +it to the library. To conserve runtime memory, however, the linker and +associated tools are usually configured to support only a subset of the +object file formats available. You can use @code{objdump -i} +(@pxref{objdump,,objdump,binutils.info,The GNU Binary Utilities}) to +list all the formats available for your configuration. + +@cindex BFD requirements +@cindex requirements for BFD +As with most implementations, BFD is a compromise between +several conflicting requirements. The major factor influencing +BFD design was efficiency: any time used converting between +formats is time which would not have been spent had BFD not +been involved. This is partly offset by abstraction payback; since +BFD simplifies applications and back ends, more time and care +may be spent optimizing algorithms for a greater speed. + +One minor artifact of the BFD solution which you should bear in +mind is the potential for information loss. There are two places where +useful information can be lost using the BFD mechanism: during +conversion and during output. @xref{BFD information loss}. + +@menu +* BFD outline:: How it works: an outline of BFD +@end menu + +@node BFD outline +@section How It Works: An Outline of BFD +@cindex opening object files +@include bfdsumm.texi +@end ifclear + +@node Reporting Bugs +@chapter Reporting Bugs +@cindex bugs in @command{ld} +@cindex reporting bugs in @command{ld} + +Your bug reports play an essential role in making @command{ld} reliable. + +Reporting a bug may help you by bringing a solution to your problem, or +it may not. But in any case the principal function of a bug report is +to help the entire community by making the next version of @command{ld} +work better. Bug reports are your contribution to the maintenance of +@command{ld}. + +In order for a bug report to serve its purpose, you must include the +information that enables us to fix the bug. + +@menu +* Bug Criteria:: Have you found a bug? +* Bug Reporting:: How to report bugs +@end menu + +@node Bug Criteria +@section Have You Found a Bug? +@cindex bug criteria + +If you are not sure whether you have found a bug, here are some guidelines: + +@itemize @bullet +@cindex fatal signal +@cindex linker crash +@cindex crash of linker +@item +If the linker gets a fatal signal, for any input whatever, that is a +@command{ld} bug. Reliable linkers never crash. + +@cindex error on valid input +@item +If @command{ld} produces an error message for valid input, that is a bug. + +@cindex invalid input +@item +If @command{ld} does not produce an error message for invalid input, that +may be a bug. In the general case, the linker can not verify that +object files are correct. + +@item +If you are an experienced user of linkers, your suggestions for +improvement of @command{ld} are welcome in any case. +@end itemize + +@node Bug Reporting +@section How to Report Bugs +@cindex bug reports +@cindex @command{ld} bugs, reporting + +A number of companies and individuals offer support for @sc{gnu} +products. If you obtained @command{ld} from a support organization, we +recommend you contact that organization first. + +You can find contact information for many support companies and +individuals in the file @file{etc/SERVICE} in the @sc{gnu} Emacs +distribution. + +Otherwise, send bug reports for @command{ld} to +@samp{bug-binutils@@gnu.org}. + +The fundamental principle of reporting bugs usefully is this: +@strong{report all the facts}. If you are not sure whether to state a +fact or leave it out, state it! + +Often people omit facts because they think they know what causes the +problem and assume that some details do not matter. Thus, you might +assume that the name of a symbol you use in an example does not +matter. Well, probably it does not, but one cannot be sure. Perhaps +the bug is a stray memory reference which happens to fetch from the +location where that name is stored in memory; perhaps, if the name +were different, the contents of that location would fool the linker +into doing the right thing despite the bug. Play it safe and give a +specific, complete example. That is the easiest thing for you to do, +and the most helpful. + +Keep in mind that the purpose of a bug report is to enable us to fix +the bug if it is new to us. Therefore, always write your bug reports +on the assumption that the bug has not been reported previously. + +Sometimes people give a few sketchy facts and ask, ``Does this ring a +bell?'' This cannot help us fix a bug, so it is basically useless. We +respond by asking for enough details to enable us to investigate. +You might as well expedite matters by sending them to begin with. + +To enable us to fix the bug, you should include all these things: + +@itemize @bullet +@item +The version of @command{ld}. @command{ld} announces it if you start it with +the @samp{--version} argument. + +Without this, we will not know whether there is any point in looking for +the bug in the current version of @command{ld}. + +@item +Any patches you may have applied to the @command{ld} source, including any +patches made to the @code{BFD} library. + +@item +The type of machine you are using, and the operating system name and +version number. + +@item +What compiler (and its version) was used to compile @command{ld}---e.g. +``@code{gcc-2.7}''. + +@item +The command arguments you gave the linker to link your example and +observe the bug. To guarantee you will not omit something important, +list them all. A copy of the Makefile (or the output from make) is +sufficient. + +If we were to try to guess the arguments, we would probably guess wrong +and then we might not encounter the bug. + +@item +A complete input file, or set of input files, that will reproduce the +bug. It is generally most helpful to send the actual object files +provided that they are reasonably small. Say no more than 10K. For +bigger files you can either make them available by FTP or HTTP or else +state that you are willing to send the object file(s) to whomever +requests them. (Note - your email will be going to a mailing list, so +we do not want to clog it up with large attachments). But small +attachments are best. + +If the source files were assembled using @code{gas} or compiled using +@code{gcc}, then it may be OK to send the source files rather than the +object files. In this case, be sure to say exactly what version of +@code{gas} or @code{gcc} was used to produce the object files. Also say +how @code{gas} or @code{gcc} were configured. + +@item +A description of what behavior you observe that you believe is +incorrect. For example, ``It gets a fatal signal.'' + +Of course, if the bug is that @command{ld} gets a fatal signal, then we +will certainly notice it. But if the bug is incorrect output, we might +not notice unless it is glaringly wrong. You might as well not give us +a chance to make a mistake. + +Even if the problem you experience is a fatal signal, you should still +say so explicitly. Suppose something strange is going on, such as, your +copy of @command{ld} is out of synch, or you have encountered a bug in the +C library on your system. (This has happened!) Your copy might crash +and ours would not. If you told us to expect a crash, then when ours +fails to crash, we would know that the bug was not happening for us. If +you had not told us to expect a crash, then we would not be able to draw +any conclusion from our observations. + +@item +If you wish to suggest changes to the @command{ld} source, send us context +diffs, as generated by @code{diff} with the @samp{-u}, @samp{-c}, or +@samp{-p} option. Always send diffs from the old file to the new file. +If you even discuss something in the @command{ld} source, refer to it by +context, not by line number. + +The line numbers in our development sources will not match those in your +sources. Your line numbers would convey no useful information to us. +@end itemize + +Here are some things that are not necessary: + +@itemize @bullet +@item +A description of the envelope of the bug. + +Often people who encounter a bug spend a lot of time investigating +which changes to the input file will make the bug go away and which +changes will not affect it. + +This is often time consuming and not very useful, because the way we +will find the bug is by running a single example under the debugger +with breakpoints, not by pure deduction from a series of examples. +We recommend that you save your time for something else. + +Of course, if you can find a simpler example to report @emph{instead} +of the original one, that is a convenience for us. Errors in the +output will be easier to spot, running under the debugger will take +less time, and so on. + +However, simplification is not vital; if you do not want to do this, +report the bug anyway and send us the entire test case you used. + +@item +A patch for the bug. + +A patch for the bug does help us if it is a good one. But do not omit +the necessary information, such as the test case, on the assumption that +a patch is all we need. We might see problems with your patch and decide +to fix the problem another way, or we might not understand it at all. + +Sometimes with a program as complicated as @command{ld} it is very hard to +construct an example that will make the program follow a certain path +through the code. If you do not send us the example, we will not be +able to construct one, so we will not be able to verify that the bug is +fixed. + +And if we cannot understand what bug you are trying to fix, or why your +patch should be an improvement, we will not install it. A test case will +help us to understand. + +@item +A guess about what the bug is or what it depends on. + +Such guesses are usually wrong. Even we cannot guess right about such +things without first using the debugger to find the facts. +@end itemize + +@node MRI +@appendix MRI Compatible Script Files +@cindex MRI compatibility +To aid users making the transition to @sc{gnu} @command{ld} from the MRI +linker, @command{ld} can use MRI compatible linker scripts as an +alternative to the more general-purpose linker scripting language +described in @ref{Scripts}. MRI compatible linker scripts have a much +simpler command set than the scripting language otherwise used with +@command{ld}. @sc{gnu} @command{ld} supports the most commonly used MRI +linker commands; these commands are described here. + +In general, MRI scripts aren't of much use with the @code{a.out} object +file format, since it only has three sections and MRI scripts lack some +features to make use of them. + +You can specify a file containing an MRI-compatible script using the +@samp{-c} command-line option. + +Each command in an MRI-compatible script occupies its own line; each +command line starts with the keyword that identifies the command (though +blank lines are also allowed for punctuation). If a line of an +MRI-compatible script begins with an unrecognized keyword, @command{ld} +issues a warning message, but continues processing the script. + +Lines beginning with @samp{*} are comments. + +You can write these commands using all upper-case letters, or all +lower case; for example, @samp{chip} is the same as @samp{CHIP}. +The following list shows only the upper-case form of each command. + +@table @code +@cindex @code{ABSOLUTE} (MRI) +@item ABSOLUTE @var{secname} +@itemx ABSOLUTE @var{secname}, @var{secname}, @dots{} @var{secname} +Normally, @command{ld} includes in the output file all sections from all +the input files. However, in an MRI-compatible script, you can use the +@code{ABSOLUTE} command to restrict the sections that will be present in +your output program. If the @code{ABSOLUTE} command is used at all in a +script, then only the sections named explicitly in @code{ABSOLUTE} +commands will appear in the linker output. You can still use other +input sections (whatever you select on the command line, or using +@code{LOAD}) to resolve addresses in the output file. + +@cindex @code{ALIAS} (MRI) +@item ALIAS @var{out-secname}, @var{in-secname} +Use this command to place the data from input section @var{in-secname} +in a section called @var{out-secname} in the linker output file. + +@var{in-secname} may be an integer. + +@cindex @code{ALIGN} (MRI) +@item ALIGN @var{secname} = @var{expression} +Align the section called @var{secname} to @var{expression}. The +@var{expression} should be a power of two. + +@cindex @code{BASE} (MRI) +@item BASE @var{expression} +Use the value of @var{expression} as the lowest address (other than +absolute addresses) in the output file. + +@cindex @code{CHIP} (MRI) +@item CHIP @var{expression} +@itemx CHIP @var{expression}, @var{expression} +This command does nothing; it is accepted only for compatibility. + +@cindex @code{END} (MRI) +@item END +This command does nothing whatever; it's only accepted for compatibility. + +@cindex @code{FORMAT} (MRI) +@item FORMAT @var{output-format} +Similar to the @code{OUTPUT_FORMAT} command in the more general linker +language, but restricted to one of these output formats: + +@enumerate +@item +S-records, if @var{output-format} is @samp{S} + +@item +IEEE, if @var{output-format} is @samp{IEEE} + +@item +COFF (the @samp{coff-m68k} variant in BFD), if @var{output-format} is +@samp{COFF} +@end enumerate + +@cindex @code{LIST} (MRI) +@item LIST @var{anything}@dots{} +Print (to the standard output file) a link map, as produced by the +@command{ld} command-line option @samp{-M}. + +The keyword @code{LIST} may be followed by anything on the +same line, with no change in its effect. + +@cindex @code{LOAD} (MRI) +@item LOAD @var{filename} +@itemx LOAD @var{filename}, @var{filename}, @dots{} @var{filename} +Include one or more object file @var{filename} in the link; this has the +same effect as specifying @var{filename} directly on the @command{ld} +command line. + +@cindex @code{NAME} (MRI) +@item NAME @var{output-name} +@var{output-name} is the name for the program produced by @command{ld}; the +MRI-compatible command @code{NAME} is equivalent to the command-line +option @samp{-o} or the general script language command @code{OUTPUT}. + +@cindex @code{ORDER} (MRI) +@item ORDER @var{secname}, @var{secname}, @dots{} @var{secname} +@itemx ORDER @var{secname} @var{secname} @var{secname} +Normally, @command{ld} orders the sections in its output file in the +order in which they first appear in the input files. In an MRI-compatible +script, you can override this ordering with the @code{ORDER} command. The +sections you list with @code{ORDER} will appear first in your output +file, in the order specified. + +@cindex @code{PUBLIC} (MRI) +@item PUBLIC @var{name}=@var{expression} +@itemx PUBLIC @var{name},@var{expression} +@itemx PUBLIC @var{name} @var{expression} +Supply a value (@var{expression}) for external symbol +@var{name} used in the linker input files. + +@cindex @code{SECT} (MRI) +@item SECT @var{secname}, @var{expression} +@itemx SECT @var{secname}=@var{expression} +@itemx SECT @var{secname} @var{expression} +You can use any of these three forms of the @code{SECT} command to +specify the start address (@var{expression}) for section @var{secname}. +If you have more than one @code{SECT} statement for the same +@var{secname}, only the @emph{first} sets the start address. +@end table + +@include fdl.texi + +@node Index +@unnumbered Index + +@printindex cp + +@tex +% I think something like @colophon should be in texinfo. In the +% meantime: +\long\def\colophon{\hbox to0pt{}\vfill +\centerline{The body of this manual is set in} +\centerline{\fontname\tenrm,} +\centerline{with headings in {\bf\fontname\tenbf}} +\centerline{and examples in {\tt\fontname\tentt}.} +\centerline{{\it\fontname\tenit\/} and} +\centerline{{\sl\fontname\tensl\/}} +\centerline{are used for emphasis.}\vfill} +\page\colophon +% Blame: doc@cygnus.com, 28mar91. +@end tex + + +@contents +@bye diff --git a/contrib/binutils-2.14/ld/ldcref.c b/contrib/binutils-2.14/ld/ldcref.c new file mode 100644 index 0000000000..fec77b0641 --- /dev/null +++ b/contrib/binutils-2.14/ld/ldcref.c @@ -0,0 +1,570 @@ +/* ldcref.c -- output a cross reference table + Copyright 1996, 1997, 1998, 2000, 2002 Free Software Foundation, Inc. + Written by Ian Lance Taylor + +This file is part of GLD, the Gnu Linker. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* This file holds routines that manage the cross reference table. + The table is used to generate cross reference reports. It is also + used to implement the NOCROSSREFS command in the linker script. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "libiberty.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" + +/* We keep an instance of this structure for each reference to a + symbol from a given object. */ + +struct cref_ref { + /* The next reference. */ + struct cref_ref *next; + /* The object. */ + bfd *abfd; + /* True if the symbol is defined. */ + unsigned int def : 1; + /* True if the symbol is common. */ + unsigned int common : 1; + /* True if the symbol is undefined. */ + unsigned int undef : 1; +}; + +/* We keep a hash table of symbols. Each entry looks like this. */ + +struct cref_hash_entry { + struct bfd_hash_entry root; + /* The demangled name. */ + char *demangled; + /* References to and definitions of this symbol. */ + struct cref_ref *refs; +}; + +/* This is what the hash table looks like. */ + +struct cref_hash_table { + struct bfd_hash_table root; +}; + +/* Local functions. */ + +static struct bfd_hash_entry *cref_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static bfd_boolean cref_fill_array PARAMS ((struct cref_hash_entry *, PTR)); +static int cref_sort_array PARAMS ((const PTR, const PTR)); +static void output_one_cref PARAMS ((FILE *, struct cref_hash_entry *)); +static bfd_boolean check_nocrossref PARAMS ((struct cref_hash_entry *, PTR)); +static void check_section_sym_xref PARAMS ((lang_input_statement_type *)); +static void check_refs + PARAMS ((const char *, asection *, bfd *, struct lang_nocrossrefs *)); +static void check_reloc_refs PARAMS ((bfd *, asection *, PTR)); + +/* Look up an entry in the cref hash table. */ + +#define cref_hash_lookup(table, string, create, copy) \ + ((struct cref_hash_entry *) \ + bfd_hash_lookup (&(table)->root, (string), (create), (copy))) + +/* Traverse the cref hash table. */ + +#define cref_hash_traverse(table, func, info) \ + (bfd_hash_traverse \ + (&(table)->root, \ + (bfd_boolean (*) PARAMS ((struct bfd_hash_entry *, PTR))) (func), \ + (info))) + +/* The cref hash table. */ + +static struct cref_hash_table cref_table; + +/* Whether the cref hash table has been initialized. */ + +static bfd_boolean cref_initialized; + +/* The number of symbols seen so far. */ + +static size_t cref_symcount; + +/* Create an entry in a cref hash table. */ + +static struct bfd_hash_entry * +cref_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct cref_hash_entry *ret = (struct cref_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == NULL) + ret = ((struct cref_hash_entry *) + bfd_hash_allocate (table, sizeof (struct cref_hash_entry))); + if (ret == NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct cref_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + if (ret != NULL) + { + /* Set local fields. */ + ret->demangled = NULL; + ret->refs = NULL; + + /* Keep a count of the number of entries created in the hash + table. */ + ++cref_symcount; + } + + return (struct bfd_hash_entry *) ret; +} + +/* Add a symbol to the cref hash table. This is called for every + symbol that is seen during the link. */ + +void +add_cref (name, abfd, section, value) + const char *name; + bfd *abfd; + asection *section; + bfd_vma value ATTRIBUTE_UNUSED; +{ + struct cref_hash_entry *h; + struct cref_ref *r; + + if (! cref_initialized) + { + if (! bfd_hash_table_init (&cref_table.root, cref_hash_newfunc)) + einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n")); + cref_initialized = TRUE; + } + + h = cref_hash_lookup (&cref_table, name, TRUE, FALSE); + if (h == NULL) + einfo (_("%X%P: cref_hash_lookup failed: %E\n")); + + for (r = h->refs; r != NULL; r = r->next) + if (r->abfd == abfd) + break; + + if (r == NULL) + { + r = (struct cref_ref *) xmalloc (sizeof *r); + r->next = h->refs; + h->refs = r; + r->abfd = abfd; + r->def = FALSE; + r->common = FALSE; + r->undef = FALSE; + } + + if (bfd_is_und_section (section)) + r->undef = TRUE; + else if (bfd_is_com_section (section)) + r->common = TRUE; + else + r->def = TRUE; +} + +/* Copy the addresses of the hash table entries into an array. This + is called via cref_hash_traverse. We also fill in the demangled + name. */ + +static bfd_boolean +cref_fill_array (h, data) + struct cref_hash_entry *h; + PTR data; +{ + struct cref_hash_entry ***pph = (struct cref_hash_entry ***) data; + + ASSERT (h->demangled == NULL); + h->demangled = demangle (h->root.string); + + **pph = h; + + ++*pph; + + return TRUE; +} + +/* Sort an array of cref hash table entries by name. */ + +static int +cref_sort_array (a1, a2) + const PTR a1; + const PTR a2; +{ + const struct cref_hash_entry **p1 = (const struct cref_hash_entry **) a1; + const struct cref_hash_entry **p2 = (const struct cref_hash_entry **) a2; + + return strcmp ((*p1)->demangled, (*p2)->demangled); +} + +/* Write out the cref table. */ + +#define FILECOL (50) + +void +output_cref (fp) + FILE *fp; +{ + int len; + struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end; + const char *msg; + + fprintf (fp, _("\nCross Reference Table\n\n")); + msg = _("Symbol"); + fprintf (fp, "%s", msg); + len = strlen (msg); + while (len < FILECOL) + { + putc (' ', fp); + ++len; + } + fprintf (fp, _("File\n")); + + if (! cref_initialized) + { + fprintf (fp, _("No symbols\n")); + return; + } + + csyms = ((struct cref_hash_entry **) + xmalloc (cref_symcount * sizeof (*csyms))); + + csym_fill = csyms; + cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill); + ASSERT ((size_t) (csym_fill - csyms) == cref_symcount); + + qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array); + + csym_end = csyms + cref_symcount; + for (csym = csyms; csym < csym_end; csym++) + output_one_cref (fp, *csym); +} + +/* Output one entry in the cross reference table. */ + +static void +output_one_cref (fp, h) + FILE *fp; + struct cref_hash_entry *h; +{ + int len; + struct bfd_link_hash_entry *hl; + struct cref_ref *r; + + hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE, + FALSE, TRUE); + if (hl == NULL) + einfo ("%P: symbol `%T' missing from main hash table\n", + h->root.string); + else + { + /* If this symbol is defined in a dynamic object but never + referenced by a normal object, then don't print it. */ + if (hl->type == bfd_link_hash_defined) + { + if (hl->u.def.section->output_section == NULL) + return; + if (hl->u.def.section->owner != NULL + && (hl->u.def.section->owner->flags & DYNAMIC) != 0) + { + for (r = h->refs; r != NULL; r = r->next) + if ((r->abfd->flags & DYNAMIC) == 0) + break; + if (r == NULL) + return; + } + } + } + + fprintf (fp, "%s ", h->demangled); + len = strlen (h->demangled) + 1; + + for (r = h->refs; r != NULL; r = r->next) + { + if (r->def) + { + while (len < FILECOL) + { + putc (' ', fp); + ++len; + } + lfinfo (fp, "%B\n", r->abfd); + len = 0; + } + } + + for (r = h->refs; r != NULL; r = r->next) + { + if (! r->def) + { + while (len < FILECOL) + { + putc (' ', fp); + ++len; + } + lfinfo (fp, "%B\n", r->abfd); + len = 0; + } + } + + ASSERT (len == 0); +} + +/* Check for prohibited cross references. */ + +void +check_nocrossrefs () +{ + if (! cref_initialized) + return; + + cref_hash_traverse (&cref_table, check_nocrossref, (PTR) NULL); + + lang_for_each_file (check_section_sym_xref); +} + +/* Checks for prohibited cross references to section symbols. */ + +static void +check_section_sym_xref (statement) + lang_input_statement_type *statement; +{ + bfd *abfd; + asection *sec; + + abfd = statement->the_bfd; + if (abfd == NULL) + return; + + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + asection *outsec; + + outsec = sec->output_section; + if (outsec != NULL) + { + const char *outsecname; + struct lang_nocrossrefs *ncrs; + struct lang_nocrossref *ncr; + + outsecname = outsec->name; + for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) + for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) + if (strcmp (ncr->name, outsecname) == 0) + check_refs (NULL, sec, abfd, ncrs); + } + } +} + +/* Check one symbol to see if it is a prohibited cross reference. */ + +static bfd_boolean +check_nocrossref (h, ignore) + struct cref_hash_entry *h; + PTR ignore ATTRIBUTE_UNUSED; +{ + struct bfd_link_hash_entry *hl; + asection *defsec; + const char *defsecname; + struct lang_nocrossrefs *ncrs; + struct lang_nocrossref *ncr; + struct cref_ref *ref; + + hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE, + FALSE, TRUE); + if (hl == NULL) + { + einfo (_("%P: symbol `%T' missing from main hash table\n"), + h->root.string); + return TRUE; + } + + if (hl->type != bfd_link_hash_defined + && hl->type != bfd_link_hash_defweak) + return TRUE; + + defsec = hl->u.def.section->output_section; + if (defsec == NULL) + return TRUE; + defsecname = bfd_get_section_name (defsec->owner, defsec); + + for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) + for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) + if (strcmp (ncr->name, defsecname) == 0) + for (ref = h->refs; ref != NULL; ref = ref->next) + check_refs (hl->root.string, hl->u.def.section, ref->abfd, ncrs); + + return TRUE; +} + +/* The struct is used to pass information from check_refs to + check_reloc_refs through bfd_map_over_sections. */ + +struct check_refs_info { + const char *sym_name; + asection *defsec; + struct lang_nocrossrefs *ncrs; + asymbol **asymbols; +}; + +/* This function is called for each symbol defined in a section which + prohibits cross references. We need to look through all references + to this symbol, and ensure that the references are not from + prohibited sections. */ + +static void +check_refs (name, sec, abfd, ncrs) + const char *name; + asection *sec; + bfd *abfd; + struct lang_nocrossrefs *ncrs; +{ + lang_input_statement_type *li; + asymbol **asymbols; + struct check_refs_info info; + + /* We need to look through the relocations for this BFD, to see + if any of the relocations which refer to this symbol are from + a prohibited section. Note that we need to do this even for + the BFD in which the symbol is defined, since even a single + BFD might contain a prohibited cross reference. */ + + li = (lang_input_statement_type *) abfd->usrdata; + if (li != NULL && li->asymbols != NULL) + asymbols = li->asymbols; + else + { + long symsize; + long symbol_count; + + symsize = bfd_get_symtab_upper_bound (abfd); + if (symsize < 0) + einfo (_("%B%F: could not read symbols; %E\n"), abfd); + asymbols = (asymbol **) xmalloc (symsize); + symbol_count = bfd_canonicalize_symtab (abfd, asymbols); + if (symbol_count < 0) + einfo (_("%B%F: could not read symbols: %E\n"), abfd); + if (li != NULL) + { + li->asymbols = asymbols; + li->symbol_count = symbol_count; + } + } + + info.sym_name = name; + info.defsec = sec; + info.ncrs = ncrs; + info.asymbols = asymbols; + bfd_map_over_sections (abfd, check_reloc_refs, (PTR) &info); + + if (li == NULL) + free (asymbols); +} + +/* This is called via bfd_map_over_sections. INFO->SYM_NAME is a symbol + defined in INFO->DEFSECNAME. If this section maps into any of the + sections listed in INFO->NCRS, other than INFO->DEFSECNAME, then we + look through the relocations. If any of the relocations are to + INFO->SYM_NAME, then we report a prohibited cross reference error. */ + +static void +check_reloc_refs (abfd, sec, iarg) + bfd *abfd; + asection *sec; + PTR iarg; +{ + struct check_refs_info *info = (struct check_refs_info *) iarg; + asection *outsec; + const char *outsecname; + asection *outdefsec; + const char *outdefsecname; + struct lang_nocrossref *ncr; + const char *symname; + long relsize; + arelent **relpp; + long relcount; + arelent **p, **pend; + + outsec = sec->output_section; + outsecname = bfd_get_section_name (outsec->owner, outsec); + + outdefsec = info->defsec->output_section; + outdefsecname = bfd_get_section_name (outdefsec->owner, outdefsec); + + /* The section where the symbol is defined is permitted. */ + if (strcmp (outsecname, outdefsecname) == 0) + return; + + for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next) + if (strcmp (outsecname, ncr->name) == 0) + break; + + if (ncr == NULL) + return; + + /* This section is one for which cross references are prohibited. + Look through the relocations, and see if any of them are to + INFO->SYM_NAME. If INFO->SYMNAME is NULL, check for relocations + against the section symbol. */ + + symname = info->sym_name; + + relsize = bfd_get_reloc_upper_bound (abfd, sec); + if (relsize < 0) + einfo (_("%B%F: could not read relocs: %E\n"), abfd); + if (relsize == 0) + return; + + relpp = (arelent **) xmalloc (relsize); + relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols); + if (relcount < 0) + einfo (_("%B%F: could not read relocs: %E\n"), abfd); + + p = relpp; + pend = p + relcount; + for (; p < pend && *p != NULL; p++) + { + arelent *q = *p; + + if (q->sym_ptr_ptr != NULL + && *q->sym_ptr_ptr != NULL + && (symname != NULL + ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0 + : (((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0 + && bfd_get_section (*q->sym_ptr_ptr) == info->defsec))) + { + /* We found a reloc for the symbol. The symbol is defined + in OUTSECNAME. This reloc is from a section which is + mapped into a section from which references to OUTSECNAME + are prohibited. We must report an error. */ + einfo (_("%X%C: prohibited cross reference from %s to `%T' in %s\n"), + abfd, sec, q->address, outsecname, + bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname); + } + } + + free (relpp); +} diff --git a/contrib/binutils-2.14/ld/ldctor.c b/contrib/binutils-2.14/ld/ldctor.c new file mode 100644 index 0000000000..a5089cfeaa --- /dev/null +++ b/contrib/binutils-2.14/ld/ldctor.c @@ -0,0 +1,383 @@ +/* ldctor.c -- constructor support routines + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002 Free Software Foundation, Inc. + By Steve Chamberlain + +This file is part of GLD, the Gnu Linker. + +GLD is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GLD is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GLD; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "safe-ctype.h" + +#include "ld.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldmisc.h" +#include +#include "ldmain.h" +#include "ldctor.h" + +static int ctor_prio PARAMS ((const char *)); +static int ctor_cmp PARAMS ((const PTR, const PTR)); + +/* The list of statements needed to handle constructors. These are + invoked by the command CONSTRUCTORS in the linker script. */ +lang_statement_list_type constructor_list; + +/* Whether the constructors should be sorted. Note that this is + global for the entire link; we assume that there is only a single + CONSTRUCTORS command in the linker script. */ +bfd_boolean constructors_sorted; + +/* The sets we have seen. */ +struct set_info *sets; + +/* Add an entry to a set. H is the entry in the linker hash table. + RELOC is the relocation to use for an entry in the set. SECTION + and VALUE are the value to add. This is called during the first + phase of the link, when we are still gathering symbols together. + We just record the information now. The ldctor_find_constructors + function will construct the sets. */ + +void +ldctor_add_set_entry (h, reloc, name, section, value) + struct bfd_link_hash_entry *h; + bfd_reloc_code_real_type reloc; + const char *name; + asection *section; + bfd_vma value; +{ + struct set_info *p; + struct set_element *e; + struct set_element **epp; + + for (p = sets; p != (struct set_info *) NULL; p = p->next) + if (p->h == h) + break; + + if (p == (struct set_info *) NULL) + { + p = (struct set_info *) xmalloc (sizeof (struct set_info)); + p->next = sets; + sets = p; + p->h = h; + p->reloc = reloc; + p->count = 0; + p->elements = NULL; + } + else + { + if (p->reloc != reloc) + { + einfo (_("%P%X: Different relocs used in set %s\n"), + h->root.string); + return; + } + + /* Don't permit a set to be constructed from different object + file formats. The same reloc may have different results. We + actually could sometimes handle this, but the case is + unlikely to ever arise. Sometimes constructor symbols are in + unusual sections, such as the absolute section--this appears + to be the case in Linux a.out--and in such cases we just + assume everything is OK. */ + if (p->elements != NULL + && section->owner != NULL + && p->elements->section->owner != NULL + && strcmp (bfd_get_target (section->owner), + bfd_get_target (p->elements->section->owner)) != 0) + { + einfo (_("%P%X: Different object file formats composing set %s\n"), + h->root.string); + return; + } + } + + e = (struct set_element *) xmalloc (sizeof (struct set_element)); + e->next = NULL; + e->name = name; + e->section = section; + e->value = value; + + for (epp = &p->elements; *epp != NULL; epp = &(*epp)->next) + ; + *epp = e; + + ++p->count; +} + +/* Get the priority of a g++ global constructor or destructor from the + symbol name. */ + +static int +ctor_prio (name) + const char *name; +{ + /* The name will look something like _GLOBAL_$I$65535$test02__Fv. + There might be extra leading underscores, and the $ characters + might be something else. The I might be a D. */ + + while (*name == '_') + ++name; + + if (strncmp (name, "GLOBAL_", sizeof "GLOBAL_" - 1) != 0) + return -1; + + name += sizeof "GLOBAL_" - 1; + + if (name[0] != name[2]) + return -1; + if (name[1] != 'I' && name[1] != 'D') + return -1; + if (! ISDIGIT (name[3])) + return -1; + + return atoi (name + 3); +} + +/* This function is used to sort constructor elements by priority. It + is called via qsort. */ + +static int +ctor_cmp (p1, p2) + const PTR p1; + const PTR p2; +{ + const struct set_element **pe1 = (const struct set_element **) p1; + const struct set_element **pe2 = (const struct set_element **) p2; + const char *n1; + const char *n2; + int prio1; + int prio2; + + n1 = (*pe1)->name; + if (n1 == NULL) + n1 = ""; + n2 = (*pe2)->name; + if (n2 == NULL) + n2 = ""; + + /* We need to sort in reverse order by priority. When two + constructors have the same priority, we should maintain their + current relative position. */ + + prio1 = ctor_prio (n1); + prio2 = ctor_prio (n2); + + /* We sort in reverse order because that is what g++ expects. */ + if (prio1 < prio2) + return 1; + else if (prio1 > prio2) + return -1; + + /* Force a stable sort. */ + + if (pe1 < pe2) + return -1; + else if (pe1 > pe2) + return 1; + else + return 0; +} + +/* This function is called after the first phase of the link and + before the second phase. At this point all set information has + been gathered. We now put the statements to build the sets + themselves into constructor_list. */ + +void +ldctor_build_sets () +{ + static bfd_boolean called; + lang_statement_list_type *old; + bfd_boolean header_printed; + struct set_info *p; + + /* The emulation code may call us directly, but we only want to do + this once. */ + if (called) + return; + called = TRUE; + + if (constructors_sorted) + { + for (p = sets; p != NULL; p = p->next) + { + int c, i; + struct set_element *e; + struct set_element **array; + + if (p->elements == NULL) + continue; + + c = 0; + for (e = p->elements; e != NULL; e = e->next) + ++c; + + array = (struct set_element **) xmalloc (c * sizeof *array); + + i = 0; + for (e = p->elements; e != NULL; e = e->next) + { + array[i] = e; + ++i; + } + + qsort (array, c, sizeof *array, ctor_cmp); + + e = array[0]; + p->elements = e; + for (i = 0; i < c - 1; i++) + array[i]->next = array[i + 1]; + array[i]->next = NULL; + + free (array); + } + } + + old = stat_ptr; + stat_ptr = &constructor_list; + + lang_list_init (stat_ptr); + + header_printed = FALSE; + for (p = sets; p != (struct set_info *) NULL; p = p->next) + { + struct set_element *e; + reloc_howto_type *howto; + int reloc_size, size; + + /* If the symbol is defined, we may have been invoked from + collect, and the sets may already have been built, so we do + not do anything. */ + if (p->h->type == bfd_link_hash_defined + || p->h->type == bfd_link_hash_defweak) + continue; + + /* For each set we build: + set: + .long number_of_elements + .long element0 + ... + .long elementN + .long 0 + except that we use the right size instead of .long. When + generating relocateable output, we generate relocs instead of + addresses. */ + howto = bfd_reloc_type_lookup (output_bfd, p->reloc); + if (howto == (reloc_howto_type *) NULL) + { + if (link_info.relocateable) + { + einfo (_("%P%X: %s does not support reloc %s for set %s\n"), + bfd_get_target (output_bfd), + bfd_get_reloc_code_name (p->reloc), + p->h->root.string); + continue; + } + + /* If this is not a relocateable link, all we need is the + size, which we can get from the input BFD. */ + if (p->elements->section->owner != NULL) + howto = bfd_reloc_type_lookup (p->elements->section->owner, + p->reloc); + if (howto == NULL) + { + einfo (_("%P%X: %s does not support reloc %s for set %s\n"), + bfd_get_target (p->elements->section->owner), + bfd_get_reloc_code_name (p->reloc), + p->h->root.string); + continue; + } + } + + reloc_size = bfd_get_reloc_size (howto); + switch (reloc_size) + { + case 1: size = BYTE; break; + case 2: size = SHORT; break; + case 4: size = LONG; break; + case 8: + if (howto->complain_on_overflow == complain_overflow_signed) + size = SQUAD; + else + size = QUAD; + break; + default: + einfo (_("%P%X: Unsupported size %d for set %s\n"), + bfd_get_reloc_size (howto), p->h->root.string); + size = LONG; + break; + } + + lang_add_assignment (exp_assop ('=', ".", + exp_unop (ALIGN_K, + exp_intop (reloc_size)))); + lang_add_assignment (exp_assop ('=', p->h->root.string, + exp_nameop (NAME, "."))); + lang_add_data (size, exp_intop ((bfd_vma) p->count)); + + for (e = p->elements; e != (struct set_element *) NULL; e = e->next) + { + if (config.map_file != NULL) + { + int len; + + if (! header_printed) + { + minfo (_("\nSet Symbol\n\n")); + header_printed = TRUE; + } + + minfo ("%s", p->h->root.string); + len = strlen (p->h->root.string); + + if (len >= 19) + { + print_nl (); + len = 0; + } + while (len < 20) + { + print_space (); + ++len; + } + + if (e->name != NULL) + minfo ("%T\n", e->name); + else + minfo ("%G\n", e->section->owner, e->section, e->value); + } + + /* Need SEC_KEEP for --gc-sections. */ + if (! bfd_is_abs_section (e->section)) + e->section->flags |= SEC_KEEP; + + if (link_info.relocateable) + lang_add_reloc (p->reloc, howto, e->section, e->name, + exp_intop (e->value)); + else + lang_add_data (size, exp_relop (e->section, e->value)); + } + + lang_add_data (size, exp_intop (0)); + } + + stat_ptr = old; +} diff --git a/contrib/binutils-2.14/ld/ldctor.h b/contrib/binutils-2.14/ld/ldctor.h new file mode 100644 index 0000000000..e5e09267e4 --- /dev/null +++ b/contrib/binutils-2.14/ld/ldctor.h @@ -0,0 +1,60 @@ +/* ldctor.h - linker constructor support + Copyright 1991, 1992, 1993, 1994, 1995, 1998, 2000, 2002 + Free Software Foundation, Inc. + +This file is part of GLD, the Gnu Linker. + +GLD is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GLD is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GLD; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#ifndef LDCTOR_H +#define LDCTOR_H + +/* List of statements needed to handle constructors */ +extern lang_statement_list_type constructor_list; + +/* Whether the constructors should be sorted. Note that this is + global for the entire link; we assume that there is only a single + CONSTRUCTORS command in the linker script. */ +extern bfd_boolean constructors_sorted; + +/* We keep a list of these structures for each set we build. */ + +struct set_info { + struct set_info *next; /* Next set. */ + struct bfd_link_hash_entry *h; /* Hash table entry. */ + bfd_reloc_code_real_type reloc; /* Reloc to use for an entry. */ + size_t count; /* Number of elements. */ + struct set_element *elements; /* Elements in set. */ +}; + +struct set_element { + struct set_element *next; /* Next element. */ + const char *name; /* Name in set (may be NULL). */ + asection *section; /* Section of value in set. */ + bfd_vma value; /* Value in set. */ +}; + +/* The sets we have seen. */ + +extern struct set_info *sets; + +extern void ldctor_add_set_entry + PARAMS ((struct bfd_link_hash_entry *, bfd_reloc_code_real_type, + const char *, asection *, bfd_vma)); +extern void ldctor_build_sets + PARAMS ((void)); + +#endif diff --git a/contrib/binutils-2.14/ld/ldemul.c b/contrib/binutils-2.14/ld/ldemul.c new file mode 100644 index 0000000000..d1891270f9 --- /dev/null +++ b/contrib/binutils-2.14/ld/ldemul.c @@ -0,0 +1,341 @@ +/* ldemul.c -- clearing house for ld emulation states + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2002, 2003 + Free Software Foundation, Inc. + +This file is part of GLD, the Gnu Linker. + +GLD is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GLD is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GLD; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "getopt.h" + +#include "ld.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include "ldmain.h" +#include "ldemul-list.h" + +ld_emulation_xfer_type *ld_emulation; + +void +ldemul_hll (name) + char *name; +{ + ld_emulation->hll (name); +} + +void +ldemul_syslib (name) + char *name; +{ + ld_emulation->syslib (name); +} + +void +ldemul_after_parse () +{ + ld_emulation->after_parse (); +} + +void +ldemul_before_parse () +{ + ld_emulation->before_parse (); +} + +void +ldemul_after_open () +{ + ld_emulation->after_open (); +} + +void +ldemul_after_allocation () +{ + ld_emulation->after_allocation (); +} + +void +ldemul_before_allocation () +{ + if (ld_emulation->before_allocation) + ld_emulation->before_allocation (); +} + +void +ldemul_set_output_arch () +{ + ld_emulation->set_output_arch (); +} + +void +ldemul_finish () +{ + if (ld_emulation->finish) + ld_emulation->finish (); +} + +void +ldemul_set_symbols () +{ + if (ld_emulation->set_symbols) + ld_emulation->set_symbols (); +} + +void +ldemul_create_output_section_statements () +{ + if (ld_emulation->create_output_section_statements) + ld_emulation->create_output_section_statements (); +} + +char * +ldemul_get_script (isfile) + int *isfile; +{ + return ld_emulation->get_script (isfile); +} + +bfd_boolean +ldemul_open_dynamic_archive (arch, search, entry) + const char *arch; + search_dirs_type *search; + lang_input_statement_type *entry; +{ + if (ld_emulation->open_dynamic_archive) + return (*ld_emulation->open_dynamic_archive) (arch, search, entry); + return FALSE; +} + +bfd_boolean +ldemul_place_orphan (file, s) + lang_input_statement_type *file; + asection *s; +{ + if (ld_emulation->place_orphan) + return (*ld_emulation->place_orphan) (file, s); + return FALSE; +} + +void +ldemul_add_options (ns, shortopts, nl, longopts, nrl, really_longopts) + int ns; + char **shortopts; + int nl; + struct option **longopts; + int nrl; + struct option **really_longopts; +{ + if (ld_emulation->add_options) + (*ld_emulation->add_options) (ns, shortopts, nl, longopts, + nrl, really_longopts); +} + +bfd_boolean +ldemul_handle_option (optc) + int optc; +{ + if (ld_emulation->handle_option) + return (*ld_emulation->handle_option) (optc); + return FALSE; +} + +bfd_boolean +ldemul_parse_args (argc, argv) + int argc; + char **argv; +{ + /* Try and use the emulation parser if there is one. */ + if (ld_emulation->parse_args) + return (*ld_emulation->parse_args) (argc, argv); + return FALSE; +} + +/* Let the emulation code handle an unrecognized file. */ + +bfd_boolean +ldemul_unrecognized_file (entry) + lang_input_statement_type *entry; +{ + if (ld_emulation->unrecognized_file) + return (*ld_emulation->unrecognized_file) (entry); + return FALSE; +} + +/* Let the emulation code handle a recognized file. */ + +bfd_boolean +ldemul_recognized_file (entry) + lang_input_statement_type *entry; +{ + if (ld_emulation->recognized_file) + return (*ld_emulation->recognized_file) (entry); + return FALSE; +} + +char * +ldemul_choose_target (argc, argv) + int argc; + char **argv; +{ + return ld_emulation->choose_target (argc, argv); +} + + +/* The default choose_target function. */ + +char * +ldemul_default_target (argc, argv) + int argc ATTRIBUTE_UNUSED; + char **argv ATTRIBUTE_UNUSED; +{ + char *from_outside = getenv (TARGET_ENVIRON); + if (from_outside != (char *) NULL) + return from_outside; + return ld_emulation->target_name; +} + +void +after_parse_default () +{ +} + +void +after_open_default () +{ +} + +void +after_allocation_default () +{ +} + +void +before_allocation_default () +{ +} + +void +set_output_arch_default () +{ + /* Set the output architecture and machine if possible. */ + bfd_set_arch_mach (output_bfd, + ldfile_output_architecture, ldfile_output_machine); +} + +void +syslib_default (ignore) + char *ignore ATTRIBUTE_UNUSED; +{ + info_msg (_("%S SYSLIB ignored\n")); +} + +void +hll_default (ignore) + char *ignore ATTRIBUTE_UNUSED; +{ + info_msg (_("%S HLL ignored\n")); +} + +ld_emulation_xfer_type *ld_emulations[] = { EMULATION_LIST }; + +void +ldemul_choose_mode (target) + char *target; +{ + ld_emulation_xfer_type **eptr = ld_emulations; + /* Ignore "gld" prefix. */ + if (target[0] == 'g' && target[1] == 'l' && target[2] == 'd') + target += 3; + for (; *eptr; eptr++) + { + if (strcmp (target, (*eptr)->emulation_name) == 0) + { + ld_emulation = *eptr; + return; + } + } + einfo (_("%P: unrecognised emulation mode: %s\n"), target); + einfo (_("Supported emulations: ")); + ldemul_list_emulations (stderr); + einfo ("%F\n"); +} + +void +ldemul_list_emulations (f) + FILE *f; +{ + ld_emulation_xfer_type **eptr = ld_emulations; + bfd_boolean first = TRUE; + + for (; *eptr; eptr++) + { + if (first) + first = FALSE; + else + fprintf (f, " "); + fprintf (f, "%s", (*eptr)->emulation_name); + } +} + +void +ldemul_list_emulation_options (f) + FILE *f; +{ + ld_emulation_xfer_type **eptr; + int options_found = 0; + + for (eptr = ld_emulations; *eptr; eptr++) + { + ld_emulation_xfer_type *emul = *eptr; + + if (emul->list_options) + { + fprintf (f, "%s: \n", emul->emulation_name); + + emul->list_options (f); + + options_found = 1; + } + } + + if (! options_found) + fprintf (f, _(" no emulation specific options.\n")); +} + +int +ldemul_find_potential_libraries (name, entry) + char *name; + lang_input_statement_type *entry; +{ + if (ld_emulation->find_potential_libraries) + return ld_emulation->find_potential_libraries (name, entry); + + return 0; +} + +struct bfd_elf_version_expr * +ldemul_new_vers_pattern (entry) + struct bfd_elf_version_expr *entry; +{ + if (ld_emulation->new_vers_pattern) + entry = (*ld_emulation->new_vers_pattern) (entry); + return entry; +} diff --git a/contrib/binutils-2.14/ld/ldemul.h b/contrib/binutils-2.14/ld/ldemul.h new file mode 100644 index 0000000000..b88fedfe25 --- /dev/null +++ b/contrib/binutils-2.14/ld/ldemul.h @@ -0,0 +1,197 @@ +/* ld-emul.h - Linker emulation header file + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2002 + Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. */ + +#ifndef LDEMUL_H +#define LDEMUL_H + +extern void ldemul_hll + PARAMS ((char *)); +extern void ldemul_syslib + PARAMS ((char *)); +extern void ldemul_after_parse + PARAMS ((void)); +extern void ldemul_before_parse + PARAMS ((void)); +extern void ldemul_after_open + PARAMS ((void)); +extern void ldemul_after_allocation + PARAMS ((void)); +extern void ldemul_before_allocation + PARAMS ((void)); +extern void ldemul_set_output_arch + PARAMS ((void)); +extern char *ldemul_choose_target + PARAMS ((int, char**)); +extern void ldemul_choose_mode + PARAMS ((char *)); +extern void ldemul_list_emulations + PARAMS ((FILE *)); +extern void ldemul_list_emulation_options + PARAMS ((FILE *)); +extern char *ldemul_get_script + PARAMS ((int *isfile)); +extern void ldemul_finish + PARAMS ((void)); +extern void ldemul_set_symbols + PARAMS ((void)); +extern void ldemul_create_output_section_statements + PARAMS ((void)); +extern bfd_boolean ldemul_place_orphan + PARAMS ((struct lang_input_statement_struct *, asection *)); +extern bfd_boolean ldemul_parse_args + PARAMS ((int, char **)); +extern void ldemul_add_options + PARAMS ((int, char **, int, struct option **, int, struct option **)); +extern bfd_boolean ldemul_handle_option + PARAMS ((int)); +extern bfd_boolean ldemul_unrecognized_file + PARAMS ((struct lang_input_statement_struct *)); +extern bfd_boolean ldemul_recognized_file + PARAMS ((struct lang_input_statement_struct *)); +extern bfd_boolean ldemul_open_dynamic_archive + PARAMS ((const char *, struct search_dirs *, + struct lang_input_statement_struct *)); +extern char *ldemul_default_target + PARAMS ((int, char**)); +extern void after_parse_default + PARAMS ((void)); +extern void after_open_default + PARAMS ((void)); +extern void after_allocation_default + PARAMS ((void)); +extern void before_allocation_default + PARAMS ((void)); +extern void set_output_arch_default + PARAMS ((void)); +extern void syslib_default + PARAMS ((char*)); +extern void hll_default + PARAMS ((char*)); +extern int ldemul_find_potential_libraries + PARAMS ((char *, struct lang_input_statement_struct *)); +extern struct bfd_elf_version_expr *ldemul_new_vers_pattern + PARAMS ((struct bfd_elf_version_expr *)); + +typedef struct ld_emulation_xfer_struct { + /* Run before parsing the command line and script file. + Set the architecture, maybe other things. */ + void (*before_parse) PARAMS ((void)); + + /* Handle the SYSLIB (low level library) script command. */ + void (*syslib) PARAMS ((char *)); + + /* Handle the HLL (high level library) script command. */ + void (*hll) PARAMS ((char *)); + + /* Run after parsing the command line and script file. */ + void (*after_parse) PARAMS ((void)); + + /* Run after opening all input files, and loading the symbols. */ + void (*after_open) PARAMS ((void)); + + /* Run after allocating output sections. */ + void (*after_allocation) PARAMS ( (void)); + + /* Set the output architecture and machine if possible. */ + void (*set_output_arch) PARAMS ((void)); + + /* Decide which target name to use. */ + char * (*choose_target) PARAMS ((int, char**)); + + /* Run before allocating output sections. */ + void (*before_allocation) PARAMS ((void)); + + /* Return the appropriate linker script. */ + char * (*get_script) PARAMS ((int *isfile)); + + /* The name of this emulation. */ + char *emulation_name; + + /* The output format. */ + char *target_name; + + /* Run after assigning values from the script. */ + void (*finish) PARAMS ((void)); + + /* Create any output sections needed by the target. */ + void (*create_output_section_statements) PARAMS ((void)); + + /* Try to open a dynamic library. ARCH is an architecture name, and + is normally the empty string. ENTRY is the lang_input_statement + that should be opened. */ + bfd_boolean (*open_dynamic_archive) + PARAMS ((const char *arch, struct search_dirs *, + struct lang_input_statement_struct *entry)); + + /* Place an orphan section. Return TRUE if it was placed, FALSE if + the default action should be taken. This field may be NULL, in + which case the default action will always be taken. */ + bfd_boolean (*place_orphan) + PARAMS ((struct lang_input_statement_struct *, asection *)); + + /* Run after assigning parsing with the args, but before + reading the script. Used to initialize symbols used in the script. */ + void (*set_symbols) PARAMS ((void)); + + /* Parse args which the base linker doesn't understand. + Return TRUE if the arg needs no further processing. */ + bfd_boolean (*parse_args) PARAMS ((int, char **)); + + /* Hook to add options to parameters passed by the base linker to + getopt_long and getopt_long_only calls. */ + void (*add_options) + PARAMS ((int, char **, int, struct option **, int, struct option **)); + + /* Companion to the above to handle an option. Returns TRUE if it is + one of our options. */ + bfd_boolean (*handle_option) PARAMS ((int)); + + /* Run to handle files which are not recognized as object files or + archives. Return TRUE if the file was handled. */ + bfd_boolean (*unrecognized_file) + PARAMS ((struct lang_input_statement_struct *)); + + /* Run to list the command line options which parse_args handles. */ + void (* list_options) PARAMS ((FILE *)); + + /* Run to specially handle files which *are* recognized as object + files or archives. Return TRUE if the file was handled. */ + bfd_boolean (*recognized_file) + PARAMS ((struct lang_input_statement_struct *)); + + /* Called when looking for libraries in a directory specified + via a linker command line option or linker script option. + Files that match the pattern "lib*.a" have already been scanned. + (For VMS files matching ":lib*.a" have also been scanned). */ + int (* find_potential_libraries) + PARAMS ((char *, struct lang_input_statement_struct *)); + + /* Called when adding a new version pattern. PowerPC64-ELF uses + this hook to add a pattern matching ".foo" for every "foo". */ + struct bfd_elf_version_expr * (*new_vers_pattern) + PARAMS ((struct bfd_elf_version_expr *)); + +} ld_emulation_xfer_type; + +typedef enum { + intel_ic960_ld_mode_enum, + default_mode_enum, + intel_gld960_ld_mode_enum +} lang_emulation_mode_enum_type; + +extern ld_emulation_xfer_type *ld_emulations[]; + +#endif diff --git a/contrib/binutils-2.14/ld/ldexp.c b/contrib/binutils-2.14/ld/ldexp.c new file mode 100644 index 0000000000..9227dd63f2 --- /dev/null +++ b/contrib/binutils-2.14/ld/ldexp.c @@ -0,0 +1,1185 @@ +/* This module handles expression trees. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002 + Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support . + +This file is part of GLD, the Gnu Linker. + +GLD is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GLD is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GLD; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* This module is in charge of working out the contents of expressions. + + It has to keep track of the relative/absness of a symbol etc. This + is done by keeping all values in a struct (an etree_value_type) + which contains a value, a section to which it is relative and a + valid bit. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldmisc.h" +#include "ldexp.h" +#include +#include "ldlang.h" +#include "libiberty.h" +#include "safe-ctype.h" + +static void exp_print_token + PARAMS ((token_code_type code, int infix_p)); +static void make_abs + PARAMS ((etree_value_type *ptr)); +static etree_value_type new_abs + PARAMS ((bfd_vma value)); +static void check + PARAMS ((lang_output_section_statement_type *os, const char *name, + const char *op)); +static etree_value_type new_rel + PARAMS ((bfd_vma, char *, lang_output_section_statement_type *section)); +static etree_value_type new_rel_from_section + PARAMS ((bfd_vma value, lang_output_section_statement_type *section)); +static etree_value_type fold_unary + PARAMS ((etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, bfd_vma *dotp)); +static etree_value_type fold_binary + PARAMS ((etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, bfd_vma *dotp)); +static etree_value_type fold_trinary + PARAMS ((etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot, bfd_vma *dotp)); +static etree_value_type fold_name + PARAMS ((etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done, + bfd_vma dot)); +static etree_value_type exp_fold_tree_no_dot + PARAMS ((etree_type *tree, + lang_output_section_statement_type *current_section, + lang_phase_type allocation_done)); + +struct exp_data_seg exp_data_seg; + +/* Print the string representation of the given token. Surround it + with spaces if INFIX_P is TRUE. */ + +static void +exp_print_token (code, infix_p) + token_code_type code; + int infix_p; +{ + static const struct + { + token_code_type code; + char * name; + } + table[] = + { + { INT, "int" }, + { NAME, "NAME" }, + { PLUSEQ, "+=" }, + { MINUSEQ, "-=" }, + { MULTEQ, "*=" }, + { DIVEQ, "/=" }, + { LSHIFTEQ, "<<=" }, + { RSHIFTEQ, ">>=" }, + { ANDEQ, "&=" }, + { OREQ, "|=" }, + { OROR, "||" }, + { ANDAND, "&&" }, + { EQ, "==" }, + { NE, "!=" }, + { LE, "<=" }, + { GE, ">=" }, + { LSHIFT, "<<" }, + { RSHIFT, ">>" }, + { ALIGN_K, "ALIGN" }, + { BLOCK, "BLOCK" }, + { QUAD, "QUAD" }, + { SQUAD, "SQUAD" }, + { LONG, "LONG" }, + { SHORT, "SHORT" }, + { BYTE, "BYTE" }, + { SECTIONS, "SECTIONS" }, + { SIZEOF_HEADERS, "SIZEOF_HEADERS" }, + { MEMORY, "MEMORY" }, + { DEFINED, "DEFINED" }, + { TARGET_K, "TARGET" }, + { SEARCH_DIR, "SEARCH_DIR" }, + { MAP, "MAP" }, + { ENTRY, "ENTRY" }, + { NEXT, "NEXT" }, + { SIZEOF, "SIZEOF" }, + { ADDR, "ADDR" }, + { LOADADDR, "LOADADDR" }, + { MAX_K, "MAX_K" }, + { REL, "relocateable" }, + { DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" }, + { DATA_SEGMENT_END, "DATA_SEGMENT_END" } + }; + unsigned int idx; + + for (idx = 0; idx < ARRAY_SIZE (table); idx++) + if (table[idx].code == code) + break; + + if (infix_p) + fputc (' ', config.map_file); + + if (idx < ARRAY_SIZE (table)) + fputs (table[idx].name, config.map_file); + else if (code < 127) + fputc (code, config.map_file); + else + fprintf (config.map_file, "", code); + + if (infix_p) + fputc (' ', config.map_file); +} + +static void +make_abs (ptr) + etree_value_type *ptr; +{ + asection *s = ptr->section->bfd_section; + ptr->value += s->vma; + ptr->section = abs_output_section; +} + +static etree_value_type +new_abs (value) + bfd_vma value; +{ + etree_value_type new; + new.valid_p = TRUE; + new.section = abs_output_section; + new.value = value; + return new; +} + +static void +check (os, name, op) + lang_output_section_statement_type *os; + const char *name; + const char *op; +{ + if (os == NULL) + einfo (_("%F%P: %s uses undefined section %s\n"), op, name); + if (! os->processed) + einfo (_("%F%P: %s forward reference of section %s\n"), op, name); +} + +etree_type * +exp_intop (value) + bfd_vma value; +{ + etree_type *new = (etree_type *) stat_alloc (sizeof (new->value)); + new->type.node_code = INT; + new->value.value = value; + new->value.str = NULL; + new->type.node_class = etree_value; + return new; +} + +etree_type * +exp_bigintop (value, str) + bfd_vma value; + char *str; +{ + etree_type *new = (etree_type *) stat_alloc (sizeof (new->value)); + new->type.node_code = INT; + new->value.value = value; + new->value.str = str; + new->type.node_class = etree_value; + return new; +} + +/* Build an expression representing an unnamed relocateable value. */ + +etree_type * +exp_relop (section, value) + asection *section; + bfd_vma value; +{ + etree_type *new = (etree_type *) stat_alloc (sizeof (new->rel)); + new->type.node_code = REL; + new->type.node_class = etree_rel; + new->rel.section = section; + new->rel.value = value; + return new; +} + +static etree_value_type +new_rel (value, str, section) + bfd_vma value; + char *str; + lang_output_section_statement_type *section; +{ + etree_value_type new; + new.valid_p = TRUE; + new.value = value; + new.str = str; + new.section = section; + return new; +} + +static etree_value_type +new_rel_from_section (value, section) + bfd_vma value; + lang_output_section_statement_type *section; +{ + etree_value_type new; + new.valid_p = TRUE; + new.value = value; + new.str = NULL; + new.section = section; + + new.value -= section->bfd_section->vma; + + return new; +} + +static etree_value_type +fold_unary (tree, current_section, allocation_done, dot, dotp) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; + bfd_vma *dotp; +{ + etree_value_type result; + + result = exp_fold_tree (tree->unary.child, + current_section, + allocation_done, dot, dotp); + if (result.valid_p) + { + switch (tree->type.node_code) + { + case ALIGN_K: + if (allocation_done != lang_first_phase_enum) + result = new_rel_from_section (align_n (dot, result.value), + current_section); + else + result.valid_p = FALSE; + break; + + case ABSOLUTE: + if (allocation_done != lang_first_phase_enum) + { + result.value += result.section->bfd_section->vma; + result.section = abs_output_section; + } + else + result.valid_p = FALSE; + break; + + case '~': + make_abs (&result); + result.value = ~result.value; + break; + + case '!': + make_abs (&result); + result.value = !result.value; + break; + + case '-': + make_abs (&result); + result.value = -result.value; + break; + + case NEXT: + /* Return next place aligned to value. */ + if (allocation_done == lang_allocating_phase_enum) + { + make_abs (&result); + result.value = align_n (dot, result.value); + } + else + result.valid_p = FALSE; + break; + + case DATA_SEGMENT_END: + if (allocation_done != lang_first_phase_enum + && current_section == abs_output_section + && (exp_data_seg.phase == exp_dataseg_align_seen + || exp_data_seg.phase == exp_dataseg_adjust + || allocation_done != lang_allocating_phase_enum)) + { + if (exp_data_seg.phase == exp_dataseg_align_seen) + { + exp_data_seg.phase = exp_dataseg_end_seen; + exp_data_seg.end = result.value; + } + } + else + result.valid_p = FALSE; + break; + + default: + FAIL (); + break; + } + } + + return result; +} + +static etree_value_type +fold_binary (tree, current_section, allocation_done, dot, dotp) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; + bfd_vma *dotp; +{ + etree_value_type result; + + result = exp_fold_tree (tree->binary.lhs, current_section, + allocation_done, dot, dotp); + if (result.valid_p) + { + etree_value_type other; + + other = exp_fold_tree (tree->binary.rhs, + current_section, + allocation_done, dot, dotp); + if (other.valid_p) + { + /* If the values are from different sections, or this is an + absolute expression, make both the source arguments + absolute. However, adding or subtracting an absolute + value from a relative value is meaningful, and is an + exception. */ + if (current_section != abs_output_section + && (other.section == abs_output_section + || (result.section == abs_output_section + && tree->type.node_code == '+')) + && (tree->type.node_code == '+' + || tree->type.node_code == '-')) + { + if (other.section != abs_output_section) + { + /* Keep the section of the other term. */ + if (tree->type.node_code == '+') + other.value = result.value + other.value; + else + other.value = result.value - other.value; + return other; + } + } + else if (result.section != other.section + || current_section == abs_output_section) + { + make_abs (&result); + make_abs (&other); + } + + switch (tree->type.node_code) + { + case '%': + if (other.value == 0) + einfo (_("%F%S %% by zero\n")); + result.value = ((bfd_signed_vma) result.value + % (bfd_signed_vma) other.value); + break; + + case '/': + if (other.value == 0) + einfo (_("%F%S / by zero\n")); + result.value = ((bfd_signed_vma) result.value + / (bfd_signed_vma) other.value); + break; + +#define BOP(x,y) case x : result.value = result.value y other.value; break; + BOP ('+', +); + BOP ('*', *); + BOP ('-', -); + BOP (LSHIFT, <<); + BOP (RSHIFT, >>); + BOP (EQ, ==); + BOP (NE, !=); + BOP ('<', <); + BOP ('>', >); + BOP (LE, <=); + BOP (GE, >=); + BOP ('&', &); + BOP ('^', ^); + BOP ('|', |); + BOP (ANDAND, &&); + BOP (OROR, ||); + + case MAX_K: + if (result.value < other.value) + result = other; + break; + + case MIN_K: + if (result.value > other.value) + result = other; + break; + + case DATA_SEGMENT_ALIGN: + if (allocation_done != lang_first_phase_enum + && current_section == abs_output_section + && (exp_data_seg.phase == exp_dataseg_none + || exp_data_seg.phase == exp_dataseg_adjust + || allocation_done != lang_allocating_phase_enum)) + { + bfd_vma maxpage = result.value; + + result.value = align_n (dot, maxpage); + if (exp_data_seg.phase != exp_dataseg_adjust) + { + result.value += dot & (maxpage - 1); + if (allocation_done == lang_allocating_phase_enum) + { + exp_data_seg.phase = exp_dataseg_align_seen; + exp_data_seg.base = result.value; + exp_data_seg.pagesize = other.value; + } + } + else if (other.value < maxpage) + result.value += (dot + other.value - 1) + & (maxpage - other.value); + } + else + result.valid_p = FALSE; + break; + + default: + FAIL (); + } + } + else + { + result.valid_p = FALSE; + } + } + + return result; +} + +static etree_value_type +fold_trinary (tree, current_section, allocation_done, dot, dotp) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; + bfd_vma *dotp; +{ + etree_value_type result; + + result = exp_fold_tree (tree->trinary.cond, current_section, + allocation_done, dot, dotp); + if (result.valid_p) + result = exp_fold_tree ((result.value + ? tree->trinary.lhs + : tree->trinary.rhs), + current_section, + allocation_done, dot, dotp); + + return result; +} + +etree_value_type +invalid () +{ + etree_value_type new; + new.valid_p = FALSE; + return new; +} + +static etree_value_type +fold_name (tree, current_section, allocation_done, dot) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; +{ + etree_value_type result; + + switch (tree->type.node_code) + { + case SIZEOF_HEADERS: + if (allocation_done != lang_first_phase_enum) + { + result = new_abs ((bfd_vma) + bfd_sizeof_headers (output_bfd, + link_info.relocateable)); + } + else + { + result.valid_p = FALSE; + } + break; + case DEFINED: + if (allocation_done == lang_first_phase_enum) + result.valid_p = FALSE; + else + { + struct bfd_link_hash_entry *h; + + h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info, + tree->name.name, + FALSE, FALSE, TRUE); + result.value = (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak + || h->type == bfd_link_hash_common)); + result.section = 0; + result.valid_p = TRUE; + } + break; + case NAME: + result.valid_p = FALSE; + if (tree->name.name[0] == '.' && tree->name.name[1] == 0) + { + if (allocation_done != lang_first_phase_enum) + result = new_rel_from_section (dot, current_section); + else + result = invalid (); + } + else if (allocation_done != lang_first_phase_enum) + { + struct bfd_link_hash_entry *h; + + h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info, + tree->name.name, + FALSE, FALSE, TRUE); + if (h != NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak)) + { + if (bfd_is_abs_section (h->u.def.section)) + result = new_abs (h->u.def.value); + else if (allocation_done == lang_final_phase_enum + || allocation_done == lang_allocating_phase_enum) + { + asection *output_section; + + output_section = h->u.def.section->output_section; + if (output_section == NULL) + einfo (_("%X%S: unresolvable symbol `%s' referenced in expression\n"), + tree->name.name); + else + { + lang_output_section_statement_type *os; + + os = (lang_output_section_statement_lookup + (bfd_get_section_name (output_bfd, + output_section))); + + /* FIXME: Is this correct if this section is + being linked with -R? */ + result = new_rel ((h->u.def.value + + h->u.def.section->output_offset), + NULL, + os); + } + } + } + else if (allocation_done == lang_final_phase_enum) + einfo (_("%F%S: undefined symbol `%s' referenced in expression\n"), + tree->name.name); + } + break; + + case ADDR: + if (allocation_done != lang_first_phase_enum) + { + lang_output_section_statement_type *os; + + os = lang_output_section_find (tree->name.name); + check (os, tree->name.name, "ADDR"); + result = new_rel (0, NULL, os); + } + else + result = invalid (); + break; + + case LOADADDR: + if (allocation_done != lang_first_phase_enum) + { + lang_output_section_statement_type *os; + + os = lang_output_section_find (tree->name.name); + check (os, tree->name.name, "LOADADDR"); + if (os->load_base == NULL) + result = new_rel (0, NULL, os); + else + result = exp_fold_tree_no_dot (os->load_base, + abs_output_section, + allocation_done); + } + else + result = invalid (); + break; + + case SIZEOF: + if (allocation_done != lang_first_phase_enum) + { + int opb = bfd_octets_per_byte (output_bfd); + lang_output_section_statement_type *os; + + os = lang_output_section_find (tree->name.name); + check (os, tree->name.name, "SIZEOF"); + result = new_abs (os->bfd_section->_raw_size / opb); + } + else + result = invalid (); + break; + + default: + FAIL (); + break; + } + + return result; +} + +etree_value_type +exp_fold_tree (tree, current_section, allocation_done, dot, dotp) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; + bfd_vma dot; + bfd_vma *dotp; +{ + etree_value_type result; + + if (tree == NULL) + { + result.valid_p = FALSE; + return result; + } + + switch (tree->type.node_class) + { + case etree_value: + result = new_rel (tree->value.value, tree->value.str, current_section); + break; + + case etree_rel: + if (allocation_done != lang_final_phase_enum) + result.valid_p = FALSE; + else + result = new_rel ((tree->rel.value + + tree->rel.section->output_section->vma + + tree->rel.section->output_offset), + NULL, + current_section); + break; + + case etree_assert: + result = exp_fold_tree (tree->assert_s.child, + current_section, + allocation_done, dot, dotp); + if (result.valid_p) + { + if (! result.value) + einfo ("%F%P: %s\n", tree->assert_s.message); + return result; + } + break; + + case etree_unary: + result = fold_unary (tree, current_section, allocation_done, + dot, dotp); + break; + + case etree_binary: + result = fold_binary (tree, current_section, allocation_done, + dot, dotp); + break; + + case etree_trinary: + result = fold_trinary (tree, current_section, allocation_done, + dot, dotp); + break; + + case etree_assign: + case etree_provide: + case etree_provided: + if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0) + { + /* Assignment to dot can only be done during allocation. */ + if (tree->type.node_class != etree_assign) + einfo (_("%F%S can not PROVIDE assignment to location counter\n")); + if (allocation_done == lang_allocating_phase_enum + || (allocation_done == lang_final_phase_enum + && current_section == abs_output_section)) + { + result = exp_fold_tree (tree->assign.src, + current_section, + allocation_done, dot, + dotp); + if (! result.valid_p) + einfo (_("%F%S invalid assignment to location counter\n")); + else + { + if (current_section == NULL) + einfo (_("%F%S assignment to location counter invalid outside of SECTION\n")); + else + { + bfd_vma nextdot; + + nextdot = (result.value + + current_section->bfd_section->vma); + if (nextdot < dot + && current_section != abs_output_section) + einfo (_("%F%S cannot move location counter backwards (from %V to %V)\n"), + dot, nextdot); + else + *dotp = nextdot; + } + } + } + } + else + { + result = exp_fold_tree (tree->assign.src, + current_section, allocation_done, + dot, dotp); + if (result.valid_p) + { + bfd_boolean create; + struct bfd_link_hash_entry *h; + + if (tree->type.node_class == etree_assign) + create = TRUE; + else + create = FALSE; + h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst, + create, FALSE, FALSE); + if (h == (struct bfd_link_hash_entry *) NULL) + { + if (tree->type.node_class == etree_assign) + einfo (_("%P%F:%s: hash creation failed\n"), + tree->assign.dst); + } + else if (tree->type.node_class == etree_provide + && h->type != bfd_link_hash_undefined + && h->type != bfd_link_hash_common) + { + /* Do nothing. The symbol was defined by some + object. */ + } + else + { + /* FIXME: Should we worry if the symbol is already + defined? */ + h->type = bfd_link_hash_defined; + h->u.def.value = result.value; + h->u.def.section = result.section->bfd_section; + if (tree->type.node_class == etree_provide) + tree->type.node_class = etree_provided; + } + } + } + break; + + case etree_name: + result = fold_name (tree, current_section, allocation_done, dot); + break; + + default: + FAIL (); + break; + } + + return result; +} + +static etree_value_type +exp_fold_tree_no_dot (tree, current_section, allocation_done) + etree_type *tree; + lang_output_section_statement_type *current_section; + lang_phase_type allocation_done; +{ + return exp_fold_tree (tree, current_section, allocation_done, + (bfd_vma) 0, (bfd_vma *) NULL); +} + +etree_type * +exp_binop (code, lhs, rhs) + int code; + etree_type *lhs; + etree_type *rhs; +{ + etree_type value, *new; + etree_value_type r; + + value.type.node_code = code; + value.binary.lhs = lhs; + value.binary.rhs = rhs; + value.type.node_class = etree_binary; + r = exp_fold_tree_no_dot (&value, + abs_output_section, + lang_first_phase_enum); + if (r.valid_p) + { + return exp_intop (r.value); + } + new = (etree_type *) stat_alloc (sizeof (new->binary)); + memcpy ((char *) new, (char *) &value, sizeof (new->binary)); + return new; +} + +etree_type * +exp_trinop (code, cond, lhs, rhs) + int code; + etree_type *cond; + etree_type *lhs; + etree_type *rhs; +{ + etree_type value, *new; + etree_value_type r; + value.type.node_code = code; + value.trinary.lhs = lhs; + value.trinary.cond = cond; + value.trinary.rhs = rhs; + value.type.node_class = etree_trinary; + r = exp_fold_tree_no_dot (&value, + (lang_output_section_statement_type *) NULL, + lang_first_phase_enum); + if (r.valid_p) + return exp_intop (r.value); + + new = (etree_type *) stat_alloc (sizeof (new->trinary)); + memcpy ((char *) new, (char *) &value, sizeof (new->trinary)); + return new; +} + +etree_type * +exp_unop (code, child) + int code; + etree_type *child; +{ + etree_type value, *new; + + etree_value_type r; + value.unary.type.node_code = code; + value.unary.child = child; + value.unary.type.node_class = etree_unary; + r = exp_fold_tree_no_dot (&value, abs_output_section, + lang_first_phase_enum); + if (r.valid_p) + return exp_intop (r.value); + + new = (etree_type *) stat_alloc (sizeof (new->unary)); + memcpy ((char *) new, (char *) &value, sizeof (new->unary)); + return new; +} + +etree_type * +exp_nameop (code, name) + int code; + const char *name; +{ + etree_type value, *new; + etree_value_type r; + value.name.type.node_code = code; + value.name.name = name; + value.name.type.node_class = etree_name; + + r = exp_fold_tree_no_dot (&value, + (lang_output_section_statement_type *) NULL, + lang_first_phase_enum); + if (r.valid_p) + return exp_intop (r.value); + + new = (etree_type *) stat_alloc (sizeof (new->name)); + memcpy ((char *) new, (char *) &value, sizeof (new->name)); + return new; + +} + +etree_type * +exp_assop (code, dst, src) + int code; + const char *dst; + etree_type *src; +{ + etree_type value, *new; + + value.assign.type.node_code = code; + + value.assign.src = src; + value.assign.dst = dst; + value.assign.type.node_class = etree_assign; + +#if 0 + if (exp_fold_tree_no_dot (&value, &result)) + return exp_intop (result); +#endif + new = (etree_type *) stat_alloc (sizeof (new->assign)); + memcpy ((char *) new, (char *) &value, sizeof (new->assign)); + return new; +} + +/* Handle PROVIDE. */ + +etree_type * +exp_provide (dst, src) + const char *dst; + etree_type *src; +{ + etree_type *n; + + n = (etree_type *) stat_alloc (sizeof (n->assign)); + n->assign.type.node_code = '='; + n->assign.type.node_class = etree_provide; + n->assign.src = src; + n->assign.dst = dst; + return n; +} + +/* Handle ASSERT. */ + +etree_type * +exp_assert (exp, message) + etree_type *exp; + const char *message; +{ + etree_type *n; + + n = (etree_type *) stat_alloc (sizeof (n->assert_s)); + n->assert_s.type.node_code = '!'; + n->assert_s.type.node_class = etree_assert; + n->assert_s.child = exp; + n->assert_s.message = message; + return n; +} + +void +exp_print_tree (tree) + etree_type *tree; +{ + if (config.map_file == NULL) + config.map_file = stderr; + + if (tree == NULL) + { + minfo ("NULL TREE\n"); + return; + } + + switch (tree->type.node_class) + { + case etree_value: + minfo ("0x%v", tree->value.value); + return; + case etree_rel: + if (tree->rel.section->owner != NULL) + minfo ("%B:", tree->rel.section->owner); + minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value); + return; + case etree_assign: +#if 0 + if (tree->assign.dst->sdefs != (asymbol *) NULL) + fprintf (config.map_file, "%s (%x) ", tree->assign.dst->name, + tree->assign.dst->sdefs->value); + else + fprintf (config.map_file, "%s (UNDEFINED)", tree->assign.dst->name); +#endif + fprintf (config.map_file, "%s", tree->assign.dst); + exp_print_token (tree->type.node_code, TRUE); + exp_print_tree (tree->assign.src); + break; + case etree_provide: + case etree_provided: + fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst); + exp_print_tree (tree->assign.src); + fprintf (config.map_file, ")"); + break; + case etree_binary: + fprintf (config.map_file, "("); + exp_print_tree (tree->binary.lhs); + exp_print_token (tree->type.node_code, TRUE); + exp_print_tree (tree->binary.rhs); + fprintf (config.map_file, ")"); + break; + case etree_trinary: + exp_print_tree (tree->trinary.cond); + fprintf (config.map_file, "?"); + exp_print_tree (tree->trinary.lhs); + fprintf (config.map_file, ":"); + exp_print_tree (tree->trinary.rhs); + break; + case etree_unary: + exp_print_token (tree->unary.type.node_code, FALSE); + if (tree->unary.child) + { + fprintf (config.map_file, " ("); + exp_print_tree (tree->unary.child); + fprintf (config.map_file, ")"); + } + break; + + case etree_assert: + fprintf (config.map_file, "ASSERT ("); + exp_print_tree (tree->assert_s.child); + fprintf (config.map_file, ", %s)", tree->assert_s.message); + break; + + case etree_undef: + fprintf (config.map_file, "????????"); + break; + case etree_name: + if (tree->type.node_code == NAME) + { + fprintf (config.map_file, "%s", tree->name.name); + } + else + { + exp_print_token (tree->type.node_code, FALSE); + if (tree->name.name) + fprintf (config.map_file, " (%s)", tree->name.name); + } + break; + default: + FAIL (); + break; + } +} + +bfd_vma +exp_get_vma (tree, def, name, allocation_done) + etree_type *tree; + bfd_vma def; + char *name; + lang_phase_type allocation_done; +{ + etree_value_type r; + + if (tree != NULL) + { + r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + if (! r.valid_p && name != NULL) + einfo (_("%F%S nonconstant expression for %s\n"), name); + return r.value; + } + else + return def; +} + +int +exp_get_value_int (tree, def, name, allocation_done) + etree_type *tree; + int def; + char *name; + lang_phase_type allocation_done; +{ + return (int) exp_get_vma (tree, (bfd_vma) def, name, allocation_done); +} + +fill_type * +exp_get_fill (tree, def, name, allocation_done) + etree_type *tree; + fill_type *def; + char *name; + lang_phase_type allocation_done; +{ + fill_type *fill; + etree_value_type r; + size_t len; + unsigned int val; + + if (tree == NULL) + return def; + + r = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + if (! r.valid_p && name != NULL) + einfo (_("%F%S nonconstant expression for %s\n"), name); + + if (r.str != NULL && (len = strlen (r.str)) != 0) + { + unsigned char *dst; + unsigned char *s; + fill = (fill_type *) xmalloc ((len + 1) / 2 + sizeof (*fill) - 1); + fill->size = (len + 1) / 2; + dst = fill->data; + s = r.str; + val = 0; + do + { + unsigned int digit; + + digit = *s++ - '0'; + if (digit > 9) + digit = (digit - 'A' + '0' + 10) & 0xf; + val <<= 4; + val += digit; + --len; + if ((len & 1) == 0) + { + *dst++ = val; + val = 0; + } + } + while (len != 0); + } + else + { + fill = (fill_type *) xmalloc (4 + sizeof (*fill) - 1); + val = r.value; + fill->data[0] = (val >> 24) & 0xff; + fill->data[1] = (val >> 16) & 0xff; + fill->data[2] = (val >> 8) & 0xff; + fill->data[3] = (val >> 0) & 0xff; + fill->size = 4; + } + return fill; +} + +bfd_vma +exp_get_abs_int (tree, def, name, allocation_done) + etree_type *tree; + int def ATTRIBUTE_UNUSED; + char *name; + lang_phase_type allocation_done; +{ + etree_value_type res; + res = exp_fold_tree_no_dot (tree, abs_output_section, allocation_done); + + if (res.valid_p) + res.value += res.section->bfd_section->vma; + else + einfo (_("%F%S non constant expression for %s\n"), name); + + return res.value; +} + +bfd_vma align_n (value, align) + bfd_vma value; + bfd_vma align; +{ + if (align <= 1) + return value; + + value = (value + align - 1) / align; + return value * align; +} diff --git a/contrib/binutils-2.14/ld/ldexp.h b/contrib/binutils-2.14/ld/ldexp.h new file mode 100644 index 0000000000..df814df4df --- /dev/null +++ b/contrib/binutils-2.14/ld/ldexp.h @@ -0,0 +1,144 @@ +/* ldexp.h - + Copyright 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002 + Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GLD; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef LDEXP_H +#define LDEXP_H + +/* The result of an expression tree */ +typedef struct { + bfd_vma value; + char *str; + struct lang_output_section_statement_struct *section; + bfd_boolean valid_p; +} etree_value_type; + +typedef struct { + int node_code; + enum { + etree_binary, + etree_trinary, + etree_unary, + etree_name, + etree_assign, + etree_provide, + etree_provided, + etree_undef, + etree_unspec, + etree_value, + etree_assert, + etree_rel + } node_class; +} node_type; + +typedef union etree_union { + node_type type; + struct { + node_type type; + union etree_union *lhs; + union etree_union *rhs; + } binary; + struct { + node_type type; + union etree_union *cond; + union etree_union *lhs; + union etree_union *rhs; + } trinary; + struct { + node_type type; + const char *dst; + union etree_union *src; + } assign; + struct { + node_type type; + union etree_union *child; + } unary; + struct { + node_type type; + const char *name; + } name; + struct { + node_type type; + bfd_vma value; + char *str; + } value; + struct { + node_type type; + asection *section; + bfd_vma value; + } rel; + struct { + node_type type; + union etree_union *child; + const char *message; + } assert_s; +} etree_type; + +extern struct exp_data_seg { + enum { + exp_dataseg_none, + exp_dataseg_align_seen, + exp_dataseg_end_seen, + exp_dataseg_adjust + } phase; + bfd_vma base, end, pagesize; +} exp_data_seg; + +typedef struct _fill_type fill_type; + +etree_type *exp_intop + PARAMS ((bfd_vma)); +etree_type *exp_bigintop + PARAMS ((bfd_vma, char *)); +etree_type *exp_relop + PARAMS ((asection *, bfd_vma)); +etree_value_type invalid + PARAMS ((void)); +etree_value_type exp_fold_tree + PARAMS ((etree_type *, struct lang_output_section_statement_struct *, + lang_phase_type, bfd_vma, bfd_vma *)); +etree_type *exp_binop + PARAMS ((int, etree_type *, etree_type *)); +etree_type *exp_trinop + PARAMS ((int,etree_type *, etree_type *, etree_type *)); +etree_type *exp_unop + PARAMS ((int, etree_type *)); +etree_type *exp_nameop + PARAMS ((int, const char *)); +etree_type *exp_assop + PARAMS ((int, const char *, etree_type *)); +etree_type *exp_provide + PARAMS ((const char *, etree_type *)); +etree_type *exp_assert + PARAMS ((etree_type *, const char *)); +void exp_print_tree + PARAMS ((etree_type *)); +bfd_vma exp_get_vma + PARAMS ((etree_type *, bfd_vma, char *, lang_phase_type)); +int exp_get_value_int + PARAMS ((etree_type *, int, char *, lang_phase_type)); +fill_type *exp_get_fill + PARAMS ((etree_type *, fill_type *, char *, lang_phase_type)); +bfd_vma exp_get_abs_int + PARAMS ((etree_type *, int, char *, lang_phase_type)); +bfd_vma align_n + PARAMS ((bfd_vma, bfd_vma)); + +#endif diff --git a/contrib/binutils-2.14/ld/ldfile.c b/contrib/binutils-2.14/ld/ldfile.c new file mode 100644 index 0000000000..4806534a74 --- /dev/null +++ b/contrib/binutils-2.14/ld/ldfile.c @@ -0,0 +1,625 @@ +/* Linker file opening and searching. + Copyright 1991, 1992, 1993, 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GLD; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* ldfile.c: look after all the file stuff. */ + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "safe-ctype.h" +#include "ld.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldmain.h" +#include +#include "ldlex.h" +#include "ldemul.h" +#include "libiberty.h" +#include "filenames.h" + +const char * ldfile_input_filename; +bfd_boolean ldfile_assumed_script = FALSE; +const char * ldfile_output_machine_name = ""; +unsigned long ldfile_output_machine; +enum bfd_architecture ldfile_output_architecture; +search_dirs_type * search_head; + +#ifndef MPW +#ifdef VMS +char * slash = ""; +#else +#if defined (_WIN32) && ! defined (__CYGWIN32__) +char * slash = "\\"; +#else +char * slash = "/"; +#endif +#endif +#else /* MPW */ +/* The MPW path char is a colon. */ +char * slash = ":"; +#endif /* MPW */ + +typedef struct search_arch +{ + char *name; + struct search_arch *next; +} search_arch_type; + +static search_dirs_type **search_tail_ptr = &search_head; +static search_arch_type *search_arch_head; +static search_arch_type **search_arch_tail_ptr = &search_arch_head; + +static FILE *try_open + PARAMS ((const char *, const char *)); +static bfd_boolean is_sysrooted_pathname + PARAMS ((const char *, bfd_boolean)); + +/* Test whether a pathname, after canonicalization, is the same or a + sub-directory of the sysroot directory. */ + +static bfd_boolean +is_sysrooted_pathname (name, notsame) + const char *name; + bfd_boolean notsame; +{ + char * realname = ld_canon_sysroot ? lrealpath (name) : NULL; + int len; + bfd_boolean result; + + if (! realname) + return FALSE; + + len = strlen (realname); + + if (((! notsame && len == ld_canon_sysroot_len) + || (len >= ld_canon_sysroot_len + && IS_DIR_SEPARATOR (realname[ld_canon_sysroot_len]) + && (realname[ld_canon_sysroot_len] = '\0') == '\0')) + && FILENAME_CMP (ld_canon_sysroot, realname) == 0) + result = TRUE; + else + result = FALSE; + + if (realname) + free (realname); + + return result; +} + +/* Adds NAME to the library search path. + Makes a copy of NAME using xmalloc(). */ + +void +ldfile_add_library_path (name, cmdline) + const char *name; + bfd_boolean cmdline; +{ + search_dirs_type *new; + + if (!cmdline && config.only_cmd_line_lib_dirs) + return; + + new = (search_dirs_type *) xmalloc (sizeof (search_dirs_type)); + new->next = NULL; + new->cmdline = cmdline; + *search_tail_ptr = new; + search_tail_ptr = &new->next; + + /* If a directory is marked as honoring sysroot, prepend the sysroot path + now. */ + if (name[0] == '=') + { + new->name = concat (ld_sysroot, name + 1, NULL); + new->sysrooted = TRUE; + } + else + { + new->name = xstrdup (name); + new->sysrooted = is_sysrooted_pathname (name, FALSE); + } +} + +/* Try to open a BFD for a lang_input_statement. */ + +bfd_boolean +ldfile_try_open_bfd (attempt, entry) + const char *attempt; + lang_input_statement_type *entry; +{ + entry->the_bfd = bfd_openr (attempt, entry->target); + + if (trace_file_tries) + { + if (entry->the_bfd == NULL) + info_msg (_("attempt to open %s failed\n"), attempt); + else + info_msg (_("attempt to open %s succeeded\n"), attempt); + } + + if (entry->the_bfd == NULL) + { + if (bfd_get_error () == bfd_error_invalid_target) + einfo (_("%F%P: invalid BFD target `%s'\n"), entry->target); + return FALSE; + } + + /* If we are searching for this file, see if the architecture is + compatible with the output file. If it isn't, keep searching. + If we can't open the file as an object file, stop the search + here. */ + + if (entry->search_dirs_flag) + { + bfd *check; + + if (bfd_check_format (entry->the_bfd, bfd_archive)) + check = bfd_openr_next_archived_file (entry->the_bfd, NULL); + else + check = entry->the_bfd; + + if (check != NULL) + { + if (! bfd_check_format (check, bfd_object)) + { + if (check == entry->the_bfd + && bfd_get_error () == bfd_error_file_not_recognized + && ! ldemul_unrecognized_file (entry)) + { + int token, skip = 0; + char *arg, *arg1, *arg2, *arg3; + extern FILE *yyin; + + /* Try to interpret the file as a linker script. */ + ldfile_open_command_file (attempt); + + ldfile_assumed_script = TRUE; + parser_input = input_selected; + ldlex_both (); + token = INPUT_SCRIPT; + while (token != 0) + { + switch (token) + { + case OUTPUT_FORMAT: + if ((token = yylex ()) != '(') + continue; + if ((token = yylex ()) != NAME) + continue; + arg1 = yylval.name; + arg2 = NULL; + arg3 = NULL; + token = yylex (); + if (token == ',') + { + if ((token = yylex ()) != NAME) + { + free (arg1); + continue; + } + arg2 = yylval.name; + if ((token = yylex ()) != ',' + || (token = yylex ()) != NAME) + { + free (arg1); + free (arg2); + continue; + } + arg3 = yylval.name; + token = yylex (); + } + if (token == ')') + { + switch (command_line.endian) + { + default: + case ENDIAN_UNSET: + arg = arg1; break; + case ENDIAN_BIG: + arg = arg2 ? arg2 : arg1; break; + case ENDIAN_LITTLE: + arg = arg3 ? arg3 : arg1; break; + } + if (strcmp (arg, lang_get_output_target ()) != 0) + skip = 1; + } + free (arg1); + if (arg2) free (arg2); + if (arg3) free (arg3); + break; + case NAME: + case LNAME: + case VERS_IDENTIFIER: + case VERS_TAG: + free (yylval.name); + break; + case INT: + if (yylval.bigint.str) + free (yylval.bigint.str); + break; + } + token = yylex (); + } + ldlex_popstate (); + ldfile_assumed_script = FALSE; + fclose (yyin); + yyin = NULL; + if (skip) + { + einfo (_("%P: skipping incompatible %s when searching for %s\n"), + attempt, entry->local_sym_name); + bfd_close (entry->the_bfd); + entry->the_bfd = NULL; + return FALSE; + } + } + return TRUE; + } + + if ((bfd_arch_get_compatible (check, output_bfd, + command_line.accept_unknown_input_arch) == NULL) + /* XCOFF archives can have 32 and 64 bit objects. */ + && ! (bfd_get_flavour (check) == bfd_target_xcoff_flavour + && bfd_get_flavour (output_bfd) == bfd_target_xcoff_flavour + && bfd_check_format (entry->the_bfd, bfd_archive))) + { + einfo (_("%P: skipping incompatible %s when searching for %s\n"), + attempt, entry->local_sym_name); + bfd_close (entry->the_bfd); + entry->the_bfd = NULL; + return FALSE; + } + } + } + + return TRUE; +} + +/* Search for and open the file specified by ENTRY. If it is an + archive, use ARCH, LIB and SUFFIX to modify the file name. */ + +bfd_boolean +ldfile_open_file_search (arch, entry, lib, suffix) + const char *arch; + lang_input_statement_type *entry; + const char *lib; + const char *suffix; +{ + search_dirs_type *search; + + /* If this is not an archive, try to open it in the current + directory first. */ + if (! entry->is_archive) + { + if (entry->sysrooted && IS_ABSOLUTE_PATH (entry->filename)) + { + char *name = concat (ld_sysroot, entry->filename, + (const char *) NULL); + if (ldfile_try_open_bfd (name, entry)) + { + entry->filename = name; + return TRUE; + } + free (name); + } + else if (ldfile_try_open_bfd (entry->filename, entry)) + { + entry->sysrooted = IS_ABSOLUTE_PATH (entry->filename) + && is_sysrooted_pathname (entry->filename, TRUE); + return TRUE; + } + + if (IS_ABSOLUTE_PATH (entry->filename)) + return FALSE; + } + + for (search = search_head; + search != (search_dirs_type *) NULL; + search = search->next) + { + char *string; + + if (entry->dynamic && ! link_info.relocateable) + { + if (ldemul_open_dynamic_archive (arch, search, entry)) + { + entry->sysrooted = search->sysrooted; + return TRUE; + } + } + + string = (char *) xmalloc (strlen (search->name) + + strlen (slash) + + strlen (lib) + + strlen (entry->filename) + + strlen (arch) + + strlen (suffix) + + 1); + + if (entry->is_archive) + sprintf (string, "%s%s%s%s%s%s", search->name, slash, + lib, entry->filename, arch, suffix); + else + sprintf (string, "%s%s%s", search->name, slash, entry->filename); + + if (ldfile_try_open_bfd (string, entry)) + { + entry->filename = string; + entry->sysrooted = search->sysrooted; + return TRUE; + } + + free (string); + } + + return FALSE; +} + +/* Open the input file specified by ENTRY. */ + +void +ldfile_open_file (entry) + lang_input_statement_type *entry; +{ + if (entry->the_bfd != NULL) + return; + + if (! entry->search_dirs_flag) + { + if (ldfile_try_open_bfd (entry->filename, entry)) + return; + if (strcmp (entry->filename, entry->local_sym_name) != 0) + einfo (_("%F%P: cannot open %s for %s: %E\n"), + entry->filename, entry->local_sym_name); + else + einfo (_("%F%P: cannot open %s: %E\n"), entry->local_sym_name); + } + else + { + search_arch_type *arch; + bfd_boolean found = FALSE; + + /* Try to open or lib.a */ + for (arch = search_arch_head; + arch != (search_arch_type *) NULL; + arch = arch->next) + { + found = ldfile_open_file_search (arch->name, entry, "lib", ".a"); + if (found) + break; +#ifdef VMS + found = ldfile_open_file_search (arch->name, entry, ":lib", ".a"); + if (found) + break; +#endif + found = ldemul_find_potential_libraries (arch->name, entry); + if (found) + break; + } + + /* If we have found the file, we don't need to search directories + again. */ + if (found) + entry->search_dirs_flag = FALSE; + else if (entry->sysrooted + && ld_sysroot + && IS_ABSOLUTE_PATH (entry->local_sym_name)) + einfo (_("%F%P: cannot find %s inside %s\n"), + entry->local_sym_name, ld_sysroot); + else + einfo (_("%F%P: cannot find %s\n"), entry->local_sym_name); + } +} + +/* Try to open NAME; if that fails, try NAME with EXTEN appended to it. */ + +static FILE * +try_open (name, exten) + const char *name; + const char *exten; +{ + FILE *result; + char buff[1000]; + + result = fopen (name, "r"); + + if (trace_file_tries) + { + if (result == NULL) + info_msg (_("cannot find script file %s\n"), name); + else + info_msg (_("opened script file %s\n"), name); + } + + if (result != NULL) + return result; + + if (*exten) + { + sprintf (buff, "%s%s", name, exten); + result = fopen (buff, "r"); + + if (trace_file_tries) + { + if (result == NULL) + info_msg (_("cannot find script file %s\n"), buff); + else + info_msg (_("opened script file %s\n"), buff); + } + } + + return result; +} + +/* Try to open NAME; if that fails, look for it in any directories + specified with -L, without and with EXTEND appended. */ + +FILE * +ldfile_find_command_file (name, extend) + const char *name; + const char *extend; +{ + search_dirs_type *search; + FILE *result; + char buffer[1000]; + + /* First try raw name. */ + result = try_open (name, ""); + if (result == (FILE *) NULL) + { + /* Try now prefixes. */ + for (search = search_head; + search != (search_dirs_type *) NULL; + search = search->next) + { + sprintf (buffer, "%s%s%s", search->name, slash, name); + + result = try_open (buffer, extend); + if (result) + break; + } + } + + return result; +} + +void +ldfile_open_command_file (name) + const char *name; +{ + FILE *ldlex_input_stack; + ldlex_input_stack = ldfile_find_command_file (name, ""); + + if (ldlex_input_stack == (FILE *) NULL) + { + bfd_set_error (bfd_error_system_call); + einfo (_("%P%F: cannot open linker script file %s: %E\n"), name); + } + + lex_push_file (ldlex_input_stack, name); + + ldfile_input_filename = name; + lineno = 1; + + saved_script_handle = ldlex_input_stack; +} + +#ifdef GNU960 +static char * +gnu960_map_archname (name) + char *name; +{ + struct tabentry { char *cmd_switch; char *arch; }; + static struct tabentry arch_tab[] = + { + "", "", + "KA", "ka", + "KB", "kb", + "KC", "mc", /* Synonym for MC */ + "MC", "mc", + "CA", "ca", + "SA", "ka", /* Functionally equivalent to KA */ + "SB", "kb", /* Functionally equivalent to KB */ + NULL, "" + }; + struct tabentry *tp; + + for (tp = arch_tab; tp->cmd_switch != NULL; tp++) + { + if (! strcmp (name,tp->cmd_switch)) + break; + } + + if (tp->cmd_switch == NULL) + einfo (_("%P%F: unknown architecture: %s\n"), name); + + return tp->arch; +} + +void +ldfile_add_arch (name) + char *name; +{ + search_arch_type *new = + (search_arch_type *) xmalloc ((bfd_size_type) (sizeof (search_arch_type))); + + if (*name != '\0') + { + if (ldfile_output_machine_name[0] != '\0') + { + einfo (_("%P%F: target architecture respecified\n")); + return; + } + + ldfile_output_machine_name = name; + } + + new->next = (search_arch_type *) NULL; + new->name = gnu960_map_archname (name); + *search_arch_tail_ptr = new; + search_arch_tail_ptr = &new->next; +} + +#else /* not GNU960 */ + +void +ldfile_add_arch (in_name) + const char *in_name; +{ + char *name = xstrdup (in_name); + search_arch_type *new = + (search_arch_type *) xmalloc (sizeof (search_arch_type)); + + ldfile_output_machine_name = in_name; + + new->name = name; + new->next = (search_arch_type *) NULL; + while (*name) + { + *name = TOLOWER (*name); + name++; + } + *search_arch_tail_ptr = new; + search_arch_tail_ptr = &new->next; + +} +#endif + +/* Set the output architecture. */ + +void +ldfile_set_output_arch (string) + const char *string; +{ + const bfd_arch_info_type *arch = bfd_scan_arch (string); + + if (arch) + { + ldfile_output_architecture = arch->arch; + ldfile_output_machine = arch->mach; + ldfile_output_machine_name = arch->printable_name; + } + else + { + einfo (_("%P%F: cannot represent machine `%s'\n"), string); + } +} diff --git a/contrib/binutils-2.14/ld/ldfile.h b/contrib/binutils-2.14/ld/ldfile.h new file mode 100644 index 0000000000..0bfea7caba --- /dev/null +++ b/contrib/binutils-2.14/ld/ldfile.h @@ -0,0 +1,64 @@ +/* ldfile.h - + Copyright 1991, 1992, 1993, 1994, 1995, 2000, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GLD; see the file COPYING. If not, write to + the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef LDFILE_H +#define LDFILE_H + +extern const char *ldfile_input_filename; +extern bfd_boolean ldfile_assumed_script; +extern unsigned long ldfile_output_machine; +extern enum bfd_architecture ldfile_output_architecture; +extern const char *ldfile_output_machine_name; + +/* Structure used to hold the list of directories to search for + libraries. */ + +typedef struct search_dirs { + /* Next directory on list. */ + struct search_dirs *next; + /* Name of directory. */ + const char *name; + /* TRUE if this is from the command line. */ + bfd_boolean cmdline; + /* true if this is from within the sys-root. */ + bfd_boolean sysrooted; +} search_dirs_type; + +extern search_dirs_type *search_head; + +extern void ldfile_add_arch + PARAMS ((const char *)); +extern void ldfile_add_library_path + PARAMS ((const char *, bfd_boolean cmdline)); +extern void ldfile_open_command_file + PARAMS ((const char *name)); +extern void ldfile_open_file + PARAMS ((struct lang_input_statement_struct *)); +extern bfd_boolean ldfile_try_open_bfd + PARAMS ((const char *, struct lang_input_statement_struct *)); +extern FILE *ldfile_find_command_file + PARAMS ((const char *name, const char *extend)); +extern void ldfile_set_output_arch + PARAMS ((const char *)); +extern bfd_boolean ldfile_open_file_search + PARAMS ((const char *arch, struct lang_input_statement_struct *, + const char *lib, const char *suffix)); + +#endif diff --git a/contrib/binutils-2.14/ld/ldgram.y b/contrib/binutils-2.14/ld/ldgram.y new file mode 100644 index 0000000000..e9c8a9fe49 --- /dev/null +++ b/contrib/binutils-2.14/ld/ldgram.y @@ -0,0 +1,1184 @@ +/* A YACC grammar to parse a superset of the AT&T linker scripting language. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002 Free Software Foundation, Inc. + Written by Steve Chamberlain of Cygnus Support (steve@cygnus.com). + +This file is part of GNU ld. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +%{ +/* + + */ + +#define DONTDECLARE_MALLOC + +#include "bfd.h" +#include "sysdep.h" +#include "bfdlink.h" +#include "ld.h" +#include "ldexp.h" +#include "ldver.h" +#include "ldlang.h" +#include "ldfile.h" +#include "ldemul.h" +#include "ldmisc.h" +#include "ldmain.h" +#include "mri.h" +#include "ldctor.h" +#include "ldlex.h" + +#ifndef YYDEBUG +#define YYDEBUG 1 +#endif + +static enum section_type sectype; + +lang_memory_region_type *region; + +bfd_boolean ldgram_want_filename = TRUE; +FILE *saved_script_handle = NULL; +bfd_boolean force_make_executable = FALSE; + +bfd_boolean ldgram_in_script = FALSE; +bfd_boolean ldgram_had_equals = FALSE; +bfd_boolean ldgram_had_keep = FALSE; +char *ldgram_vers_current_lang = NULL; + +#define ERROR_NAME_MAX 20 +static char *error_names[ERROR_NAME_MAX]; +static int error_index; +#define PUSH_ERROR(x) if (error_index < ERROR_NAME_MAX) error_names[error_index] = x; error_index++; +#define POP_ERROR() error_index--; +%} +%union { + bfd_vma integer; + struct big_int + { + bfd_vma integer; + char *str; + } bigint; + fill_type *fill; + char *name; + const char *cname; + struct wildcard_spec wildcard; + struct wildcard_list *wildcard_list; + struct name_list *name_list; + int token; + union etree_union *etree; + struct phdr_info + { + bfd_boolean filehdr; + bfd_boolean phdrs; + union etree_union *at; + union etree_union *flags; + } phdr; + struct lang_nocrossref *nocrossref; + struct lang_output_section_phdr_list *section_phdr; + struct bfd_elf_version_deps *deflist; + struct bfd_elf_version_expr *versyms; + struct bfd_elf_version_tree *versnode; +} + +%type exp opt_exp_with_type mustbe_exp opt_at phdr_type phdr_val +%type opt_exp_without_type +%type fill_opt fill_exp +%type exclude_name_list +%type file_NAME_list +%type memspec_opt casesymlist +%type memspec_at_opt +%type wildcard_name +%type wildcard_spec +%token INT +%token NAME LNAME +%type length +%type phdr_qualifiers +%type nocrossref_list +%type phdr_opt +%type opt_nocrossrefs + +%right PLUSEQ MINUSEQ MULTEQ DIVEQ '=' LSHIFTEQ RSHIFTEQ ANDEQ OREQ +%right '?' ':' +%left OROR +%left ANDAND +%left '|' +%left '^' +%left '&' +%left EQ NE +%left '<' '>' LE GE +%left LSHIFT RSHIFT + +%left '+' '-' +%left '*' '/' '%' + +%right UNARY +%token END +%left '(' +%token ALIGN_K BLOCK BIND QUAD SQUAD LONG SHORT BYTE +%token SECTIONS PHDRS SORT DATA_SEGMENT_ALIGN DATA_SEGMENT_END +%token '{' '}' +%token SIZEOF_HEADERS OUTPUT_FORMAT FORCE_COMMON_ALLOCATION OUTPUT_ARCH +%token INHIBIT_COMMON_ALLOCATION +%token SIZEOF_HEADERS +%token INCLUDE +%token MEMORY DEFSYMEND +%token NOLOAD DSECT COPY INFO OVERLAY +%token NAME LNAME DEFINED TARGET_K SEARCH_DIR MAP ENTRY +%token NEXT +%token SIZEOF ADDR LOADADDR MAX_K MIN_K +%token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS +%token ORIGIN FILL +%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS +%token ALIGNMOD AT PROVIDE +%type assign_op atype attributes_opt +%type filename +%token CHIP LIST SECT ABSOLUTE LOAD NEWLINE ENDWORD ORDER NAMEWORD ASSERT_K +%token FORMAT PUBLIC DEFSYMEND BASE ALIAS TRUNCATE REL +%token INPUT_SCRIPT INPUT_MRI_SCRIPT INPUT_DEFSYM CASE EXTERN START +%token VERS_TAG VERS_IDENTIFIER +%token GLOBAL LOCAL VERSIONK INPUT_VERSION_SCRIPT +%token KEEP +%token EXCLUDE_FILE +%type vers_defns +%type vers_tag +%type verdep + +%% + +file: + INPUT_SCRIPT script_file + | INPUT_MRI_SCRIPT mri_script_file + | INPUT_VERSION_SCRIPT version_script_file + | INPUT_DEFSYM defsym_expr + ; + + +filename: NAME; + + +defsym_expr: + { ldlex_defsym(); } + NAME '=' exp + { + ldlex_popstate(); + lang_add_assignment(exp_assop($3,$2,$4)); + } + ; + +/* SYNTAX WITHIN AN MRI SCRIPT FILE */ +mri_script_file: + { + ldlex_mri_script (); + PUSH_ERROR (_("MRI style script")); + } + mri_script_lines + { + ldlex_popstate (); + mri_draw_tree (); + POP_ERROR (); + } + ; + +mri_script_lines: + mri_script_lines mri_script_command NEWLINE + | + ; + +mri_script_command: + CHIP exp + | CHIP exp ',' exp + | NAME { + einfo(_("%P%F: unrecognised keyword in MRI style script '%s'\n"),$1); + } + | LIST { + config.map_filename = "-"; + } + | ORDER ordernamelist + | ENDWORD + | PUBLIC NAME '=' exp + { mri_public($2, $4); } + | PUBLIC NAME ',' exp + { mri_public($2, $4); } + | PUBLIC NAME exp + { mri_public($2, $3); } + | FORMAT NAME + { mri_format($2); } + | SECT NAME ',' exp + { mri_output_section($2, $4);} + | SECT NAME exp + { mri_output_section($2, $3);} + | SECT NAME '=' exp + { mri_output_section($2, $4);} + | ALIGN_K NAME '=' exp + { mri_align($2,$4); } + | ALIGN_K NAME ',' exp + { mri_align($2,$4); } + | ALIGNMOD NAME '=' exp + { mri_alignmod($2,$4); } + | ALIGNMOD NAME ',' exp + { mri_alignmod($2,$4); } + | ABSOLUTE mri_abs_name_list + | LOAD mri_load_name_list + | NAMEWORD NAME + { mri_name($2); } + | ALIAS NAME ',' NAME + { mri_alias($2,$4,0);} + | ALIAS NAME ',' INT + { mri_alias ($2, 0, (int) $4.integer); } + | BASE exp + { mri_base($2); } + | TRUNCATE INT + { mri_truncate ((unsigned int) $2.integer); } + | CASE casesymlist + | EXTERN extern_name_list + | INCLUDE filename + { ldlex_script (); ldfile_open_command_file($2); } + mri_script_lines END + { ldlex_popstate (); } + | START NAME + { lang_add_entry ($2, FALSE); } + | + ; + +ordernamelist: + ordernamelist ',' NAME { mri_order($3); } + | ordernamelist NAME { mri_order($2); } + | + ; + +mri_load_name_list: + NAME + { mri_load($1); } + | mri_load_name_list ',' NAME { mri_load($3); } + ; + +mri_abs_name_list: + NAME + { mri_only_load($1); } + | mri_abs_name_list ',' NAME + { mri_only_load($3); } + ; + +casesymlist: + /* empty */ { $$ = NULL; } + | NAME + | casesymlist ',' NAME + ; + +extern_name_list: + NAME + { ldlang_add_undef ($1); } + | extern_name_list NAME + { ldlang_add_undef ($2); } + | extern_name_list ',' NAME + { ldlang_add_undef ($3); } + ; + +script_file: + { + ldlex_both(); + } + ifile_list + { + ldlex_popstate(); + } + ; + + +ifile_list: + ifile_list ifile_p1 + | + ; + + + +ifile_p1: + memory + | sections + | phdrs + | startup + | high_level_library + | low_level_library + | floating_point_support + | statement_anywhere + | version + | ';' + | TARGET_K '(' NAME ')' + { lang_add_target($3); } + | SEARCH_DIR '(' filename ')' + { ldfile_add_library_path ($3, FALSE); } + | OUTPUT '(' filename ')' + { lang_add_output($3, 1); } + | OUTPUT_FORMAT '(' NAME ')' + { lang_add_output_format ($3, (char *) NULL, + (char *) NULL, 1); } + | OUTPUT_FORMAT '(' NAME ',' NAME ',' NAME ')' + { lang_add_output_format ($3, $5, $7, 1); } + | OUTPUT_ARCH '(' NAME ')' + { ldfile_set_output_arch($3); } + | FORCE_COMMON_ALLOCATION + { command_line.force_common_definition = TRUE ; } + | INHIBIT_COMMON_ALLOCATION + { command_line.inhibit_common_definition = TRUE ; } + | INPUT '(' input_list ')' + | GROUP + { lang_enter_group (); } + '(' input_list ')' + { lang_leave_group (); } + | MAP '(' filename ')' + { lang_add_map($3); } + | INCLUDE filename + { ldlex_script (); ldfile_open_command_file($2); } + ifile_list END + { ldlex_popstate (); } + | NOCROSSREFS '(' nocrossref_list ')' + { + lang_add_nocrossref ($3); + } + | EXTERN '(' extern_name_list ')' + ; + +input_list: + NAME + { lang_add_input_file($1,lang_input_file_is_search_file_enum, + (char *)NULL); } + | input_list ',' NAME + { lang_add_input_file($3,lang_input_file_is_search_file_enum, + (char *)NULL); } + | input_list NAME + { lang_add_input_file($2,lang_input_file_is_search_file_enum, + (char *)NULL); } + | LNAME + { lang_add_input_file($1,lang_input_file_is_l_enum, + (char *)NULL); } + | input_list ',' LNAME + { lang_add_input_file($3,lang_input_file_is_l_enum, + (char *)NULL); } + | input_list LNAME + { lang_add_input_file($2,lang_input_file_is_l_enum, + (char *)NULL); } + ; + +sections: + SECTIONS '{' sec_or_group_p1 '}' + ; + +sec_or_group_p1: + sec_or_group_p1 section + | sec_or_group_p1 statement_anywhere + | + ; + +statement_anywhere: + ENTRY '(' NAME ')' + { lang_add_entry ($3, FALSE); } + | assignment end + ; + +/* The '*' and '?' cases are there because the lexer returns them as + separate tokens rather than as NAME. */ +wildcard_name: + NAME + { + $$ = $1; + } + | '*' + { + $$ = "*"; + } + | '?' + { + $$ = "?"; + } + ; + +wildcard_spec: + wildcard_name + { + $$.name = $1; + $$.sorted = FALSE; + $$.exclude_name_list = NULL; + } + | EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name + { + $$.name = $5; + $$.sorted = FALSE; + $$.exclude_name_list = $3; + } + | SORT '(' wildcard_name ')' + { + $$.name = $3; + $$.sorted = TRUE; + $$.exclude_name_list = NULL; + } + | SORT '(' EXCLUDE_FILE '(' exclude_name_list ')' wildcard_name ')' + { + $$.name = $7; + $$.sorted = TRUE; + $$.exclude_name_list = $5; + } + ; + +exclude_name_list: + exclude_name_list wildcard_name + { + struct name_list *tmp; + tmp = (struct name_list *) xmalloc (sizeof *tmp); + tmp->name = $2; + tmp->next = $1; + $$ = tmp; + } + | + wildcard_name + { + struct name_list *tmp; + tmp = (struct name_list *) xmalloc (sizeof *tmp); + tmp->name = $1; + tmp->next = NULL; + $$ = tmp; + } + ; + +file_NAME_list: + file_NAME_list opt_comma wildcard_spec + { + struct wildcard_list *tmp; + tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); + tmp->next = $1; + tmp->spec = $3; + $$ = tmp; + } + | + wildcard_spec + { + struct wildcard_list *tmp; + tmp = (struct wildcard_list *) xmalloc (sizeof *tmp); + tmp->next = NULL; + tmp->spec = $1; + $$ = tmp; + } + ; + +input_section_spec_no_keep: + NAME + { + struct wildcard_spec tmp; + tmp.name = $1; + tmp.exclude_name_list = NULL; + tmp.sorted = FALSE; + lang_add_wild (&tmp, NULL, ldgram_had_keep); + } + | '[' file_NAME_list ']' + { + lang_add_wild (NULL, $2, ldgram_had_keep); + } + | wildcard_spec '(' file_NAME_list ')' + { + lang_add_wild (&$1, $3, ldgram_had_keep); + } + ; + +input_section_spec: + input_section_spec_no_keep + | KEEP '(' + { ldgram_had_keep = TRUE; } + input_section_spec_no_keep ')' + { ldgram_had_keep = FALSE; } + ; + +statement: + assignment end + | CREATE_OBJECT_SYMBOLS + { + lang_add_attribute(lang_object_symbols_statement_enum); + } + | ';' + | CONSTRUCTORS + { + + lang_add_attribute(lang_constructors_statement_enum); + } + | SORT '(' CONSTRUCTORS ')' + { + constructors_sorted = TRUE; + lang_add_attribute (lang_constructors_statement_enum); + } + | input_section_spec + | length '(' mustbe_exp ')' + { + lang_add_data ((int) $1, $3); + } + + | FILL '(' fill_exp ')' + { + lang_add_fill ($3); + } + ; + +statement_list: + statement_list statement + | statement + ; + +statement_list_opt: + /* empty */ + | statement_list + ; + +length: + QUAD + { $$ = $1; } + | SQUAD + { $$ = $1; } + | LONG + { $$ = $1; } + | SHORT + { $$ = $1; } + | BYTE + { $$ = $1; } + ; + +fill_exp: + mustbe_exp + { + $$ = exp_get_fill ($1, + 0, + "fill value", + lang_first_phase_enum); + } + ; + +fill_opt: + '=' fill_exp + { $$ = $2; } + | { $$ = (fill_type *) 0; } + ; + +assign_op: + PLUSEQ + { $$ = '+'; } + | MINUSEQ + { $$ = '-'; } + | MULTEQ + { $$ = '*'; } + | DIVEQ + { $$ = '/'; } + | LSHIFTEQ + { $$ = LSHIFT; } + | RSHIFTEQ + { $$ = RSHIFT; } + | ANDEQ + { $$ = '&'; } + | OREQ + { $$ = '|'; } + + ; + +end: ';' | ',' + ; + + +assignment: + NAME '=' mustbe_exp + { + lang_add_assignment (exp_assop ($2, $1, $3)); + } + | NAME assign_op mustbe_exp + { + lang_add_assignment (exp_assop ('=', $1, + exp_binop ($2, + exp_nameop (NAME, + $1), + $3))); + } + | PROVIDE '(' NAME '=' mustbe_exp ')' + { + lang_add_assignment (exp_provide ($3, $5)); + } + ; + + +opt_comma: + ',' | ; + + +memory: + MEMORY '{' memory_spec memory_spec_list '}' + ; + +memory_spec_list: + memory_spec_list memory_spec + | memory_spec_list ',' memory_spec + | + ; + + +memory_spec: NAME + { region = lang_memory_region_lookup($1); } + attributes_opt ':' + origin_spec opt_comma length_spec + {} + ; + +origin_spec: + ORIGIN '=' mustbe_exp + { region->current = + region->origin = + exp_get_vma($3, 0L,"origin", lang_first_phase_enum); +} + ; + +length_spec: + LENGTH '=' mustbe_exp + { region->length = exp_get_vma($3, + ~((bfd_vma)0), + "length", + lang_first_phase_enum); + } + ; + +attributes_opt: + /* empty */ + { /* dummy action to avoid bison 1.25 error message */ } + | '(' attributes_list ')' + ; + +attributes_list: + attributes_string + | attributes_list attributes_string + ; + +attributes_string: + NAME + { lang_set_flags (region, $1, 0); } + | '!' NAME + { lang_set_flags (region, $2, 1); } + ; + +startup: + STARTUP '(' filename ')' + { lang_startup($3); } + ; + +high_level_library: + HLL '(' high_level_library_NAME_list ')' + | HLL '(' ')' + { ldemul_hll((char *)NULL); } + ; + +high_level_library_NAME_list: + high_level_library_NAME_list opt_comma filename + { ldemul_hll($3); } + | filename + { ldemul_hll($1); } + + ; + +low_level_library: + SYSLIB '(' low_level_library_NAME_list ')' + ; low_level_library_NAME_list: + low_level_library_NAME_list opt_comma filename + { ldemul_syslib($3); } + | + ; + +floating_point_support: + FLOAT + { lang_float(TRUE); } + | NOFLOAT + { lang_float(FALSE); } + ; + +nocrossref_list: + /* empty */ + { + $$ = NULL; + } + | NAME nocrossref_list + { + struct lang_nocrossref *n; + + n = (struct lang_nocrossref *) xmalloc (sizeof *n); + n->name = $1; + n->next = $2; + $$ = n; + } + | NAME ',' nocrossref_list + { + struct lang_nocrossref *n; + + n = (struct lang_nocrossref *) xmalloc (sizeof *n); + n->name = $1; + n->next = $3; + $$ = n; + } + ; + +mustbe_exp: { ldlex_expression(); } + exp + { ldlex_popstate(); $$=$2;} + ; + +exp : + '-' exp %prec UNARY + { $$ = exp_unop('-', $2); } + | '(' exp ')' + { $$ = $2; } + | NEXT '(' exp ')' %prec UNARY + { $$ = exp_unop((int) $1,$3); } + | '!' exp %prec UNARY + { $$ = exp_unop('!', $2); } + | '+' exp %prec UNARY + { $$ = $2; } + | '~' exp %prec UNARY + { $$ = exp_unop('~', $2);} + + | exp '*' exp + { $$ = exp_binop('*', $1, $3); } + | exp '/' exp + { $$ = exp_binop('/', $1, $3); } + | exp '%' exp + { $$ = exp_binop('%', $1, $3); } + | exp '+' exp + { $$ = exp_binop('+', $1, $3); } + | exp '-' exp + { $$ = exp_binop('-' , $1, $3); } + | exp LSHIFT exp + { $$ = exp_binop(LSHIFT , $1, $3); } + | exp RSHIFT exp + { $$ = exp_binop(RSHIFT , $1, $3); } + | exp EQ exp + { $$ = exp_binop(EQ , $1, $3); } + | exp NE exp + { $$ = exp_binop(NE , $1, $3); } + | exp LE exp + { $$ = exp_binop(LE , $1, $3); } + | exp GE exp + { $$ = exp_binop(GE , $1, $3); } + | exp '<' exp + { $$ = exp_binop('<' , $1, $3); } + | exp '>' exp + { $$ = exp_binop('>' , $1, $3); } + | exp '&' exp + { $$ = exp_binop('&' , $1, $3); } + | exp '^' exp + { $$ = exp_binop('^' , $1, $3); } + | exp '|' exp + { $$ = exp_binop('|' , $1, $3); } + | exp '?' exp ':' exp + { $$ = exp_trinop('?' , $1, $3, $5); } + | exp ANDAND exp + { $$ = exp_binop(ANDAND , $1, $3); } + | exp OROR exp + { $$ = exp_binop(OROR , $1, $3); } + | DEFINED '(' NAME ')' + { $$ = exp_nameop(DEFINED, $3); } + | INT + { $$ = exp_bigintop ($1.integer, $1.str); } + | SIZEOF_HEADERS + { $$ = exp_nameop(SIZEOF_HEADERS,0); } + + | SIZEOF '(' NAME ')' + { $$ = exp_nameop(SIZEOF,$3); } + | ADDR '(' NAME ')' + { $$ = exp_nameop(ADDR,$3); } + | LOADADDR '(' NAME ')' + { $$ = exp_nameop(LOADADDR,$3); } + | ABSOLUTE '(' exp ')' + { $$ = exp_unop(ABSOLUTE, $3); } + | ALIGN_K '(' exp ')' + { $$ = exp_unop(ALIGN_K,$3); } + | DATA_SEGMENT_ALIGN '(' exp ',' exp ')' + { $$ = exp_binop (DATA_SEGMENT_ALIGN, $3, $5); } + | DATA_SEGMENT_END '(' exp ')' + { $$ = exp_unop(DATA_SEGMENT_END, $3); } + | BLOCK '(' exp ')' + { $$ = exp_unop(ALIGN_K,$3); } + | NAME + { $$ = exp_nameop(NAME,$1); } + | MAX_K '(' exp ',' exp ')' + { $$ = exp_binop (MAX_K, $3, $5 ); } + | MIN_K '(' exp ',' exp ')' + { $$ = exp_binop (MIN_K, $3, $5 ); } + | ASSERT_K '(' exp ',' NAME ')' + { $$ = exp_assert ($3, $5); } + ; + + +memspec_at_opt: + AT '>' NAME { $$ = $3; } + | { $$ = 0; } + ; + +opt_at: + AT '(' exp ')' { $$ = $3; } + | { $$ = 0; } + ; + +section: NAME { ldlex_expression(); } + opt_exp_with_type + opt_at { ldlex_popstate (); ldlex_script (); } + '{' + { + lang_enter_output_section_statement($1, $3, + sectype, + 0, 0, 0, $4); + } + statement_list_opt + '}' { ldlex_popstate (); ldlex_expression (); } + memspec_opt memspec_at_opt phdr_opt fill_opt + { + ldlex_popstate (); + lang_leave_output_section_statement ($14, $11, $13, $12); + } + opt_comma + {} + | OVERLAY + { ldlex_expression (); } + opt_exp_without_type opt_nocrossrefs opt_at + { ldlex_popstate (); ldlex_script (); } + '{' + { + lang_enter_overlay ($3); + } + overlay_section + '}' + { ldlex_popstate (); ldlex_expression (); } + memspec_opt memspec_at_opt phdr_opt fill_opt + { + ldlex_popstate (); + lang_leave_overlay ($5, (int) $4, + $15, $12, $14, $13); + } + opt_comma + | /* The GROUP case is just enough to support the gcc + svr3.ifile script. It is not intended to be full + support. I'm not even sure what GROUP is supposed + to mean. */ + GROUP { ldlex_expression (); } + opt_exp_with_type + { + ldlex_popstate (); + lang_add_assignment (exp_assop ('=', ".", $3)); + } + '{' sec_or_group_p1 '}' + ; + +type: + NOLOAD { sectype = noload_section; } + | DSECT { sectype = dsect_section; } + | COPY { sectype = copy_section; } + | INFO { sectype = info_section; } + | OVERLAY { sectype = overlay_section; } + ; + +atype: + '(' type ')' + | /* EMPTY */ { sectype = normal_section; } + | '(' ')' { sectype = normal_section; } + ; + +opt_exp_with_type: + exp atype ':' { $$ = $1; } + | atype ':' { $$ = (etree_type *)NULL; } + | /* The BIND cases are to support the gcc svr3.ifile + script. They aren't intended to implement full + support for the BIND keyword. I'm not even sure + what BIND is supposed to mean. */ + BIND '(' exp ')' atype ':' { $$ = $3; } + | BIND '(' exp ')' BLOCK '(' exp ')' atype ':' + { $$ = $3; } + ; + +opt_exp_without_type: + exp ':' { $$ = $1; } + | ':' { $$ = (etree_type *) NULL; } + ; + +opt_nocrossrefs: + /* empty */ + { $$ = 0; } + | NOCROSSREFS + { $$ = 1; } + ; + +memspec_opt: + '>' NAME + { $$ = $2; } + | { $$ = "*default*"; } + ; + +phdr_opt: + /* empty */ + { + $$ = NULL; + } + | phdr_opt ':' NAME + { + struct lang_output_section_phdr_list *n; + + n = ((struct lang_output_section_phdr_list *) + xmalloc (sizeof *n)); + n->name = $3; + n->used = FALSE; + n->next = $1; + $$ = n; + } + ; + +overlay_section: + /* empty */ + | overlay_section + NAME + { + ldlex_script (); + lang_enter_overlay_section ($2); + } + '{' statement_list_opt '}' + { ldlex_popstate (); ldlex_expression (); } + phdr_opt fill_opt + { + ldlex_popstate (); + lang_leave_overlay_section ($9, $8); + } + opt_comma + ; + +phdrs: + PHDRS '{' phdr_list '}' + ; + +phdr_list: + /* empty */ + | phdr_list phdr + ; + +phdr: + NAME { ldlex_expression (); } + phdr_type phdr_qualifiers { ldlex_popstate (); } + ';' + { + lang_new_phdr ($1, $3, $4.filehdr, $4.phdrs, $4.at, + $4.flags); + } + ; + +phdr_type: + exp + { + $$ = $1; + + if ($1->type.node_class == etree_name + && $1->type.node_code == NAME) + { + const char *s; + unsigned int i; + static const char * const phdr_types[] = + { + "PT_NULL", "PT_LOAD", "PT_DYNAMIC", + "PT_INTERP", "PT_NOTE", "PT_SHLIB", + "PT_PHDR", "PT_TLS" + }; + + s = $1->name.name; + for (i = 0; + i < sizeof phdr_types / sizeof phdr_types[0]; + i++) + if (strcmp (s, phdr_types[i]) == 0) + { + $$ = exp_intop (i); + break; + } + if (i == sizeof phdr_types / sizeof phdr_types[0]) + { + if (strcmp (s, "PT_GNU_EH_FRAME") == 0) + $$ = exp_intop (0x6474e550); + else + { + einfo (_("\ +%X%P:%S: unknown phdr type `%s' (try integer literal)\n"), + s); + $$ = exp_intop (0); + } + } + } + } + ; + +phdr_qualifiers: + /* empty */ + { + memset (&$$, 0, sizeof (struct phdr_info)); + } + | NAME phdr_val phdr_qualifiers + { + $$ = $3; + if (strcmp ($1, "FILEHDR") == 0 && $2 == NULL) + $$.filehdr = TRUE; + else if (strcmp ($1, "PHDRS") == 0 && $2 == NULL) + $$.phdrs = TRUE; + else if (strcmp ($1, "FLAGS") == 0 && $2 != NULL) + $$.flags = $2; + else + einfo (_("%X%P:%S: PHDRS syntax error at `%s'\n"), $1); + } + | AT '(' exp ')' phdr_qualifiers + { + $$ = $5; + $$.at = $3; + } + ; + +phdr_val: + /* empty */ + { + $$ = NULL; + } + | '(' exp ')' + { + $$ = $2; + } + ; + +/* This syntax is used within an external version script file. */ + +version_script_file: + { + ldlex_version_file (); + PUSH_ERROR (_("VERSION script")); + } + vers_nodes + { + ldlex_popstate (); + POP_ERROR (); + } + ; + +/* This is used within a normal linker script file. */ + +version: + { + ldlex_version_script (); + } + VERSIONK '{' vers_nodes '}' + { + ldlex_popstate (); + } + ; + +vers_nodes: + vers_node + | vers_nodes vers_node + ; + +vers_node: + '{' vers_tag '}' ';' + { + lang_register_vers_node (NULL, $2, NULL); + } + | VERS_TAG '{' vers_tag '}' ';' + { + lang_register_vers_node ($1, $3, NULL); + } + | VERS_TAG '{' vers_tag '}' verdep ';' + { + lang_register_vers_node ($1, $3, $5); + } + ; + +verdep: + VERS_TAG + { + $$ = lang_add_vers_depend (NULL, $1); + } + | verdep VERS_TAG + { + $$ = lang_add_vers_depend ($1, $2); + } + ; + +vers_tag: + /* empty */ + { + $$ = lang_new_vers_node (NULL, NULL); + } + | vers_defns ';' + { + $$ = lang_new_vers_node ($1, NULL); + } + | GLOBAL ':' vers_defns ';' + { + $$ = lang_new_vers_node ($3, NULL); + } + | LOCAL ':' vers_defns ';' + { + $$ = lang_new_vers_node (NULL, $3); + } + | GLOBAL ':' vers_defns ';' LOCAL ':' vers_defns ';' + { + $$ = lang_new_vers_node ($3, $7); + } + ; + +vers_defns: + VERS_IDENTIFIER + { + $$ = lang_new_vers_pattern (NULL, $1, ldgram_vers_current_lang); + } + | vers_defns ';' VERS_IDENTIFIER + { + $$ = lang_new_vers_pattern ($1, $3, ldgram_vers_current_lang); + } + | vers_defns ';' EXTERN NAME '{' + { + $$ = ldgram_vers_current_lang; + ldgram_vers_current_lang = $4; + } + vers_defns opt_semicolon '}' + { + $$ = $7; + ldgram_vers_current_lang = $6; + } + | EXTERN NAME '{' + { + $$ = ldgram_vers_current_lang; + ldgram_vers_current_lang = $2; + } + vers_defns opt_semicolon '}' + { + $$ = $5; + ldgram_vers_current_lang = $4; + } + ; + +opt_semicolon: + /* empty */ + | ';' + ; + +%% +void +yyerror(arg) + const char *arg; +{ + if (ldfile_assumed_script) + einfo (_("%P:%s: file format not recognized; treating as linker script\n"), + ldfile_input_filename); + if (error_index > 0 && error_index < ERROR_NAME_MAX) + einfo ("%P%F:%S: %s in %s\n", arg, error_names[error_index-1]); + else + einfo ("%P%F:%S: %s\n", arg); +} diff --git a/contrib/binutils-2.14/ld/ldlang.c b/contrib/binutils-2.14/ld/ldlang.c new file mode 100644 index 0000000000..884691702c --- /dev/null +++ b/contrib/binutils-2.14/ld/ldlang.c @@ -0,0 +1,5419 @@ +/* Linker command language support. + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GLD; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#include "bfd.h" +#include "sysdep.h" +#include "libiberty.h" +#include "safe-ctype.h" +#include "obstack.h" +#include "bfdlink.h" + +#include "ld.h" +#include "ldmain.h" +#include "ldexp.h" +#include "ldlang.h" +#include +#include "ldlex.h" +#include "ldmisc.h" +#include "ldctor.h" +#include "ldfile.h" +#include "ldemul.h" +#include "fnmatch.h" +#include "demangle.h" + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER)) +#endif + +/* Locals variables. */ +static struct obstack stat_obstack; + +#define obstack_chunk_alloc xmalloc +#define obstack_chunk_free free +static const char *startup_file; +static lang_statement_list_type input_file_chain; +static bfd_boolean placed_commons = FALSE; +static lang_output_section_statement_type *default_common_section; +static bfd_boolean map_option_f; +static bfd_vma print_dot; +static lang_input_statement_type *first_file; +static const char *current_target; +static const char *output_target; +static lang_statement_list_type statement_list; +static struct lang_phdr *lang_phdr_list; + +/* Forward declarations. */ +static lang_statement_union_type *new_statement + PARAMS ((enum statement_enum, size_t, lang_statement_list_type *)); +static void lang_for_each_statement_worker + PARAMS ((void (*) (lang_statement_union_type *), + lang_statement_union_type *)); +static lang_input_statement_type *new_afile + PARAMS ((const char *, lang_input_file_enum_type, const char *, + bfd_boolean)); +static lang_memory_region_type *lang_memory_default + PARAMS ((asection *)); +static void lang_map_flags + PARAMS ((flagword)); +static void init_os + PARAMS ((lang_output_section_statement_type *)); +static void exp_init_os + PARAMS ((etree_type *)); +static void section_already_linked + PARAMS ((bfd *, asection *, PTR)); +static struct bfd_hash_entry *already_linked_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static void already_linked_table_init + PARAMS ((void)); +static void already_linked_table_free + PARAMS ((void)); +static bfd_boolean wildcardp + PARAMS ((const char *)); +static lang_statement_union_type *wild_sort + PARAMS ((lang_wild_statement_type *, struct wildcard_list *, + lang_input_statement_type *, asection *)); +static void output_section_callback + PARAMS ((lang_wild_statement_type *, struct wildcard_list *, asection *, + lang_input_statement_type *, PTR)); +static lang_input_statement_type *lookup_name + PARAMS ((const char *)); +static bfd_boolean load_symbols + PARAMS ((lang_input_statement_type *, lang_statement_list_type *)); +static void wild + PARAMS ((lang_wild_statement_type *, + const char *, lang_output_section_statement_type *)); +static bfd *open_output + PARAMS ((const char *)); +static void ldlang_open_output + PARAMS ((lang_statement_union_type *)); +static void open_input_bfds + PARAMS ((lang_statement_union_type *, bfd_boolean)); +static void lang_reasonable_defaults + PARAMS ((void)); +static void insert_undefined + PARAMS ((const char *)); +static void lang_place_undefineds + PARAMS ((void)); +static void map_input_to_output_sections + PARAMS ((lang_statement_union_type *, const char *, + lang_output_section_statement_type *)); +static void strip_excluded_output_sections + PARAMS ((void)); +static void print_output_section_statement + PARAMS ((lang_output_section_statement_type *)); +static void print_assignment + PARAMS ((lang_assignment_statement_type *, + lang_output_section_statement_type *)); +static void print_input_statement + PARAMS ((lang_input_statement_type *)); +static bfd_boolean print_one_symbol + PARAMS ((struct bfd_link_hash_entry *, PTR)); +static void print_input_section + PARAMS ((lang_input_section_type *)); +static void print_fill_statement + PARAMS ((lang_fill_statement_type *)); +static void print_data_statement + PARAMS ((lang_data_statement_type *)); +static void print_address_statement + PARAMS ((lang_address_statement_type *)); +static void print_reloc_statement + PARAMS ((lang_reloc_statement_type *)); +static void print_padding_statement + PARAMS ((lang_padding_statement_type *)); +static void print_wild_statement + PARAMS ((lang_wild_statement_type *, lang_output_section_statement_type *)); +static void print_group + PARAMS ((lang_group_statement_type *, lang_output_section_statement_type *)); +static void print_statement + PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *)); +static void print_statement_list + PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *)); +static void print_statements + PARAMS ((void)); +static void insert_pad + PARAMS ((lang_statement_union_type **, fill_type *, + unsigned int, asection *, bfd_vma)); +static bfd_vma size_input_section + PARAMS ((lang_statement_union_type **, lang_output_section_statement_type *, + fill_type *, bfd_vma)); +static void lang_finish + PARAMS ((void)); +static void ignore_bfd_errors + PARAMS ((const char *, ...)); +static void lang_check + PARAMS ((void)); +static void lang_common + PARAMS ((void)); +static bfd_boolean lang_one_common + PARAMS ((struct bfd_link_hash_entry *, PTR)); +static void lang_place_orphans + PARAMS ((void)); +static int topower + PARAMS ((int)); +static void lang_set_startof + PARAMS ((void)); +static void gc_section_callback + PARAMS ((lang_wild_statement_type *, struct wildcard_list *, asection *, + lang_input_statement_type *, PTR)); +static void lang_get_regions + PARAMS ((struct memory_region_struct **, struct memory_region_struct **, + const char *, const char *, int)); +static void lang_record_phdrs + PARAMS ((void)); +static void lang_gc_wild + PARAMS ((lang_wild_statement_type *)); +static void lang_gc_sections_1 + PARAMS ((lang_statement_union_type *)); +static void lang_gc_sections + PARAMS ((void)); +static int lang_vers_match_lang_c + PARAMS ((struct bfd_elf_version_expr *, const char *)); +static int lang_vers_match_lang_cplusplus + PARAMS ((struct bfd_elf_version_expr *, const char *)); +static int lang_vers_match_lang_java + PARAMS ((struct bfd_elf_version_expr *, const char *)); +static void lang_do_version_exports_section + PARAMS ((void)); +static void lang_check_section_addresses + PARAMS ((void)); +static void os_region_check + PARAMS ((lang_output_section_statement_type *, + struct memory_region_struct *, etree_type *, bfd_vma)); +static bfd_vma lang_size_sections_1 + PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *, + lang_statement_union_type **, fill_type *, bfd_vma, bfd_boolean *, + bfd_boolean)); +typedef void (*callback_t) + PARAMS ((lang_wild_statement_type *, struct wildcard_list *, asection *, + lang_input_statement_type *, PTR)); +static void walk_wild + PARAMS ((lang_wild_statement_type *, callback_t, PTR)); +static void walk_wild_section + PARAMS ((lang_wild_statement_type *, lang_input_statement_type *, + callback_t, PTR)); +static void walk_wild_file + PARAMS ((lang_wild_statement_type *, lang_input_statement_type *, + callback_t, PTR)); +static int get_target + PARAMS ((const bfd_target *, PTR)); +static void stricpy + PARAMS ((char *, char *)); +static void strcut + PARAMS ((char *, char *)); +static int name_compare + PARAMS ((char *, char *)); +static int closest_target_match + PARAMS ((const bfd_target *, PTR)); +static char * get_first_input_target + PARAMS ((void)); + +/* Exported variables. */ +lang_output_section_statement_type *abs_output_section; +lang_statement_list_type lang_output_section_statement; +lang_statement_list_type *stat_ptr = &statement_list; +lang_statement_list_type file_chain = { NULL, NULL }; +struct bfd_sym_chain entry_symbol = { NULL, NULL }; +const char *entry_section = ".text"; +bfd_boolean entry_from_cmdline; +bfd_boolean lang_has_input_file = FALSE; +bfd_boolean had_output_filename = FALSE; +bfd_boolean lang_float_flag = FALSE; +bfd_boolean delete_output_file_on_failure = FALSE; +struct lang_nocrossrefs *nocrossref_list; +struct unique_sections *unique_section_list; +static bfd_boolean ldlang_sysrooted_script = FALSE; + +etree_type *base; /* Relocation base - or null */ + +#if defined (__STDC__) || defined (ALMOST_STDC) +#define cat(a,b) a##b +#else +#define cat(a,b) a/**/b +#endif + +/* Don't beautify the line below with "innocent" whitespace, it breaks + the K&R C preprocessor! */ +#define new_stat(x, y) \ + (cat (x,_type)*) new_statement (cat (x,_enum), sizeof (cat (x,_type)), y) + +#define outside_section_address(q) \ + ((q)->output_offset + (q)->output_section->vma) + +#define outside_symbol_address(q) \ + ((q)->value + outside_section_address (q->section)) + +#define SECTION_NAME_MAP_LENGTH (16) + +PTR +stat_alloc (size) + size_t size; +{ + return obstack_alloc (&stat_obstack, size); +} + +bfd_boolean +unique_section_p (secnam) + const char *secnam; +{ + struct unique_sections *unam; + + for (unam = unique_section_list; unam; unam = unam->next) + if (wildcardp (unam->name) + ? fnmatch (unam->name, secnam, 0) == 0 + : strcmp (unam->name, secnam) == 0) + { + return TRUE; + } + + return FALSE; +} + +/* Generic traversal routines for finding matching sections. */ + +static void +walk_wild_section (ptr, file, callback, data) + lang_wild_statement_type *ptr; + lang_input_statement_type *file; + callback_t callback; + PTR data; +{ + asection *s; + + if (file->just_syms_flag) + return; + + for (s = file->the_bfd->sections; s != NULL; s = s->next) + { + struct wildcard_list *sec; + + sec = ptr->section_list; + if (sec == NULL) + (*callback) (ptr, sec, s, file, data); + + while (sec != NULL) + { + bfd_boolean skip = FALSE; + struct name_list *list_tmp; + + /* Don't process sections from files which were + excluded. */ + for (list_tmp = sec->spec.exclude_name_list; + list_tmp; + list_tmp = list_tmp->next) + { + if (wildcardp (list_tmp->name)) + skip = fnmatch (list_tmp->name, file->filename, 0) == 0; + else + skip = strcmp (list_tmp->name, file->filename) == 0; + + /* If this file is part of an archive, and the archive is + excluded, exclude this file. */ + if (! skip && file->the_bfd != NULL + && file->the_bfd->my_archive != NULL + && file->the_bfd->my_archive->filename != NULL) + { + if (wildcardp (list_tmp->name)) + skip = fnmatch (list_tmp->name, + file->the_bfd->my_archive->filename, + 0) == 0; + else + skip = strcmp (list_tmp->name, + file->the_bfd->my_archive->filename) == 0; + } + + if (skip) + break; + } + + if (!skip && sec->spec.name != NULL) + { + const char *sname = bfd_get_section_name (file->the_bfd, s); + + if (wildcardp (sec->spec.name)) + skip = fnmatch (sec->spec.name, sname, 0) != 0; + else + skip = strcmp (sec->spec.name, sname) != 0; + } + + if (!skip) + (*callback) (ptr, sec, s, file, data); + + sec = sec->next; + } + } +} + +/* Handle a wild statement for a single file F. */ + +static void +walk_wild_file (s, f, callback, data) + lang_wild_statement_type *s; + lang_input_statement_type *f; + callback_t callback; + PTR data; +{ + if (f->the_bfd == NULL + || ! bfd_check_format (f->the_bfd, bfd_archive)) + walk_wild_section (s, f, callback, data); + else + { + bfd *member; + + /* This is an archive file. We must map each member of the + archive separately. */ + member = bfd_openr_next_archived_file (f->the_bfd, (bfd *) NULL); + while (member != NULL) + { + /* When lookup_name is called, it will call the add_symbols + entry point for the archive. For each element of the + archive which is included, BFD will call ldlang_add_file, + which will set the usrdata field of the member to the + lang_input_statement. */ + if (member->usrdata != NULL) + { + walk_wild_section (s, + (lang_input_statement_type *) member->usrdata, + callback, data); + } + + member = bfd_openr_next_archived_file (f->the_bfd, member); + } + } +} + +static void +walk_wild (s, callback, data) + lang_wild_statement_type *s; + callback_t callback; + PTR data; +{ + const char *file_spec = s->filename; + + if (file_spec == NULL) + { + /* Perform the iteration over all files in the list. */ + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + walk_wild_file (s, f, callback, data); + } + } + else if (wildcardp (file_spec)) + { + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + if (fnmatch (file_spec, f->filename, FNM_FILE_NAME) == 0) + walk_wild_file (s, f, callback, data); + } + } + else + { + lang_input_statement_type *f; + + /* Perform the iteration over a single file. */ + f = lookup_name (file_spec); + if (f) + walk_wild_file (s, f, callback, data); + } +} + +/* lang_for_each_statement walks the parse tree and calls the provided + function for each node. */ + +static void +lang_for_each_statement_worker (func, s) + void (*func) PARAMS ((lang_statement_union_type *)); + lang_statement_union_type *s; +{ + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) + { + func (s); + + switch (s->header.type) + { + case lang_constructors_statement_enum: + lang_for_each_statement_worker (func, constructor_list.head); + break; + case lang_output_section_statement_enum: + lang_for_each_statement_worker + (func, + s->output_section_statement.children.head); + break; + case lang_wild_statement_enum: + lang_for_each_statement_worker + (func, + s->wild_statement.children.head); + break; + case lang_group_statement_enum: + lang_for_each_statement_worker (func, + s->group_statement.children.head); + break; + case lang_data_statement_enum: + case lang_reloc_statement_enum: + case lang_object_symbols_statement_enum: + case lang_output_statement_enum: + case lang_target_statement_enum: + case lang_input_section_enum: + case lang_input_statement_enum: + case lang_assignment_statement_enum: + case lang_padding_statement_enum: + case lang_address_statement_enum: + case lang_fill_statement_enum: + break; + default: + FAIL (); + break; + } + } +} + +void +lang_for_each_statement (func) + void (*func) PARAMS ((lang_statement_union_type *)); +{ + lang_for_each_statement_worker (func, statement_list.head); +} + +/*----------------------------------------------------------------------*/ + +void +lang_list_init (list) + lang_statement_list_type *list; +{ + list->head = (lang_statement_union_type *) NULL; + list->tail = &list->head; +} + +/* Build a new statement node for the parse tree. */ + +static lang_statement_union_type * +new_statement (type, size, list) + enum statement_enum type; + size_t size; + lang_statement_list_type *list; +{ + lang_statement_union_type *new = (lang_statement_union_type *) + stat_alloc (size); + + new->header.type = type; + new->header.next = (lang_statement_union_type *) NULL; + lang_statement_append (list, new, &new->header.next); + return new; +} + +/* Build a new input file node for the language. There are several + ways in which we treat an input file, eg, we only look at symbols, + or prefix it with a -l etc. + + We can be supplied with requests for input files more than once; + they may, for example be split over several lines like foo.o(.text) + foo.o(.data) etc, so when asked for a file we check that we haven't + got it already so we don't duplicate the bfd. */ + +static lang_input_statement_type * +new_afile (name, file_type, target, add_to_list) + const char *name; + lang_input_file_enum_type file_type; + const char *target; + bfd_boolean add_to_list; +{ + lang_input_statement_type *p; + + if (add_to_list) + p = new_stat (lang_input_statement, stat_ptr); + else + { + p = ((lang_input_statement_type *) + stat_alloc (sizeof (lang_input_statement_type))); + p->header.next = NULL; + } + + lang_has_input_file = TRUE; + p->target = target; + p->sysrooted = FALSE; + switch (file_type) + { + case lang_input_file_is_symbols_only_enum: + p->filename = name; + p->is_archive = FALSE; + p->real = TRUE; + p->local_sym_name = name; + p->just_syms_flag = TRUE; + p->search_dirs_flag = FALSE; + break; + case lang_input_file_is_fake_enum: + p->filename = name; + p->is_archive = FALSE; + p->real = FALSE; + p->local_sym_name = name; + p->just_syms_flag = FALSE; + p->search_dirs_flag = FALSE; + break; + case lang_input_file_is_l_enum: + p->is_archive = TRUE; + p->filename = name; + p->real = TRUE; + p->local_sym_name = concat ("-l", name, (const char *) NULL); + p->just_syms_flag = FALSE; + p->search_dirs_flag = TRUE; + break; + case lang_input_file_is_marker_enum: + p->filename = name; + p->is_archive = FALSE; + p->real = FALSE; + p->local_sym_name = name; + p->just_syms_flag = FALSE; + p->search_dirs_flag = TRUE; + break; + case lang_input_file_is_search_file_enum: + p->sysrooted = ldlang_sysrooted_script; + p->filename = name; + p->is_archive = FALSE; + p->real = TRUE; + p->local_sym_name = name; + p->just_syms_flag = FALSE; + p->search_dirs_flag = TRUE; + break; + case lang_input_file_is_file_enum: + p->filename = name; + p->is_archive = FALSE; + p->real = TRUE; + p->local_sym_name = name; + p->just_syms_flag = FALSE; + p->search_dirs_flag = FALSE; + break; + default: + FAIL (); + } + p->the_bfd = (bfd *) NULL; + p->asymbols = (asymbol **) NULL; + p->next_real_file = (lang_statement_union_type *) NULL; + p->next = (lang_statement_union_type *) NULL; + p->symbol_count = 0; + p->dynamic = config.dynamic_link; + p->whole_archive = whole_archive; + p->loaded = FALSE; + lang_statement_append (&input_file_chain, + (lang_statement_union_type *) p, + &p->next_real_file); + return p; +} + +lang_input_statement_type * +lang_add_input_file (name, file_type, target) + const char *name; + lang_input_file_enum_type file_type; + const char *target; +{ + lang_has_input_file = TRUE; + return new_afile (name, file_type, target, TRUE); +} + +/* Build enough state so that the parser can build its tree. */ + +void +lang_init () +{ + obstack_begin (&stat_obstack, 1000); + + stat_ptr = &statement_list; + + lang_list_init (stat_ptr); + + lang_list_init (&input_file_chain); + lang_list_init (&lang_output_section_statement); + lang_list_init (&file_chain); + first_file = lang_add_input_file ((char *) NULL, + lang_input_file_is_marker_enum, + (char *) NULL); + abs_output_section = + lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME); + + abs_output_section->bfd_section = bfd_abs_section_ptr; + +} + +/*---------------------------------------------------------------------- + A region is an area of memory declared with the + MEMORY { name:org=exp, len=exp ... } + syntax. + + We maintain a list of all the regions here. + + If no regions are specified in the script, then the default is used + which is created when looked up to be the entire data space. */ + +static lang_memory_region_type *lang_memory_region_list; +static lang_memory_region_type **lang_memory_region_list_tail = &lang_memory_region_list; + +lang_memory_region_type * +lang_memory_region_lookup (name) + const char *const name; +{ + lang_memory_region_type *p; + + /* NAME is NULL for LMA memspecs if no region was specified. */ + if (name == NULL) + return NULL; + + for (p = lang_memory_region_list; + p != (lang_memory_region_type *) NULL; + p = p->next) + { + if (strcmp (p->name, name) == 0) + { + return p; + } + } + +#if 0 + /* This code used to always use the first region in the list as the + default region. I changed it to instead use a region + encompassing all of memory as the default region. This permits + NOLOAD sections to work reasonably without requiring a region. + People should specify what region they mean, if they really want + a region. */ + if (strcmp (name, "*default*") == 0) + { + if (lang_memory_region_list != (lang_memory_region_type *) NULL) + { + return lang_memory_region_list; + } + } +#endif + + { + lang_memory_region_type *new = + (lang_memory_region_type *) stat_alloc (sizeof (lang_memory_region_type)); + + new->name = xstrdup (name); + new->next = (lang_memory_region_type *) NULL; + + *lang_memory_region_list_tail = new; + lang_memory_region_list_tail = &new->next; + new->origin = 0; + new->flags = 0; + new->not_flags = 0; + new->length = ~(bfd_size_type) 0; + new->current = 0; + new->had_full_message = FALSE; + + return new; + } +} + +static lang_memory_region_type * +lang_memory_default (section) + asection *section; +{ + lang_memory_region_type *p; + + flagword sec_flags = section->flags; + + /* Override SEC_DATA to mean a writable section. */ + if ((sec_flags & (SEC_ALLOC | SEC_READONLY | SEC_CODE)) == SEC_ALLOC) + sec_flags |= SEC_DATA; + + for (p = lang_memory_region_list; + p != (lang_memory_region_type *) NULL; + p = p->next) + { + if ((p->flags & sec_flags) != 0 + && (p->not_flags & sec_flags) == 0) + { + return p; + } + } + return lang_memory_region_lookup ("*default*"); +} + +lang_output_section_statement_type * +lang_output_section_find (name) + const char *const name; +{ + lang_statement_union_type *u; + lang_output_section_statement_type *lookup; + + for (u = lang_output_section_statement.head; + u != (lang_statement_union_type *) NULL; + u = lookup->next) + { + lookup = &u->output_section_statement; + if (strcmp (name, lookup->name) == 0) + { + return lookup; + } + } + return (lang_output_section_statement_type *) NULL; +} + +lang_output_section_statement_type * +lang_output_section_statement_lookup (name) + const char *const name; +{ + lang_output_section_statement_type *lookup; + + lookup = lang_output_section_find (name); + if (lookup == (lang_output_section_statement_type *) NULL) + { + + lookup = (lang_output_section_statement_type *) + new_stat (lang_output_section_statement, stat_ptr); + lookup->region = (lang_memory_region_type *) NULL; + lookup->lma_region = (lang_memory_region_type *) NULL; + lookup->fill = (fill_type *) 0; + lookup->block_value = 1; + lookup->name = name; + + lookup->next = (lang_statement_union_type *) NULL; + lookup->bfd_section = (asection *) NULL; + lookup->processed = FALSE; + lookup->sectype = normal_section; + lookup->addr_tree = (etree_type *) NULL; + lang_list_init (&lookup->children); + + lookup->memspec = (const char *) NULL; + lookup->flags = 0; + lookup->subsection_alignment = -1; + lookup->section_alignment = -1; + lookup->load_base = (union etree_union *) NULL; + lookup->update_dot_tree = NULL; + lookup->phdrs = NULL; + + lang_statement_append (&lang_output_section_statement, + (lang_statement_union_type *) lookup, + &lookup->next); + } + return lookup; +} + +static void +lang_map_flags (flag) + flagword flag; +{ + if (flag & SEC_ALLOC) + minfo ("a"); + + if (flag & SEC_CODE) + minfo ("x"); + + if (flag & SEC_READONLY) + minfo ("r"); + + if (flag & SEC_DATA) + minfo ("w"); + + if (flag & SEC_LOAD) + minfo ("l"); +} + +void +lang_map () +{ + lang_memory_region_type *m; + + minfo (_("\nMemory Configuration\n\n")); + fprintf (config.map_file, "%-16s %-18s %-18s %s\n", + _("Name"), _("Origin"), _("Length"), _("Attributes")); + + for (m = lang_memory_region_list; + m != (lang_memory_region_type *) NULL; + m = m->next) + { + char buf[100]; + int len; + + fprintf (config.map_file, "%-16s ", m->name); + + sprintf_vma (buf, m->origin); + minfo ("0x%s ", buf); + len = strlen (buf); + while (len < 16) + { + print_space (); + ++len; + } + + minfo ("0x%V", m->length); + if (m->flags || m->not_flags) + { +#ifndef BFD64 + minfo (" "); +#endif + if (m->flags) + { + print_space (); + lang_map_flags (m->flags); + } + + if (m->not_flags) + { + minfo (" !"); + lang_map_flags (m->not_flags); + } + } + + print_nl (); + } + + fprintf (config.map_file, _("\nLinker script and memory map\n\n")); + + print_statements (); +} + +/* Initialize an output section. */ + +static void +init_os (s) + lang_output_section_statement_type *s; +{ + section_userdata_type *new; + + if (s->bfd_section != NULL) + return; + + if (strcmp (s->name, DISCARD_SECTION_NAME) == 0) + einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME); + + new = ((section_userdata_type *) + stat_alloc (sizeof (section_userdata_type))); + + s->bfd_section = bfd_get_section_by_name (output_bfd, s->name); + if (s->bfd_section == (asection *) NULL) + s->bfd_section = bfd_make_section (output_bfd, s->name); + if (s->bfd_section == (asection *) NULL) + { + einfo (_("%P%F: output format %s cannot represent section called %s\n"), + output_bfd->xvec->name, s->name); + } + s->bfd_section->output_section = s->bfd_section; + + /* We initialize an output sections output offset to minus its own + vma to allow us to output a section through itself. */ + s->bfd_section->output_offset = 0; + get_userdata (s->bfd_section) = (PTR) new; + + /* If there is a base address, make sure that any sections it might + mention are initialized. */ + if (s->addr_tree != NULL) + exp_init_os (s->addr_tree); + + if (s->load_base != NULL) + exp_init_os (s->load_base); +} + +/* Make sure that all output sections mentioned in an expression are + initialized. */ + +static void +exp_init_os (exp) + etree_type *exp; +{ + switch (exp->type.node_class) + { + case etree_assign: + exp_init_os (exp->assign.src); + break; + + case etree_binary: + exp_init_os (exp->binary.lhs); + exp_init_os (exp->binary.rhs); + break; + + case etree_trinary: + exp_init_os (exp->trinary.cond); + exp_init_os (exp->trinary.lhs); + exp_init_os (exp->trinary.rhs); + break; + + case etree_unary: + exp_init_os (exp->unary.child); + break; + + case etree_name: + switch (exp->type.node_code) + { + case ADDR: + case LOADADDR: + case SIZEOF: + { + lang_output_section_statement_type *os; + + os = lang_output_section_find (exp->name.name); + if (os != NULL && os->bfd_section == NULL) + init_os (os); + } + } + break; + + default: + break; + } +} + +/* Sections marked with the SEC_LINK_ONCE flag should only be linked + once into the output. This routine checks each section, and + arrange to discard it if a section of the same name has already + been linked. If the section has COMDAT information, then it uses + that to decide whether the section should be included. This code + assumes that all relevant sections have the SEC_LINK_ONCE flag set; + that is, it does not depend solely upon the section name. + section_already_linked is called via bfd_map_over_sections. */ + +/* This is the shape of the elements inside the already_linked hash + table. It maps a name onto a list of already_linked elements with + the same name. It's possible to get more than one element in a + list if the COMDAT sections have different names. */ + +struct already_linked_hash_entry +{ + struct bfd_hash_entry root; + struct already_linked *entry; +}; + +struct already_linked +{ + struct already_linked *next; + asection *sec; +}; + +/* The hash table. */ + +static struct bfd_hash_table already_linked_table; + +static void +section_already_linked (abfd, sec, data) + bfd *abfd; + asection *sec; + PTR data; +{ + lang_input_statement_type *entry = (lang_input_statement_type *) data; + flagword flags; + const char *name; + struct already_linked *l; + struct already_linked_hash_entry *already_linked_list; + + /* If we are only reading symbols from this object, then we want to + discard all sections. */ + if (entry->just_syms_flag) + { + bfd_link_just_syms (sec, &link_info); + return; + } + + flags = bfd_get_section_flags (abfd, sec); + + if ((flags & SEC_LINK_ONCE) == 0) + return; + + /* FIXME: When doing a relocatable link, we may have trouble + copying relocations in other sections that refer to local symbols + in the section being discarded. Those relocations will have to + be converted somehow; as of this writing I'm not sure that any of + the backends handle that correctly. + + It is tempting to instead not discard link once sections when + doing a relocatable link (technically, they should be discarded + whenever we are building constructors). However, that fails, + because the linker winds up combining all the link once sections + into a single large link once section, which defeats the purpose + of having link once sections in the first place. + + Also, not merging link once sections in a relocatable link + causes trouble for MIPS ELF, which relies on link once semantics + to handle the .reginfo section correctly. */ + + name = bfd_get_section_name (abfd, sec); + + already_linked_list = + ((struct already_linked_hash_entry *) + bfd_hash_lookup (&already_linked_table, name, TRUE, FALSE)); + + for (l = already_linked_list->entry; l != NULL; l = l->next) + { + if (sec->comdat == NULL + || l->sec->comdat == NULL + || strcmp (sec->comdat->name, l->sec->comdat->name) == 0) + { + /* The section has already been linked. See if we should + issue a warning. */ + switch (flags & SEC_LINK_DUPLICATES) + { + default: + abort (); + + case SEC_LINK_DUPLICATES_DISCARD: + break; + + case SEC_LINK_DUPLICATES_ONE_ONLY: + if (sec->comdat == NULL) + einfo (_("%P: %B: warning: ignoring duplicate section `%s'\n"), + abfd, name); + else + einfo (_("%P: %B: warning: ignoring duplicate `%s' section symbol `%s'\n"), + abfd, name, sec->comdat->name); + break; + + case SEC_LINK_DUPLICATES_SAME_CONTENTS: + /* FIXME: We should really dig out the contents of both + sections and memcmp them. The COFF/PE spec says that + the Microsoft linker does not implement this + correctly, so I'm not going to bother doing it + either. */ + /* Fall through. */ + case SEC_LINK_DUPLICATES_SAME_SIZE: + if (bfd_section_size (abfd, sec) + != bfd_section_size (l->sec->owner, l->sec)) + einfo (_("%P: %B: warning: duplicate section `%s' has different size\n"), + abfd, name); + break; + } + + /* Set the output_section field so that lang_add_section + does not create a lang_input_section structure for this + section. */ + sec->output_section = bfd_abs_section_ptr; + + if (flags & SEC_GROUP) + bfd_discard_group (abfd, sec); + + return; + } + } + + /* This is the first section with this name. Record it. Allocate + the memory from the same obstack as the hash table is kept in. */ + + l = ((struct already_linked *) + bfd_hash_allocate (&already_linked_table, sizeof *l)); + + l->sec = sec; + l->next = already_linked_list->entry; + already_linked_list->entry = l; +} + +/* Support routines for the hash table used by section_already_linked, + initialize the table, fill in an entry and remove the table. */ + +static struct bfd_hash_entry * +already_linked_newfunc (entry, table, string) + struct bfd_hash_entry *entry ATTRIBUTE_UNUSED; + struct bfd_hash_table *table; + const char *string ATTRIBUTE_UNUSED; +{ + struct already_linked_hash_entry *ret = + bfd_hash_allocate (table, sizeof (struct already_linked_hash_entry)); + + ret->entry = NULL; + + return (struct bfd_hash_entry *) ret; +} + +static void +already_linked_table_init () +{ + if (! bfd_hash_table_init_n (&already_linked_table, + already_linked_newfunc, + 42)) + einfo (_("%P%F: Failed to create hash table\n")); +} + +static void +already_linked_table_free () +{ + bfd_hash_table_free (&already_linked_table); +} + +/* The wild routines. + + These expand statements like *(.text) and foo.o to a list of + explicit actions, like foo.o(.text), bar.o(.text) and + foo.o(.text, .data). */ + +/* Return TRUE if the PATTERN argument is a wildcard pattern. + Although backslashes are treated specially if a pattern contains + wildcards, we do not consider the mere presence of a backslash to + be enough to cause the pattern to be treated as a wildcard. + That lets us handle DOS filenames more naturally. */ + +static bfd_boolean +wildcardp (pattern) + const char *pattern; +{ + const char *s; + + for (s = pattern; *s != '\0'; ++s) + if (*s == '?' + || *s == '*' + || *s == '[') + return TRUE; + return FALSE; +} + +/* Add SECTION to the output section OUTPUT. Do this by creating a + lang_input_section statement which is placed at PTR. FILE is the + input file which holds SECTION. */ + +void +lang_add_section (ptr, section, output, file) + lang_statement_list_type *ptr; + asection *section; + lang_output_section_statement_type *output; + lang_input_statement_type *file; +{ + flagword flags; + bfd_boolean discard; + + flags = bfd_get_section_flags (section->owner, section); + + discard = FALSE; + + /* Discard sections marked with SEC_EXCLUDE if we are doing a final + link. Discard debugging sections marked with SEC_EXCLUDE on a + relocatable link too. */ + if ((flags & SEC_EXCLUDE) != 0 + && ((flags & SEC_DEBUGGING) != 0 || !link_info.relocateable)) + discard = TRUE; + + /* Discard input sections which are assigned to a section named + DISCARD_SECTION_NAME. */ + if (strcmp (output->name, DISCARD_SECTION_NAME) == 0) + discard = TRUE; + + /* Discard debugging sections if we are stripping debugging + information. */ + if ((link_info.strip == strip_debugger || link_info.strip == strip_all) + && (flags & SEC_DEBUGGING) != 0) + discard = TRUE; + + if (discard) + { + if (section->output_section == NULL) + { + /* This prevents future calls from assigning this section. */ + section->output_section = bfd_abs_section_ptr; + } + return; + } + + if (section->output_section == NULL) + { + bfd_boolean first; + lang_input_section_type *new; + flagword flags; + + if (output->bfd_section == NULL) + init_os (output); + + first = ! output->bfd_section->linker_has_input; + output->bfd_section->linker_has_input = 1; + + /* Add a section reference to the list. */ + new = new_stat (lang_input_section, ptr); + + new->section = section; + new->ifile = file; + section->output_section = output->bfd_section; + + flags = section->flags; + + /* We don't copy the SEC_NEVER_LOAD flag from an input section + to an output section, because we want to be able to include a + SEC_NEVER_LOAD section in the middle of an otherwise loaded + section (I don't know why we want to do this, but we do). + build_link_order in ldwrite.c handles this case by turning + the embedded SEC_NEVER_LOAD section into a fill. */ + + flags &= ~ SEC_NEVER_LOAD; + + /* If final link, don't copy the SEC_LINK_ONCE flags, they've + already been processed. One reason to do this is that on pe + format targets, .text$foo sections go into .text and it's odd + to see .text with SEC_LINK_ONCE set. */ + + if (! link_info.relocateable) + flags &= ~ (SEC_LINK_ONCE | SEC_LINK_DUPLICATES); + + /* If this is not the first input section, and the SEC_READONLY + flag is not currently set, then don't set it just because the + input section has it set. */ + + if (! first && (section->output_section->flags & SEC_READONLY) == 0) + flags &= ~ SEC_READONLY; + + /* Keep SEC_MERGE and SEC_STRINGS only if they are the same. */ + if (! first + && ((section->output_section->flags & (SEC_MERGE | SEC_STRINGS)) + != (flags & (SEC_MERGE | SEC_STRINGS)) + || ((flags & SEC_MERGE) + && section->output_section->entsize != section->entsize))) + { + section->output_section->flags &= ~ (SEC_MERGE | SEC_STRINGS); + flags &= ~ (SEC_MERGE | SEC_STRINGS); + } + + /* For now make .tbss normal section. */ + if ((flags & SEC_THREAD_LOCAL) && ! link_info.relocateable) + flags |= SEC_LOAD; + + section->output_section->flags |= flags; + + if (flags & SEC_MERGE) + section->output_section->entsize = section->entsize; + + /* If SEC_READONLY is not set in the input section, then clear + it from the output section. */ + if ((section->flags & SEC_READONLY) == 0) + section->output_section->flags &= ~SEC_READONLY; + + switch (output->sectype) + { + case normal_section: + break; + case dsect_section: + case copy_section: + case info_section: + case overlay_section: + output->bfd_section->flags &= ~SEC_ALLOC; + break; + case noload_section: + output->bfd_section->flags &= ~SEC_LOAD; + output->bfd_section->flags |= SEC_NEVER_LOAD; + break; + } + + /* Copy over SEC_SMALL_DATA. */ + if (section->flags & SEC_SMALL_DATA) + section->output_section->flags |= SEC_SMALL_DATA; + + if (section->alignment_power > output->bfd_section->alignment_power) + output->bfd_section->alignment_power = section->alignment_power; + + /* If supplied an alignment, then force it. */ + if (output->section_alignment != -1) + output->bfd_section->alignment_power = output->section_alignment; + + if (section->flags & SEC_BLOCK) + { + section->output_section->flags |= SEC_BLOCK; + /* FIXME: This value should really be obtained from the bfd... */ + output->block_value = 128; + } + } +} + +/* Handle wildcard sorting. This returns the lang_input_section which + should follow the one we are going to create for SECTION and FILE, + based on the sorting requirements of WILD. It returns NULL if the + new section should just go at the end of the current list. */ + +static lang_statement_union_type * +wild_sort (wild, sec, file, section) + lang_wild_statement_type *wild; + struct wildcard_list *sec; + lang_input_statement_type *file; + asection *section; +{ + const char *section_name; + lang_statement_union_type *l; + + if (!wild->filenames_sorted && (sec == NULL || !sec->spec.sorted)) + return NULL; + + section_name = bfd_get_section_name (file->the_bfd, section); + for (l = wild->children.head; l != NULL; l = l->header.next) + { + lang_input_section_type *ls; + + if (l->header.type != lang_input_section_enum) + continue; + ls = &l->input_section; + + /* Sorting by filename takes precedence over sorting by section + name. */ + + if (wild->filenames_sorted) + { + const char *fn, *ln; + bfd_boolean fa, la; + int i; + + /* The PE support for the .idata section as generated by + dlltool assumes that files will be sorted by the name of + the archive and then the name of the file within the + archive. */ + + if (file->the_bfd != NULL + && bfd_my_archive (file->the_bfd) != NULL) + { + fn = bfd_get_filename (bfd_my_archive (file->the_bfd)); + fa = TRUE; + } + else + { + fn = file->filename; + fa = FALSE; + } + + if (ls->ifile->the_bfd != NULL + && bfd_my_archive (ls->ifile->the_bfd) != NULL) + { + ln = bfd_get_filename (bfd_my_archive (ls->ifile->the_bfd)); + la = TRUE; + } + else + { + ln = ls->ifile->filename; + la = FALSE; + } + + i = strcmp (fn, ln); + if (i > 0) + continue; + else if (i < 0) + break; + + if (fa || la) + { + if (fa) + fn = file->filename; + if (la) + ln = ls->ifile->filename; + + i = strcmp (fn, ln); + if (i > 0) + continue; + else if (i < 0) + break; + } + } + + /* Here either the files are not sorted by name, or we are + looking at the sections for this file. */ + + if (sec != NULL && sec->spec.sorted) + { + if (strcmp (section_name, + bfd_get_section_name (ls->ifile->the_bfd, + ls->section)) + < 0) + break; + } + } + + return l; +} + +/* Expand a wild statement for a particular FILE. SECTION may be + NULL, in which case it is a wild card. */ + +static void +output_section_callback (ptr, sec, section, file, output) + lang_wild_statement_type *ptr; + struct wildcard_list *sec; + asection *section; + lang_input_statement_type *file; + PTR output; +{ + lang_statement_union_type *before; + + /* Exclude sections that match UNIQUE_SECTION_LIST. */ + if (unique_section_p (bfd_get_section_name (file->the_bfd, section))) + return; + + /* If the wild pattern was marked KEEP, the member sections + should be as well. */ + if (ptr->keep_sections) + section->flags |= SEC_KEEP; + + before = wild_sort (ptr, sec, file, section); + + /* Here BEFORE points to the lang_input_section which + should follow the one we are about to add. If BEFORE + is NULL, then the section should just go at the end + of the current list. */ + + if (before == NULL) + lang_add_section (&ptr->children, section, + (lang_output_section_statement_type *) output, + file); + else + { + lang_statement_list_type list; + lang_statement_union_type **pp; + + lang_list_init (&list); + lang_add_section (&list, section, + (lang_output_section_statement_type *) output, + file); + + /* If we are discarding the section, LIST.HEAD will + be NULL. */ + if (list.head != NULL) + { + ASSERT (list.head->header.next == NULL); + + for (pp = &ptr->children.head; + *pp != before; + pp = &(*pp)->header.next) + ASSERT (*pp != NULL); + + list.head->header.next = *pp; + *pp = list.head; + } + } +} + +/* This is passed a file name which must have been seen already and + added to the statement tree. We will see if it has been opened + already and had its symbols read. If not then we'll read it. */ + +static lang_input_statement_type * +lookup_name (name) + const char *name; +{ + lang_input_statement_type *search; + + for (search = (lang_input_statement_type *) input_file_chain.head; + search != (lang_input_statement_type *) NULL; + search = (lang_input_statement_type *) search->next_real_file) + { + if (search->filename == (char *) NULL && name == (char *) NULL) + return search; + if (search->filename != (char *) NULL + && name != (char *) NULL + && strcmp (search->filename, name) == 0) + break; + } + + if (search == (lang_input_statement_type *) NULL) + search = new_afile (name, lang_input_file_is_file_enum, default_target, + FALSE); + + /* If we have already added this file, or this file is not real + (FIXME: can that ever actually happen?) or the name is NULL + (FIXME: can that ever actually happen?) don't add this file. */ + if (search->loaded + || ! search->real + || search->filename == (const char *) NULL) + return search; + + if (! load_symbols (search, (lang_statement_list_type *) NULL)) + return NULL; + + return search; +} + +/* Get the symbols for an input file. */ + +static bfd_boolean +load_symbols (entry, place) + lang_input_statement_type *entry; + lang_statement_list_type *place; +{ + char **matching; + + if (entry->loaded) + return TRUE; + + ldfile_open_file (entry); + + if (! bfd_check_format (entry->the_bfd, bfd_archive) + && ! bfd_check_format_matches (entry->the_bfd, bfd_object, &matching)) + { + bfd_error_type err; + lang_statement_list_type *hold; + bfd_boolean bad_load = TRUE; + bfd_boolean save_ldlang_sysrooted_script; + + err = bfd_get_error (); + + /* See if the emulation has some special knowledge. */ + if (ldemul_unrecognized_file (entry)) + return TRUE; + + if (err == bfd_error_file_ambiguously_recognized) + { + char **p; + + einfo (_("%B: file not recognized: %E\n"), entry->the_bfd); + einfo (_("%B: matching formats:"), entry->the_bfd); + for (p = matching; *p != NULL; p++) + einfo (" %s", *p); + einfo ("%F\n"); + } + else if (err != bfd_error_file_not_recognized + || place == NULL) + einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd); + else + bad_load = FALSE; + + bfd_close (entry->the_bfd); + entry->the_bfd = NULL; + + /* Try to interpret the file as a linker script. */ + ldfile_open_command_file (entry->filename); + + hold = stat_ptr; + stat_ptr = place; + save_ldlang_sysrooted_script = ldlang_sysrooted_script; + ldlang_sysrooted_script = entry->sysrooted; + + ldfile_assumed_script = TRUE; + parser_input = input_script; + yyparse (); + ldfile_assumed_script = FALSE; + + ldlang_sysrooted_script = save_ldlang_sysrooted_script; + stat_ptr = hold; + + return ! bad_load; + } + + if (ldemul_recognized_file (entry)) + return TRUE; + + /* We don't call ldlang_add_file for an archive. Instead, the + add_symbols entry point will call ldlang_add_file, via the + add_archive_element callback, for each element of the archive + which is used. */ + switch (bfd_get_format (entry->the_bfd)) + { + default: + break; + + case bfd_object: + ldlang_add_file (entry); + if (trace_files || trace_file_tries) + info_msg ("%I\n", entry); + break; + + case bfd_archive: + if (entry->whole_archive) + { + bfd *member = NULL; + bfd_boolean loaded = TRUE; + + for (;;) + { + member = bfd_openr_next_archived_file (entry->the_bfd, member); + + if (member == NULL) + break; + + if (! bfd_check_format (member, bfd_object)) + { + einfo (_("%F%B: member %B in archive is not an object\n"), + entry->the_bfd, member); + loaded = FALSE; + } + + if (! ((*link_info.callbacks->add_archive_element) + (&link_info, member, "--whole-archive"))) + abort (); + + if (! bfd_link_add_symbols (member, &link_info)) + { + einfo (_("%F%B: could not read symbols: %E\n"), member); + loaded = FALSE; + } + } + + entry->loaded = loaded; + return loaded; + } + break; + } + + if (bfd_link_add_symbols (entry->the_bfd, &link_info)) + entry->loaded = TRUE; + else + einfo (_("%F%B: could not read symbols: %E\n"), entry->the_bfd); + + return entry->loaded; +} + +/* Handle a wild statement. S->FILENAME or S->SECTION_LIST or both + may be NULL, indicating that it is a wildcard. Separate + lang_input_section statements are created for each part of the + expansion; they are added after the wild statement S. OUTPUT is + the output section. */ + +static void +wild (s, target, output) + lang_wild_statement_type *s; + const char *target ATTRIBUTE_UNUSED; + lang_output_section_statement_type *output; +{ + struct wildcard_list *sec; + + walk_wild (s, output_section_callback, (PTR) output); + + for (sec = s->section_list; sec != NULL; sec = sec->next) + { + if (default_common_section != NULL) + break; + if (sec->spec.name != NULL && strcmp (sec->spec.name, "COMMON") == 0) + { + /* Remember the section that common is going to in case we + later get something which doesn't know where to put it. */ + default_common_section = output; + } + } +} + +/* Return TRUE iff target is the sought target. */ + +static int +get_target (target, data) + const bfd_target *target; + PTR data; +{ + const char *sought = (const char *) data; + + return strcmp (target->name, sought) == 0; +} + +/* Like strcpy() but convert to lower case as well. */ + +static void +stricpy (dest, src) + char *dest; + char *src; +{ + char c; + + while ((c = *src++) != 0) + *dest++ = TOLOWER (c); + + *dest = 0; +} + +/* Remove the first occurrence of needle (if any) in haystack + from haystack. */ + +static void +strcut (haystack, needle) + char *haystack; + char *needle; +{ + haystack = strstr (haystack, needle); + + if (haystack) + { + char *src; + + for (src = haystack + strlen (needle); *src;) + *haystack++ = *src++; + + *haystack = 0; + } +} + +/* Compare two target format name strings. + Return a value indicating how "similar" they are. */ + +static int +name_compare (first, second) + char *first; + char *second; +{ + char *copy1; + char *copy2; + int result; + + copy1 = xmalloc (strlen (first) + 1); + copy2 = xmalloc (strlen (second) + 1); + + /* Convert the names to lower case. */ + stricpy (copy1, first); + stricpy (copy2, second); + + /* Remove and endian strings from the name. */ + strcut (copy1, "big"); + strcut (copy1, "little"); + strcut (copy2, "big"); + strcut (copy2, "little"); + + /* Return a value based on how many characters match, + starting from the beginning. If both strings are + the same then return 10 * their length. */ + for (result = 0; copy1[result] == copy2[result]; result++) + if (copy1[result] == 0) + { + result *= 10; + break; + } + + free (copy1); + free (copy2); + + return result; +} + +/* Set by closest_target_match() below. */ +static const bfd_target *winner; + +/* Scan all the valid bfd targets looking for one that has the endianness + requirement that was specified on the command line, and is the nearest + match to the original output target. */ + +static int +closest_target_match (target, data) + const bfd_target *target; + PTR data; +{ + const bfd_target *original = (const bfd_target *) data; + + if (command_line.endian == ENDIAN_BIG + && target->byteorder != BFD_ENDIAN_BIG) + return 0; + + if (command_line.endian == ENDIAN_LITTLE + && target->byteorder != BFD_ENDIAN_LITTLE) + return 0; + + /* Must be the same flavour. */ + if (target->flavour != original->flavour) + return 0; + + /* If we have not found a potential winner yet, then record this one. */ + if (winner == NULL) + { + winner = target; + return 0; + } + + /* Oh dear, we now have two potential candidates for a successful match. + Compare their names and choose the better one. */ + if (name_compare (target->name, original->name) + > name_compare (winner->name, original->name)) + winner = target; + + /* Keep on searching until wqe have checked them all. */ + return 0; +} + +/* Return the BFD target format of the first input file. */ + +static char * +get_first_input_target () +{ + char *target = NULL; + + LANG_FOR_EACH_INPUT_STATEMENT (s) + { + if (s->header.type == lang_input_statement_enum + && s->real) + { + ldfile_open_file (s); + + if (s->the_bfd != NULL + && bfd_check_format (s->the_bfd, bfd_object)) + { + target = bfd_get_target (s->the_bfd); + + if (target != NULL) + break; + } + } + } + + return target; +} + +const char * +lang_get_output_target () +{ + const char *target; + + /* Has the user told us which output format to use? */ + if (output_target != (char *) NULL) + return output_target; + + /* No - has the current target been set to something other than + the default? */ + if (current_target != default_target) + return current_target; + + /* No - can we determine the format of the first input file? */ + target = get_first_input_target (); + if (target != NULL) + return target; + + /* Failed - use the default output target. */ + return default_target; +} + +/* Open the output file. */ + +static bfd * +open_output (name) + const char *name; +{ + bfd *output; + + output_target = lang_get_output_target (); + + /* Has the user requested a particular endianness on the command + line? */ + if (command_line.endian != ENDIAN_UNSET) + { + const bfd_target *target; + enum bfd_endian desired_endian; + + /* Get the chosen target. */ + target = bfd_search_for_target (get_target, (PTR) output_target); + + /* If the target is not supported, we cannot do anything. */ + if (target != NULL) + { + if (command_line.endian == ENDIAN_BIG) + desired_endian = BFD_ENDIAN_BIG; + else + desired_endian = BFD_ENDIAN_LITTLE; + + /* See if the target has the wrong endianness. This should + not happen if the linker script has provided big and + little endian alternatives, but some scrips don't do + this. */ + if (target->byteorder != desired_endian) + { + /* If it does, then see if the target provides + an alternative with the correct endianness. */ + if (target->alternative_target != NULL + && (target->alternative_target->byteorder == desired_endian)) + output_target = target->alternative_target->name; + else + { + /* Try to find a target as similar as possible to + the default target, but which has the desired + endian characteristic. */ + (void) bfd_search_for_target (closest_target_match, + (PTR) target); + + /* Oh dear - we could not find any targets that + satisfy our requirements. */ + if (winner == NULL) + einfo (_("%P: warning: could not find any targets that match endianness requirement\n")); + else + output_target = winner->name; + } + } + } + } + + output = bfd_openw (name, output_target); + + if (output == (bfd *) NULL) + { + if (bfd_get_error () == bfd_error_invalid_target) + einfo (_("%P%F: target %s not found\n"), output_target); + + einfo (_("%P%F: cannot open output file %s: %E\n"), name); + } + + delete_output_file_on_failure = TRUE; + +#if 0 + output->flags |= D_PAGED; +#endif + + if (! bfd_set_format (output, bfd_object)) + einfo (_("%P%F:%s: can not make object file: %E\n"), name); + if (! bfd_set_arch_mach (output, + ldfile_output_architecture, + ldfile_output_machine)) + einfo (_("%P%F:%s: can not set architecture: %E\n"), name); + + link_info.hash = bfd_link_hash_table_create (output); + if (link_info.hash == (struct bfd_link_hash_table *) NULL) + einfo (_("%P%F: can not create link hash table: %E\n")); + + bfd_set_gp_size (output, g_switch_value); + return output; +} + +static void +ldlang_open_output (statement) + lang_statement_union_type *statement; +{ + switch (statement->header.type) + { + case lang_output_statement_enum: + ASSERT (output_bfd == (bfd *) NULL); + output_bfd = open_output (statement->output_statement.name); + ldemul_set_output_arch (); + if (config.magic_demand_paged && !link_info.relocateable) + output_bfd->flags |= D_PAGED; + else + output_bfd->flags &= ~D_PAGED; + if (config.text_read_only) + output_bfd->flags |= WP_TEXT; + else + output_bfd->flags &= ~WP_TEXT; + if (link_info.traditional_format) + output_bfd->flags |= BFD_TRADITIONAL_FORMAT; + else + output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT; + break; + + case lang_target_statement_enum: + current_target = statement->target_statement.target; + break; + default: + break; + } +} + +/* Open all the input files. */ + +static void +open_input_bfds (s, force) + lang_statement_union_type *s; + bfd_boolean force; +{ + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) + { + switch (s->header.type) + { + case lang_constructors_statement_enum: + open_input_bfds (constructor_list.head, force); + break; + case lang_output_section_statement_enum: + open_input_bfds (s->output_section_statement.children.head, force); + break; + case lang_wild_statement_enum: + /* Maybe we should load the file's symbols. */ + if (s->wild_statement.filename + && ! wildcardp (s->wild_statement.filename)) + (void) lookup_name (s->wild_statement.filename); + open_input_bfds (s->wild_statement.children.head, force); + break; + case lang_group_statement_enum: + { + struct bfd_link_hash_entry *undefs; + + /* We must continually search the entries in the group + until no new symbols are added to the list of undefined + symbols. */ + + do + { + undefs = link_info.hash->undefs_tail; + open_input_bfds (s->group_statement.children.head, TRUE); + } + while (undefs != link_info.hash->undefs_tail); + } + break; + case lang_target_statement_enum: + current_target = s->target_statement.target; + break; + case lang_input_statement_enum: + if (s->input_statement.real) + { + lang_statement_list_type add; + + s->input_statement.target = current_target; + + /* If we are being called from within a group, and this + is an archive which has already been searched, then + force it to be researched unless the whole archive + has been loaded already. */ + if (force + && !s->input_statement.whole_archive + && s->input_statement.loaded + && bfd_check_format (s->input_statement.the_bfd, + bfd_archive)) + s->input_statement.loaded = FALSE; + + lang_list_init (&add); + + if (! load_symbols (&s->input_statement, &add)) + config.make_executable = FALSE; + + if (add.head != NULL) + { + *add.tail = s->header.next; + s->header.next = add.head; + } + } + break; + default: + break; + } + } +} + +/* If there are [COMMONS] statements, put a wild one into the bss + section. */ + +static void +lang_reasonable_defaults () +{ +#if 0 + lang_output_section_statement_lookup (".text"); + lang_output_section_statement_lookup (".data"); + + default_common_section = lang_output_section_statement_lookup (".bss"); + + if (!placed_commons) + { + lang_wild_statement_type *new = + new_stat (lang_wild_statement, + &default_common_section->children); + + new->section_name = "COMMON"; + new->filename = (char *) NULL; + lang_list_init (&new->children); + } +#endif +} + +/* Add the supplied name to the symbol table as an undefined reference. + This is a two step process as the symbol table doesn't even exist at + the time the ld command line is processed. First we put the name + on a list, then, once the output file has been opened, transfer the + name to the symbol table. */ + +typedef struct bfd_sym_chain ldlang_undef_chain_list_type; + +#define ldlang_undef_chain_list_head entry_symbol.next + +void +ldlang_add_undef (name) + const char *const name; +{ + ldlang_undef_chain_list_type *new = + ((ldlang_undef_chain_list_type *) + stat_alloc (sizeof (ldlang_undef_chain_list_type))); + + new->next = ldlang_undef_chain_list_head; + ldlang_undef_chain_list_head = new; + + new->name = xstrdup (name); + + if (output_bfd != NULL) + insert_undefined (new->name); +} + +/* Insert NAME as undefined in the symbol table. */ + +static void +insert_undefined (name) + const char *name; +{ + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE); + if (h == (struct bfd_link_hash_entry *) NULL) + einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); + if (h->type == bfd_link_hash_new) + { + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = NULL; + bfd_link_add_undef (link_info.hash, h); + } +} + +/* Run through the list of undefineds created above and place them + into the linker hash table as undefined symbols belonging to the + script file. */ + +static void +lang_place_undefineds () +{ + ldlang_undef_chain_list_type *ptr; + + for (ptr = ldlang_undef_chain_list_head; + ptr != (ldlang_undef_chain_list_type *) NULL; + ptr = ptr->next) + { + insert_undefined (ptr->name); + } +} + +/* Open input files and attach to output sections. */ + +static void +map_input_to_output_sections (s, target, output_section_statement) + lang_statement_union_type *s; + const char *target; + lang_output_section_statement_type *output_section_statement; +{ + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) + { + switch (s->header.type) + { + case lang_wild_statement_enum: + wild (&s->wild_statement, target, output_section_statement); + break; + case lang_constructors_statement_enum: + map_input_to_output_sections (constructor_list.head, + target, + output_section_statement); + break; + case lang_output_section_statement_enum: + map_input_to_output_sections (s->output_section_statement.children.head, + target, + &s->output_section_statement); + break; + case lang_output_statement_enum: + break; + case lang_target_statement_enum: + target = s->target_statement.target; + break; + case lang_group_statement_enum: + map_input_to_output_sections (s->group_statement.children.head, + target, + output_section_statement); + break; + case lang_fill_statement_enum: + case lang_input_section_enum: + case lang_object_symbols_statement_enum: + case lang_data_statement_enum: + case lang_reloc_statement_enum: + case lang_padding_statement_enum: + case lang_input_statement_enum: + if (output_section_statement != NULL + && output_section_statement->bfd_section == NULL) + init_os (output_section_statement); + break; + case lang_assignment_statement_enum: + if (output_section_statement != NULL + && output_section_statement->bfd_section == NULL) + init_os (output_section_statement); + + /* Make sure that any sections mentioned in the assignment + are initialized. */ + exp_init_os (s->assignment_statement.exp); + break; + case lang_afile_asection_pair_statement_enum: + FAIL (); + break; + case lang_address_statement_enum: + /* Mark the specified section with the supplied address. */ + { + lang_output_section_statement_type *os = + lang_output_section_statement_lookup + (s->address_statement.section_name); + + if (os->bfd_section == NULL) + init_os (os); + os->addr_tree = s->address_statement.address; + } + break; + } + } +} + +/* An output section might have been removed after its statement was + added. For example, ldemul_before_allocation can remove dynamic + sections if they turn out to be not needed. Clean them up here. */ + +static void +strip_excluded_output_sections () +{ + lang_statement_union_type *u; + + for (u = lang_output_section_statement.head; + u != NULL; + u = u->output_section_statement.next) + { + lang_output_section_statement_type *os; + asection *s; + + os = &u->output_section_statement; + s = os->bfd_section; + if (s != NULL && (s->flags & SEC_EXCLUDE) != 0) + { + asection **p; + + os->bfd_section = NULL; + + for (p = &output_bfd->sections; *p; p = &(*p)->next) + if (*p == s) + { + bfd_section_list_remove (output_bfd, p); + output_bfd->section_count--; + break; + } + } + } +} + +static void +print_output_section_statement (output_section_statement) + lang_output_section_statement_type *output_section_statement; +{ + asection *section = output_section_statement->bfd_section; + int len; + + if (output_section_statement != abs_output_section) + { + minfo ("\n%s", output_section_statement->name); + + if (section != NULL) + { + print_dot = section->vma; + + len = strlen (output_section_statement->name); + if (len >= SECTION_NAME_MAP_LENGTH - 1) + { + print_nl (); + len = 0; + } + while (len < SECTION_NAME_MAP_LENGTH) + { + print_space (); + ++len; + } + + minfo ("0x%V %W", section->vma, section->_raw_size); + + if (output_section_statement->load_base != NULL) + { + bfd_vma addr; + + addr = exp_get_abs_int (output_section_statement->load_base, 0, + "load base", lang_final_phase_enum); + minfo (_(" load address 0x%V"), addr); + } + } + + print_nl (); + } + + print_statement_list (output_section_statement->children.head, + output_section_statement); +} + +static void +print_assignment (assignment, output_section) + lang_assignment_statement_type *assignment; + lang_output_section_statement_type *output_section; +{ + int i; + etree_value_type result; + + for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) + print_space (); + + result = exp_fold_tree (assignment->exp->assign.src, output_section, + lang_final_phase_enum, print_dot, &print_dot); + if (result.valid_p) + { + const char *dst; + bfd_vma value; + + value = result.value + result.section->bfd_section->vma; + dst = assignment->exp->assign.dst; + + minfo ("0x%V", value); + if (dst[0] == '.' && dst[1] == 0) + print_dot = value; + } + else + { + minfo ("*undef* "); +#ifdef BFD64 + minfo (" "); +#endif + } + + minfo (" "); + + exp_print_tree (assignment->exp); + + print_nl (); +} + +static void +print_input_statement (statm) + lang_input_statement_type *statm; +{ + if (statm->filename != (char *) NULL) + { + fprintf (config.map_file, "LOAD %s\n", statm->filename); + } +} + +/* Print all symbols defined in a particular section. This is called + via bfd_link_hash_traverse. */ + +static bfd_boolean +print_one_symbol (hash_entry, ptr) + struct bfd_link_hash_entry *hash_entry; + PTR ptr; +{ + asection *sec = (asection *) ptr; + + if ((hash_entry->type == bfd_link_hash_defined + || hash_entry->type == bfd_link_hash_defweak) + && sec == hash_entry->u.def.section) + { + int i; + + for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) + print_space (); + minfo ("0x%V ", + (hash_entry->u.def.value + + hash_entry->u.def.section->output_offset + + hash_entry->u.def.section->output_section->vma)); + + minfo (" %T\n", hash_entry->root.string); + } + + return TRUE; +} + +/* Print information about an input section to the map file. */ + +static void +print_input_section (in) + lang_input_section_type *in; +{ + asection *i = in->section; + bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + if (size != 0) + { + print_space (); + + minfo ("%s", i->name); + + if (i->output_section != NULL) + { + int len; + + len = 1 + strlen (i->name); + if (len >= SECTION_NAME_MAP_LENGTH - 1) + { + print_nl (); + len = 0; + } + while (len < SECTION_NAME_MAP_LENGTH) + { + print_space (); + ++len; + } + + minfo ("0x%V %W %B\n", + i->output_section->vma + i->output_offset, size / opb, + i->owner); + + if (i->_cooked_size != 0 && i->_cooked_size != i->_raw_size) + { + len = SECTION_NAME_MAP_LENGTH + 3; +#ifdef BFD64 + len += 16; +#else + len += 8; +#endif + while (len > 0) + { + print_space (); + --len; + } + + minfo (_("%W (size before relaxing)\n"), i->_raw_size); + } + + bfd_link_hash_traverse (link_info.hash, print_one_symbol, (PTR) i); + + print_dot = i->output_section->vma + i->output_offset + size / opb; + } + } +} + +static void +print_fill_statement (fill) + lang_fill_statement_type *fill; +{ + size_t size; + unsigned char *p; + fputs (" FILL mask 0x", config.map_file); + for (p = fill->fill->data, size = fill->fill->size; size != 0; p++, size--) + fprintf (config.map_file, "%02x", *p); + fputs ("\n", config.map_file); +} + +static void +print_data_statement (data) + lang_data_statement_type *data; +{ + int i; + bfd_vma addr; + bfd_size_type size; + const char *name; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + + for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) + print_space (); + + addr = data->output_vma; + if (data->output_section != NULL) + addr += data->output_section->vma; + + switch (data->type) + { + default: + abort (); + case BYTE: + size = BYTE_SIZE; + name = "BYTE"; + break; + case SHORT: + size = SHORT_SIZE; + name = "SHORT"; + break; + case LONG: + size = LONG_SIZE; + name = "LONG"; + break; + case QUAD: + size = QUAD_SIZE; + name = "QUAD"; + break; + case SQUAD: + size = QUAD_SIZE; + name = "SQUAD"; + break; + } + + minfo ("0x%V %W %s 0x%v", addr, size, name, data->value); + + if (data->exp->type.node_class != etree_value) + { + print_space (); + exp_print_tree (data->exp); + } + + print_nl (); + + print_dot = addr + size / opb; + +} + +/* Print an address statement. These are generated by options like + -Ttext. */ + +static void +print_address_statement (address) + lang_address_statement_type *address; +{ + minfo (_("Address of section %s set to "), address->section_name); + exp_print_tree (address->address); + print_nl (); +} + +/* Print a reloc statement. */ + +static void +print_reloc_statement (reloc) + lang_reloc_statement_type *reloc; +{ + int i; + bfd_vma addr; + bfd_size_type size; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + + for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) + print_space (); + + addr = reloc->output_vma; + if (reloc->output_section != NULL) + addr += reloc->output_section->vma; + + size = bfd_get_reloc_size (reloc->howto); + + minfo ("0x%V %W RELOC %s ", addr, size, reloc->howto->name); + + if (reloc->name != NULL) + minfo ("%s+", reloc->name); + else + minfo ("%s+", reloc->section->name); + + exp_print_tree (reloc->addend_exp); + + print_nl (); + + print_dot = addr + size / opb; +} + +static void +print_padding_statement (s) + lang_padding_statement_type *s; +{ + int len; + bfd_vma addr; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + + minfo (" *fill*"); + + len = sizeof " *fill*" - 1; + while (len < SECTION_NAME_MAP_LENGTH) + { + print_space (); + ++len; + } + + addr = s->output_offset; + if (s->output_section != NULL) + addr += s->output_section->vma; + minfo ("0x%V %W ", addr, s->size); + + if (s->fill->size != 0) + { + size_t size; + unsigned char *p; + for (p = s->fill->data, size = s->fill->size; size != 0; p++, size--) + fprintf (config.map_file, "%02x", *p); + } + + print_nl (); + + print_dot = addr + s->size / opb; +} + +static void +print_wild_statement (w, os) + lang_wild_statement_type *w; + lang_output_section_statement_type *os; +{ + struct wildcard_list *sec; + + print_space (); + + if (w->filenames_sorted) + minfo ("SORT("); + if (w->filename != NULL) + minfo ("%s", w->filename); + else + minfo ("*"); + if (w->filenames_sorted) + minfo (")"); + + minfo ("("); + for (sec = w->section_list; sec; sec = sec->next) + { + if (sec->spec.sorted) + minfo ("SORT("); + if (sec->spec.exclude_name_list != NULL) + { + name_list *tmp; + minfo ("EXCLUDE_FILE(%s", sec->spec.exclude_name_list->name); + for (tmp = sec->spec.exclude_name_list->next; tmp; tmp = tmp->next) + minfo (" %s", tmp->name); + minfo (") "); + } + if (sec->spec.name != NULL) + minfo ("%s", sec->spec.name); + else + minfo ("*"); + if (sec->spec.sorted) + minfo (")"); + if (sec->next) + minfo (" "); + } + minfo (")"); + + print_nl (); + + print_statement_list (w->children.head, os); +} + +/* Print a group statement. */ + +static void +print_group (s, os) + lang_group_statement_type *s; + lang_output_section_statement_type *os; +{ + fprintf (config.map_file, "START GROUP\n"); + print_statement_list (s->children.head, os); + fprintf (config.map_file, "END GROUP\n"); +} + +/* Print the list of statements in S. + This can be called for any statement type. */ + +static void +print_statement_list (s, os) + lang_statement_union_type *s; + lang_output_section_statement_type *os; +{ + while (s != NULL) + { + print_statement (s, os); + s = s->header.next; + } +} + +/* Print the first statement in statement list S. + This can be called for any statement type. */ + +static void +print_statement (s, os) + lang_statement_union_type *s; + lang_output_section_statement_type *os; +{ + switch (s->header.type) + { + default: + fprintf (config.map_file, _("Fail with %d\n"), s->header.type); + FAIL (); + break; + case lang_constructors_statement_enum: + if (constructor_list.head != NULL) + { + if (constructors_sorted) + minfo (" SORT (CONSTRUCTORS)\n"); + else + minfo (" CONSTRUCTORS\n"); + print_statement_list (constructor_list.head, os); + } + break; + case lang_wild_statement_enum: + print_wild_statement (&s->wild_statement, os); + break; + case lang_address_statement_enum: + print_address_statement (&s->address_statement); + break; + case lang_object_symbols_statement_enum: + minfo (" CREATE_OBJECT_SYMBOLS\n"); + break; + case lang_fill_statement_enum: + print_fill_statement (&s->fill_statement); + break; + case lang_data_statement_enum: + print_data_statement (&s->data_statement); + break; + case lang_reloc_statement_enum: + print_reloc_statement (&s->reloc_statement); + break; + case lang_input_section_enum: + print_input_section (&s->input_section); + break; + case lang_padding_statement_enum: + print_padding_statement (&s->padding_statement); + break; + case lang_output_section_statement_enum: + print_output_section_statement (&s->output_section_statement); + break; + case lang_assignment_statement_enum: + print_assignment (&s->assignment_statement, os); + break; + case lang_target_statement_enum: + fprintf (config.map_file, "TARGET(%s)\n", s->target_statement.target); + break; + case lang_output_statement_enum: + minfo ("OUTPUT(%s", s->output_statement.name); + if (output_target != NULL) + minfo (" %s", output_target); + minfo (")\n"); + break; + case lang_input_statement_enum: + print_input_statement (&s->input_statement); + break; + case lang_group_statement_enum: + print_group (&s->group_statement, os); + break; + case lang_afile_asection_pair_statement_enum: + FAIL (); + break; + } +} + +static void +print_statements () +{ + print_statement_list (statement_list.head, abs_output_section); +} + +/* Print the first N statements in statement list S to STDERR. + If N == 0, nothing is printed. + If N < 0, the entire list is printed. + Intended to be called from GDB. */ + +void +dprint_statement (s, n) + lang_statement_union_type *s; + int n; +{ + FILE *map_save = config.map_file; + + config.map_file = stderr; + + if (n < 0) + print_statement_list (s, abs_output_section); + else + { + while (s && --n >= 0) + { + print_statement (s, abs_output_section); + s = s->header.next; + } + } + + config.map_file = map_save; +} + +static void +insert_pad (ptr, fill, alignment_needed, output_section, dot) + lang_statement_union_type **ptr; + fill_type *fill; + unsigned int alignment_needed; + asection *output_section; + bfd_vma dot; +{ + static fill_type zero_fill = { 1, { 0 } }; + lang_statement_union_type *pad; + + pad = ((lang_statement_union_type *) + ((char *) ptr - offsetof (lang_statement_union_type, header.next))); + if (ptr != &statement_list.head + && pad->header.type == lang_padding_statement_enum + && pad->padding_statement.output_section == output_section) + { + /* Use the existing pad statement. The above test on output + section is probably redundant, but it doesn't hurt to check. */ + } + else + { + /* Make a new padding statement, linked into existing chain. */ + pad = ((lang_statement_union_type *) + stat_alloc (sizeof (lang_padding_statement_type))); + pad->header.next = *ptr; + *ptr = pad; + pad->header.type = lang_padding_statement_enum; + pad->padding_statement.output_section = output_section; + if (fill == (fill_type *) 0) + fill = &zero_fill; + pad->padding_statement.fill = fill; + } + pad->padding_statement.output_offset = dot - output_section->vma; + pad->padding_statement.size = alignment_needed; + output_section->_raw_size += alignment_needed; +} + +/* Work out how much this section will move the dot point. */ + +static bfd_vma +size_input_section (this_ptr, output_section_statement, fill, dot) + lang_statement_union_type **this_ptr; + lang_output_section_statement_type *output_section_statement; + fill_type *fill; + bfd_vma dot; +{ + lang_input_section_type *is = &((*this_ptr)->input_section); + asection *i = is->section; + + if (!is->ifile->just_syms_flag) + { + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + unsigned int alignment_needed; + asection *o; + + /* Align this section first to the input sections requirement, + then to the output section's requirement. If this alignment + is greater than any seen before, then record it too. Perform + the alignment by inserting a magic 'padding' statement. */ + + if (output_section_statement->subsection_alignment != -1) + i->alignment_power = output_section_statement->subsection_alignment; + + o = output_section_statement->bfd_section; + if (o->alignment_power < i->alignment_power) + o->alignment_power = i->alignment_power; + + alignment_needed = align_power (dot, i->alignment_power) - dot; + + if (alignment_needed != 0) + { + insert_pad (this_ptr, fill, alignment_needed * opb, o, dot); + dot += alignment_needed; + } + + /* Remember where in the output section this input section goes. */ + + i->output_offset = dot - o->vma; + + /* Mark how big the output section must be to contain this now. */ + if (i->_cooked_size != 0) + dot += i->_cooked_size / opb; + else + dot += i->_raw_size / opb; + o->_raw_size = (dot - o->vma) * opb; + } + else + { + i->output_offset = i->vma - output_section_statement->bfd_section->vma; + } + + return dot; +} + +#define IGNORE_SECTION(bfd, s) \ + (((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_LOAD)) \ + != (SEC_ALLOC | SEC_LOAD)) \ + || bfd_section_size (bfd, s) == 0) + +/* Check to see if any allocated sections overlap with other allocated + sections. This can happen when the linker script specifically specifies + the output section addresses of the two sections. */ + +static void +lang_check_section_addresses () +{ + asection *s; + unsigned opb = bfd_octets_per_byte (output_bfd); + + /* Scan all sections in the output list. */ + for (s = output_bfd->sections; s != NULL; s = s->next) + { + asection *os; + + /* Ignore sections which are not loaded or which have no contents. */ + if (IGNORE_SECTION (output_bfd, s)) + continue; + + /* Once we reach section 's' stop our seach. This prevents two + warning messages from being produced, one for 'section A overlaps + section B' and one for 'section B overlaps section A'. */ + for (os = output_bfd->sections; os != s; os = os->next) + { + bfd_vma s_start; + bfd_vma s_end; + bfd_vma os_start; + bfd_vma os_end; + + /* Only consider loadable sections with real contents. */ + if (IGNORE_SECTION (output_bfd, os)) + continue; + + /* We must check the sections' LMA addresses not their + VMA addresses because overlay sections can have + overlapping VMAs but they must have distinct LMAs. */ + s_start = bfd_section_lma (output_bfd, s); + os_start = bfd_section_lma (output_bfd, os); + s_end = s_start + bfd_section_size (output_bfd, s) / opb - 1; + os_end = os_start + bfd_section_size (output_bfd, os) / opb - 1; + + /* Look for an overlap. */ + if ((s_end < os_start) || (s_start > os_end)) + continue; + + einfo ( +_("%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"), + s->name, s_start, s_end, os->name, os_start, os_end); + + /* Once we have found one overlap for this section, + stop looking for others. */ + break; + } + } +} + +/* Make sure the new address is within the region. We explicitly permit the + current address to be at the exact end of the region when the address is + non-zero, in case the region is at the end of addressable memory and the + calculation wraps around. */ + +static void +os_region_check (os, region, tree, base) + lang_output_section_statement_type *os; + struct memory_region_struct *region; + etree_type *tree; + bfd_vma base; +{ + if ((region->current < region->origin + || (region->current - region->origin > region->length)) + && ((region->current != region->origin + region->length) + || base == 0)) + { + if (tree != (etree_type *) NULL) + { + einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"), + region->current, + os->bfd_section->owner, + os->bfd_section->name, + region->name); + } + else + { + einfo (_("%X%P: region %s is full (%B section %s)\n"), + region->name, + os->bfd_section->owner, + os->bfd_section->name); + } + /* Reset the region pointer. */ + region->current = region->origin; + } +} + +/* Set the sizes for all the output sections. */ + +static bfd_vma +lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax, + check_regions) + lang_statement_union_type *s; + lang_output_section_statement_type *output_section_statement; + lang_statement_union_type **prev; + fill_type *fill; + bfd_vma dot; + bfd_boolean *relax; + bfd_boolean check_regions; +{ + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + + /* Size up the sections from their constituent parts. */ + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) + { + switch (s->header.type) + { + case lang_output_section_statement_enum: + { + bfd_vma after; + lang_output_section_statement_type *os; + + os = &s->output_section_statement; + if (os->bfd_section == NULL) + /* This section was never actually created. */ + break; + + /* If this is a COFF shared library section, use the size and + address from the input section. FIXME: This is COFF + specific; it would be cleaner if there were some other way + to do this, but nothing simple comes to mind. */ + if ((os->bfd_section->flags & SEC_COFF_SHARED_LIBRARY) != 0) + { + asection *input; + + if (os->children.head == NULL + || os->children.head->header.next != NULL + || os->children.head->header.type != lang_input_section_enum) + einfo (_("%P%X: Internal error on COFF shared library section %s\n"), + os->name); + + input = os->children.head->input_section.section; + bfd_set_section_vma (os->bfd_section->owner, + os->bfd_section, + bfd_section_vma (input->owner, input)); + os->bfd_section->_raw_size = input->_raw_size; + break; + } + + if (bfd_is_abs_section (os->bfd_section)) + { + /* No matter what happens, an abs section starts at zero. */ + ASSERT (os->bfd_section->vma == 0); + } + else + { + if (os->addr_tree == (etree_type *) NULL) + { + /* No address specified for this section, get one + from the region specification. */ + if (os->region == (lang_memory_region_type *) NULL + || (((bfd_get_section_flags (output_bfd, os->bfd_section) + & (SEC_ALLOC | SEC_LOAD)) != 0) + && os->region->name[0] == '*' + && strcmp (os->region->name, "*default*") == 0)) + { + os->region = lang_memory_default (os->bfd_section); + } + + /* If a loadable section is using the default memory + region, and some non default memory regions were + defined, issue a warning. */ + if ((bfd_get_section_flags (output_bfd, os->bfd_section) + & (SEC_ALLOC | SEC_LOAD)) != 0 + && (bfd_get_section_flags (output_bfd, os->bfd_section) + & SEC_NEVER_LOAD) == 0 + && ! link_info.relocateable + && check_regions + && strcmp (os->region->name, "*default*") == 0 + && lang_memory_region_list != NULL + && (strcmp (lang_memory_region_list->name, + "*default*") != 0 + || lang_memory_region_list->next != NULL)) + einfo (_("%P: warning: no memory region specified for section `%s'\n"), + bfd_get_section_name (output_bfd, + os->bfd_section)); + + dot = os->region->current; + + if (os->section_alignment == -1) + { + bfd_vma olddot; + + olddot = dot; + dot = align_power (dot, + os->bfd_section->alignment_power); + + if (dot != olddot && config.warn_section_align) + einfo (_("%P: warning: changing start of section %s by %u bytes\n"), + os->name, (unsigned int) (dot - olddot)); + } + } + else + { + etree_value_type r; + + r = exp_fold_tree (os->addr_tree, + abs_output_section, + lang_allocating_phase_enum, + dot, &dot); + if (!r.valid_p) + einfo (_("%F%S: non constant address expression for section %s\n"), + os->name); + + dot = r.value + r.section->bfd_section->vma; + } + + /* The section starts here. + First, align to what the section needs. */ + + if (os->section_alignment != -1) + dot = align_power (dot, os->section_alignment); + + bfd_set_section_vma (0, os->bfd_section, dot); + + os->bfd_section->output_offset = 0; + } + + lang_size_sections_1 (os->children.head, os, &os->children.head, + os->fill, dot, relax, check_regions); + + /* Put the section within the requested block size, or + align at the block boundary. */ + after = align_n (os->bfd_section->vma + + os->bfd_section->_raw_size / opb, + (bfd_vma) os->block_value); + + if (bfd_is_abs_section (os->bfd_section)) + ASSERT (after == os->bfd_section->vma); + else if ((os->bfd_section->flags & SEC_HAS_CONTENTS) == 0 + && (os->bfd_section->flags & SEC_THREAD_LOCAL) + && ! link_info.relocateable) + os->bfd_section->_raw_size = 0; + else + os->bfd_section->_raw_size = + (after - os->bfd_section->vma) * opb; + + dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb; + os->processed = TRUE; + + if (os->update_dot_tree != 0) + exp_fold_tree (os->update_dot_tree, abs_output_section, + lang_allocating_phase_enum, dot, &dot); + + /* Update dot in the region ? + We only do this if the section is going to be allocated, + since unallocated sections do not contribute to the region's + overall size in memory. + + If the SEC_NEVER_LOAD bit is not set, it will affect the + addresses of sections after it. We have to update + dot. */ + if (os->region != (lang_memory_region_type *) NULL + && ((bfd_get_section_flags (output_bfd, os->bfd_section) + & SEC_NEVER_LOAD) == 0 + || (bfd_get_section_flags (output_bfd, os->bfd_section) + & (SEC_ALLOC | SEC_LOAD)))) + { + os->region->current = dot; + + if (check_regions) + /* Make sure the new address is within the region. */ + os_region_check (os, os->region, os->addr_tree, + os->bfd_section->vma); + + /* If there's no load address specified, use the run + region as the load region. */ + if (os->lma_region == NULL && os->load_base == NULL) + os->lma_region = os->region; + + if (os->lma_region != NULL && os->lma_region != os->region) + { + /* Set load_base, which will be handled later. */ + os->load_base = exp_intop (os->lma_region->current); + os->lma_region->current += + os->bfd_section->_raw_size / opb; + if (check_regions) + os_region_check (os, os->lma_region, NULL, + os->bfd_section->lma); + } + } + } + break; + + case lang_constructors_statement_enum: + dot = lang_size_sections_1 (constructor_list.head, + output_section_statement, + &s->wild_statement.children.head, + fill, dot, relax, check_regions); + break; + + case lang_data_statement_enum: + { + unsigned int size = 0; + + s->data_statement.output_vma = + dot - output_section_statement->bfd_section->vma; + s->data_statement.output_section = + output_section_statement->bfd_section; + + switch (s->data_statement.type) + { + default: + abort (); + case QUAD: + case SQUAD: + size = QUAD_SIZE; + break; + case LONG: + size = LONG_SIZE; + break; + case SHORT: + size = SHORT_SIZE; + break; + case BYTE: + size = BYTE_SIZE; + break; + } + if (size < opb) + size = opb; + dot += size / opb; + output_section_statement->bfd_section->_raw_size += size; + /* The output section gets contents, and then we inspect for + any flags set in the input script which override any ALLOC. */ + output_section_statement->bfd_section->flags |= SEC_HAS_CONTENTS; + if (!(output_section_statement->flags & SEC_NEVER_LOAD)) + { + output_section_statement->bfd_section->flags |= + SEC_ALLOC | SEC_LOAD; + } + } + break; + + case lang_reloc_statement_enum: + { + int size; + + s->reloc_statement.output_vma = + dot - output_section_statement->bfd_section->vma; + s->reloc_statement.output_section = + output_section_statement->bfd_section; + size = bfd_get_reloc_size (s->reloc_statement.howto); + dot += size / opb; + output_section_statement->bfd_section->_raw_size += size; + } + break; + + case lang_wild_statement_enum: + + dot = lang_size_sections_1 (s->wild_statement.children.head, + output_section_statement, + &s->wild_statement.children.head, + fill, dot, relax, check_regions); + + break; + + case lang_object_symbols_statement_enum: + link_info.create_object_symbols_section = + output_section_statement->bfd_section; + break; + case lang_output_statement_enum: + case lang_target_statement_enum: + break; + case lang_input_section_enum: + { + asection *i; + + i = (*prev)->input_section.section; + if (! relax) + { + if (i->_cooked_size == 0) + i->_cooked_size = i->_raw_size; + } + else + { + bfd_boolean again; + + if (! bfd_relax_section (i->owner, i, &link_info, &again)) + einfo (_("%P%F: can't relax section: %E\n")); + if (again) + *relax = TRUE; + } + dot = size_input_section (prev, output_section_statement, + output_section_statement->fill, dot); + } + break; + case lang_input_statement_enum: + break; + case lang_fill_statement_enum: + s->fill_statement.output_section = + output_section_statement->bfd_section; + + fill = s->fill_statement.fill; + break; + case lang_assignment_statement_enum: + { + bfd_vma newdot = dot; + + exp_fold_tree (s->assignment_statement.exp, + output_section_statement, + lang_allocating_phase_enum, + dot, + &newdot); + + if (newdot != dot) + { + if (output_section_statement == abs_output_section) + { + /* If we don't have an output section, then just adjust + the default memory address. */ + lang_memory_region_lookup ("*default*")->current = newdot; + } + else + { + /* Insert a pad after this statement. We can't + put the pad before when relaxing, in case the + assignment references dot. */ + insert_pad (&s->header.next, fill, (newdot - dot) * opb, + output_section_statement->bfd_section, dot); + + /* Don't neuter the pad below when relaxing. */ + s = s->header.next; + } + + dot = newdot; + } + } + break; + + case lang_padding_statement_enum: + /* If this is the first time lang_size_sections is called, + we won't have any padding statements. If this is the + second or later passes when relaxing, we should allow + padding to shrink. If padding is needed on this pass, it + will be added back in. */ + s->padding_statement.size = 0; + + /* Make sure output_offset is valid. If relaxation shrinks + the section and this pad isn't needed, it's possible to + have output_offset larger than the final size of the + section. bfd_set_section_contents will complain even for + a pad size of zero. */ + s->padding_statement.output_offset + = dot - output_section_statement->bfd_section->vma; + break; + + case lang_group_statement_enum: + dot = lang_size_sections_1 (s->group_statement.children.head, + output_section_statement, + &s->group_statement.children.head, + fill, dot, relax, check_regions); + break; + + default: + FAIL (); + break; + + /* We can only get here when relaxing is turned on. */ + case lang_address_statement_enum: + break; + } + prev = &s->header.next; + } + return dot; +} + +bfd_vma +lang_size_sections (s, output_section_statement, prev, fill, dot, relax, + check_regions) + lang_statement_union_type *s; + lang_output_section_statement_type *output_section_statement; + lang_statement_union_type **prev; + fill_type *fill; + bfd_vma dot; + bfd_boolean *relax; + bfd_boolean check_regions; +{ + bfd_vma result; + + exp_data_seg.phase = exp_dataseg_none; + result = lang_size_sections_1 (s, output_section_statement, prev, fill, + dot, relax, check_regions); + if (exp_data_seg.phase == exp_dataseg_end_seen) + { + /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether + a page could be saved in the data segment. */ + bfd_vma first, last; + + first = -exp_data_seg.base & (exp_data_seg.pagesize - 1); + last = exp_data_seg.end & (exp_data_seg.pagesize - 1); + if (first && last + && ((exp_data_seg.base & ~(exp_data_seg.pagesize - 1)) + != (exp_data_seg.end & ~(exp_data_seg.pagesize - 1))) + && first + last <= exp_data_seg.pagesize) + { + exp_data_seg.phase = exp_dataseg_adjust; + result = lang_size_sections_1 (s, output_section_statement, prev, + fill, dot, relax, check_regions); + } + } + + return result; +} + +bfd_vma +lang_do_assignments (s, output_section_statement, fill, dot) + lang_statement_union_type *s; + lang_output_section_statement_type *output_section_statement; + fill_type *fill; + bfd_vma dot; +{ + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) + { + switch (s->header.type) + { + case lang_constructors_statement_enum: + dot = lang_do_assignments (constructor_list.head, + output_section_statement, + fill, + dot); + break; + + case lang_output_section_statement_enum: + { + lang_output_section_statement_type *os; + + os = &(s->output_section_statement); + if (os->bfd_section != NULL) + { + dot = os->bfd_section->vma; + (void) lang_do_assignments (os->children.head, os, + os->fill, dot); + dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb; + + } + if (os->load_base) + { + /* If nothing has been placed into the output section then + it won't have a bfd_section. */ + if (os->bfd_section) + { + os->bfd_section->lma + = exp_get_abs_int (os->load_base, 0, "load base", + lang_final_phase_enum); + } + } + } + break; + case lang_wild_statement_enum: + + dot = lang_do_assignments (s->wild_statement.children.head, + output_section_statement, + fill, dot); + + break; + + case lang_object_symbols_statement_enum: + case lang_output_statement_enum: + case lang_target_statement_enum: +#if 0 + case lang_common_statement_enum: +#endif + break; + case lang_data_statement_enum: + { + etree_value_type value; + + value = exp_fold_tree (s->data_statement.exp, + abs_output_section, + lang_final_phase_enum, dot, &dot); + s->data_statement.value = value.value; + if (!value.valid_p) + einfo (_("%F%P: invalid data statement\n")); + } + { + unsigned int size; + switch (s->data_statement.type) + { + default: + abort (); + case QUAD: + case SQUAD: + size = QUAD_SIZE; + break; + case LONG: + size = LONG_SIZE; + break; + case SHORT: + size = SHORT_SIZE; + break; + case BYTE: + size = BYTE_SIZE; + break; + } + if (size < opb) + size = opb; + dot += size / opb; + } + break; + + case lang_reloc_statement_enum: + { + etree_value_type value; + + value = exp_fold_tree (s->reloc_statement.addend_exp, + abs_output_section, + lang_final_phase_enum, dot, &dot); + s->reloc_statement.addend_value = value.value; + if (!value.valid_p) + einfo (_("%F%P: invalid reloc statement\n")); + } + dot += bfd_get_reloc_size (s->reloc_statement.howto) / opb; + break; + + case lang_input_section_enum: + { + asection *in = s->input_section.section; + + if (in->_cooked_size != 0) + dot += in->_cooked_size / opb; + else + dot += in->_raw_size / opb; + } + break; + + case lang_input_statement_enum: + break; + case lang_fill_statement_enum: + fill = s->fill_statement.fill; + break; + case lang_assignment_statement_enum: + { + exp_fold_tree (s->assignment_statement.exp, + output_section_statement, + lang_final_phase_enum, + dot, + &dot); + } + + break; + case lang_padding_statement_enum: + dot += s->padding_statement.size / opb; + break; + + case lang_group_statement_enum: + dot = lang_do_assignments (s->group_statement.children.head, + output_section_statement, + fill, dot); + + break; + + default: + FAIL (); + break; + case lang_address_statement_enum: + break; + } + + } + return dot; +} + +/* Fix any .startof. or .sizeof. symbols. When the assemblers see the + operator .startof. (section_name), it produces an undefined symbol + .startof.section_name. Similarly, when it sees + .sizeof. (section_name), it produces an undefined symbol + .sizeof.section_name. For all the output sections, we look for + such symbols, and set them to the correct value. */ + +static void +lang_set_startof () +{ + asection *s; + + if (link_info.relocateable) + return; + + for (s = output_bfd->sections; s != NULL; s = s->next) + { + const char *secname; + char *buf; + struct bfd_link_hash_entry *h; + + secname = bfd_get_section_name (output_bfd, s); + buf = xmalloc (10 + strlen (secname)); + + sprintf (buf, ".startof.%s", secname); + h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE); + if (h != NULL && h->type == bfd_link_hash_undefined) + { + h->type = bfd_link_hash_defined; + h->u.def.value = bfd_get_section_vma (output_bfd, s); + h->u.def.section = bfd_abs_section_ptr; + } + + sprintf (buf, ".sizeof.%s", secname); + h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE); + if (h != NULL && h->type == bfd_link_hash_undefined) + { + unsigned opb; + + opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + h->type = bfd_link_hash_defined; + if (s->_cooked_size != 0) + h->u.def.value = s->_cooked_size / opb; + else + h->u.def.value = s->_raw_size / opb; + h->u.def.section = bfd_abs_section_ptr; + } + + free (buf); + } +} + +static void +lang_finish () +{ + struct bfd_link_hash_entry *h; + bfd_boolean warn; + + if (link_info.relocateable || link_info.shared) + warn = FALSE; + else + warn = TRUE; + + if (entry_symbol.name == (const char *) NULL) + { + /* No entry has been specified. Look for start, but don't warn + if we don't find it. */ + entry_symbol.name = "start"; + warn = FALSE; + } + + h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name, + FALSE, FALSE, TRUE); + if (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak) + && h->u.def.section->output_section != NULL) + { + bfd_vma val; + + val = (h->u.def.value + + bfd_get_section_vma (output_bfd, + h->u.def.section->output_section) + + h->u.def.section->output_offset); + if (! bfd_set_start_address (output_bfd, val)) + einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name); + } + else + { + bfd_vma val; + const char *send; + + /* We couldn't find the entry symbol. Try parsing it as a + number. */ + val = bfd_scan_vma (entry_symbol.name, &send, 0); + if (*send == '\0') + { + if (! bfd_set_start_address (output_bfd, val)) + einfo (_("%P%F: can't set start address\n")); + } + else + { + asection *ts; + + /* Can't find the entry symbol, and it's not a number. Use + the first address in the text section. */ + ts = bfd_get_section_by_name (output_bfd, entry_section); + if (ts != (asection *) NULL) + { + if (warn) + einfo (_("%P: warning: cannot find entry symbol %s; defaulting to %V\n"), + entry_symbol.name, + bfd_get_section_vma (output_bfd, ts)); + if (! bfd_set_start_address (output_bfd, + bfd_get_section_vma (output_bfd, + ts))) + einfo (_("%P%F: can't set start address\n")); + } + else + { + if (warn) + einfo (_("%P: warning: cannot find entry symbol %s; not setting start address\n"), + entry_symbol.name); + } + } + } +} + +/* This is a small function used when we want to ignore errors from + BFD. */ + +static void +#ifdef ANSI_PROTOTYPES +ignore_bfd_errors (const char *s ATTRIBUTE_UNUSED, ...) +#else +ignore_bfd_errors (s) + const char *s ATTRIBUTE_UNUSED; +#endif +{ + /* Don't do anything. */ +} + +/* Check that the architecture of all the input files is compatible + with the output file. Also call the backend to let it do any + other checking that is needed. */ + +static void +lang_check () +{ + lang_statement_union_type *file; + bfd *input_bfd; + const bfd_arch_info_type *compatible; + + for (file = file_chain.head; + file != (lang_statement_union_type *) NULL; + file = file->input_statement.next) + { + input_bfd = file->input_statement.the_bfd; + compatible = bfd_arch_get_compatible (input_bfd, output_bfd, + command_line.accept_unknown_input_arch); + + /* In general it is not possible to perform a relocatable + link between differing object formats when the input + file has relocations, because the relocations in the + input format may not have equivalent representations in + the output format (and besides BFD does not translate + relocs for other link purposes than a final link). */ + if ((link_info.relocateable || link_info.emitrelocations) + && (compatible == NULL + || bfd_get_flavour (input_bfd) != bfd_get_flavour (output_bfd)) + && (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0) + { + einfo (_("%P%F: Relocatable linking with relocations from format %s (%B) to format %s (%B) is not supported\n"), + bfd_get_target (input_bfd), input_bfd, + bfd_get_target (output_bfd), output_bfd); + /* einfo with %F exits. */ + } + + if (compatible == NULL) + { + if (command_line.warn_mismatch) + einfo (_("%P: warning: %s architecture of input file `%B' is incompatible with %s output\n"), + bfd_printable_name (input_bfd), input_bfd, + bfd_printable_name (output_bfd)); + } + else if (bfd_count_sections (input_bfd)) + { + /* If the input bfd has no contents, it shouldn't set the + private data of the output bfd. */ + + bfd_error_handler_type pfn = NULL; + + /* If we aren't supposed to warn about mismatched input + files, temporarily set the BFD error handler to a + function which will do nothing. We still want to call + bfd_merge_private_bfd_data, since it may set up + information which is needed in the output file. */ + if (! command_line.warn_mismatch) + pfn = bfd_set_error_handler (ignore_bfd_errors); + if (! bfd_merge_private_bfd_data (input_bfd, output_bfd)) + { + if (command_line.warn_mismatch) + einfo (_("%E%X: failed to merge target specific data of file %B\n"), + input_bfd); + } + if (! command_line.warn_mismatch) + bfd_set_error_handler (pfn); + } + } +} + +/* Look through all the global common symbols and attach them to the + correct section. The -sort-common command line switch may be used + to roughly sort the entries by size. */ + +static void +lang_common () +{ + if (command_line.inhibit_common_definition) + return; + if (link_info.relocateable + && ! command_line.force_common_definition) + return; + + if (! config.sort_common) + bfd_link_hash_traverse (link_info.hash, lang_one_common, (PTR) NULL); + else + { + int power; + + for (power = 4; power >= 0; power--) + bfd_link_hash_traverse (link_info.hash, lang_one_common, + (PTR) &power); + } +} + +/* Place one common symbol in the correct section. */ + +static bfd_boolean +lang_one_common (h, info) + struct bfd_link_hash_entry *h; + PTR info; +{ + unsigned int power_of_two; + bfd_vma size; + asection *section; + unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); + + if (h->type != bfd_link_hash_common) + return TRUE; + + size = h->u.c.size; + power_of_two = h->u.c.p->alignment_power; + + if (config.sort_common + && power_of_two < (unsigned int) *(int *) info) + return TRUE; + + section = h->u.c.p->section; + + /* Increase the size of the section. */ + section->_cooked_size = align_n ((section->_cooked_size + opb - 1) / opb, + (bfd_vma) 1 << power_of_two) * opb; + + /* Adjust the alignment if necessary. */ + if (power_of_two > section->alignment_power) + section->alignment_power = power_of_two; + + /* Change the symbol from common to defined. */ + h->type = bfd_link_hash_defined; + h->u.def.section = section; + h->u.def.value = section->_cooked_size; + + /* Increase the size of the section. */ + section->_cooked_size += size; + + /* Make sure the section is allocated in memory, and make sure that + it is no longer a common section. */ + section->flags |= SEC_ALLOC; + section->flags &= ~SEC_IS_COMMON; + + if (config.map_file != NULL) + { + static bfd_boolean header_printed; + int len; + char *name; + char buf[50]; + + if (! header_printed) + { + minfo (_("\nAllocating common symbols\n")); + minfo (_("Common symbol size file\n\n")); + header_printed = TRUE; + } + + name = demangle (h->root.string); + minfo ("%s", name); + len = strlen (name); + free (name); + + if (len >= 19) + { + print_nl (); + len = 0; + } + while (len < 20) + { + print_space (); + ++len; + } + + minfo ("0x"); + if (size <= 0xffffffff) + sprintf (buf, "%lx", (unsigned long) size); + else + sprintf_vma (buf, size); + minfo ("%s", buf); + len = strlen (buf); + + while (len < 16) + { + print_space (); + ++len; + } + + minfo ("%B\n", section->owner); + } + + return TRUE; +} + +/* Run through the input files and ensure that every input section has + somewhere to go. If one is found without a destination then create + an input request and place it into the statement tree. */ + +static void +lang_place_orphans () +{ + LANG_FOR_EACH_INPUT_STATEMENT (file) + { + asection *s; + + for (s = file->the_bfd->sections; + s != (asection *) NULL; + s = s->next) + { + if (s->output_section == (asection *) NULL) + { + /* This section of the file is not attached, root + around for a sensible place for it to go. */ + + if (file->just_syms_flag) + { + abort (); + } + else if (strcmp (s->name, "COMMON") == 0) + { + /* This is a lonely common section which must have + come from an archive. We attach to the section + with the wildcard. */ + if (! link_info.relocateable + || command_line.force_common_definition) + { + if (default_common_section == NULL) + { +#if 0 + /* This message happens when using the + svr3.ifile linker script, so I have + disabled it. */ + info_msg (_("%P: no [COMMON] command, defaulting to .bss\n")); +#endif + default_common_section = + lang_output_section_statement_lookup (".bss"); + + } + lang_add_section (&default_common_section->children, s, + default_common_section, file); + } + } + else if (ldemul_place_orphan (file, s)) + ; + else + { + lang_output_section_statement_type *os; + + os = lang_output_section_statement_lookup (s->name); + lang_add_section (&os->children, s, os, file); + } + } + } + } +} + +void +lang_set_flags (ptr, flags, invert) + lang_memory_region_type *ptr; + const char *flags; + int invert; +{ + flagword *ptr_flags; + + ptr_flags = invert ? &ptr->not_flags : &ptr->flags; + while (*flags) + { + switch (*flags) + { + case 'A': case 'a': + *ptr_flags |= SEC_ALLOC; + break; + + case 'R': case 'r': + *ptr_flags |= SEC_READONLY; + break; + + case 'W': case 'w': + *ptr_flags |= SEC_DATA; + break; + + case 'X': case 'x': + *ptr_flags |= SEC_CODE; + break; + + case 'L': case 'l': + case 'I': case 'i': + *ptr_flags |= SEC_LOAD; + break; + + default: + einfo (_("%P%F: invalid syntax in flags\n")); + break; + } + flags++; + } +} + +/* Call a function on each input file. This function will be called + on an archive, but not on the elements. */ + +void +lang_for_each_input_file (func) + void (*func) PARAMS ((lang_input_statement_type *)); +{ + lang_input_statement_type *f; + + for (f = (lang_input_statement_type *) input_file_chain.head; + f != NULL; + f = (lang_input_statement_type *) f->next_real_file) + func (f); +} + +/* Call a function on each file. The function will be called on all + the elements of an archive which are included in the link, but will + not be called on the archive file itself. */ + +void +lang_for_each_file (func) + void (*func) PARAMS ((lang_input_statement_type *)); +{ + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + func (f); + } +} + +#if 0 + +/* Not used. */ + +void +lang_for_each_input_section (func) + void (*func) PARAMS ((bfd *ab, asection *as)); +{ + LANG_FOR_EACH_INPUT_STATEMENT (f) + { + asection *s; + + for (s = f->the_bfd->sections; + s != (asection *) NULL; + s = s->next) + { + func (f->the_bfd, s); + } + } +} + +#endif + +void +ldlang_add_file (entry) + lang_input_statement_type *entry; +{ + bfd **pp; + + lang_statement_append (&file_chain, + (lang_statement_union_type *) entry, + &entry->next); + + /* The BFD linker needs to have a list of all input BFDs involved in + a link. */ + ASSERT (entry->the_bfd->link_next == (bfd *) NULL); + ASSERT (entry->the_bfd != output_bfd); + for (pp = &link_info.input_bfds; + *pp != (bfd *) NULL; + pp = &(*pp)->link_next) + ; + *pp = entry->the_bfd; + entry->the_bfd->usrdata = (PTR) entry; + bfd_set_gp_size (entry->the_bfd, g_switch_value); + + /* Look through the sections and check for any which should not be + included in the link. We need to do this now, so that we can + notice when the backend linker tries to report multiple + definition errors for symbols which are in sections we aren't + going to link. FIXME: It might be better to entirely ignore + symbols which are defined in sections which are going to be + discarded. This would require modifying the backend linker for + each backend which might set the SEC_LINK_ONCE flag. If we do + this, we should probably handle SEC_EXCLUDE in the same way. */ + + bfd_map_over_sections (entry->the_bfd, section_already_linked, (PTR) entry); +} + +void +lang_add_output (name, from_script) + const char *name; + int from_script; +{ + /* Make -o on command line override OUTPUT in script. */ + if (!had_output_filename || !from_script) + { + output_filename = name; + had_output_filename = TRUE; + } +} + +static lang_output_section_statement_type *current_section; + +static int +topower (x) + int x; +{ + unsigned int i = 1; + int l; + + if (x < 0) + return -1; + + for (l = 0; l < 32; l++) + { + if (i >= (unsigned int) x) + return l; + i <<= 1; + } + + return 0; +} + +lang_output_section_statement_type * +lang_enter_output_section_statement (output_section_statement_name, + address_exp, sectype, block_value, + align, subalign, ebase) + const char *output_section_statement_name; + etree_type *address_exp; + enum section_type sectype; + bfd_vma block_value; + etree_type *align; + etree_type *subalign; + etree_type *ebase; +{ + lang_output_section_statement_type *os; + + current_section = + os = + lang_output_section_statement_lookup (output_section_statement_name); + + /* Add this statement to tree. */ +#if 0 + add_statement (lang_output_section_statement_enum, + output_section_statement); +#endif + /* Make next things chain into subchain of this. */ + + if (os->addr_tree == (etree_type *) NULL) + { + os->addr_tree = address_exp; + } + os->sectype = sectype; + if (sectype != noload_section) + os->flags = SEC_NO_FLAGS; + else + os->flags = SEC_NEVER_LOAD; + os->block_value = block_value ? block_value : 1; + stat_ptr = &os->children; + + os->subsection_alignment = + topower (exp_get_value_int (subalign, -1, "subsection alignment", 0)); + os->section_alignment = + topower (exp_get_value_int (align, -1, "section alignment", 0)); + + os->load_base = ebase; + return os; +} + +void +lang_final () +{ + lang_output_statement_type *new = + new_stat (lang_output_statement, stat_ptr); + + new->name = output_filename; +} + +/* Reset the current counters in the regions. */ + +void +lang_reset_memory_regions () +{ + lang_memory_region_type *p = lang_memory_region_list; + asection *o; + + for (p = lang_memory_region_list; + p != (lang_memory_region_type *) NULL; + p = p->next) + { + p->old_length = (bfd_size_type) (p->current - p->origin); + p->current = p->origin; + } + + for (o = output_bfd->sections; o != NULL; o = o->next) + o->_raw_size = 0; +} + +/* If the wild pattern was marked KEEP, the member sections + should be as well. */ + +static void +gc_section_callback (ptr, sec, section, file, data) + lang_wild_statement_type *ptr; + struct wildcard_list *sec ATTRIBUTE_UNUSED; + asection *section; + lang_input_statement_type *file ATTRIBUTE_UNUSED; + PTR data ATTRIBUTE_UNUSED; +{ + if (ptr->keep_sections) + section->flags |= SEC_KEEP; +} + +/* Handle a wild statement, marking it against GC. */ + +static void +lang_gc_wild (s) + lang_wild_statement_type *s; +{ + walk_wild (s, gc_section_callback, NULL); +} + +/* Iterate over sections marking them against GC. */ + +static void +lang_gc_sections_1 (s) + lang_statement_union_type *s; +{ + for (; s != (lang_statement_union_type *) NULL; s = s->header.next) + { + switch (s->header.type) + { + case lang_wild_statement_enum: + lang_gc_wild (&s->wild_statement); + break; + case lang_constructors_statement_enum: + lang_gc_sections_1 (constructor_list.head); + break; + case lang_output_section_statement_enum: + lang_gc_sections_1 (s->output_section_statement.children.head); + break; + case lang_group_statement_enum: + lang_gc_sections_1 (s->group_statement.children.head); + break; + default: + break; + } + } +} + +static void +lang_gc_sections () +{ + struct bfd_link_hash_entry *h; + ldlang_undef_chain_list_type *ulist; + + /* Keep all sections so marked in the link script. */ + + lang_gc_sections_1 (statement_list.head); + + /* Keep all sections containing symbols undefined on the command-line, + and the section containing the entry symbol. */ + + for (ulist = link_info.gc_sym_list; ulist; ulist = ulist->next) + { + h = bfd_link_hash_lookup (link_info.hash, ulist->name, + FALSE, FALSE, FALSE); + + if (h != (struct bfd_link_hash_entry *) NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak) + && ! bfd_is_abs_section (h->u.def.section)) + { + h->u.def.section->flags |= SEC_KEEP; + } + } + + bfd_gc_sections (output_bfd, &link_info); +} + +void +lang_process () +{ + lang_reasonable_defaults (); + current_target = default_target; + + /* Open the output file. */ + lang_for_each_statement (ldlang_open_output); + + ldemul_create_output_section_statements (); + + /* Add to the hash table all undefineds on the command line. */ + lang_place_undefineds (); + + already_linked_table_init (); + + /* Create a bfd for each input file. */ + current_target = default_target; + open_input_bfds (statement_list.head, FALSE); + + link_info.gc_sym_list = &entry_symbol; + if (entry_symbol.name == NULL) + link_info.gc_sym_list = ldlang_undef_chain_list_head; + + ldemul_after_open (); + + already_linked_table_free (); + + /* Make sure that we're not mixing architectures. We call this + after all the input files have been opened, but before we do any + other processing, so that any operations merge_private_bfd_data + does on the output file will be known during the rest of the + link. */ + lang_check (); + + /* Handle .exports instead of a version script if we're told to do so. */ + if (command_line.version_exports_section) + lang_do_version_exports_section (); + + /* Build all sets based on the information gathered from the input + files. */ + ldctor_build_sets (); + + /* Remove unreferenced sections if asked to. */ + if (command_line.gc_sections) + lang_gc_sections (); + + /* If there were any SEC_MERGE sections, finish their merging, so that + section sizes can be computed. This has to be done after GC of sections, + so that GCed sections are not merged, but before assigning output + sections, since removing whole input sections is hard then. */ + bfd_merge_sections (output_bfd, &link_info); + + /* Size up the common data. */ + lang_common (); + + /* Run through the contours of the script and attach input sections + to the correct output sections. */ + map_input_to_output_sections (statement_list.head, (char *) NULL, + (lang_output_section_statement_type *) NULL); + + /* Find any sections not attached explicitly and handle them. */ + lang_place_orphans (); + + if (! link_info.relocateable) + { + /* Look for a text section and set the readonly attribute in it. */ + asection *found = bfd_get_section_by_name (output_bfd, ".text"); + + if (found != (asection *) NULL) + { + if (config.text_read_only) + found->flags |= SEC_READONLY; + else + found->flags &= ~SEC_READONLY; + } + } + + /* Do anything special before sizing sections. This is where ELF + and other back-ends size dynamic sections. */ + ldemul_before_allocation (); + + if (!link_info.relocateable) + strip_excluded_output_sections (); + + /* We must record the program headers before we try to fix the + section positions, since they will affect SIZEOF_HEADERS. */ + lang_record_phdrs (); + + /* Size up the sections. */ + lang_size_sections (statement_list.head, + abs_output_section, + &statement_list.head, 0, (bfd_vma) 0, NULL, + command_line.relax ? FALSE : TRUE); + + /* Now run around and relax if we can. */ + if (command_line.relax) + { + /* Keep relaxing until bfd_relax_section gives up. */ + bfd_boolean relax_again; + + do + { + lang_reset_memory_regions (); + + relax_again = FALSE; + + /* Note: pe-dll.c does something like this also. If you find + you need to change this code, you probably need to change + pe-dll.c also. DJ */ + + /* Do all the assignments with our current guesses as to + section sizes. */ + lang_do_assignments (statement_list.head, + abs_output_section, + (fill_type *) 0, (bfd_vma) 0); + + /* Perform another relax pass - this time we know where the + globals are, so can make a better guess. */ + lang_size_sections (statement_list.head, + abs_output_section, + &statement_list.head, 0, (bfd_vma) 0, + &relax_again, FALSE); + + /* If the normal relax is done and the relax finalize pass + is not performed yet, we perform another relax pass. */ + if (!relax_again && !link_info.relax_finalizing) + { + link_info.relax_finalizing = TRUE; + relax_again = TRUE; + } + } + while (relax_again); + + /* Final extra sizing to report errors. */ + lang_reset_memory_regions (); + lang_do_assignments (statement_list.head, + abs_output_section, + (fill_type *) 0, (bfd_vma) 0); + lang_size_sections (statement_list.head, + abs_output_section, + & statement_list.head, 0, (bfd_vma) 0, + NULL, TRUE); + } + + /* See if anything special should be done now we know how big + everything is. */ + ldemul_after_allocation (); + + /* Fix any .startof. or .sizeof. symbols. */ + lang_set_startof (); + + /* Do all the assignments, now that we know the final resting places + of all the symbols. */ + + lang_do_assignments (statement_list.head, + abs_output_section, + (fill_type *) 0, (bfd_vma) 0); + + /* Make sure that the section addresses make sense. */ + if (! link_info.relocateable + && command_line.check_section_addresses) + lang_check_section_addresses (); + + /* Final stuffs. */ + + ldemul_finish (); + lang_finish (); +} + +/* EXPORTED TO YACC */ + +void +lang_add_wild (filespec, section_list, keep_sections) + struct wildcard_spec *filespec; + struct wildcard_list *section_list; + bfd_boolean keep_sections; +{ + struct wildcard_list *curr, *next; + lang_wild_statement_type *new; + + /* Reverse the list as the parser puts it back to front. */ + for (curr = section_list, section_list = NULL; + curr != NULL; + section_list = curr, curr = next) + { + if (curr->spec.name != NULL && strcmp (curr->spec.name, "COMMON") == 0) + placed_commons = TRUE; + + next = curr->next; + curr->next = section_list; + } + + if (filespec != NULL && filespec->name != NULL) + { + if (strcmp (filespec->name, "*") == 0) + filespec->name = NULL; + else if (! wildcardp (filespec->name)) + lang_has_input_file = TRUE; + } + + new = new_stat (lang_wild_statement, stat_ptr); + new->filename = NULL; + new->filenames_sorted = FALSE; + if (filespec != NULL) + { + new->filename = filespec->name; + new->filenames_sorted = filespec->sorted; + } + new->section_list = section_list; + new->keep_sections = keep_sections; + lang_list_init (&new->children); +} + +void +lang_section_start (name, address) + const char *name; + etree_type *address; +{ + lang_address_statement_type *ad; + + ad = new_stat (lang_address_statement, stat_ptr); + ad->section_name = name; + ad->address = address; +} + +/* Set the start symbol to NAME. CMDLINE is nonzero if this is called + because of a -e argument on the command line, or zero if this is + called by ENTRY in a linker script. Command line arguments take + precedence. */ + +void +lang_add_entry (name, cmdline) + const char *name; + bfd_boolean cmdline; +{ + if (entry_symbol.name == NULL + || cmdline + || ! entry_from_cmdline) + { + entry_symbol.name = name; + entry_from_cmdline = cmdline; + } +} + +void +lang_add_target (name) + const char *name; +{ + lang_target_statement_type *new = new_stat (lang_target_statement, + stat_ptr); + + new->target = name; + +} + +void +lang_add_map (name) + const char *name; +{ + while (*name) + { + switch (*name) + { + case 'F': + map_option_f = TRUE; + break; + } + name++; + } +} + +void +lang_add_fill (fill) + fill_type *fill; +{ + lang_fill_statement_type *new = new_stat (lang_fill_statement, + stat_ptr); + + new->fill = fill; +} + +void +lang_add_data (type, exp) + int type; + union etree_union *exp; +{ + + lang_data_statement_type *new = new_stat (lang_data_statement, + stat_ptr); + + new->exp = exp; + new->type = type; + +} + +/* Create a new reloc statement. RELOC is the BFD relocation type to + generate. HOWTO is the corresponding howto structure (we could + look this up, but the caller has already done so). SECTION is the + section to generate a reloc against, or NAME is the name of the + symbol to generate a reloc against. Exactly one of SECTION and + NAME must be NULL. ADDEND is an expression for the addend. */ + +void +lang_add_reloc (reloc, howto, section, name, addend) + bfd_reloc_code_real_type reloc; + reloc_howto_type *howto; + asection *section; + const char *name; + union etree_union *addend; +{ + lang_reloc_statement_type *p = new_stat (lang_reloc_statement, stat_ptr); + + p->reloc = reloc; + p->howto = howto; + p->section = section; + p->name = name; + p->addend_exp = addend; + + p->addend_value = 0; + p->output_section = NULL; + p->output_vma = 0; +} + +lang_assignment_statement_type * +lang_add_assignment (exp) + etree_type *exp; +{ + lang_assignment_statement_type *new = new_stat (lang_assignment_statement, + stat_ptr); + + new->exp = exp; + return new; +} + +void +lang_add_attribute (attribute) + enum statement_enum attribute; +{ + new_statement (attribute, sizeof (lang_statement_union_type), stat_ptr); +} + +void +lang_startup (name) + const char *name; +{ + if (startup_file != (char *) NULL) + { + einfo (_("%P%Fmultiple STARTUP files\n")); + } + first_file->filename = name; + first_file->local_sym_name = name; + first_file->real = TRUE; + + startup_file = name; +} + +void +lang_float (maybe) + bfd_boolean maybe; +{ + lang_float_flag = maybe; +} + + +/* Work out the load- and run-time regions from a script statement, and + store them in *LMA_REGION and *REGION respectively. + + MEMSPEC is the name of the run-time region, or "*default*" if the + statement didn't specify one. LMA_MEMSPEC is the name of the + load-time region, or null if the statement didn't specify one. + HAVE_LMA_P is TRUE if the statement had an explicit load address. + + It is an error to specify both a load region and a load address. */ + +static void +lang_get_regions (region, lma_region, memspec, lma_memspec, have_lma_p) + struct memory_region_struct **region, **lma_region; + const char *memspec, *lma_memspec; + int have_lma_p; +{ + *lma_region = lang_memory_region_lookup (lma_memspec); + + /* If no runtime region has been given, but the load region has + been, use the load region. */ + if (lma_memspec != 0 && strcmp (memspec, "*default*") == 0) + *region = *lma_region; + else + *region = lang_memory_region_lookup (memspec); + + if (have_lma_p && lma_memspec != 0) + einfo (_("%X%P:%S: section has both a load address and a load region\n")); +} + +void +lang_leave_output_section_statement (fill, memspec, phdrs, lma_memspec) + fill_type *fill; + const char *memspec; + struct lang_output_section_phdr_list *phdrs; + const char *lma_memspec; +{ + lang_get_regions (¤t_section->region, + ¤t_section->lma_region, + memspec, lma_memspec, + current_section->load_base != 0); + current_section->fill = fill; + current_section->phdrs = phdrs; + stat_ptr = &statement_list; +} + +/* Create an absolute symbol with the given name with the value of the + address of first byte of the section named. + + If the symbol already exists, then do nothing. */ + +void +lang_abs_symbol_at_beginning_of (secname, name) + const char *secname; + const char *name; +{ + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE); + if (h == (struct bfd_link_hash_entry *) NULL) + einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); + + if (h->type == bfd_link_hash_new + || h->type == bfd_link_hash_undefined) + { + asection *sec; + + h->type = bfd_link_hash_defined; + + sec = bfd_get_section_by_name (output_bfd, secname); + if (sec == (asection *) NULL) + h->u.def.value = 0; + else + h->u.def.value = bfd_get_section_vma (output_bfd, sec); + + h->u.def.section = bfd_abs_section_ptr; + } +} + +/* Create an absolute symbol with the given name with the value of the + address of the first byte after the end of the section named. + + If the symbol already exists, then do nothing. */ + +void +lang_abs_symbol_at_end_of (secname, name) + const char *secname; + const char *name; +{ + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE); + if (h == (struct bfd_link_hash_entry *) NULL) + einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); + + if (h->type == bfd_link_hash_new + || h->type == bfd_link_hash_undefined) + { + asection *sec; + + h->type = bfd_link_hash_defined; + + sec = bfd_get_section_by_name (output_bfd, secname); + if (sec == (asection *) NULL) + h->u.def.value = 0; + else + h->u.def.value = (bfd_get_section_vma (output_bfd, sec) + + bfd_section_size (output_bfd, sec) / + bfd_octets_per_byte (output_bfd)); + + h->u.def.section = bfd_abs_section_ptr; + } +} + +void +lang_statement_append (list, element, field) + lang_statement_list_type *list; + lang_statement_union_type *element; + lang_statement_union_type **field; +{ + *(list->tail) = element; + list->tail = field; +} + +/* Set the output format type. -oformat overrides scripts. */ + +void +lang_add_output_format (format, big, little, from_script) + const char *format; + const char *big; + const char *little; + int from_script; +{ + if (output_target == NULL || !from_script) + { + if (command_line.endian == ENDIAN_BIG + && big != NULL) + format = big; + else if (command_line.endian == ENDIAN_LITTLE + && little != NULL) + format = little; + + output_target = format; + } +} + +/* Enter a group. This creates a new lang_group_statement, and sets + stat_ptr to build new statements within the group. */ + +void +lang_enter_group () +{ + lang_group_statement_type *g; + + g = new_stat (lang_group_statement, stat_ptr); + lang_list_init (&g->children); + stat_ptr = &g->children; +} + +/* Leave a group. This just resets stat_ptr to start writing to the + regular list of statements again. Note that this will not work if + groups can occur inside anything else which can adjust stat_ptr, + but currently they can't. */ + +void +lang_leave_group () +{ + stat_ptr = &statement_list; +} + +/* Add a new program header. This is called for each entry in a PHDRS + command in a linker script. */ + +void +lang_new_phdr (name, type, filehdr, phdrs, at, flags) + const char *name; + etree_type *type; + bfd_boolean filehdr; + bfd_boolean phdrs; + etree_type *at; + etree_type *flags; +{ + struct lang_phdr *n, **pp; + + n = (struct lang_phdr *) stat_alloc (sizeof (struct lang_phdr)); + n->next = NULL; + n->name = name; + n->type = exp_get_value_int (type, 0, "program header type", + lang_final_phase_enum); + n->filehdr = filehdr; + n->phdrs = phdrs; + n->at = at; + n->flags = flags; + + for (pp = &lang_phdr_list; *pp != NULL; pp = &(*pp)->next) + ; + *pp = n; +} + +/* Record the program header information in the output BFD. FIXME: We + should not be calling an ELF specific function here. */ + +static void +lang_record_phdrs () +{ + unsigned int alc; + asection **secs; + struct lang_output_section_phdr_list *last; + struct lang_phdr *l; + lang_statement_union_type *u; + + alc = 10; + secs = (asection **) xmalloc (alc * sizeof (asection *)); + last = NULL; + for (l = lang_phdr_list; l != NULL; l = l->next) + { + unsigned int c; + flagword flags; + bfd_vma at; + + c = 0; + for (u = lang_output_section_statement.head; + u != NULL; + u = u->output_section_statement.next) + { + lang_output_section_statement_type *os; + struct lang_output_section_phdr_list *pl; + + os = &u->output_section_statement; + + pl = os->phdrs; + if (pl != NULL) + last = pl; + else + { + if (os->sectype == noload_section + || os->bfd_section == NULL + || (os->bfd_section->flags & SEC_ALLOC) == 0) + continue; + pl = last; + } + + if (os->bfd_section == NULL) + continue; + + for (; pl != NULL; pl = pl->next) + { + if (strcmp (pl->name, l->name) == 0) + { + if (c >= alc) + { + alc *= 2; + secs = ((asection **) + xrealloc (secs, alc * sizeof (asection *))); + } + secs[c] = os->bfd_section; + ++c; + pl->used = TRUE; + } + } + } + + if (l->flags == NULL) + flags = 0; + else + flags = exp_get_vma (l->flags, 0, "phdr flags", + lang_final_phase_enum); + + if (l->at == NULL) + at = 0; + else + at = exp_get_vma (l->at, 0, "phdr load address", + lang_final_phase_enum); + + if (! bfd_record_phdr (output_bfd, l->type, + l->flags != NULL, flags, l->at != NULL, + at, l->filehdr, l->phdrs, c, secs)) + einfo (_("%F%P: bfd_record_phdr failed: %E\n")); + } + + free (secs); + + /* Make sure all the phdr assignments succeeded. */ + for (u = lang_output_section_statement.head; + u != NULL; + u = u->output_section_statement.next) + { + struct lang_output_section_phdr_list *pl; + + if (u->output_section_statement.bfd_section == NULL) + continue; + + for (pl = u->output_section_statement.phdrs; + pl != NULL; + pl = pl->next) + if (! pl->used && strcmp (pl->name, "NONE") != 0) + einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"), + u->output_section_statement.name, pl->name); + } +} + +/* Record a list of sections which may not be cross referenced. */ + +void +lang_add_nocrossref (l) + struct lang_nocrossref *l; +{ + struct lang_nocrossrefs *n; + + n = (struct lang_nocrossrefs *) xmalloc (sizeof *n); + n->next = nocrossref_list; + n->list = l; + nocrossref_list = n; + + /* Set notice_all so that we get informed about all symbols. */ + link_info.notice_all = TRUE; +} + +/* Overlay handling. We handle overlays with some static variables. */ + +/* The overlay virtual address. */ +static etree_type *overlay_vma; + +/* An expression for the maximum section size seen so far. */ +static etree_type *overlay_max; + +/* A list of all the sections in this overlay. */ + +struct overlay_list { + struct overlay_list *next; + lang_output_section_statement_type *os; +}; + +static struct overlay_list *overlay_list; + +/* Start handling an overlay. */ + +void +lang_enter_overlay (vma_expr) + etree_type *vma_expr; +{ + /* The grammar should prevent nested overlays from occurring. */ + ASSERT (overlay_vma == NULL && overlay_max == NULL); + + overlay_vma = vma_expr; +} + +/* Start a section in an overlay. We handle this by calling + lang_enter_output_section_statement with the correct VMA. + lang_leave_overlay sets up the LMA and memory regions. */ + +void +lang_enter_overlay_section (name) + const char *name; +{ + struct overlay_list *n; + etree_type *size; + + lang_enter_output_section_statement (name, overlay_vma, normal_section, + 0, 0, 0, 0); + + /* If this is the first section, then base the VMA of future + sections on this one. This will work correctly even if `.' is + used in the addresses. */ + if (overlay_list == NULL) + overlay_vma = exp_nameop (ADDR, name); + + /* Remember the section. */ + n = (struct overlay_list *) xmalloc (sizeof *n); + n->os = current_section; + n->next = overlay_list; + overlay_list = n; + + size = exp_nameop (SIZEOF, name); + + /* Arrange to work out the maximum section end address. */ + if (overlay_max == NULL) + overlay_max = size; + else + overlay_max = exp_binop (MAX_K, overlay_max, size); +} + +/* Finish a section in an overlay. There isn't any special to do + here. */ + +void +lang_leave_overlay_section (fill, phdrs) + fill_type *fill; + struct lang_output_section_phdr_list *phdrs; +{ + const char *name; + char *clean, *s2; + const char *s1; + char *buf; + + name = current_section->name; + + /* For now, assume that "*default*" is the run-time memory region and + that no load-time region has been specified. It doesn't really + matter what we say here, since lang_leave_overlay will override it. */ + lang_leave_output_section_statement (fill, "*default*", phdrs, 0); + + /* Define the magic symbols. */ + + clean = xmalloc (strlen (name) + 1); + s2 = clean; + for (s1 = name; *s1 != '\0'; s1++) + if (ISALNUM (*s1) || *s1 == '_') + *s2++ = *s1; + *s2 = '\0'; + + buf = xmalloc (strlen (clean) + sizeof "__load_start_"); + sprintf (buf, "__load_start_%s", clean); + lang_add_assignment (exp_assop ('=', buf, + exp_nameop (LOADADDR, name))); + + buf = xmalloc (strlen (clean) + sizeof "__load_stop_"); + sprintf (buf, "__load_stop_%s", clean); + lang_add_assignment (exp_assop ('=', buf, + exp_binop ('+', + exp_nameop (LOADADDR, name), + exp_nameop (SIZEOF, name)))); + + free (clean); +} + +/* Finish an overlay. If there are any overlay wide settings, this + looks through all the sections in the overlay and sets them. */ + +void +lang_leave_overlay (lma_expr, nocrossrefs, fill, memspec, phdrs, lma_memspec) + etree_type *lma_expr; + int nocrossrefs; + fill_type *fill; + const char *memspec; + struct lang_output_section_phdr_list *phdrs; + const char *lma_memspec; +{ + lang_memory_region_type *region; + lang_memory_region_type *lma_region; + struct overlay_list *l; + struct lang_nocrossref *nocrossref; + + lang_get_regions (®ion, &lma_region, + memspec, lma_memspec, + lma_expr != 0); + + nocrossref = NULL; + + /* After setting the size of the last section, set '.' to end of the + overlay region. */ + if (overlay_list != NULL) + overlay_list->os->update_dot_tree + = exp_assop ('=', ".", exp_binop ('+', overlay_vma, overlay_max)); + + l = overlay_list; + while (l != NULL) + { + struct overlay_list *next; + + if (fill != (fill_type *) 0 && l->os->fill == (fill_type *) 0) + l->os->fill = fill; + + l->os->region = region; + l->os->lma_region = lma_region; + + /* The first section has the load address specified in the + OVERLAY statement. The rest are worked out from that. + The base address is not needed (and should be null) if + an LMA region was specified. */ + if (l->next == 0) + l->os->load_base = lma_expr; + else if (lma_region == 0) + l->os->load_base = exp_binop ('+', + exp_nameop (LOADADDR, l->next->os->name), + exp_nameop (SIZEOF, l->next->os->name)); + + if (phdrs != NULL && l->os->phdrs == NULL) + l->os->phdrs = phdrs; + + if (nocrossrefs) + { + struct lang_nocrossref *nc; + + nc = (struct lang_nocrossref *) xmalloc (sizeof *nc); + nc->name = l->os->name; + nc->next = nocrossref; + nocrossref = nc; + } + + next = l->next; + free (l); + l = next; + } + + if (nocrossref != NULL) + lang_add_nocrossref (nocrossref); + + overlay_vma = NULL; + overlay_list = NULL; + overlay_max = NULL; +} + +/* Version handling. This is only useful for ELF. */ + +/* This global variable holds the version tree that we build. */ + +struct bfd_elf_version_tree *lang_elf_version_info; + +static int +lang_vers_match_lang_c (expr, sym) + struct bfd_elf_version_expr *expr; + const char *sym; +{ + if (expr->pattern[0] == '*' && expr->pattern[1] == '\0') + return 1; + return fnmatch (expr->pattern, sym, 0) == 0; +} + +static int +lang_vers_match_lang_cplusplus (expr, sym) + struct bfd_elf_version_expr *expr; + const char *sym; +{ + char *alt_sym; + int result; + + if (expr->pattern[0] == '*' && expr->pattern[1] == '\0') + return 1; + + alt_sym = cplus_demangle (sym, /* DMGL_NO_TPARAMS */ 0); + if (!alt_sym) + { + /* cplus_demangle (also) returns NULL when it is not a C++ symbol. + Should we early out FALSE in this case? */ + result = fnmatch (expr->pattern, sym, 0) == 0; + } + else + { + result = fnmatch (expr->pattern, alt_sym, 0) == 0; + free (alt_sym); + } + + return result; +} + +static int +lang_vers_match_lang_java (expr, sym) + struct bfd_elf_version_expr *expr; + const char *sym; +{ + char *alt_sym; + int result; + + if (expr->pattern[0] == '*' && expr->pattern[1] == '\0') + return 1; + + alt_sym = cplus_demangle (sym, DMGL_JAVA); + if (!alt_sym) + { + /* cplus_demangle (also) returns NULL when it is not a Java symbol. + Should we early out FALSE in this case? */ + result = fnmatch (expr->pattern, sym, 0) == 0; + } + else + { + result = fnmatch (expr->pattern, alt_sym, 0) == 0; + free (alt_sym); + } + + return result; +} + +/* This is called for each variable name or match expression. */ + +struct bfd_elf_version_expr * +lang_new_vers_pattern (orig, new, lang) + struct bfd_elf_version_expr *orig; + const char *new; + const char *lang; +{ + struct bfd_elf_version_expr *ret; + + ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret); + ret->next = orig; + ret->pattern = new; + ret->symver = 0; + ret->script = 0; + + if (lang == NULL || strcasecmp (lang, "C") == 0) + ret->match = lang_vers_match_lang_c; + else if (strcasecmp (lang, "C++") == 0) + ret->match = lang_vers_match_lang_cplusplus; + else if (strcasecmp (lang, "Java") == 0) + ret->match = lang_vers_match_lang_java; + else + { + einfo (_("%X%P: unknown language `%s' in version information\n"), + lang); + ret->match = lang_vers_match_lang_c; + } + + return ldemul_new_vers_pattern (ret); +} + +/* This is called for each set of variable names and match + expressions. */ + +struct bfd_elf_version_tree * +lang_new_vers_node (globals, locals) + struct bfd_elf_version_expr *globals; + struct bfd_elf_version_expr *locals; +{ + struct bfd_elf_version_tree *ret; + + ret = (struct bfd_elf_version_tree *) xmalloc (sizeof *ret); + ret->next = NULL; + ret->name = NULL; + ret->vernum = 0; + ret->globals = globals; + ret->locals = locals; + ret->deps = NULL; + ret->name_indx = (unsigned int) -1; + ret->used = 0; + return ret; +} + +/* This static variable keeps track of version indices. */ + +static int version_index; + +/* This is called when we know the name and dependencies of the + version. */ + +void +lang_register_vers_node (name, version, deps) + const char *name; + struct bfd_elf_version_tree *version; + struct bfd_elf_version_deps *deps; +{ + struct bfd_elf_version_tree *t, **pp; + struct bfd_elf_version_expr *e1; + + if (name == NULL) + name = ""; + + if ((name[0] == '\0' && lang_elf_version_info != NULL) + || (lang_elf_version_info && lang_elf_version_info->name[0] == '\0')) + { + einfo (_("%X%P: anonymous version tag cannot be combined with other version tags\n")); + free (version); + return; + } + + /* Make sure this node has a unique name. */ + for (t = lang_elf_version_info; t != NULL; t = t->next) + if (strcmp (t->name, name) == 0) + einfo (_("%X%P: duplicate version tag `%s'\n"), name); + + /* Check the global and local match names, and make sure there + aren't any duplicates. */ + + for (e1 = version->globals; e1 != NULL; e1 = e1->next) + { + for (t = lang_elf_version_info; t != NULL; t = t->next) + { + struct bfd_elf_version_expr *e2; + + for (e2 = t->locals; e2 != NULL; e2 = e2->next) + if (strcmp (e1->pattern, e2->pattern) == 0) + einfo (_("%X%P: duplicate expression `%s' in version information\n"), + e1->pattern); + } + } + + for (e1 = version->locals; e1 != NULL; e1 = e1->next) + { + for (t = lang_elf_version_info; t != NULL; t = t->next) + { + struct bfd_elf_version_expr *e2; + + for (e2 = t->globals; e2 != NULL; e2 = e2->next) + if (strcmp (e1->pattern, e2->pattern) == 0) + einfo (_("%X%P: duplicate expression `%s' in version information\n"), + e1->pattern); + } + } + + version->deps = deps; + version->name = name; + if (name[0] != '\0') + { + ++version_index; + version->vernum = version_index; + } + else + version->vernum = 0; + + for (pp = &lang_elf_version_info; *pp != NULL; pp = &(*pp)->next) + ; + *pp = version; +} + +/* This is called when we see a version dependency. */ + +struct bfd_elf_version_deps * +lang_add_vers_depend (list, name) + struct bfd_elf_version_deps *list; + const char *name; +{ + struct bfd_elf_version_deps *ret; + struct bfd_elf_version_tree *t; + + ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret); + ret->next = list; + + for (t = lang_elf_version_info; t != NULL; t = t->next) + { + if (strcmp (t->name, name) == 0) + { + ret->version_needed = t; + return ret; + } + } + + einfo (_("%X%P: unable to find version dependency `%s'\n"), name); + + return ret; +} + +static void +lang_do_version_exports_section () +{ + struct bfd_elf_version_expr *greg = NULL, *lreg; + + LANG_FOR_EACH_INPUT_STATEMENT (is) + { + asection *sec = bfd_get_section_by_name (is->the_bfd, ".exports"); + char *contents, *p; + bfd_size_type len; + + if (sec == NULL) + continue; + + len = bfd_section_size (is->the_bfd, sec); + contents = xmalloc (len); + if (!bfd_get_section_contents (is->the_bfd, sec, contents, 0, len)) + einfo (_("%X%P: unable to read .exports section contents\n"), sec); + + p = contents; + while (p < contents + len) + { + greg = lang_new_vers_pattern (greg, p, NULL); + p = strchr (p, '\0') + 1; + } + + /* Do not free the contents, as we used them creating the regex. */ + + /* Do not include this section in the link. */ + bfd_set_section_flags (is->the_bfd, sec, + bfd_get_section_flags (is->the_bfd, sec) | SEC_EXCLUDE); + } + + lreg = lang_new_vers_pattern (NULL, "*", NULL); + lang_register_vers_node (command_line.version_exports_section, + lang_new_vers_node (greg, lreg), NULL); +} + +void +lang_add_unique (name) + const char *name; +{ + struct unique_sections *ent; + + for (ent = unique_section_list; ent; ent = ent->next) + if (strcmp (ent->name, name) == 0) + return; + + ent = (struct unique_sections *) xmalloc (sizeof *ent); + ent->name = xstrdup (name); + ent->next = unique_section_list; + unique_section_list = ent; +} diff --git a/contrib/binutils-2.14/ld/ldlang.h b/contrib/binutils-2.14/ld/ldlang.h new file mode 100644 index 0000000000..3c4936b7fa --- /dev/null +++ b/contrib/binutils-2.14/ld/ldlang.h @@ -0,0 +1,527 @@ +/* ldlang.h - linker command language support + Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + 2001, 2002, 2003 + Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GLD; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef LDLANG_H +#define LDLANG_H + +typedef enum { + lang_input_file_is_l_enum, + lang_input_file_is_symbols_only_enum, + lang_input_file_is_marker_enum, + lang_input_file_is_fake_enum, + lang_input_file_is_search_file_enum, + lang_input_file_is_file_enum +} lang_input_file_enum_type; + +struct _fill_type { + size_t size; + unsigned char data[1]; +}; + +typedef struct statement_list { + union lang_statement_union *head; + union lang_statement_union **tail; +} lang_statement_list_type; + +typedef struct memory_region_struct { + char *name; + struct memory_region_struct *next; + bfd_vma origin; + bfd_size_type length; + bfd_vma current; + bfd_size_type old_length; + flagword flags; + flagword not_flags; + bfd_boolean had_full_message; +} lang_memory_region_type; + +typedef struct lang_statement_header_struct { + union lang_statement_union *next; + enum statement_enum { + lang_output_section_statement_enum, + lang_assignment_statement_enum, + lang_input_statement_enum, + lang_address_statement_enum, + lang_wild_statement_enum, + lang_input_section_enum, + lang_object_symbols_statement_enum, + lang_fill_statement_enum, + lang_data_statement_enum, + lang_reloc_statement_enum, + lang_target_statement_enum, + lang_output_statement_enum, + lang_padding_statement_enum, + lang_group_statement_enum, + + lang_afile_asection_pair_statement_enum, + lang_constructors_statement_enum + } type; +} lang_statement_header_type; + +typedef struct { + lang_statement_header_type header; + union etree_union *exp; +} lang_assignment_statement_type; + +typedef struct lang_target_statement_struct { + lang_statement_header_type header; + const char *target; +} lang_target_statement_type; + +typedef struct lang_output_statement_struct { + lang_statement_header_type header; + const char *name; +} lang_output_statement_type; + +/* Section types specified in a linker script. */ + +enum section_type { + normal_section, + dsect_section, + copy_section, + noload_section, + info_section, + overlay_section +}; + +/* This structure holds a list of program headers describing segments + in which this section should be placed. */ + +struct lang_output_section_phdr_list { + struct lang_output_section_phdr_list *next; + const char *name; + bfd_boolean used; +}; + +typedef struct lang_output_section_statement_struct { + lang_statement_header_type header; + union etree_union *addr_tree; + lang_statement_list_type children; + const char *memspec; + union lang_statement_union *next; + const char *name; + + bfd_boolean processed; + + asection *bfd_section; + flagword flags; /* Or together of all input sections */ + enum section_type sectype; + struct memory_region_struct *region; + struct memory_region_struct *lma_region; + size_t block_value; + fill_type *fill; + + int subsection_alignment; /* alignment of components */ + int section_alignment; /* alignment of start of section */ + + union etree_union *load_base; + + /* If non-null, an expression to evaluate after setting the section's + size. The expression is evaluated inside REGION (above) with '.' + set to the end of the section. Used in the last overlay section + to move '.' past all the overlaid sections. */ + union etree_union *update_dot_tree; + + struct lang_output_section_phdr_list *phdrs; +} lang_output_section_statement_type; + +typedef struct { + lang_statement_header_type header; +} lang_common_statement_type; + +typedef struct { + lang_statement_header_type header; +} lang_object_symbols_statement_type; + +typedef struct { + lang_statement_header_type header; + fill_type *fill; + int size; + asection *output_section; +} lang_fill_statement_type; + +typedef struct { + lang_statement_header_type header; + unsigned int type; + union etree_union *exp; + bfd_vma value; + asection *output_section; + bfd_vma output_vma; +} lang_data_statement_type; + +/* Generate a reloc in the output file. */ + +typedef struct { + lang_statement_header_type header; + + /* Reloc to generate. */ + bfd_reloc_code_real_type reloc; + + /* Reloc howto structure. */ + reloc_howto_type *howto; + + /* Section to generate reloc against. Exactly one of section and + name must be NULL. */ + asection *section; + + /* Name of symbol to generate reloc against. Exactly one of section + and name must be NULL. */ + const char *name; + + /* Expression for addend. */ + union etree_union *addend_exp; + + /* Resolved addend. */ + bfd_vma addend_value; + + /* Output section where reloc should be performed. */ + asection *output_section; + + /* VMA within output section. */ + bfd_vma output_vma; +} lang_reloc_statement_type; + +typedef struct lang_input_statement_struct { + lang_statement_header_type header; + /* Name of this file. */ + const char *filename; + /* Name to use for the symbol giving address of text start */ + /* Usually the same as filename, but for a file spec'd with -l + this is the -l switch itself rather than the filename. */ + const char *local_sym_name; + + bfd *the_bfd; + + bfd_boolean closed; + file_ptr passive_position; + + /* Symbol table of the file. */ + asymbol **asymbols; + unsigned int symbol_count; + + /* Point to the next file - whatever it is, wanders up and down + archives */ + + union lang_statement_union *next; + /* Point to the next file, but skips archive contents */ + union lang_statement_union *next_real_file; + + bfd_boolean is_archive; + + /* 1 means search a set of directories for this file. */ + bfd_boolean search_dirs_flag; + + /* 1 means this was found in a search directory marked as sysrooted, + if search_dirs_flag is false, otherwise, that it should be + searched in ld_sysroot before any other location, as long as it + starts with a slash. */ + bfd_boolean sysrooted; + + /* 1 means this is base file of incremental load. + Do not load this file's text or data. + Also default text_start to after this file's bss. */ + + bfd_boolean just_syms_flag; + + /* Whether to search for this entry as a dynamic archive. */ + bfd_boolean dynamic; + + /* Whether to include the entire contents of an archive. */ + bfd_boolean whole_archive; + + bfd_boolean loaded; + +#if 0 + unsigned int globals_in_this_file; +#endif + const char *target; + bfd_boolean real; +} lang_input_statement_type; + +typedef struct { + lang_statement_header_type header; + asection *section; + lang_input_statement_type *ifile; + +} lang_input_section_type; + +typedef struct { + lang_statement_header_type header; + asection *section; + union lang_statement_union *file; +} lang_afile_asection_pair_statement_type; + +typedef struct lang_wild_statement_struct { + lang_statement_header_type header; + const char *filename; + bfd_boolean filenames_sorted; + struct wildcard_list *section_list; + bfd_boolean keep_sections; + lang_statement_list_type children; +} lang_wild_statement_type; + +typedef struct lang_address_statement_struct { + lang_statement_header_type header; + const char *section_name; + union etree_union *address; +} lang_address_statement_type; + +typedef struct { + lang_statement_header_type header; + bfd_vma output_offset; + size_t size; + asection *output_section; + fill_type *fill; +} lang_padding_statement_type; + +/* A group statement collects a set of libraries together. The + libraries are searched multiple times, until no new undefined + symbols are found. The effect is to search a group of libraries as + though they were a single library. */ + +typedef struct { + lang_statement_header_type header; + lang_statement_list_type children; +} lang_group_statement_type; + +typedef union lang_statement_union { + lang_statement_header_type header; + lang_wild_statement_type wild_statement; + lang_data_statement_type data_statement; + lang_reloc_statement_type reloc_statement; + lang_address_statement_type address_statement; + lang_output_section_statement_type output_section_statement; + lang_afile_asection_pair_statement_type afile_asection_pair_statement; + lang_assignment_statement_type assignment_statement; + lang_input_statement_type input_statement; + lang_target_statement_type target_statement; + lang_output_statement_type output_statement; + lang_input_section_type input_section; + lang_common_statement_type common_statement; + lang_object_symbols_statement_type object_symbols_statement; + lang_fill_statement_type fill_statement; + lang_padding_statement_type padding_statement; + lang_group_statement_type group_statement; +} lang_statement_union_type; + +/* This structure holds information about a program header, from the + PHDRS command in the linker script. */ + +struct lang_phdr { + struct lang_phdr *next; + const char *name; + unsigned long type; + bfd_boolean filehdr; + bfd_boolean phdrs; + etree_type *at; + etree_type *flags; +}; + +/* This structure is used to hold a list of sections which may not + cross reference each other. */ + +struct lang_nocrossref { + struct lang_nocrossref *next; + const char *name; +}; + +/* The list of nocrossref lists. */ + +struct lang_nocrossrefs { + struct lang_nocrossrefs *next; + struct lang_nocrossref *list; +}; + +extern struct lang_nocrossrefs *nocrossref_list; + +/* This structure is used to hold a list of input section names which + will not match an output section in the linker script. */ + +struct unique_sections { + struct unique_sections *next; + const char *name; +}; + +extern struct unique_sections *unique_section_list; + +extern lang_output_section_statement_type *abs_output_section; +extern lang_statement_list_type lang_output_section_statement; +extern bfd_boolean lang_has_input_file; +extern etree_type *base; +extern lang_statement_list_type *stat_ptr; +extern bfd_boolean delete_output_file_on_failure; + +extern struct bfd_sym_chain entry_symbol; +extern const char *entry_section; +extern bfd_boolean entry_from_cmdline; +extern lang_statement_list_type file_chain; + +extern void lang_init + PARAMS ((void)); +extern struct memory_region_struct *lang_memory_region_lookup + PARAMS ((const char *const)); +extern struct memory_region_struct *lang_memory_region_default + PARAMS ((asection *)); +extern void lang_map + PARAMS ((void)); +extern void lang_set_flags + PARAMS ((lang_memory_region_type *, const char *, int)); +extern void lang_add_output + PARAMS ((const char *, int from_script)); +extern lang_output_section_statement_type *lang_enter_output_section_statement + PARAMS ((const char *output_section_statement_name, + etree_type *address_exp, + enum section_type sectype, + bfd_vma block_value, + etree_type *align, + etree_type *subalign, + etree_type *)); +extern void lang_final + PARAMS ((void)); +extern void lang_process + PARAMS ((void)); +extern void lang_section_start + PARAMS ((const char *, union etree_union *)); +extern void lang_add_entry + PARAMS ((const char *, bfd_boolean)); +extern void lang_add_target + PARAMS ((const char *)); +extern void lang_add_wild + PARAMS ((struct wildcard_spec *, struct wildcard_list *, bfd_boolean)); +extern void lang_add_map + PARAMS ((const char *)); +extern void lang_add_fill + PARAMS ((fill_type *)); +extern lang_assignment_statement_type * lang_add_assignment + PARAMS ((union etree_union *)); +extern void lang_add_attribute + PARAMS ((enum statement_enum)); +extern void lang_startup + PARAMS ((const char *)); +extern void lang_float + PARAMS ((bfd_boolean)); +extern void lang_leave_output_section_statement + PARAMS ((fill_type *, const char *, struct lang_output_section_phdr_list *, + const char *)); +extern void lang_abs_symbol_at_end_of + PARAMS ((const char *, const char *)); +extern void lang_abs_symbol_at_beginning_of + PARAMS ((const char *, const char *)); +extern void lang_statement_append + PARAMS ((struct statement_list *, union lang_statement_union *, + union lang_statement_union **)); +extern void lang_for_each_input_file + PARAMS ((void (*dothis) (lang_input_statement_type *))); +extern void lang_for_each_file + PARAMS ((void (*dothis) (lang_input_statement_type *))); +extern void lang_reset_memory_regions + PARAMS ((void)); +extern bfd_vma lang_do_assignments + PARAMS ((lang_statement_union_type * s, + lang_output_section_statement_type *output_section_statement, + fill_type *fill, + bfd_vma dot)); + +#define LANG_FOR_EACH_INPUT_STATEMENT(statement) \ + lang_input_statement_type *statement; \ + for (statement = (lang_input_statement_type *) file_chain.head; \ + statement != (lang_input_statement_type *) NULL; \ + statement = (lang_input_statement_type *) statement->next) \ + +extern void lang_process + PARAMS ((void)); +extern void ldlang_add_file + PARAMS ((lang_input_statement_type *)); +extern lang_output_section_statement_type *lang_output_section_find + PARAMS ((const char * const)); +extern lang_input_statement_type *lang_add_input_file + PARAMS ((const char *name, lang_input_file_enum_type file_type, + const char *target)); +extern void lang_add_keepsyms_file + PARAMS ((const char *filename)); +extern lang_output_section_statement_type * + lang_output_section_statement_lookup + PARAMS ((const char * const name)); +extern void ldlang_add_undef + PARAMS ((const char *const name)); +extern void lang_add_output_format + PARAMS ((const char *, const char *, const char *, int from_script)); +extern void lang_list_init + PARAMS ((lang_statement_list_type*)); +extern void lang_add_data + PARAMS ((int type, union etree_union *)); +extern void lang_add_reloc + PARAMS ((bfd_reloc_code_real_type reloc, reloc_howto_type *howto, + asection *section, const char *name, union etree_union *addend)); +extern void lang_for_each_statement + PARAMS ((void (*func) (lang_statement_union_type *))); +extern PTR stat_alloc + PARAMS ((size_t size)); +extern void dprint_statement + PARAMS ((lang_statement_union_type *, int)); +extern bfd_vma lang_size_sections + PARAMS ((lang_statement_union_type *s, + lang_output_section_statement_type *output_section_statement, + lang_statement_union_type **prev, fill_type *fill, + bfd_vma dot, bfd_boolean *relax, bfd_boolean check_regions)); +extern void lang_enter_group + PARAMS ((void)); +extern void lang_leave_group + PARAMS ((void)); +extern void lang_add_section + PARAMS ((lang_statement_list_type *ptr, asection *section, + lang_output_section_statement_type *output, + lang_input_statement_type *file)); +extern void lang_new_phdr + PARAMS ((const char *, etree_type *, bfd_boolean, bfd_boolean, etree_type *, + etree_type *)); +extern void lang_add_nocrossref + PARAMS ((struct lang_nocrossref *)); +extern void lang_enter_overlay + PARAMS ((etree_type *)); +extern void lang_enter_overlay_section + PARAMS ((const char *)); +extern void lang_leave_overlay_section + PARAMS ((fill_type *, struct lang_output_section_phdr_list *)); +extern void lang_leave_overlay + PARAMS ((etree_type *, int, fill_type *, const char *, + struct lang_output_section_phdr_list *, const char *)); + +extern struct bfd_elf_version_tree *lang_elf_version_info; + +extern struct bfd_elf_version_expr *lang_new_vers_pattern + PARAMS ((struct bfd_elf_version_expr *, const char *, const char *)); +extern struct bfd_elf_version_tree *lang_new_vers_node + PARAMS ((struct bfd_elf_version_expr *, struct bfd_elf_version_expr *)); +extern struct bfd_elf_version_deps *lang_add_vers_depend + PARAMS ((struct bfd_elf_version_deps *, const char *)); +extern void lang_register_vers_node + PARAMS ((const char *, struct bfd_elf_version_tree *, + struct bfd_elf_version_deps *)); +bfd_boolean unique_section_p + PARAMS ((const char *)); +extern void lang_add_unique + PARAMS ((const char *)); +extern const char *lang_get_output_target + PARAMS ((void)); + +#endif diff --git a/contrib/binutils-2.14/ld/ldlex.h b/contrib/binutils-2.14/ld/ldlex.h new file mode 100644 index 0000000000..36f2ad309b --- /dev/null +++ b/contrib/binutils-2.14/ld/ldlex.h @@ -0,0 +1,63 @@ +/* ldlex.h - + Copyright 1991, 1992, 1993, 1994, 1995, 1997, 2000 + Free Software Foundation, Inc. + + This file is part of GLD, the Gnu Linker. + + GLD is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 1, or (at your option) + any later version. + + GLD is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GLD; see the file COPYING. If not, write to the Free + Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +#ifndef LDLEX_H +#define LDLEX_H + +#include + +/* The initial parser states. */ +typedef enum input_enum { + input_selected, /* We've set the initial state. */ + input_script, + input_mri_script, + input_version_script, + input_defsym +} input_type; + +extern input_type parser_input; + +extern unsigned int lineno; +extern const char *lex_string; + +/* In ldlex.l. */ +extern int yylex PARAMS ((void)); +extern void lex_push_file PARAMS ((FILE *, const char *)); +extern void lex_redirect PARAMS ((const char *)); +extern void ldlex_script PARAMS ((void)); +extern void ldlex_mri_script PARAMS ((void)); +extern void ldlex_version_script PARAMS ((void)); +extern void ldlex_version_file PARAMS ((void)); +extern void ldlex_defsym PARAMS ((void)); +extern void ldlex_expression PARAMS ((void)); +extern void ldlex_both PARAMS ((void)); +extern void ldlex_command PARAMS ((void)); +extern void ldlex_popstate PARAMS ((void)); + +/* In lexsup.c. */ +extern int lex_input PARAMS ((void)); +extern void lex_unput PARAMS ((int)); +#ifndef yywrap +extern int yywrap PARAMS ((void)); +#endif +extern void parse_args PARAMS ((unsigned, char **)); + +#endif diff --git a/contrib/binutils-2.14/ld/ldlex.l b/contrib/binutils-2.14/ld/ldlex.l new file mode 100644 index 0000000000..c9eb1afe39 --- /dev/null +++ b/contrib/binutils-2.14/ld/ldlex.l @@ -0,0 +1,688 @@ +%{ + +/* Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, + 2000, 2001, 2002 Free Software Foundation, Inc. + +This file is part of GLD, the Gnu Linker. + +GLD is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GLD is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GLD; see the file COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +/* +This was written by steve chamberlain + sac@cygnus.com +*/ + + +#include "ansidecl.h" +#include + +#ifdef MPW +/* Prevent enum redefinition problems. */ +#define TRUE_FALSE_ALREADY_DEFINED +#endif /* MPW */ + +#include "bfd.h" +#include "sysdep.h" +#include "safe-ctype.h" +#include "bfdlink.h" +#include "ld.h" +#include "ldmisc.h" +#include "ldexp.h" +#include "ldlang.h" +#include +#include "ldfile.h" +#include "ldlex.h" +#include "ldmain.h" +#include "libiberty.h" + +/* The type of top-level parser input. + yylex and yyparse (indirectly) both check this. */ +input_type parser_input; + +/* Line number in the current input file. + (FIXME Actually, it doesn't appear to get reset for each file?) */ +unsigned int lineno = 1; + +/* The string we are currently lexing, or NULL if we are reading a + file. */ +const char *lex_string = NULL; + +/* Support for flex reading from more than one input file (stream). + `include_stack' is flex's input state for each open file; + `file_name_stack' is the file names. `lineno_stack' is the current + line numbers. + + If `include_stack_ptr' is 0, we haven't started reading anything yet. + Otherwise, stack elements 0 through `include_stack_ptr - 1' are valid. */ + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) yy_input(buf, &result, max_size) + +#define MAX_INCLUDE_DEPTH 10 +static YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; +static const char *file_name_stack[MAX_INCLUDE_DEPTH]; +static unsigned int lineno_stack[MAX_INCLUDE_DEPTH]; +static unsigned int include_stack_ptr = 0; +static int vers_node_nesting = 0; + +static YY_BUFFER_STATE yy_create_string_buffer PARAMS ((const char *string, + size_t size)); +static void yy_input PARAMS ((char *, int *result, int max_size)); + +static void comment PARAMS ((void)); +static void lex_warn_invalid PARAMS ((char *where, char *what)); + +/* STATES + EXPRESSION definitely in an expression + SCRIPT definitely in a script + BOTH either EXPRESSION or SCRIPT + DEFSYMEXP in an argument to -defsym + MRI in an MRI script + VERS_START starting a Sun style mapfile + VERS_SCRIPT a Sun style mapfile + VERS_NODE a node within a Sun style mapfile +*/ +#define RTOKEN(x) { yylval.token = x; return x; } + +/* Some versions of flex want this. */ +#ifndef yywrap +int yywrap () { return 1; } +#endif +%} + +%a 4000 +%o 5000 + +CMDFILENAMECHAR [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\-\~] +CMDFILENAMECHAR1 [_a-zA-Z0-9\/\.\\_\+\$\:\[\]\\\,\=\&\!\<\>\~] +FILENAMECHAR1 [_a-zA-Z\/\.\\\$\_\~] +SYMBOLCHARN [_a-zA-Z\/\.\\\$\_\~0-9] +FILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~] +WILDCHAR [_a-zA-Z0-9\/\.\-\_\+\=\$\:\[\]\\\,\~\?\*] +WHITE [ \t\n\r]+ + +NOCFILENAMECHAR [_a-zA-Z0-9\/\.\-\_\+\$\:\[\]\\\~] + +V_TAG [.$_a-zA-Z][._a-zA-Z0-9]* +V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^]([*?.$_a-zA-Z0-9\[\]\-\!\^]|::)* + +%s SCRIPT +%s EXPRESSION +%s BOTH +%s DEFSYMEXP +%s MRI +%s VERS_START +%s VERS_SCRIPT +%s VERS_NODE +%% + + if (parser_input != input_selected) + { + /* The first token of the input determines the initial parser state. */ + input_type t = parser_input; + parser_input = input_selected; + switch (t) + { + case input_script: return INPUT_SCRIPT; break; + case input_mri_script: return INPUT_MRI_SCRIPT; break; + case input_version_script: return INPUT_VERSION_SCRIPT; break; + case input_defsym: return INPUT_DEFSYM; break; + default: abort (); + } + } + +"/*" { comment(); } + + +"-" { RTOKEN('-');} +"+" { RTOKEN('+');} +{FILENAMECHAR1}{SYMBOLCHARN}* { yylval.name = xstrdup(yytext); return NAME; } +"=" { RTOKEN('='); } + +"$"([0-9A-Fa-f])+ { + yylval.integer = bfd_scan_vma (yytext+1, 0,16); + yylval.bigint.str = (char *) 0; + return INT; + } + +([0-9A-Fa-f])+(H|h|X|x|B|b|O|o|D|d) { + int ibase ; + switch (yytext[yyleng-1]) { + case 'X': + case 'x': + case 'H': + case 'h': + ibase = 16; + break; + case 'O': + case 'o': + ibase = 8; + break; + case 'B': + case 'b': + ibase = 2; + break; + default: + ibase = 10; + } + yylval.integer = bfd_scan_vma (yytext, 0, + ibase); + yylval.bigint.str = (char *) 0; + return INT; + } +((("$"|0[xX])([0-9A-Fa-f])+)|(([0-9])+))(M|K|m|k)? { + char *s = yytext; + int ibase = 0; + + if (*s == '$') + { + ++s; + ibase = 16; + } + yylval.integer = bfd_scan_vma (s, 0, ibase); + yylval.bigint.str = (char *) 0; + if (yytext[yyleng-1] == 'M' + || yytext[yyleng-1] == 'm') + { + yylval.integer *= 1024 * 1024; + } + else if (yytext[yyleng-1] == 'K' + || yytext[yyleng-1]=='k') + { + yylval.integer *= 1024; + } + else if (yytext[0] == '0' + && (yytext[1] == 'x' + || yytext[1] == 'X')) + { + yylval.bigint.str = xstrdup (yytext + 2); + } + return INT; + } +"]" { RTOKEN(']');} +"[" { RTOKEN('[');} +"<<=" { RTOKEN(LSHIFTEQ);} +">>=" { RTOKEN(RSHIFTEQ);} +"||" { RTOKEN(OROR);} +"==" { RTOKEN(EQ);} +"!=" { RTOKEN(NE);} +">=" { RTOKEN(GE);} +"<=" { RTOKEN(LE);} +"<<" { RTOKEN(LSHIFT);} +">>" { RTOKEN(RSHIFT);} +"+=" { RTOKEN(PLUSEQ);} +"-=" { RTOKEN(MINUSEQ);} +"*=" { RTOKEN(MULTEQ);} +"/=" { RTOKEN(DIVEQ);} +"&=" { RTOKEN(ANDEQ);} +"|=" { RTOKEN(OREQ);} +"&&" { RTOKEN(ANDAND);} +">" { RTOKEN('>');} +"," { RTOKEN(',');} +"&" { RTOKEN('&');} +"|" { RTOKEN('|');} +"~" { RTOKEN('~');} +"!" { RTOKEN('!');} +"?" { RTOKEN('?');} +"*" { RTOKEN('*');} +"+" { RTOKEN('+');} +"-" { RTOKEN('-');} +"/" { RTOKEN('/');} +"%" { RTOKEN('%');} +"<" { RTOKEN('<');} +"=" { RTOKEN('=');} +"}" { RTOKEN('}') ; } +"{" { RTOKEN('{'); } +")" { RTOKEN(')');} +"(" { RTOKEN('(');} +":" { RTOKEN(':'); } +";" { RTOKEN(';');} +"MEMORY" { RTOKEN(MEMORY);} +"ORIGIN" { RTOKEN(ORIGIN);} +"VERSION" { RTOKEN(VERSIONK);} +"BLOCK" { RTOKEN(BLOCK);} +"BIND" { RTOKEN(BIND);} +"LENGTH" { RTOKEN(LENGTH);} +"ALIGN" { RTOKEN(ALIGN_K);} +"DATA_SEGMENT_ALIGN" { RTOKEN(DATA_SEGMENT_ALIGN);} +"DATA_SEGMENT_END" { RTOKEN(DATA_SEGMENT_END);} +"ADDR" { RTOKEN(ADDR);} +"LOADADDR" { RTOKEN(LOADADDR);} +"MAX" { RTOKEN(MAX_K); } +"MIN" { RTOKEN(MIN_K); } +"ASSERT" { RTOKEN(ASSERT_K); } +"ENTRY" { RTOKEN(ENTRY);} +"EXTERN" { RTOKEN(EXTERN);} +"NEXT" { RTOKEN(NEXT);} +"sizeof_headers" { RTOKEN(SIZEOF_HEADERS);} +"SIZEOF_HEADERS" { RTOKEN(SIZEOF_HEADERS);} +"MAP" { RTOKEN(MAP);} +"SIZEOF" { RTOKEN(SIZEOF);} +"TARGET" { RTOKEN(TARGET_K);} +"SEARCH_DIR" { RTOKEN(SEARCH_DIR);} +"OUTPUT" { RTOKEN(OUTPUT);} +"INPUT" { RTOKEN(INPUT);} +"GROUP" { RTOKEN(GROUP);} +"DEFINED" { RTOKEN(DEFINED);} +"CREATE_OBJECT_SYMBOLS" { RTOKEN(CREATE_OBJECT_SYMBOLS);} +"CONSTRUCTORS" { RTOKEN( CONSTRUCTORS);} +"FORCE_COMMON_ALLOCATION" { RTOKEN(FORCE_COMMON_ALLOCATION);} +"INHIBIT_COMMON_ALLOCATION" { RTOKEN(INHIBIT_COMMON_ALLOCATION);} +"SECTIONS" { RTOKEN(SECTIONS);} +"FILL" { RTOKEN(FILL);} +"STARTUP" { RTOKEN(STARTUP);} +"OUTPUT_FORMAT" { RTOKEN(OUTPUT_FORMAT);} +"OUTPUT_ARCH" { RTOKEN( OUTPUT_ARCH);} +"HLL" { RTOKEN(HLL);} +"SYSLIB" { RTOKEN(SYSLIB);} +"FLOAT" { RTOKEN(FLOAT);} +"QUAD" { RTOKEN( QUAD);} +"SQUAD" { RTOKEN( SQUAD);} +"LONG" { RTOKEN( LONG);} +"SHORT" { RTOKEN( SHORT);} +"BYTE" { RTOKEN( BYTE);} +"NOFLOAT" { RTOKEN(NOFLOAT);} +"NOCROSSREFS" { RTOKEN(NOCROSSREFS);} +"OVERLAY" { RTOKEN(OVERLAY); } +"SORT" { RTOKEN(SORT); } +"NOLOAD" { RTOKEN(NOLOAD);} +"DSECT" { RTOKEN(DSECT);} +"COPY" { RTOKEN(COPY);} +"INFO" { RTOKEN(INFO);} +"OVERLAY" { RTOKEN(OVERLAY);} +"o" { RTOKEN(ORIGIN);} +"org" { RTOKEN(ORIGIN);} +"l" { RTOKEN( LENGTH);} +"len" { RTOKEN( LENGTH);} +"INCLUDE" { RTOKEN(INCLUDE);} +"PHDRS" { RTOKEN (PHDRS); } +"AT" { RTOKEN(AT);} +"PROVIDE" { RTOKEN(PROVIDE); } +"KEEP" { RTOKEN(KEEP); } +"EXCLUDE_FILE" { RTOKEN(EXCLUDE_FILE); } +"#".*\n? { ++ lineno; } +"\n" { ++ lineno; RTOKEN(NEWLINE); } +"*".* { /* Mri comment line */ } +";".* { /* Mri comment line */ } +"END" { RTOKEN(ENDWORD); } +"ALIGNMOD" { RTOKEN(ALIGNMOD);} +"ALIGN" { RTOKEN(ALIGN_K);} +"CHIP" { RTOKEN(CHIP); } +"BASE" { RTOKEN(BASE); } +"ALIAS" { RTOKEN(ALIAS); } +"TRUNCATE" { RTOKEN(TRUNCATE); } +"LOAD" { RTOKEN(LOAD); } +"PUBLIC" { RTOKEN(PUBLIC); } +"ORDER" { RTOKEN(ORDER); } +"NAME" { RTOKEN(NAMEWORD); } +"FORMAT" { RTOKEN(FORMAT); } +"CASE" { RTOKEN(CASE); } +"START" { RTOKEN(START); } +"LIST".* { RTOKEN(LIST); /* LIST and ignore to end of line */ } +"SECT" { RTOKEN(SECT); } +"ABSOLUTE" { RTOKEN(ABSOLUTE); } +"end" { RTOKEN(ENDWORD); } +"alignmod" { RTOKEN(ALIGNMOD);} +"align" { RTOKEN(ALIGN_K);} +"chip" { RTOKEN(CHIP); } +"base" { RTOKEN(BASE); } +"alias" { RTOKEN(ALIAS); } +"truncate" { RTOKEN(TRUNCATE); } +"load" { RTOKEN(LOAD); } +"public" { RTOKEN(PUBLIC); } +"order" { RTOKEN(ORDER); } +"name" { RTOKEN(NAMEWORD); } +"format" { RTOKEN(FORMAT); } +"case" { RTOKEN(CASE); } +"extern" { RTOKEN(EXTERN); } +"start" { RTOKEN(START); } +"list".* { RTOKEN(LIST); /* LIST and ignore to end of line */ } +"sect" { RTOKEN(SECT); } +"absolute" { RTOKEN(ABSOLUTE); } + +{FILENAMECHAR1}{NOCFILENAMECHAR}* { +/* Filename without commas, needed to parse mri stuff */ + yylval.name = xstrdup(yytext); + return NAME; + } + + +{FILENAMECHAR1}{FILENAMECHAR}* { + yylval.name = xstrdup(yytext); + return NAME; + } +"-l"{FILENAMECHAR}+ { + yylval.name = xstrdup (yytext + 2); + return LNAME; + } +